Merge pull request #51233 from bowei/add-alias

Automatic merge from submit-queue (batch tested with PRs 51114, 51233, 51024, 51053, 51197)

Add AddAliasToInstance() to gce cloud provider

- Adds AddAliasToInstance() to the GCE cloud provider.
- Adds field "secondary-range-name" to the gce.conf configuration file.

```release-note
NONE
```
pull/6/head
Kubernetes Submit Queue 2017-08-25 06:22:12 -07:00 committed by GitHub
commit c025965db3
3 changed files with 72 additions and 11 deletions

View File

@ -103,6 +103,7 @@ type GCECloud struct {
managedZones []string // List of zones we are spanning (for multi-AZ clusters, primarily when running on master) managedZones []string // List of zones we are spanning (for multi-AZ clusters, primarily when running on master)
networkURL string networkURL string
subnetworkURL string subnetworkURL string
secondaryRangeName string
networkProjectID string networkProjectID string
onXPN bool onXPN bool
nodeTags []string // List of tags to use on firewall rules for load balancers nodeTags []string // List of tags to use on firewall rules for load balancers
@ -143,21 +144,30 @@ type GCEServiceManager struct {
gce *GCECloud gce *GCECloud
} }
// ConfigFile is the struct used to parse the /etc/gce.conf configuration file.
type ConfigFile struct { type ConfigFile struct {
Global struct { Global struct {
TokenURL string `gcfg:"token-url"` TokenURL string `gcfg:"token-url"`
TokenBody string `gcfg:"token-body"` TokenBody string `gcfg:"token-body"`
ProjectID string `gcfg:"project-id"` ProjectID string `gcfg:"project-id"`
NetworkName string `gcfg:"network-name"` NetworkName string `gcfg:"network-name"`
SubnetworkName string `gcfg:"subnetwork-name"` SubnetworkName string `gcfg:"subnetwork-name"`
// SecondaryRangeName is the name of the secondary range to allocate IP
// aliases. The secondary range must be present on the subnetwork the
// cluster is attached to.
SecondaryRangeName string `gcfg:"secondary-range-name"`
NodeTags []string `gcfg:"node-tags"` NodeTags []string `gcfg:"node-tags"`
NodeInstancePrefix string `gcfg:"node-instance-prefix"` NodeInstancePrefix string `gcfg:"node-instance-prefix"`
Multizone bool `gcfg:"multizone"` Multizone bool `gcfg:"multizone"`
// Specifying ApiEndpoint will override the default GCE compute API endpoint. // ApiEndpoint is the GCE compute API endpoint to use. If this is blank,
// then the default endpoint is used.
ApiEndpoint string `gcfg:"api-endpoint"` ApiEndpoint string `gcfg:"api-endpoint"`
LocalZone string `gcfg:"local-zone"` // LocalZone specifies the GCE zone that gce cloud client instance is
// Possible values: List of api names separated by comma. Default to none. // located in (i.e. where the controller will be running). If this is
// For example: MyFeatureFlag // blank, then the local zone will be discovered via the metadata server.
LocalZone string `gcfg:"local-zone"`
// AlphaFeatures is a list of API flags to be enabled. Defaults to none.
// Example API name format: "MyFeatureFlag"
AlphaFeatures []string `gcfg:"alpha-features"` AlphaFeatures []string `gcfg:"alpha-features"`
} }
} }
@ -171,6 +181,7 @@ type CloudConfig struct {
ManagedZones []string ManagedZones []string
NetworkURL string NetworkURL string
SubnetworkURL string SubnetworkURL string
SecondaryRangeName string
NodeTags []string NodeTags []string
NodeInstancePrefix string NodeInstancePrefix string
TokenSource oauth2.TokenSource TokenSource oauth2.TokenSource
@ -313,6 +324,11 @@ func generateCloudConfig(configFile *ConfigFile) (cloudConfig *CloudConfig, err
cloudConfig.SubnetworkURL = gceSubnetworkURL(cloudConfig.ApiEndpoint, cloudConfig.ProjectID, cloudConfig.Region, configFile.Global.SubnetworkName) cloudConfig.SubnetworkURL = gceSubnetworkURL(cloudConfig.ApiEndpoint, cloudConfig.ProjectID, cloudConfig.Region, configFile.Global.SubnetworkName)
} }
} }
if configFile != nil {
cloudConfig.SecondaryRangeName = configFile.Global.SecondaryRangeName
}
return cloudConfig, err return cloudConfig, err
} }
@ -409,6 +425,7 @@ func CreateGCECloud(config *CloudConfig) (*GCECloud, error) {
managedZones: config.ManagedZones, managedZones: config.ManagedZones,
networkURL: config.NetworkURL, networkURL: config.NetworkURL,
subnetworkURL: config.SubnetworkURL, subnetworkURL: config.SubnetworkURL,
secondaryRangeName: config.SecondaryRangeName,
nodeTags: config.NodeTags, nodeTags: config.NodeTags,
nodeInstancePrefix: config.NodeInstancePrefix, nodeInstancePrefix: config.NodeInstancePrefix,
useMetadataServer: config.UseMetadataServer, useMetadataServer: config.UseMetadataServer,

View File

@ -18,6 +18,7 @@ package gce
import ( import (
"fmt" "fmt"
"net"
"net/http" "net/http"
"strconv" "strconv"
"strings" "strings"
@ -25,6 +26,7 @@ import (
"cloud.google.com/go/compute/metadata" "cloud.google.com/go/compute/metadata"
"github.com/golang/glog" "github.com/golang/glog"
computealpha "google.golang.org/api/compute/v0.alpha"
computebeta "google.golang.org/api/compute/v0.beta" computebeta "google.golang.org/api/compute/v0.beta"
compute "google.golang.org/api/compute/v1" compute "google.golang.org/api/compute/v1"
@ -315,6 +317,43 @@ func (gce *GCECloud) AliasRanges(nodeName types.NodeName) (cidrs []string, err e
return return
} }
// AddAliasToInstance adds an alias to the given instance from the named
// secondary range.
func (gce *GCECloud) AddAliasToInstance(nodeName types.NodeName, alias *net.IPNet) error {
v1instance, err := gce.getInstanceByName(mapNodeNameToInstanceName(nodeName))
if err != nil {
return err
}
instance, err := gce.serviceAlpha.Instances.Get(gce.projectID, v1instance.Zone, v1instance.Name).Do()
if err != nil {
return err
}
switch len(instance.NetworkInterfaces) {
case 0:
return fmt.Errorf("Instance %q has no network interfaces", nodeName)
case 1:
default:
glog.Warningf("Instance %q has more than one network interface, using only the first (%v)",
nodeName, instance.NetworkInterfaces)
}
iface := instance.NetworkInterfaces[0]
iface.AliasIpRanges = append(iface.AliasIpRanges, &computealpha.AliasIpRange{
IpCidrRange: alias.String(),
SubnetworkRangeName: gce.secondaryRangeName,
})
mc := newInstancesMetricContext("addalias", v1instance.Zone)
op, err := gce.serviceAlpha.Instances.UpdateNetworkInterface(
gce.projectID, instance.Zone, instance.Name, iface.Name, iface).Do()
if err != nil {
return mc.Observe(err)
}
return gce.waitForZoneOp(op, v1instance.Zone, mc)
}
// Gets the named instances, returning cloudprovider.InstanceNotFound if any instance is not found // Gets the named instances, returning cloudprovider.InstanceNotFound if any instance is not found
func (gce *GCECloud) getInstancesByNames(names []string) ([]*gceInstance, error) { func (gce *GCECloud) getInstancesByNames(names []string) ([]*gceInstance, error) {
instances := make(map[string]*gceInstance) instances := make(map[string]*gceInstance)

View File

@ -18,11 +18,12 @@ package gce
import ( import (
"encoding/json" "encoding/json"
"golang.org/x/oauth2/google"
"reflect" "reflect"
"strings" "strings"
"testing" "testing"
"golang.org/x/oauth2/google"
computealpha "google.golang.org/api/compute/v0.alpha" computealpha "google.golang.org/api/compute/v0.alpha"
computebeta "google.golang.org/api/compute/v0.beta" computebeta "google.golang.org/api/compute/v0.beta"
computev1 "google.golang.org/api/compute/v1" computev1 "google.golang.org/api/compute/v1"
@ -268,6 +269,7 @@ type generateConfigParams struct {
ProjectID string ProjectID string
NetworkName string NetworkName string
SubnetworkName string SubnetworkName string
SecondaryRangeName string
NodeTags []string NodeTags []string
NodeInstancePrefix string NodeInstancePrefix string
Multizone bool Multizone bool
@ -283,6 +285,7 @@ func newGenerateConfigDefaults() *generateConfigParams {
ProjectID: "project-id", ProjectID: "project-id",
NetworkName: "network-name", NetworkName: "network-name",
SubnetworkName: "", SubnetworkName: "",
SecondaryRangeName: "",
NodeTags: []string{"node-tag"}, NodeTags: []string{"node-tag"},
NodeInstancePrefix: "node-prefix", NodeInstancePrefix: "node-prefix",
Multizone: false, Multizone: false,
@ -452,6 +455,7 @@ func TestGenerateCloudConfigs(t *testing.T) {
ProjectID string `gcfg:"project-id"` ProjectID string `gcfg:"project-id"`
NetworkName string `gcfg:"network-name"` NetworkName string `gcfg:"network-name"`
SubnetworkName string `gcfg:"subnetwork-name"` SubnetworkName string `gcfg:"subnetwork-name"`
SecondaryRangeName string `gcfg:"secondary-range-name"`
NodeTags []string `gcfg:"node-tags"` NodeTags []string `gcfg:"node-tags"`
NodeInstancePrefix string `gcfg:"node-instance-prefix"` NodeInstancePrefix string `gcfg:"node-instance-prefix"`
Multizone bool `gcfg:"multizone"` Multizone bool `gcfg:"multizone"`
@ -464,6 +468,7 @@ func TestGenerateCloudConfigs(t *testing.T) {
ProjectID: config.ProjectID, ProjectID: config.ProjectID,
NetworkName: config.NetworkName, NetworkName: config.NetworkName,
SubnetworkName: config.SubnetworkName, SubnetworkName: config.SubnetworkName,
SecondaryRangeName: config.SecondaryRangeName,
NodeTags: config.NodeTags, NodeTags: config.NodeTags,
NodeInstancePrefix: config.NodeInstancePrefix, NodeInstancePrefix: config.NodeInstancePrefix,
Multizone: config.Multizone, Multizone: config.Multizone,
@ -477,7 +482,7 @@ func TestGenerateCloudConfigs(t *testing.T) {
} }
if !reflect.DeepEqual(cloudConfig, tc.cloudConfig) { if !reflect.DeepEqual(cloudConfig, tc.cloudConfig) {
t.Errorf("Expecting cloud config: %v, but got %v", tc.cloudConfig, cloudConfig) t.Errorf("Got %v, want %v", cloudConfig, tc.cloudConfig)
} }
} }
} }