diff --git a/bin/images/azure/REGISTRY b/bin/images/azure/REGISTRY index 1be5c30c0e..86aa593bfc 100644 --- a/bin/images/azure/REGISTRY +++ b/bin/images/azure/REGISTRY @@ -1 +1 @@ -eosregistry.azurecr.io/keos/offline \ No newline at end of file +offlineregistry.azurecr.io/keos \ No newline at end of file diff --git a/bin/images/azure/imagenes-cloud-controller.txt b/bin/images/azure/imagenes-cloud-controller.txt index be925266ad..0cbba77bdd 100644 --- a/bin/images/azure/imagenes-cloud-controller.txt +++ b/bin/images/azure/imagenes-cloud-controller.txt @@ -1,2 +1,3 @@ mcr.microsoft.com/oss/kubernetes/azure-cloud-controller-manager:v1.24.22 -mcr.microsoft.com/oss/kubernetes/azure-cloud-controller-manager:v1.26.14 \ No newline at end of file +mcr.microsoft.com/oss/kubernetes/azure-cloud-controller-manager:v1.26.14 +mcr.microsoft.com/oss/kubernetes/azure-cloud-controller-manager:v1.27.8 diff --git a/bin/images/azure/imagenes-cloud-node.txt b/bin/images/azure/imagenes-cloud-node.txt index 9e01bbdd3f..32a3a6a5da 100644 --- a/bin/images/azure/imagenes-cloud-node.txt +++ b/bin/images/azure/imagenes-cloud-node.txt @@ -1,2 +1,3 @@ mcr.microsoft.com/oss/kubernetes/azure-cloud-node-manager:v1.24.22 -mcr.microsoft.com/oss/kubernetes/azure-cloud-node-manager:v1.26.14 \ No newline at end of file +mcr.microsoft.com/oss/kubernetes/azure-cloud-node-manager:v1.26.14 +mcr.microsoft.com/oss/kubernetes/azure-cloud-node-manager:v1.27.8 \ No newline at end of file diff --git a/bin/images/commons/REGISTRY b/bin/images/commons/REGISTRY index 41a81d7923..fb549bb478 100644 --- a/bin/images/commons/REGISTRY +++ b/bin/images/commons/REGISTRY @@ -1,2 +1,3 @@ #963353511234.dkr.ecr.eu-west-1.amazonaws.com/keos/offline -eosregistry.azurecr.io/keos/offline \ No newline at end of file +#eosregistry.azurecr.io/keos/offline +offlineregistry.azurecr.io/keos \ No newline at end of file diff --git a/bin/images/commons/imagenes-cert-manager.txt b/bin/images/commons/imagenes-cert-manager.txt index 9e71989be7..fc343ab52c 100644 --- a/bin/images/commons/imagenes-cert-manager.txt +++ b/bin/images/commons/imagenes-cert-manager.txt @@ -7,4 +7,4 @@ quay.io/jetstack/cert-manager-controller:v1.13.1 quay.io/jetstack/cert-manager-cainjector:v1.13.1 quay.io/jetstack/cert-manager-webhook:v1.13.1 quay.io/jetstack/cert-manager-acmesolver:v1.13.1 -quay.io/jetstack/cert-manager-ctl:v1.13.1 \ No newline at end of file +quay.io/jetstack/cert-manager-ctl:v1.13.1 diff --git a/bin/images/commons/imagenes-kind.txt b/bin/images/commons/imagenes-kind.txt index 23f5e33158..7d3453abab 100644 --- a/bin/images/commons/imagenes-kind.txt +++ b/bin/images/commons/imagenes-kind.txt @@ -1 +1,2 @@ docker.io/kindest/node:v1.27.0 +docker.io/kindest/kindnetd:v20221004-44d545d1 diff --git a/pkg/cluster/internal/create/actions/createworker/createworker.go b/pkg/cluster/internal/create/actions/createworker/createworker.go index f347c98e2a..c1dabbcfc4 100644 --- a/pkg/cluster/internal/create/actions/createworker/createworker.go +++ b/pkg/cluster/internal/create/actions/createworker/createworker.go @@ -38,7 +38,7 @@ type action struct { avoidCreation bool keosCluster commons.KeosCluster clusterCredentials commons.ClusterCredentials - clusterConfig commons.ClusterConfig + clusterConfig *commons.ClusterConfig } type keosRegistry struct { @@ -59,6 +59,7 @@ const ( storageDefaultPath = "/kind/manifests/default-storage.yaml" infraGCPVersion = "v1.4.0" infraAWSVersion = "v2.2.1" + infraAzureVersion = "v1.11.4" ) var PathsToBackupLocally = []string{ @@ -73,7 +74,7 @@ var allowCommonEgressNetPol string var rbacInternalLoadBalancing string // NewAction returns a new action for installing default CAPI -func NewAction(vaultPassword string, descriptorPath string, moveManagement bool, avoidCreation bool, keosCluster commons.KeosCluster, clusterCredentials commons.ClusterCredentials, clusterConfig commons.ClusterConfig) actions.Action { +func NewAction(vaultPassword string, descriptorPath string, moveManagement bool, avoidCreation bool, keosCluster commons.KeosCluster, clusterCredentials commons.ClusterCredentials, clusterConfig *commons.ClusterConfig) actions.Action { return &action{ vaultPassword: vaultPassword, descriptorPath: descriptorPath, @@ -121,13 +122,22 @@ func (a *action) Execute(ctx *actions.ActionContext) error { awsEKSEnabled := a.keosCluster.Spec.InfraProvider == "aws" && a.keosCluster.Spec.ControlPlane.Managed isMachinePool := a.keosCluster.Spec.InfraProvider != "aws" && a.keosCluster.Spec.ControlPlane.Managed - privateParams := PrivateParams{ - KeosCluster: a.keosCluster, - KeosRegUrl: keosRegistry.url, - Private: a.clusterConfig.Spec.Private, + var privateParams PrivateParams + if a.clusterConfig != nil { + privateParams = PrivateParams{ + KeosCluster: a.keosCluster, + KeosRegUrl: keosRegistry.url, + Private: a.clusterConfig.Spec.Private, + } + } else { + privateParams = PrivateParams{ + KeosCluster: a.keosCluster, + KeosRegUrl: keosRegistry.url, + Private: false, + } } - if a.clusterConfig.Spec.Private { + if privateParams.Private { ctx.Status.Start("Installing Private CNI 🎖️") defer ctx.Status.End(false) c = `sed -i 's/@sha256:[[:alnum:]_-].*$//g' ` + cniDefaultFile @@ -222,7 +232,7 @@ func (a *action) Execute(ctx *actions.ActionContext) error { } } - if a.clusterConfig.Spec.Private { + if privateParams.Private { err = provider.deployCertManager(n, keosRegistry.url, "") if err != nil { return err @@ -231,20 +241,36 @@ func (a *action) Execute(ctx *actions.ActionContext) error { c = "echo \"images:\" >> /root/.cluster-api/clusterctl.yaml && " + "echo \" cluster-api:\" >> /root/.cluster-api/clusterctl.yaml && " + "echo \" repository: " + keosRegistry.url + "/cluster-api\" >> /root/.cluster-api/clusterctl.yaml && " + + "echo \" timeout: 10m\" >> /root/.cluster-api/clusterctl.yaml && " + "echo \" bootstrap-kubeadm:\" >> /root/.cluster-api/clusterctl.yaml && " + "echo \" repository: " + keosRegistry.url + "/cluster-api\" >> /root/.cluster-api/clusterctl.yaml && " + + "echo \" timeout: 10m\" >> /root/.cluster-api/clusterctl.yaml && " + "echo \" control-plane-kubeadm:\" >> /root/.cluster-api/clusterctl.yaml && " + "echo \" repository: " + keosRegistry.url + "/cluster-api\" >> /root/.cluster-api/clusterctl.yaml && " + + "echo \" timeout: 10m\" >> /root/.cluster-api/clusterctl.yaml && " + "echo \" infrastructure-aws:\" >> /root/.cluster-api/clusterctl.yaml && " + "echo \" repository: " + keosRegistry.url + "/cluster-api-aws\" >> /root/.cluster-api/clusterctl.yaml && " + "echo \" tag: " + infraAWSVersion + "\" >> /root/.cluster-api/clusterctl.yaml && " + + "echo \" timeout: 10m\" >> /root/.cluster-api/clusterctl.yaml && " + "echo \" infrastructure-gcp:\" >> /root/.cluster-api/clusterctl.yaml && " + "echo \" repository: " + keosRegistry.url + "/cluster-api-gcp\" >> /root/.cluster-api/clusterctl.yaml && " + "echo \" tag: " + infraGCPVersion + "\" >> /root/.cluster-api/clusterctl.yaml && " + + "echo \" timeout: 10m\" >> /root/.cluster-api/clusterctl.yaml && " + "echo \" infrastructure-azure:\" >> /root/.cluster-api/clusterctl.yaml && " + "echo \" repository: " + keosRegistry.url + "/cluster-api-azure\" >> /root/.cluster-api/clusterctl.yaml && " + + "echo \" timeout: 10m\" >> /root/.cluster-api/clusterctl.yaml && " + + "echo \" infrastructure-azure/azureserviceoperator:\" >> /root/.cluster-api/clusterctl.yaml && " + + "echo \" repository: " + keosRegistry.url + "/k8s\" >> /root/.cluster-api/clusterctl.yaml && " + + "echo \" timeout: 10m\" >> /root/.cluster-api/clusterctl.yaml && " + + "echo \" infrastructure-azure/kube-rbac-proxy:\" >> /root/.cluster-api/clusterctl.yaml && " + + "echo \" repository: " + keosRegistry.url + "/kubebuilder\" >> /root/.cluster-api/clusterctl.yaml && " + + "echo \" timeout: 10m\" >> /root/.cluster-api/clusterctl.yaml && " + + "echo \" infrastructure-azure/nmi:\" >> /root/.cluster-api/clusterctl.yaml && " + + "echo \" repository: " + keosRegistry.url + "/oss/azure/aad-pod-identity\" >> /root/.cluster-api/clusterctl.yaml && " + + "echo \" timeout: 10m\" >> /root/.cluster-api/clusterctl.yaml && " + "echo \" cert-manager:\" >> /root/.cluster-api/clusterctl.yaml && " + - "echo \" repository: " + keosRegistry.url + "/cert-manager\" >> /root/.cluster-api/clusterctl.yaml " + "echo \" repository: " + keosRegistry.url + "/cert-manager\" >> /root/.cluster-api/clusterctl.yaml && " + + "echo \" timeout: 10m\" >> /root/.cluster-api/clusterctl.yaml " _, err = commons.ExecuteCommand(n, c) @@ -295,7 +321,7 @@ func (a *action) Execute(ctx *actions.ActionContext) error { ctx.Status.Start("Installing keos cluster operator 💻") defer ctx.Status.End(false) - err = provider.deployClusterOperator(n, privateParams, a.clusterCredentials, keosRegistry, "", true) + err = provider.deployClusterOperator(n, privateParams, a.clusterCredentials, keosRegistry, a.clusterConfig, "", true) if err != nil { return errors.Wrap(err, "failed to deploy cluster operator") } @@ -317,11 +343,20 @@ func (a *action) Execute(ctx *actions.ActionContext) error { ctx.Status.Start("Creating the workload cluster 💥") defer ctx.Status.End(false) + if a.clusterConfig != nil { + // Apply cluster manifests + c = "kubectl apply -f " + manifestsPath + "/clusterconfig.yaml" + _, err = commons.ExecuteCommand(n, c) + if err != nil { + return errors.Wrap(err, "failed to apply clusterconfig manifests") + } + } + // Apply cluster manifests c = "kubectl apply -f " + manifestsPath + "/keoscluster.yaml" _, err = commons.ExecuteCommand(n, c) if err != nil { - return errors.Wrap(err, "failed to apply manifests") + return errors.Wrap(err, "failed to apply keoscluster manifests") } time.Sleep(20 * time.Second) @@ -498,7 +533,7 @@ func (a *action) Execute(ctx *actions.ActionContext) error { ctx.Status.Start("Installing CAPx in workload cluster 🎖️") defer ctx.Status.End(false) - if a.clusterConfig.Spec.Private { + if privateParams.Private { err = provider.deployCertManager(n, keosRegistry.url, kubeconfigPath) if err != nil { return err @@ -592,7 +627,7 @@ func (a *action) Execute(ctx *actions.ActionContext) error { " --set clusterAPIMode=incluster-incluster" + " --set replicaCount=2" - if a.clusterConfig.Spec.Private { + if privateParams.Private { c += " --set image.repository=" + keosRegistry.url + "/autoscaling/cluster-autoscaler" } @@ -607,7 +642,7 @@ func (a *action) Execute(ctx *actions.ActionContext) error { ctx.Status.Start("Installing keos cluster operator in workload cluster 💻") defer ctx.Status.End(false) - err = provider.deployClusterOperator(n, privateParams, a.clusterCredentials, keosRegistry, kubeconfigPath, true) + err = provider.deployClusterOperator(n, privateParams, a.clusterCredentials, keosRegistry, a.clusterConfig, kubeconfigPath, true) if err != nil { return errors.Wrap(err, "failed to deploy cluster operator in workload cluster") } @@ -690,6 +725,30 @@ func (a *action) Execute(ctx *actions.ActionContext) error { return errors.Wrap(err, "failed to wait for keoscluster controller ready") } + if a.clusterConfig != nil { + + c = "kubectl -n " + capiClustersNamespace + " patch clusterconfig " + a.clusterConfig.Metadata.Name + " -p '{\"metadata\":{\"ownerReferences\":null,\"finalizers\":null}}' --type=merge" + _, err = commons.ExecuteCommand(n, c) + if err != nil { + return errors.Wrap(err, "failed to remove clusterconfig ownerReferences and finalizers") + } + + // Move clusterConfig to workload cluster + c = "kubectl -n " + capiClustersNamespace + " get clusterconfig " + a.clusterConfig.Metadata.Name + " -o json | kubectl apply --kubeconfig " + kubeconfigPath + " -f-" + _, err = commons.ExecuteCommand(n, c) + if err != nil { + return errors.Wrap(err, "failed to move clusterconfig to workload cluster") + } + + // Delete clusterconfig in management cluster + c = "kubectl -n " + capiClustersNamespace + " delete clusterconfig " + a.clusterConfig.Metadata.Name + _, err = commons.ExecuteCommand(n, c) + if err != nil { + return errors.Wrap(err, "failed to delete clusterconfig in management cluster") + } + + } + // Move keoscluster to workload cluster c = "kubectl -n " + capiClustersNamespace + " get keoscluster " + a.keosCluster.Metadata.Name + " -o json | jq 'del(.status)' | kubectl apply --kubeconfig " + kubeconfigPath + " -f-" _, err = commons.ExecuteCommand(n, c) @@ -710,24 +769,25 @@ func (a *action) Execute(ctx *actions.ActionContext) error { return errors.Wrap(err, "failed to delete keoscluster in management cluster") } - err = provider.deployClusterOperator(n, privateParams, a.clusterCredentials, keosRegistry, "", false) + err = provider.deployClusterOperator(n, privateParams, a.clusterCredentials, keosRegistry, a.clusterConfig, "", false) if err != nil { return errors.Wrap(err, "failed to deploy cluster operator") } ctx.Status.End(true) // End Moving the cluster-operator } - } - ctx.Status.Start("Executing post-install steps 🎖️") - defer ctx.Status.End(false) + ctx.Status.Start("Executing post-install steps 🎖️") + defer ctx.Status.End(false) - err = infra.postInstallPhase(n, kubeconfigPath) - if err != nil { - return err - } + err = infra.postInstallPhase(n, kubeconfigPath) + if err != nil { + return err + } + + ctx.Status.End(true) - ctx.Status.End(true) + } ctx.Status.Start("Generating the KEOS descriptor 📝") defer ctx.Status.End(false) diff --git a/pkg/cluster/internal/create/actions/createworker/provider.go b/pkg/cluster/internal/create/actions/createworker/provider.go index 751c31ef8a..1eb9ac0f36 100644 --- a/pkg/cluster/internal/create/actions/createworker/provider.go +++ b/pkg/cluster/internal/create/actions/createworker/provider.go @@ -56,8 +56,8 @@ const ( scName = "keos" certManagerVersion = "v1.12.3" - clusterOperatorChart = "0.2.0-SNAPSHOT" - clusterOperatorImage = "0.2.0-SNAPSHOT" + clusterOperatorChart = "0.2.0-PR158-SNAPSHOT" + clusterOperatorImage = "0.2.0-PR158-SNAPSHOT" postInstallAnnotation = "cluster-autoscaler.kubernetes.io/safe-to-evict-local-volumes" ) @@ -287,7 +287,7 @@ func (p *Provider) deployCertManager(n nodes.Node, keosRegistryUrl string, kubec return nil } -func (p *Provider) deployClusterOperator(n nodes.Node, privateParams PrivateParams, clusterCredentials commons.ClusterCredentials, keosRegistry keosRegistry, kubeconfigPath string, firstInstallation bool) error { +func (p *Provider) deployClusterOperator(n nodes.Node, privateParams PrivateParams, clusterCredentials commons.ClusterCredentials, keosRegistry keosRegistry, clusterConfig *commons.ClusterConfig, kubeconfigPath string, firstInstallation bool) error { var c string var err error var helmRepository helmRepository @@ -333,6 +333,20 @@ func (p *Provider) deployClusterOperator(n nodes.Node, privateParams PrivatePara Flavour string `yaml:"flavour,omitempty"` Version string `yaml:"version,omitempty"` }{} + + if clusterConfig != nil { + clusterConfigYAML, err := yaml.Marshal(clusterConfig) + if err != nil { + return err + } + // Write keoscluster file + c = "echo '" + string(clusterConfigYAML) + "' > " + manifestsPath + "/clusterconfig.yaml" + _, err = commons.ExecuteCommand(n, c) + if err != nil { + return errors.Wrap(err, "failed to write the keoscluster file") + } + keosCluster.Spec.ClusterConfigRef.Name = clusterConfig.Metadata.Name + } keosClusterYAML, err := yaml.Marshal(keosCluster) if err != nil { return err diff --git a/pkg/cluster/internal/create/create.go b/pkg/cluster/internal/create/create.go index c54a894b52..de096d2ed1 100644 --- a/pkg/cluster/internal/create/create.go +++ b/pkg/cluster/internal/create/create.go @@ -63,7 +63,7 @@ type ClusterOptions struct { MoveManagement bool AvoidCreation bool KeosCluster commons.KeosCluster - ClusterConfig commons.ClusterConfig + ClusterConfig *commons.ClusterConfig ClusterCredentials commons.ClusterCredentials DockerRegUrl string @@ -121,7 +121,7 @@ func Cluster(logger log.Logger, p providers.Provider, opts *ClusterOptions) erro logger.V(0).Infof("Creating temporary cluster %q ...\n", opts.Config.Name) // Create node containers implementing defined config Nodes - if err := p.Provision(status, opts.Config, opts.DockerRegUrl); err != nil { + if err := p.Provision(status, opts.Config, opts.DockerRegUrl, !opts.KeosCluster.Spec.ControlPlane.Public); err != nil { // In case of errors nodes are deleted (except if retain is explicitly set) if !opts.Retain { _ = delete.Cluster(logger, p, opts.Config.Name, opts.KubeconfigPath) diff --git a/pkg/cluster/internal/providers/docker/images.go b/pkg/cluster/internal/providers/docker/images.go index c8eac0c30e..58ea9f4d77 100644 --- a/pkg/cluster/internal/providers/docker/images.go +++ b/pkg/cluster/internal/providers/docker/images.go @@ -40,7 +40,7 @@ var ( // ensureNodeImages ensures that the node images used by the create // configuration are present -func ensureNodeImages(logger log.Logger, status *cli.Status, cfg *config.Cluster, dockerRegUrl string) error { +func ensureNodeImages(logger log.Logger, status *cli.Status, cfg *config.Cluster, dockerRegUrl string, fullyPrivate bool) error { // pull each required image for _, image := range common.RequiredNodeImages(cfg).List() { // prints user friendly message @@ -62,17 +62,22 @@ func ensureNodeImages(logger log.Logger, status *cli.Status, cfg *config.Cluster return err } stratioImage := "stratio-capi-image:" + strings.Split(friendlyImageName, ":")[1] - // if dockerRegUrl != "" { - // cmd := exec.Command("docker", "inspect", "--type=image", stratioImage) - // if err := cmd.Run(); err == nil { - // logger.V(1).Infof("stratioImage: %s present locally", image) - // } else { - // err = buildStratioImage(logger, stratioImage, dockerfileDir) - // } - // } else { - // err = buildStratioImage(logger, stratioImage, dockerfileDir) - // } - err = buildStratioImage(logger, stratioImage, dockerfileDir) + args := []string{} + if dockerRegUrl != "" { + args = append(args, "--build-arg=DOCKER_REG="+dockerRegUrl) + if fullyPrivate { + cmd := exec.Command("docker", "inspect", "--type=image", stratioImage) + if err := cmd.Run(); err == nil { + logger.V(1).Infof("stratioImage: %s present locally", image) + } else { + err = buildStratioImage(logger, stratioImage, dockerfileDir, args...) + } + } else { + err = buildStratioImage(logger, stratioImage, dockerfileDir, args...) + } + } else { + err = buildStratioImage(logger, stratioImage, dockerfileDir) + } if err != nil { status.End(false) return err @@ -113,8 +118,13 @@ func ensureStratioImageFiles(logger log.Logger) (dir string, err error) { } // buildStratioImage builds the stratio image -func buildStratioImage(logger log.Logger, image string, path string) error { +func buildStratioImage(logger log.Logger, image string, path string, args ...string) error { cmd := exec.Command("docker", "build", "--tag="+image, path) + if len(args) != 0 { + arg := strings.Join(args, " ") + cmd = exec.Command("docker", "build", "--tag="+image, arg, path) + } + if err := cmd.Run(); err != nil { return errors.Wrapf(err, "failed to build image %q", image) } diff --git a/pkg/cluster/internal/providers/docker/provider.go b/pkg/cluster/internal/providers/docker/provider.go index e8c4f8d962..990a74a7e6 100644 --- a/pkg/cluster/internal/providers/docker/provider.go +++ b/pkg/cluster/internal/providers/docker/provider.go @@ -61,10 +61,10 @@ func (p *provider) String() string { } // Provision is part of the providers.Provider interface -func (p *provider) Provision(status *cli.Status, cfg *config.Cluster, dockerRegUrl string) (err error) { +func (p *provider) Provision(status *cli.Status, cfg *config.Cluster, dockerRegUrl string, fullyPrivate bool) (err error) { // TODO: validate cfg // ensure node images are pulled before actually provisioning - if err := ensureNodeImages(p.logger, status, cfg, dockerRegUrl); err != nil { + if err := ensureNodeImages(p.logger, status, cfg, dockerRegUrl, fullyPrivate); err != nil { return err } diff --git a/pkg/cluster/internal/providers/podman/provider.go b/pkg/cluster/internal/providers/podman/provider.go index d969a6a526..c13ec22b1a 100644 --- a/pkg/cluster/internal/providers/podman/provider.go +++ b/pkg/cluster/internal/providers/podman/provider.go @@ -63,7 +63,7 @@ func (p *provider) String() string { } // Provision is part of the providers.Provider interface -func (p *provider) Provision(status *cli.Status, cfg *config.Cluster, dockerRegUrl string) (err error) { +func (p *provider) Provision(status *cli.Status, cfg *config.Cluster, dockerRegUrl string, fullyPrivate bool) (err error) { if err := ensureMinVersion(); err != nil { return err } diff --git a/pkg/cluster/internal/providers/provider.go b/pkg/cluster/internal/providers/provider.go index 881bba6f99..06e58b2871 100644 --- a/pkg/cluster/internal/providers/provider.go +++ b/pkg/cluster/internal/providers/provider.go @@ -28,7 +28,7 @@ import ( type Provider interface { // Provision should create and start the nodes, just short of // actually starting up Kubernetes, based on the given cluster config - Provision(status *cli.Status, cfg *config.Cluster, dockerRegUrl string) error + Provision(status *cli.Status, cfg *config.Cluster, dockerRegUrl string, fullyPrivate bool) error // ListClusters discovers the clusters that currently have resources // under this providers ListClusters() ([]string, error) diff --git a/pkg/cluster/internal/validate/aws.go b/pkg/cluster/internal/validate/aws.go index 1d949789e7..3ab3380089 100644 --- a/pkg/cluster/internal/validate/aws.go +++ b/pkg/cluster/internal/validate/aws.go @@ -176,6 +176,11 @@ func validateAWSNetwork(ctx context.Context, cfg aws.Config, spec commons.KeosSp } } } + if spec.Networks.AdditionalSecurityGroupId != "" { + if err := validateSecurityGroup(spec.Networks.AdditionalSecurityGroupId, spec.Networks.VPCID, cfg); err != nil { + return err + } + } } else { if len(spec.Networks.Subnets) > 0 { return errors.New("\"vpc_id\": is required when \"subnets\" is set") @@ -183,6 +188,9 @@ func validateAWSNetwork(ctx context.Context, cfg aws.Config, spec commons.KeosSp if len(spec.Networks.PodsSubnets) > 0 { return errors.New("\"vpc_id\": is required when \"pods_subnets\" is set") } + if spec.Networks.AdditionalSecurityGroupId != "" { + return errors.New("\"vpc_id\": is required when \"additional_sg_id\" is set") + } } if len(spec.Networks.Subnets) > 0 { for _, s := range spec.Networks.Subnets { @@ -194,6 +202,7 @@ func validateAWSNetwork(ctx context.Context, cfg aws.Config, spec commons.KeosSp return err } } + return nil } @@ -249,6 +258,44 @@ func getAWSRegions(config aws.Config) ([]string, error) { return regions, nil } +func validateSecurityGroup(sgId string, vpcId string, config aws.Config) error { + findSg := false + ec2Client := ec2.NewFromConfig(config) + params := ec2.DescribeSecurityGroupsInput{ + Filters: []types.Filter{ + { + Name: toPtr[string]("group-id"), + Values: []string{sgId}, + }, + }, + } + if vpcId != "" { + vpcFilter := types.Filter{Name: toPtr[string]("vpc-id"), Values: []string{vpcId}} + params.Filters = append(params.Filters, vpcFilter) + } + sgsOutput, err := ec2Client.DescribeSecurityGroups(context.Background(), ¶ms) + if err != nil { + return err + } + for _, sg := range sgsOutput.SecurityGroups { + if *sg.GroupId == sgId { + findSg = true + continue + } + } + if !findSg { + errMsg := "SecurityGroup with sg_id: " + sgId + " does not exist in" + if vpcId == "" { + errMsg += " default vpc." + } else { + errMsg += " vpc: " + vpcId + "." + } + return errors.New(errMsg) + + } + return nil +} + func getAWSVPCs(config aws.Config) ([]string, error) { vpcs := []string{} diff --git a/pkg/cluster/internal/validate/common.go b/pkg/cluster/internal/validate/common.go index 93a5cdbd74..da291dba0e 100644 --- a/pkg/cluster/internal/validate/common.go +++ b/pkg/cluster/internal/validate/common.go @@ -34,8 +34,9 @@ const ( var k8sVersionSupported = []string{"1.24", "1.25", "1.26", "1.27", "1.28"} -func validateCommon(spec commons.KeosSpec) error { +func validateCommon(spec commons.KeosSpec, clusterConfig *commons.ClusterConfig) error { var err error + if err = validateK8SVersion(spec.K8SVersion); err != nil { return err } @@ -45,6 +46,30 @@ func validateCommon(spec commons.KeosSpec) error { if err = validateVolumes(spec); err != nil { return err } + if err = validatePublicControlPlane(spec, clusterConfig); err != nil { + return err + } + return nil +} + +func validatePublicControlPlane(spec commons.KeosSpec, clusterConfig *commons.ClusterConfig) error { + if spec.InfraProvider == "gcp" { + if !spec.ControlPlane.Public { + return errors.New("spec.control_plane.public cannot be false for gcp installations") + } + } else if !spec.ControlPlane.Public { + if clusterConfig == nil || !clusterConfig.Spec.Private { + return errors.New("If keoscluster's .spec.control_plane.public is false, clusterConfig .spec.private_registry must be true") + } + if spec.Networks.VPCID == "" || len(spec.Networks.Subnets) == 0 { + return errors.New("If keoscluster's .spec.control_plane.public is false, its .spec.networks.vpc_id and .spec.networks.subnets must be indicated.") + } + if spec.Networks.AdditionalSecurityGroupId == "" && spec.ControlPlane.Managed && spec.InfraProvider == "aws" { + return errors.New("If keoscluster's .spec.control_plane.public is false and .spec.control_plane.managed, its .spec.networks.additional_sg must be indicated. This sg must be created as a requirement and must allow the internal vpc traffic.") + } + + } + return nil } diff --git a/pkg/cluster/internal/validate/utils.go b/pkg/cluster/internal/validate/utils.go index dc3fa3e9f0..ee14e71bdf 100644 --- a/pkg/cluster/internal/validate/utils.go +++ b/pkg/cluster/internal/validate/utils.go @@ -72,3 +72,7 @@ func getFieldNames(s interface{}) []string { } return fieldNames } + +func toPtr[T any](v T) *T { + return &v +} diff --git a/pkg/cluster/internal/validate/validate.go b/pkg/cluster/internal/validate/validate.go index 135438a0d1..f82f0c364d 100644 --- a/pkg/cluster/internal/validate/validate.go +++ b/pkg/cluster/internal/validate/validate.go @@ -24,6 +24,7 @@ type ValidateParams struct { KeosCluster commons.KeosCluster SecretsPath string VaultPassword string + ClusterConfig *commons.ClusterConfig } func Cluster(params *ValidateParams) (commons.ClusterCredentials, error) { @@ -35,7 +36,7 @@ func Cluster(params *ValidateParams) (commons.ClusterCredentials, error) { return commons.ClusterCredentials{}, err } - if err := validateCommon(params.KeosCluster.Spec); err != nil { + if err := validateCommon(params.KeosCluster.Spec, params.ClusterConfig); err != nil { return commons.ClusterCredentials{}, err } diff --git a/pkg/cluster/provider.go b/pkg/cluster/provider.go index 7c3806f51b..cb1a847249 100644 --- a/pkg/cluster/provider.go +++ b/pkg/cluster/provider.go @@ -171,7 +171,7 @@ func ProviderWithPodman() ProviderOption { } // Create provisions and starts a kubernetes-in-docker cluster -func (p *Provider) Create(name string, vaultPassword string, descriptorPath string, moveManagement bool, avoidCreation bool, dockerRegUrl string, clusterConfig commons.ClusterConfig, keosCluster commons.KeosCluster, clusterCredentials commons.ClusterCredentials, options ...CreateOption) error { // apply options +func (p *Provider) Create(name string, vaultPassword string, descriptorPath string, moveManagement bool, avoidCreation bool, dockerRegUrl string, clusterConfig *commons.ClusterConfig, keosCluster commons.KeosCluster, clusterCredentials commons.ClusterCredentials, options ...CreateOption) error { // apply options opts := &internalcreate.ClusterOptions{ NameOverride: name, VaultPassword: vaultPassword, @@ -255,9 +255,10 @@ func (p *Provider) CollectLogs(name, dir string) error { return p.provider.CollectLogs(dir, n) } -func (p *Provider) Validate(keosCluster commons.KeosCluster, secretsPath string, vaultPassword string) (commons.ClusterCredentials, error) { +func (p *Provider) Validate(keosCluster commons.KeosCluster, clusterConfig *commons.ClusterConfig, secretsPath string, vaultPassword string) (commons.ClusterCredentials, error) { params := &internalvalidate.ValidateParams{ KeosCluster: keosCluster, + ClusterConfig: clusterConfig, SecretsPath: secretsPath, VaultPassword: vaultPassword, } diff --git a/pkg/cmd/kind/create/cluster/createcluster.go b/pkg/cmd/kind/create/cluster/createcluster.go index eddc0214cf..9128505147 100644 --- a/pkg/cmd/kind/create/cluster/createcluster.go +++ b/pkg/cmd/kind/create/cluster/createcluster.go @@ -180,6 +180,7 @@ func runE(logger log.Logger, streams cmd.IOStreams, flags *flagpole) error { clusterCredentials, err := provider.Validate( *keosCluster, + clusterConfig, secretsDefaultPath, flags.VaultPassword, ) @@ -188,7 +189,8 @@ func runE(logger log.Logger, streams cmd.IOStreams, flags *flagpole) error { } dockerRegUrl := "" - if clusterConfig.Spec.Private { + if clusterConfig != nil && clusterConfig.Spec.Private { + configFile, err := getConfigFile(keosCluster, clusterCredentials) if err != nil { return errors.Wrap(err, "Error getting private kubeadm config") @@ -220,7 +222,7 @@ func runE(logger log.Logger, streams cmd.IOStreams, flags *flagpole) error { flags.MoveManagement, flags.AvoidCreation, dockerRegUrl, - *clusterConfig, + clusterConfig, *keosCluster, clusterCredentials, withConfig, diff --git a/pkg/commons/cluster.go b/pkg/commons/cluster.go index d7826dda4a..336a9f836d 100644 --- a/pkg/commons/cluster.go +++ b/pkg/commons/cluster.go @@ -58,7 +58,11 @@ type Metadata struct { } type ClusterConfigSpec struct { - Private bool `yaml:"private_registry,omitempty"` + Private bool `yaml:"private_registry"` +} + +type ClusterConfigRef struct { + Name string `json:"name,omitempty"` } // Spec represents the YAML structure in the spec field of the descriptor file @@ -106,18 +110,22 @@ type KeosSpec struct { AWS AWSCP `yaml:"aws,omitempty"` Azure AzureCP `yaml:"azure,omitempty"` ExtraVolumes []ExtraVolume `yaml:"extra_volumes,omitempty" validate:"dive"` + Public bool `yaml:"public" validate:"boolean"` } `yaml:"control_plane"` WorkerNodes WorkerNodes `yaml:"worker_nodes" validate:"required,dive"` + + ClusterConfigRef ClusterConfigRef `yaml:"cluster_config_ref,omitempty" validate:"dive"` } type Networks struct { - VPCID string `yaml:"vpc_id,omitempty"` - VPCCidrBlock string `yaml:"vpc_cidr,omitempty" validate:"omitempty,cidrv4"` - PodsCidrBlock string `yaml:"pods_cidr,omitempty" validate:"omitempty,cidrv4"` - PodsSubnets []Subnets `yaml:"pods_subnets,omitempty" validate:"dive"` - Subnets []Subnets `yaml:"subnets,omitempty" validate:"dive"` - ResourceGroup string `yaml:"resource_group,omitempty"` + VPCID string `yaml:"vpc_id,omitempty"` + VPCCidrBlock string `yaml:"vpc_cidr,omitempty" validate:"omitempty,cidrv4"` + PodsCidrBlock string `yaml:"pods_cidr,omitempty" validate:"omitempty,cidrv4"` + PodsSubnets []Subnets `yaml:"pods_subnets,omitempty" validate:"dive"` + Subnets []Subnets `yaml:"subnets,omitempty" validate:"dive"` + ResourceGroup string `yaml:"resource_group,omitempty"` + AdditionalSecurityGroupId string `yaml:"additional_sg_id,omitempty"` } type Subnets struct { @@ -343,6 +351,7 @@ func (s ClusterConfigSpec) Init() ClusterConfigSpec { func (s KeosSpec) Init() KeosSpec { highlyAvailable := true s.ControlPlane.HighlyAvailable = &highlyAvailable + s.ControlPlane.Public = true // AKS s.ControlPlane.Azure.Tier = "Paid" @@ -372,6 +381,7 @@ func (s KeosSpec) Init() KeosSpec { func GetClusterDescriptor(descriptorPath string) (*KeosCluster, *ClusterConfig, error) { var keosCluster KeosCluster var clusterConfig ClusterConfig + findClusterConfig := false _, err := os.Stat(descriptorPath) if err != nil { @@ -416,6 +426,7 @@ func GetClusterDescriptor(descriptorPath string) (*KeosCluster, *ClusterConfig, keosCluster.Metadata.Namespace = "cluster-" + keosCluster.Metadata.Name case "ClusterConfig": + findClusterConfig = true clusterConfig.Spec = new(ClusterConfigSpec).Init() err = yaml.Unmarshal([]byte(manifest), &clusterConfig) if err != nil { @@ -426,7 +437,7 @@ func GetClusterDescriptor(descriptorPath string) (*KeosCluster, *ClusterConfig, if err != nil { return nil, nil, err } - + clusterConfig.Metadata.Namespace = "cluster-" + keosCluster.Metadata.Name default: return nil, nil, errors.New("Unsupported manifest kind: " + resource.Kind) } @@ -436,13 +447,12 @@ func GetClusterDescriptor(descriptorPath string) (*KeosCluster, *ClusterConfig, if reflect.DeepEqual(keosCluster, KeosCluster{}) { return nil, nil, errors.New("Keoscluster's manifest has not been found.") } - if !reflect.DeepEqual(clusterConfig, ClusterConfig{}) { - if clusterConfig.Metadata.Name != keosCluster.Metadata.Name { - return nil, nil, errors.New("ClusterConfig name does not match keoscluster name.") - } + + if findClusterConfig { + return &keosCluster, &clusterConfig, nil } - return &keosCluster, &clusterConfig, nil + return &keosCluster, nil, nil } func DecryptFile(filePath string, vaultPassword string) (string, error) {