mirror of https://github.com/kubernetes/kops.git
250 lines
8.1 KiB
Go
250 lines
8.1 KiB
Go
/*
|
|
Copyright 2019 The Kubernetes Authors.
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
*/
|
|
|
|
package model
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"os"
|
|
"strings"
|
|
|
|
"k8s.io/kops/pkg/apis/kops"
|
|
"k8s.io/kops/upup/pkg/fi"
|
|
"k8s.io/kops/upup/pkg/fi/nodeup/nodetasks"
|
|
)
|
|
|
|
const (
|
|
CloudConfigFilePath = "/etc/kubernetes/cloud.config"
|
|
InTreeCloudConfigFilePath = "/etc/kubernetes/in-tree-cloud.config"
|
|
|
|
// VM UUID is set by cloud-init
|
|
VM_UUID_FILE_PATH = "/etc/vmware/vm_uuid"
|
|
)
|
|
|
|
// azureCloudConfig is the configuration passed to Cloud Provider Azure.
|
|
// The specification is described in https://kubernetes-sigs.github.io/cloud-provider-azure/install/configs/.
|
|
type azureCloudConfig struct {
|
|
// SubscriptionID is the ID of the Azure Subscription that the cluster is deployed in.
|
|
SubscriptionID string `json:"subscriptionId,omitempty"`
|
|
// TenantID is the ID of the tenant that the cluster is deployed in.
|
|
TenantID string `json:"tenantId"`
|
|
// CloudConfigType is the cloud configure type for Azure cloud provider. Supported values are file, secret and merge.
|
|
CloudConfigType string `json:"cloudConfigType,omitempty"`
|
|
// VMType is the type of azure nodes.
|
|
VMType string `json:"vmType,omitempty" yaml:"vmType,omitempty"`
|
|
// ResourceGroup is the name of the resource group that the cluster is deployed in.
|
|
ResourceGroup string `json:"resourceGroup,omitempty"`
|
|
// Location is the location of the resource group that the cluster is deployed in.
|
|
Location string `json:"location,omitempty"`
|
|
// RouteTableName is the name of the route table attached to the subnet that the cluster is deployed in.
|
|
RouteTableName string `json:"routeTableName,omitempty"`
|
|
// VnetName is the name of the virtual network that the cluster is deployed in.
|
|
VnetName string `json:"vnetName"`
|
|
|
|
// UseInstanceMetadata specifies where instance metadata service is used where possible.
|
|
UseInstanceMetadata bool `json:"useInstanceMetadata,omitempty"`
|
|
// UseManagedIdentityExtension specifies where managed service
|
|
// identity is used for the virtual machine to access Azure
|
|
// ARM APIs.
|
|
UseManagedIdentityExtension bool `json:"useManagedIdentityExtension,omitempty"`
|
|
// DisableAvailabilitySetNodes disables VMAS nodes support.
|
|
DisableAvailabilitySetNodes bool `json:"disableAvailabilitySetNodes,omitempty"`
|
|
}
|
|
|
|
// CloudConfigBuilder creates the cloud configuration file
|
|
type CloudConfigBuilder struct {
|
|
*NodeupModelContext
|
|
}
|
|
|
|
var _ fi.ModelBuilder = &CloudConfigBuilder{}
|
|
|
|
func (b *CloudConfigBuilder) Build(c *fi.ModelBuilderContext) error {
|
|
if err := b.build(c, true); err != nil {
|
|
return err
|
|
}
|
|
if err := b.build(c, false); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (b *CloudConfigBuilder) build(c *fi.ModelBuilderContext, inTree bool) error {
|
|
// Add cloud config file if needed
|
|
var lines []string
|
|
|
|
cloudProvider := b.CloudProvider
|
|
cloudConfig := b.Cluster.Spec.CloudConfig
|
|
|
|
if cloudConfig == nil {
|
|
cloudConfig = &kops.CloudConfiguration{}
|
|
}
|
|
|
|
var config string
|
|
requireGlobal := true
|
|
switch cloudProvider {
|
|
case "gce":
|
|
if cloudConfig.NodeTags != nil {
|
|
lines = append(lines, "node-tags = "+*cloudConfig.NodeTags)
|
|
}
|
|
if cloudConfig.NodeInstancePrefix != nil {
|
|
lines = append(lines, "node-instance-prefix = "+*cloudConfig.NodeInstancePrefix)
|
|
}
|
|
if cloudConfig.Multizone != nil {
|
|
lines = append(lines, fmt.Sprintf("multizone = %t", *cloudConfig.Multizone))
|
|
}
|
|
case "aws":
|
|
if cloudConfig.DisableSecurityGroupIngress != nil {
|
|
lines = append(lines, fmt.Sprintf("DisableSecurityGroupIngress = %t", *cloudConfig.DisableSecurityGroupIngress))
|
|
}
|
|
if cloudConfig.ElbSecurityGroup != nil {
|
|
lines = append(lines, "ElbSecurityGroup = "+*cloudConfig.ElbSecurityGroup)
|
|
}
|
|
if !inTree {
|
|
for _, family := range cloudConfig.NodeIPFamilies {
|
|
lines = append(lines, "NodeIPFamilies = "+family)
|
|
}
|
|
}
|
|
case "openstack":
|
|
osc := cloudConfig.Openstack
|
|
if osc == nil {
|
|
break
|
|
}
|
|
// Support mapping of older keystone API
|
|
tenantName := os.Getenv("OS_TENANT_NAME")
|
|
if tenantName == "" {
|
|
tenantName = os.Getenv("OS_PROJECT_NAME")
|
|
}
|
|
tenantID := os.Getenv("OS_TENANT_ID")
|
|
if tenantID == "" {
|
|
tenantID = os.Getenv("OS_PROJECT_ID")
|
|
}
|
|
lines = append(lines,
|
|
fmt.Sprintf("auth-url=\"%s\"", os.Getenv("OS_AUTH_URL")),
|
|
fmt.Sprintf("username=\"%s\"", os.Getenv("OS_USERNAME")),
|
|
fmt.Sprintf("password=\"%s\"", os.Getenv("OS_PASSWORD")),
|
|
fmt.Sprintf("region=\"%s\"", os.Getenv("OS_REGION_NAME")),
|
|
fmt.Sprintf("tenant-id=\"%s\"", tenantID),
|
|
fmt.Sprintf("tenant-name=\"%s\"", tenantName),
|
|
fmt.Sprintf("domain-name=\"%s\"", os.Getenv("OS_DOMAIN_NAME")),
|
|
fmt.Sprintf("domain-id=\"%s\"", os.Getenv("OS_DOMAIN_ID")),
|
|
)
|
|
if b.Cluster.Spec.ExternalCloudControllerManager != nil {
|
|
lines = append(lines,
|
|
fmt.Sprintf("application-credential-id=\"%s\"", os.Getenv("OS_APPLICATION_CREDENTIAL_ID")),
|
|
fmt.Sprintf("application-credential-secret=\"%s\"", os.Getenv("OS_APPLICATION_CREDENTIAL_SECRET")),
|
|
)
|
|
}
|
|
|
|
lines = append(lines,
|
|
"",
|
|
)
|
|
|
|
if lb := osc.Loadbalancer; lb != nil {
|
|
ingressHostnameSuffix := "nip.io"
|
|
if fi.StringValue(lb.IngressHostnameSuffix) != "" {
|
|
ingressHostnameSuffix = fi.StringValue(lb.IngressHostnameSuffix)
|
|
}
|
|
|
|
lines = append(lines,
|
|
"[LoadBalancer]",
|
|
fmt.Sprintf("floating-network-id=%s", fi.StringValue(lb.FloatingNetworkID)),
|
|
fmt.Sprintf("lb-method=%s", fi.StringValue(lb.Method)),
|
|
fmt.Sprintf("lb-provider=%s", fi.StringValue(lb.Provider)),
|
|
fmt.Sprintf("use-octavia=%t", fi.BoolValue(lb.UseOctavia)),
|
|
fmt.Sprintf("manage-security-groups=%t", fi.BoolValue(lb.ManageSecGroups)),
|
|
fmt.Sprintf("enable-ingress-hostname=%t", fi.BoolValue(lb.EnableIngressHostname)),
|
|
fmt.Sprintf("ingress-hostname-suffix=%s", ingressHostnameSuffix),
|
|
"",
|
|
)
|
|
|
|
if monitor := osc.Monitor; monitor != nil {
|
|
lines = append(lines,
|
|
"create-monitor=yes",
|
|
fmt.Sprintf("monitor-delay=%s", fi.StringValue(monitor.Delay)),
|
|
fmt.Sprintf("monitor-timeout=%s", fi.StringValue(monitor.Timeout)),
|
|
fmt.Sprintf("monitor-max-retries=%d", fi.IntValue(monitor.MaxRetries)),
|
|
"",
|
|
)
|
|
}
|
|
}
|
|
|
|
if bs := osc.BlockStorage; bs != nil {
|
|
// Block Storage Config
|
|
lines = append(lines,
|
|
"[BlockStorage]",
|
|
fmt.Sprintf("bs-version=%s", fi.StringValue(bs.Version)),
|
|
fmt.Sprintf("ignore-volume-az=%t", fi.BoolValue(bs.IgnoreAZ)),
|
|
"")
|
|
}
|
|
case "azure":
|
|
requireGlobal = false
|
|
|
|
var region string
|
|
for _, subnet := range b.Cluster.Spec.Subnets {
|
|
if subnet.Region != "" {
|
|
region = subnet.Region
|
|
break
|
|
}
|
|
}
|
|
if region == "" {
|
|
return fmt.Errorf("on Azure, subnets must include Regions")
|
|
}
|
|
|
|
vnetName := b.Cluster.Spec.NetworkID
|
|
if vnetName == "" {
|
|
vnetName = b.Cluster.Name
|
|
}
|
|
|
|
az := b.Cluster.Spec.CloudConfig.Azure
|
|
c := &azureCloudConfig{
|
|
CloudConfigType: "file",
|
|
SubscriptionID: az.SubscriptionID,
|
|
TenantID: az.TenantID,
|
|
Location: region,
|
|
VMType: "vmss",
|
|
ResourceGroup: b.Cluster.AzureResourceGroupName(),
|
|
RouteTableName: az.RouteTableName,
|
|
VnetName: vnetName,
|
|
UseInstanceMetadata: true,
|
|
UseManagedIdentityExtension: true,
|
|
// Disable availability set nodes as we currently use VMSS.
|
|
DisableAvailabilitySetNodes: true,
|
|
}
|
|
data, err := json.Marshal(c)
|
|
if err != nil {
|
|
return fmt.Errorf("error marshalling azure config: %s", err)
|
|
}
|
|
config = string(data)
|
|
}
|
|
|
|
if requireGlobal {
|
|
config = "[global]\n" + strings.Join(lines, "\n") + "\n"
|
|
}
|
|
path := CloudConfigFilePath
|
|
if inTree {
|
|
path = InTreeCloudConfigFilePath
|
|
}
|
|
t := &nodetasks.File{
|
|
Path: path,
|
|
Contents: fi.NewStringResource(config),
|
|
Type: nodetasks.FileType_File,
|
|
}
|
|
c.AddTask(t)
|
|
|
|
return nil
|
|
}
|