Add API client for Azure custom vnet (#271)

* Update vendor for azure vent support

* Add support for Azure custom vnets.

Use pointers intead of values. This allows the client to pass back
returned data from Azure.
This commit is contained in:
Brian Goff
2018-07-25 16:49:39 -07:00
committed by Robbie Zhang
parent 36eb3db8a9
commit 25e454d18f
56 changed files with 36373 additions and 3 deletions

View File

@@ -10,6 +10,8 @@ import (
"errors"
"fmt"
"io"
"io/ioutil"
"net"
"net/http"
"os"
"reflect"
@@ -23,6 +25,7 @@ import (
"github.com/virtual-kubelet/virtual-kubelet/manager"
client "github.com/virtual-kubelet/virtual-kubelet/providers/azure/client"
"github.com/virtual-kubelet/virtual-kubelet/providers/azure/client/aci"
"github.com/virtual-kubelet/virtual-kubelet/providers/azure/client/network"
"k8s.io/api/core/v1"
k8serr "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/api/resource"
@@ -32,10 +35,16 @@ import (
stats "k8s.io/kubernetes/pkg/kubelet/apis/stats/v1alpha1"
)
// The service account secret mount path.
const serviceAccountSecretMountPath = "/var/run/secrets/kubernetes.io/serviceaccount"
const (
// The service account secret mount path.
serviceAccountSecretMountPath = "/var/run/secrets/kubernetes.io/serviceaccount"
const virtualKubeletDNSNameLabel = "virtualkubelet.io/dnsnamelabel"
virtualKubeletDNSNameLabel = "virtualkubelet.io/dnsnamelabel"
subnetsAction = "Microsoft.Network/virtualNetworks/subnets/action"
subnetDelegationService = "Microsoft.ContainerInstance/containerGroups"
networkProfileType = "Microsoft.Network/networkProfiles"
)
// ACIProvider implements the virtual-kubelet provider interface and communicates with Azure's ACI APIs.
type ACIProvider struct {
@@ -51,6 +60,10 @@ type ACIProvider struct {
internalIP string
daemonEndpointPort int32
diagnostics *aci.ContainerGroupDiagnostics
subnetName string
subnetCIDR string
vnetName string
networkProfile string
metricsSync sync.Mutex
metricsSyncTime time.Time
@@ -146,6 +159,8 @@ func NewACIProvider(config string, rm *manager.ResourceManager, nodeName, operat
p.resourceGroup = acsCredential.ResourceGroup
p.region = acsCredential.Region
}
p.vnetName = acsCredential.VNetName
}
if clientID := os.Getenv("AZURE_CLIENT_ID"); clientID != "" {
@@ -225,6 +240,25 @@ func NewACIProvider(config string, rm *manager.ResourceManager, nodeName, operat
p.pods = podsQuota
}
if subnetName := os.Getenv("ACI_SUBNET_NAME"); subnetName != "" {
p.subnetName = subnetName
}
if subnetCIDR := os.Getenv("ACI_SUBNET_CIDR"); subnetCIDR != "" {
if p.subnetName == "" {
return nil, fmt.Errorf("subnet CIDR defined but no subnet name, subnet name is required to set a subnet CIDR")
}
if _, _, err := net.ParseCIDR(subnetCIDR); err != nil {
return nil, fmt.Errorf("error parsing provided subnet range: %v", err)
}
p.subnetCIDR = subnetCIDR
}
if p.subnetName != "" {
if err := p.setupNetworkProfile(azAuth); err != nil {
return nil, fmt.Errorf("error setting up network profile: %v", err)
}
}
p.operatingSystem = operatingSystem
p.nodeName = nodeName
p.internalIP = internalIP
@@ -233,6 +267,103 @@ func NewACIProvider(config string, rm *manager.ResourceManager, nodeName, operat
return &p, err
}
func (p *ACIProvider) setupNetworkProfile(auth *client.Authentication) error {
c, err := network.NewClient(auth)
if err != nil {
return fmt.Errorf("error creating azure networking client: %v", err)
}
createSubnet := true
subnet, err := c.GetSubnet(p.resourceGroup, p.vnetName, p.subnetName)
if err != nil && !network.IsNotFound(err) {
return fmt.Errorf("error while looking up subnet: %v", err)
}
if err == nil {
if p.subnetCIDR != subnet.Properties.AddressPrefix {
return fmt.Errorf("found existing subnet with different CIDR")
}
for _, d := range subnet.Properties.Delegations {
if d.Properties.ServiceName == subnetDelegationService {
createSubnet = false
break
}
}
}
if createSubnet {
if subnet == nil {
subnet = &network.Subnet{Name: p.subnetName}
}
populateSubnet(subnet, p.subnetCIDR)
if err = c.CreateOrUpdateSubnet(p.resourceGroup, p.vnetName, subnet); err != nil {
return fmt.Errorf("error creating subnet: %v", err)
}
}
profile, err := c.GetProfile(p.resourceGroup, p.nodeName)
if err != nil && !network.IsNotFound(err) {
return fmt.Errorf("error while looking up network profile: %v", err)
}
if err == nil {
for _, config := range profile.Properties.ContainerNetworkInterfaceConfigurations {
for _, ipConfig := range config.Properties.IPConfigurations {
if ipConfig.Properties.Subnet.ID == subnet.ID {
return nil
}
}
}
return fmt.Errorf("found existing network profile but the profile is not linked to the subnet")
}
// at this point, profile should be nil
profile = &network.Profile{
Name: p.nodeName,
Type: networkProfileType,
}
populateNetworkProfile(profile, subnet)
if err := c.CreateOrUpdateProfile(p.resourceGroup, profile); err != nil {
return err
}
p.networkProfile = profile.ID
return nil
}
func populateSubnet(s *network.Subnet, cidr string) {
if s.Properties == nil {
s.Properties = &network.SubnetProperties{
AddressPrefix: cidr,
}
}
s.Properties.Delegations = append(s.Properties.Delegations, network.Delegation{
Name: "aciDelegation",
Properties: network.DelegationProperties{
ServiceName: subnetDelegationService,
Actions: []string{subnetsAction},
},
})
}
func populateNetworkProfile(p *network.Profile, subnet *network.Subnet) {
p.Properties.ContainerNetworkInterfaceConfigurations = append(p.Properties.ContainerNetworkInterfaceConfigurations, network.InterfaceConfiguration{
Name: "eth0",
Properties: network.InterfaceConfigurationProperties{
IPConfigurations: []network.IPConfiguration{
{
Name: "ipconfigprofile1",
Properties: network.IPConfigurationProperties{
Subnet: network.ID{
ID: subnet.ID,
},
},
},
},
},
})
}
// CreatePod accepts a Pod definition and creates
// an ACI deployment
func (p *ACIProvider) CreatePod(pod *v1.Pod) error {
@@ -240,6 +371,7 @@ func (p *ACIProvider) CreatePod(pod *v1.Pod) error {
containerGroup.Location = p.region
containerGroup.RestartPolicy = aci.ContainerGroupRestartPolicy(pod.Spec.RestartPolicy)
containerGroup.ContainerGroupProperties.OsType = aci.OperatingSystemTypes(p.OperatingSystem())
containerGroup.NetworkProfile = &aci.NetworkProfileDefinition{ID: p.networkProfile}
// get containers
containers, err := p.getContainers(pod)