Merge pull request #14996 from johngmyers/topology-cp

Determine default API access method by IG subnet type
This commit is contained in:
Kubernetes Prow Robot 2023-07-18 23:28:04 -07:00 committed by GitHub
commit be2cf1532f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 70 additions and 73 deletions

View File

@ -657,7 +657,7 @@ func RunCreateCluster(ctx context.Context, f *util.Factory, out io.Writer, c *Cr
}
assetBuilder := assets.NewAssetBuilder(clientset.VFSContext(), cluster.Spec.Assets, cluster.Spec.KubernetesVersion, false)
fullCluster, err := cloudup.PopulateClusterSpec(ctx, clientset, cluster, cloud, assetBuilder)
fullCluster, err := cloudup.PopulateClusterSpec(ctx, clientset, cluster, instanceGroups, cloud, assetBuilder)
if err != nil {
return err
}

View File

@ -261,7 +261,7 @@ func updateCluster(ctx context.Context, clientset simple.Clientset, oldCluster,
}
assetBuilder := assets.NewAssetBuilder(clientset.VFSContext(), newCluster.Spec.Assets, newCluster.Spec.KubernetesVersion, false)
fullCluster, err := cloudup.PopulateClusterSpec(ctx, clientset, newCluster, cloud, assetBuilder)
fullCluster, err := cloudup.PopulateClusterSpec(ctx, clientset, newCluster, instanceGroups, cloud, assetBuilder)
if err != nil {
return fmt.Sprintf("error populating cluster spec: %s", err), nil
}

View File

@ -296,7 +296,7 @@ func updateInstanceGroup(ctx context.Context, clientset simple.Clientset, channe
}
assetBuilder := assets.NewAssetBuilder(clientset.VFSContext(), cluster.Spec.Assets, cluster.Spec.KubernetesVersion, false)
fullCluster, err := cloudup.PopulateClusterSpec(ctx, clientset, cluster, cloud, assetBuilder)
fullCluster, err := cloudup.PopulateClusterSpec(ctx, clientset, cluster, []*api.InstanceGroup{newGroup}, cloud, assetBuilder)
if err != nil {
return fmt.Sprintf("error populating cluster spec: %s", err), nil
}

View File

@ -254,7 +254,7 @@ func BuildNodeupModelContext(model *testutils.Model) (*NodeupModelContext, error
return nil, fmt.Errorf("error from PerformAssignments: %v", err)
}
nodeupModelContext.Cluster, err = mockedPopulateClusterSpec(ctx, model.Cluster, cloud)
nodeupModelContext.Cluster, err = mockedPopulateClusterSpec(ctx, model.Cluster, model.InstanceGroups, cloud)
if err != nil {
return nil, fmt.Errorf("unexpected error from mockedPopulateClusterSpec: %v", err)
}
@ -289,7 +289,7 @@ func BuildNodeupModelContext(model *testutils.Model) (*NodeupModelContext, error
return nodeupModelContext, nil
}
func mockedPopulateClusterSpec(ctx context.Context, c *kops.Cluster, cloud fi.Cloud) (*kops.Cluster, error) {
func mockedPopulateClusterSpec(ctx context.Context, c *kops.Cluster, instanceGroups []*kops.InstanceGroup, cloud fi.Cloud) (*kops.Cluster, error) {
vfs.Context.ResetMemfsContext(true)
assetBuilder := assets.NewAssetBuilder(vfs.Context, c.Spec.Assets, c.Spec.KubernetesVersion, false)
@ -298,7 +298,7 @@ func mockedPopulateClusterSpec(ctx context.Context, c *kops.Cluster, cloud fi.Cl
return nil, fmt.Errorf("error building vfspath: %v", err)
}
clientset := vfsclientset.NewVFSClientset(vfs.Context, basePath)
return cloudup.PopulateClusterSpec(ctx, clientset, c, cloud, assetBuilder)
return cloudup.PopulateClusterSpec(ctx, clientset, c, instanceGroups, cloud, assetBuilder)
}
// Fixed cert and key, borrowed from the create_kubecfg_test.go test

View File

@ -18,7 +18,6 @@ package v1alpha2
import (
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/klog/v2"
)
func addDefaultingFuncs(scheme *runtime.Scheme) error {
@ -54,27 +53,6 @@ func SetDefaults_ClusterSpec(obj *ClusterSpec) {
if obj.LegacyAPI == nil {
obj.LegacyAPI = &APISpec{}
}
if obj.LegacyAPI.IsEmpty() {
switch obj.Topology.ControlPlane {
case TopologyPublic:
obj.LegacyAPI.DNS = &DNSAccessSpec{}
case TopologyPrivate:
obj.LegacyAPI.LoadBalancer = &LoadBalancerAccessSpec{}
default:
klog.Infof("unknown master topology type: %q", obj.Topology.ControlPlane)
}
}
if obj.LegacyAPI.LoadBalancer != nil && obj.LegacyAPI.LoadBalancer.Type == "" {
obj.LegacyAPI.LoadBalancer.Type = LoadBalancerTypePublic
}
if obj.LegacyAPI.LoadBalancer != nil && obj.LegacyAPI.LoadBalancer.Class == "" && obj.LegacyCloudProvider == "aws" {
obj.LegacyAPI.LoadBalancer.Class = LoadBalancerClassClassic
}
}
if obj.Authorization == nil {

View File

@ -18,7 +18,6 @@ package v1alpha3
import (
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/klog/v2"
)
func addDefaultingFuncs(scheme *runtime.Scheme) error {
@ -46,30 +45,6 @@ func SetDefaults_ClusterSpec(obj *ClusterSpec) {
obj.Networking.Topology.DNS = DNSTypePublic
}
if obj.CloudProvider.Openstack == nil {
if obj.API.DNS == nil && obj.API.LoadBalancer == nil {
switch obj.Networking.Topology.ControlPlane {
case TopologyPublic:
obj.API.DNS = &DNSAccessSpec{}
case TopologyPrivate:
obj.API.LoadBalancer = &LoadBalancerAccessSpec{}
default:
klog.Infof("unknown controlPlane topology type: %q", obj.Networking.Topology.ControlPlane)
}
}
if obj.API.LoadBalancer != nil && obj.API.LoadBalancer.Type == "" {
obj.API.LoadBalancer.Type = LoadBalancerTypePublic
}
}
if obj.API.LoadBalancer != nil && obj.API.LoadBalancer.Class == "" && obj.CloudProvider.AWS != nil {
obj.API.LoadBalancer.Class = LoadBalancerClassClassic
}
if obj.Authorization == nil {
obj.Authorization = &AuthorizationSpec{}
}

View File

@ -32,13 +32,15 @@ import (
"k8s.io/kops/upup/pkg/fi/cloudup/awsup"
)
func awsValidateCluster(c *kops.Cluster) field.ErrorList {
func awsValidateCluster(c *kops.Cluster, strict bool) field.ErrorList {
allErrs := field.ErrorList{}
if c.Spec.API.LoadBalancer != nil {
lbPath := field.NewPath("spec", "api", "loadBalancer")
lbSpec := c.Spec.API.LoadBalancer
allErrs = append(allErrs, IsValidValue(lbPath.Child("class"), &lbSpec.Class, kops.SupportedLoadBalancerClasses)...)
if strict || lbSpec.Class != "" {
allErrs = append(allErrs, IsValidValue(lbPath.Child("class"), &lbSpec.Class, kops.SupportedLoadBalancerClasses)...)
}
allErrs = append(allErrs, awsValidateTopologyDNS(lbPath.Child("type"), c)...)
allErrs = append(allErrs, awsValidateSecurityGroupOverride(lbPath.Child("securityGroupOverride"), lbSpec)...)
allErrs = append(allErrs, awsValidateAdditionalSecurityGroups(lbPath.Child("additionalSecurityGroups"), lbSpec.AdditionalSecurityGroups)...)

View File

@ -600,7 +600,7 @@ func TestLoadBalancerSubnets(t *testing.T) {
})
}
cluster.Spec.API.LoadBalancer.Subnets = test.lbSubnets
errs := awsValidateCluster(&cluster)
errs := awsValidateCluster(&cluster, true)
testErrors(t, test, errs, test.expected)
}
}
@ -670,7 +670,7 @@ func TestAWSAuthentication(t *testing.T) {
},
},
}
errs := awsValidateCluster(&cluster)
errs := awsValidateCluster(&cluster, true)
testErrors(t, test, errs, test.expected)
}
}

View File

@ -68,7 +68,7 @@ func newValidateCluster(cluster *kops.Cluster, strict bool) field.ErrorList {
// Additional cloud-specific validation rules
switch cluster.Spec.GetCloudProvider() {
case kops.CloudProviderAWS:
allErrs = append(allErrs, awsValidateCluster(cluster)...)
allErrs = append(allErrs, awsValidateCluster(cluster, strict)...)
case kops.CloudProviderGCE:
allErrs = append(allErrs, gceValidateCluster(cluster)...)
}

View File

@ -41,7 +41,7 @@ func UpdateCluster(ctx context.Context, clientset simple.Clientset, cluster *kop
}
assetBuilder := assets.NewAssetBuilder(clientset.VFSContext(), cluster.Spec.Assets, cluster.Spec.KubernetesVersion, false)
fullCluster, err := cloudup.PopulateClusterSpec(ctx, clientset, cluster, cloud, assetBuilder)
fullCluster, err := cloudup.PopulateClusterSpec(ctx, clientset, cluster, instanceGroups, cloud, assetBuilder)
if err != nil {
return err
}
@ -79,7 +79,7 @@ func UpdateInstanceGroup(ctx context.Context, clientset simple.Clientset, cluste
}
assetBuilder := assets.NewAssetBuilder(clientset.VFSContext(), cluster.Spec.Assets, cluster.Spec.KubernetesVersion, false)
fullCluster, err := cloudup.PopulateClusterSpec(ctx, clientset, cluster, cloud, assetBuilder)
fullCluster, err := cloudup.PopulateClusterSpec(ctx, clientset, cluster, allInstanceGroups, cloud, assetBuilder)
if err != nil {
return err
}

View File

@ -61,7 +61,7 @@ func getTestSetupOS(t *testing.T, ctx context.Context) (*RollingUpdateCluster, *
assetBuilder := assets.NewAssetBuilder(vfs.Context, inCluster.Spec.Assets, inCluster.Spec.KubernetesVersion, false)
basePath, _ := vfs.Context.BuildVfsPath(inCluster.Spec.ConfigBase)
clientset := vfsclientset.NewVFSClientset(vfs.Context, basePath)
cluster, err := cloudup.PopulateClusterSpec(ctx, clientset, inCluster, mockcloud, assetBuilder)
cluster, err := cloudup.PopulateClusterSpec(ctx, clientset, inCluster, nil, mockcloud, assetBuilder)
if err != nil {
t.Fatalf("Failed to populate cluster spec: %v", err)
}

View File

@ -2,8 +2,7 @@ metadata:
creationTimestamp: null
name: minimal.example.com
spec:
api:
dns: {}
api: {}
authorization:
alwaysAllow: {}
cloudProvider: {}

View File

@ -2,8 +2,7 @@ metadata:
creationTimestamp: null
name: minimal.example.com
spec:
api:
dns: {}
api: {}
authorization:
alwaysAllow: {}
cloudProvider: {}

View File

@ -2,8 +2,7 @@ metadata:
creationTimestamp: null
name: minimal.example.com
spec:
api:
dns: {}
api: {}
authorization:
alwaysAllow: {}
cloudProvider: {}

View File

@ -815,7 +815,7 @@ func (c *ApplyClusterCmd) Run(ctx context.Context) error {
// upgradeSpecs ensures that fields are fully populated / defaulted
func (c *ApplyClusterCmd) upgradeSpecs(ctx context.Context, assetBuilder *assets.AssetBuilder) error {
fullCluster, err := PopulateClusterSpec(ctx, c.Clientset, c.Cluster, c.Cloud, assetBuilder)
fullCluster, err := PopulateClusterSpec(ctx, c.Clientset, c.Cluster, c.InstanceGroups, c.Cloud, assetBuilder)
if err != nil {
return err
}

View File

@ -44,6 +44,9 @@ type populateClusterSpec struct {
// We build it up into a complete config, but we write the values as input
InputCluster *kopsapi.Cluster
// InputInstanceGroups are the instance groups in the cluster
InputInstanceGroups []*kopsapi.InstanceGroup
// fullCluster holds the built completed cluster spec
fullCluster *kopsapi.Cluster
@ -53,11 +56,12 @@ type populateClusterSpec struct {
// PopulateClusterSpec takes a user-specified cluster spec, and computes the full specification that should be set on the cluster.
// We do this so that we don't need any real "brains" on the node side.
func PopulateClusterSpec(ctx context.Context, clientset simple.Clientset, cluster *kopsapi.Cluster, cloud fi.Cloud, assetBuilder *assets.AssetBuilder) (*kopsapi.Cluster, error) {
func PopulateClusterSpec(ctx context.Context, clientset simple.Clientset, cluster *kopsapi.Cluster, instanceGroups []*kopsapi.InstanceGroup, cloud fi.Cloud, assetBuilder *assets.AssetBuilder) (*kopsapi.Cluster, error) {
c := &populateClusterSpec{
cloud: cloud,
InputCluster: cluster,
assetBuilder: assetBuilder,
cloud: cloud,
InputCluster: cluster,
InputInstanceGroups: instanceGroups,
assetBuilder: assetBuilder,
}
err := c.run(ctx, clientset)
if err != nil {
@ -217,6 +221,47 @@ func (c *populateClusterSpec) run(ctx context.Context, clientset simple.Clientse
klog.V(2).Infof("Normalizing kubernetes version: %q -> %q", cluster.Spec.KubernetesVersion, versionWithoutV)
cluster.Spec.KubernetesVersion = versionWithoutV
}
if cluster.Spec.CloudProvider.Openstack == nil {
if cluster.Spec.API.DNS == nil && cluster.Spec.API.LoadBalancer == nil {
subnetTypesByName := map[string]kopsapi.SubnetType{}
for _, subnet := range cluster.Spec.Networking.Subnets {
subnetTypesByName[subnet.Name] = subnet.Type
}
haveAPIServerNodes := false
for _, ig := range c.InputInstanceGroups {
if ig.Spec.Role == kopsapi.InstanceGroupRoleAPIServer {
haveAPIServerNodes = true
}
}
for _, ig := range c.InputInstanceGroups {
if ig.Spec.Role == kopsapi.InstanceGroupRoleAPIServer || (!haveAPIServerNodes && ig.Spec.Role == kopsapi.InstanceGroupRoleControlPlane) {
for _, subnet := range ig.Spec.Subnets {
switch subnetTypesByName[subnet] {
case kopsapi.SubnetTypePrivate:
cluster.Spec.API.LoadBalancer = &kopsapi.LoadBalancerAccessSpec{}
case kopsapi.SubnetTypePublic:
cluster.Spec.API.DNS = &kopsapi.DNSAccessSpec{}
}
}
}
}
// If both public and private, go with the load balancer.
if cluster.Spec.API.LoadBalancer != nil {
cluster.Spec.API.DNS = nil
}
}
if cluster.Spec.API.LoadBalancer != nil && cluster.Spec.API.LoadBalancer.Type == "" {
cluster.Spec.API.LoadBalancer.Type = kopsapi.LoadBalancerTypePublic
}
}
if cluster.Spec.API.LoadBalancer != nil && cluster.Spec.API.LoadBalancer.Class == "" && cluster.Spec.CloudProvider.AWS != nil {
cluster.Spec.API.LoadBalancer.Class = kopsapi.LoadBalancerClassClassic
}
if cluster.Spec.DNSZone == "" && cluster.PublishesDNSRecords() {
dns, err := cloud.DNS()
if err != nil {

View File

@ -116,7 +116,7 @@ func mockedPopulateClusterSpec(ctx context.Context, c *kopsapi.Cluster, cloud fi
return nil, fmt.Errorf("error building vfspath: %v", err)
}
clientset := vfsclientset.NewVFSClientset(vfs.Context, basePath)
return PopulateClusterSpec(ctx, clientset, c, cloud, assetBuilder)
return PopulateClusterSpec(ctx, clientset, c, nil, cloud, assetBuilder)
}
func TestPopulateCluster_Docker_Spec(t *testing.T) {