From 533f3847ac1f7b26bbb4ab4116e5a8c1284ef8a0 Mon Sep 17 00:00:00 2001 From: goncalo-rodrigues Date: Wed, 22 Jun 2022 17:45:05 +0100 Subject: [PATCH 1/6] feat: kubernetes gcp --- .../kubernetes_node_pool/gcp_gke_node_pool.go | 32 ++++++ .../output/kubernetes_service/gcp_gke.go | 26 +++++ resources/types/gcp/kubernetes_cluster.go | 63 +++++++++++ resources/types/gcp/kubernetes_node_pool.go | 103 ++++++++++++++++++ 4 files changed, 224 insertions(+) create mode 100644 resources/output/kubernetes_node_pool/gcp_gke_node_pool.go create mode 100644 resources/output/kubernetes_service/gcp_gke.go create mode 100644 resources/types/gcp/kubernetes_cluster.go create mode 100644 resources/types/gcp/kubernetes_node_pool.go diff --git a/resources/output/kubernetes_node_pool/gcp_gke_node_pool.go b/resources/output/kubernetes_node_pool/gcp_gke_node_pool.go new file mode 100644 index 00000000..cac0636c --- /dev/null +++ b/resources/output/kubernetes_node_pool/gcp_gke_node_pool.go @@ -0,0 +1,32 @@ +package kubernetes_node_pool + +import "github.com/multycloud/multy/resources/common" + +type GoogleContainerNodePool struct { + *common.GcpResource `hcl:",squash" default:"name=google_container_node_pool"` + Cluster string `hcl:"cluster,expr"` //expr + InitialNodeCount int `hcl:"initial_node_count"` + Autoscaling GoogleContainerNodePoolAutoScaling `hcl:"autoscaling"` + NodeConfig GoogleContainerNodeConfig `hcl:"node_config"` + NetworkConfig GoogleContainerNetworkConfig `hcl:"network_config"` +} + +type GoogleContainerNodePoolAutoScaling struct { + MinNodeCount int `hcl:"min_node_count"` + MaxNodeCount int `hcl:"max_node_count"` +} + +type GoogleContainerNodeConfig struct { + DiskSizeGb int `hcl:"disk_size_gb"` + DiskType string `hcl:"disk_type" hcle:"omitempty"` + ImageType string `hcl:"image_type"` + Labels map[string]string `hcl:"labels" hcle:"omitempty"` + MachineType string `hcl:"machine_type"` + Metadata map[string]string `hcl:"metadata" hcle:"omitempty"` + Tags []string `hcl:"tags" hcle:"omitempty"` +} + +type GoogleContainerNetworkConfig struct { + CreatePodRange bool `hcl:"create_pod_range"` + PodIpv4CidrBlock string `hcl:"pod_ipv4_cidr_block"` +} diff --git a/resources/output/kubernetes_service/gcp_gke.go b/resources/output/kubernetes_service/gcp_gke.go new file mode 100644 index 00000000..6f1b5de4 --- /dev/null +++ b/resources/output/kubernetes_service/gcp_gke.go @@ -0,0 +1,26 @@ +package kubernetes_service + +import "github.com/multycloud/multy/resources/common" + +type GoogleContainerCluster struct { + *common.GcpResource `hcl:",squash" default:"name=google_container_cluster"` + RemoveDefaultNodePool bool `hcl:"remove_default_node_pool"` + InitialNodeCount int `hcl:"initial_node_count"` + Network string `hcl:"network,expr"` + IpAllocationPolicy GoogleContainerClusterIpAllocationPolicy `hcl:"ip_allocation_policy"` + + // outputs + Endpoint string `json:"endpoint" hcle:"omitempty"` + MasterAuth []GoogleContainerClusterAuth `json:"master_auth" hcle:"omitempty"` +} + +type GoogleContainerClusterAuth struct { + ClusterCaCertificate string `json:"cluster_ca_certificate"` + ClientCertificate string `json:"client_certificate"` + ClientKey string `json:"client_key"` +} + +type GoogleContainerClusterIpAllocationPolicy struct { + //ClusterIpv4CidrBlock string `hcl:"cluster_ipv_4_cidr_block"` + ServicesIpv4CidrBlock string `hcl:"services_ipv_4_cidr_block"` +} diff --git a/resources/types/gcp/kubernetes_cluster.go b/resources/types/gcp/kubernetes_cluster.go new file mode 100644 index 00000000..d9218af8 --- /dev/null +++ b/resources/types/gcp/kubernetes_cluster.go @@ -0,0 +1,63 @@ +package gcp_resources + +import ( + "fmt" + "github.com/multycloud/multy/api/proto/commonpb" + "github.com/multycloud/multy/api/proto/resourcespb" + "github.com/multycloud/multy/flags" + "github.com/multycloud/multy/resources" + "github.com/multycloud/multy/resources/output" + "github.com/multycloud/multy/resources/output/kubernetes_service" + "github.com/multycloud/multy/resources/output/virtual_network" + "github.com/multycloud/multy/resources/types" +) + +type GcpKubernetesCluster struct { + *types.KubernetesCluster +} + +func InitKubernetesCluster(r *types.KubernetesCluster) resources.ResourceTranslator[*resourcespb.KubernetesClusterResource] { + return GcpKubernetesCluster{r} +} + +func (r GcpKubernetesCluster) FromState(state *output.TfState) (*resourcespb.KubernetesClusterResource, error) { + result := &resourcespb.KubernetesClusterResource{ + CommonParameters: &commonpb.CommonResourceParameters{ + ResourceId: r.ResourceId, + ResourceGroupId: r.Args.CommonParameters.ResourceGroupId, + Location: r.Args.CommonParameters.Location, + CloudProvider: r.Args.CommonParameters.CloudProvider, + NeedsUpdate: false, + }, + Name: r.Args.Name, + ServiceCidr: r.Args.ServiceCidr, + VirtualNetworkId: r.Args.VirtualNetworkId, + } + result.Endpoint = "dryrun" + if !flags.DryRun { + //cluster, err := output.GetParsedById[kubernetes_service.GoogleContainerCluster](state, r.ResourceId) + //if err != nil { + // return nil, err + //} + //result.Endpoint = cluster.KubeConfig[0].Host + //result.CaCertificate = cluster.KubeConfig[0].ClusterCaCertificate + //result.KubeConfigRaw = cluster.KubeConfigRaw + } + + return result, nil +} + +func (r GcpKubernetesCluster) Translate(_ resources.MultyContext) ([]output.TfBlock, error) { + return []output.TfBlock{ + &kubernetes_service.GoogleContainerCluster{ + RemoveDefaultNodePool: true, + InitialNodeCount: 1, + Network: fmt.Sprintf("%s.%s.id", output.GetResourceName(virtual_network.GoogleComputeNetwork{}), r.VirtualNetwork.ResourceId), + IpAllocationPolicy: kubernetes_service.GoogleContainerClusterIpAllocationPolicy{ + ServicesIpv4CidrBlock: r.Args.ServiceCidr, + }, + }}, nil +} +func (r GcpKubernetesCluster) GetMainResourceName() (string, error) { + return output.GetResourceName(kubernetes_service.GoogleContainerCluster{}), nil +} diff --git a/resources/types/gcp/kubernetes_node_pool.go b/resources/types/gcp/kubernetes_node_pool.go new file mode 100644 index 00000000..4fe7ca73 --- /dev/null +++ b/resources/types/gcp/kubernetes_node_pool.go @@ -0,0 +1,103 @@ +package gcp_resources + +import ( + "fmt" + "github.com/multycloud/multy/api/proto/commonpb" + "github.com/multycloud/multy/api/proto/resourcespb" + "github.com/multycloud/multy/resources" + "github.com/multycloud/multy/resources/common" + "github.com/multycloud/multy/resources/output" + "github.com/multycloud/multy/resources/output/iam" + "github.com/multycloud/multy/resources/output/kubernetes_node_pool" + "github.com/multycloud/multy/resources/types" +) + +type GcpKubernetesNodePool struct { + *types.KubernetesNodePool +} + +func InitKubernetesNodePool(r *types.KubernetesNodePool) resources.ResourceTranslator[*resourcespb.KubernetesNodePoolResource] { + return GcpKubernetesNodePool{r} +} + +func (r GcpKubernetesNodePool) FromState(state *output.TfState) (*resourcespb.KubernetesNodePoolResource, error) { + return &resourcespb.KubernetesNodePoolResource{ + CommonParameters: &commonpb.CommonChildResourceParameters{ + ResourceId: r.ResourceId, + NeedsUpdate: false, + }, + Name: r.Args.Name, + SubnetId: r.Args.SubnetId, + ClusterId: r.Args.ClusterId, + StartingNodeCount: r.Args.StartingNodeCount, + MinNodeCount: r.Args.MinNodeCount, + MaxNodeCount: r.Args.MaxNodeCount, + VmSize: r.Args.VmSize, + DiskSizeGb: r.Args.DiskSizeGb, + Labels: r.Args.Labels, + GcpOverride: r.Args.GcpOverride, + AzureOverride: r.Args.AzureOverride, + }, nil +} + +func (r GcpKubernetesNodePool) Translate(_ resources.MultyContext) ([]output.TfBlock, error) { + subnetId, err := resources.GetMainOutputId(GcpSubnet{r.Subnet}) + if err != nil { + return nil, err + } + + var instanceTypes []string + if r.Args.GcpOverride.GetInstanceTypes() != nil { + instanceTypes = r.Args.GcpOverride.GetInstanceTypes() + } else { + instanceTypes = []string{common.VMSIZE[r.Args.VmSize][r.GetCloud()]} + } + + roleName := fmt.Sprintf("multy-k8nodepool-%s-%s-role", r.KubernetesCluster.Args.Name, r.Args.Name) + role := iam.GcpIamRole{ + GcpResource: common.NewGcpResource(r.ResourceId, roleName), + Name: roleName, + AssumeRolePolicy: iam.NewAssumeRolePolicy("ec2.amazonGcp.com"), + } + clusterId, err := resources.GetMainOutputId(GcpKubernetesCluster{r.KubernetesCluster}) + if err != nil { + return nil, err + } + return []output.TfBlock{ + &role, + iam.GcpIamRolePolicyAttachment{ + GcpResource: common.NewGcpResourceWithIdOnly(fmt.Sprintf("%s_%s", r.ResourceId, "AmazonEKSWorkerNodePolicy")), + Role: fmt.Sprintf("Gcp_iam_role.%s.name", r.ResourceId), + PolicyArn: "arn:Gcp:iam::Gcp:policy/AmazonEKSWorkerNodePolicy", + }, + iam.GcpIamRolePolicyAttachment{ + GcpResource: common.NewGcpResourceWithIdOnly(fmt.Sprintf("%s_%s", r.ResourceId, "AmazonEKS_CNI_Policy")), + Role: fmt.Sprintf("Gcp_iam_role.%s.name", r.ResourceId), + PolicyArn: "arn:Gcp:iam::Gcp:policy/AmazonEKS_CNI_Policy", + }, + iam.GcpIamRolePolicyAttachment{ + GcpResource: common.NewGcpResourceWithIdOnly(fmt.Sprintf("%s_%s", r.ResourceId, "AmazonEC2ContainerRegistryReadOnly")), + Role: fmt.Sprintf("Gcp_iam_role.%s.name", r.ResourceId), + PolicyArn: "arn:Gcp:iam::Gcp:policy/AmazonEC2ContainerRegistryReadOnly", + }, + &kubernetes_node_pool.GcpKubernetesNodeGroup{ + GcpResource: common.NewGcpResourceWithIdOnly(r.ResourceId), + ClusterName: clusterId, + NodeGroupName: r.Args.Name, + NodeRoleArn: fmt.Sprintf("Gcp_iam_role.%s.arn", r.ResourceId), + SubnetIds: []string{subnetId}, + ScalingConfig: kubernetes_node_pool.ScalingConfig{ + DesiredSize: int(r.Args.StartingNodeCount), + MaxSize: int(r.Args.MaxNodeCount), + MinSize: int(r.Args.MinNodeCount), + }, + Labels: r.Args.Labels, + InstanceTypes: instanceTypes, + }, + }, nil + +} + +func (r GcpKubernetesNodePool) GetMainResourceName() (string, error) { + return output.GetResourceName(kubernetes_node_pool.GcpKubernetesNodeGroup{}), nil +} From 928b45dbe961d17ee1cb76ee677adf22f6eed895 Mon Sep 17 00:00:00 2001 From: goncalo-rodrigues Date: Mon, 4 Jul 2022 17:43:18 +0200 Subject: [PATCH 2/6] gke node pools and test update --- .../resourcespb/kubernetes_cluster.pb.go | 222 +++++++++++++----- .../resourcespb/kubernetes_cluster.proto | 6 + resources/common/helper.go | 9 +- resources/output/iam/gcp_service_account.go | 9 + .../kubernetes_node_pool/gcp_gke_node_pool.go | 9 +- .../output/kubernetes_service/azure_aks.go | 6 +- .../output/kubernetes_service/gcp_gke.go | 18 +- .../output/kubernetes_service/kube_config.go | 46 ++++ resources/types/aws/kubernetes_cluster.go | 60 +---- resources/types/gcp/kubernetes_cluster.go | 123 ++++++++-- resources/types/gcp/kubernetes_node_pool.go | 69 ++---- .../types/metadata/all_resources_metadata.go | 2 + resources/types/virtual_network.go | 2 +- .../kubernetes/kubernetes/config.textproto | 85 +++++++ test/_configs/kubernetes/kubernetes/main.tf | 88 ++++++- 15 files changed, 546 insertions(+), 208 deletions(-) create mode 100644 resources/output/iam/gcp_service_account.go create mode 100644 resources/output/kubernetes_service/kube_config.go mode change 100644 => 100755 test/_configs/kubernetes/kubernetes/main.tf diff --git a/api/proto/resourcespb/kubernetes_cluster.pb.go b/api/proto/resourcespb/kubernetes_cluster.pb.go index 9d23509f..20a40208 100644 --- a/api/proto/resourcespb/kubernetes_cluster.pb.go +++ b/api/proto/resourcespb/kubernetes_cluster.pb.go @@ -217,6 +217,53 @@ func (x *DeleteKubernetesClusterRequest) GetResourceId() string { return "" } +type KubernetesClusterOverrides struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Project string `protobuf:"bytes,1,opt,name=project,proto3" json:"project,omitempty"` +} + +func (x *KubernetesClusterOverrides) Reset() { + *x = KubernetesClusterOverrides{} + if protoimpl.UnsafeEnabled { + mi := &file_api_proto_resourcespb_kubernetes_cluster_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *KubernetesClusterOverrides) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*KubernetesClusterOverrides) ProtoMessage() {} + +func (x *KubernetesClusterOverrides) ProtoReflect() protoreflect.Message { + mi := &file_api_proto_resourcespb_kubernetes_cluster_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use KubernetesClusterOverrides.ProtoReflect.Descriptor instead. +func (*KubernetesClusterOverrides) Descriptor() ([]byte, []int) { + return file_api_proto_resourcespb_kubernetes_cluster_proto_rawDescGZIP(), []int{4} +} + +func (x *KubernetesClusterOverrides) GetProject() string { + if x != nil { + return x.Project + } + return "" +} + type KubernetesClusterArgs struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -227,12 +274,13 @@ type KubernetesClusterArgs struct { ServiceCidr string `protobuf:"bytes,3,opt,name=service_cidr,json=serviceCidr,proto3" json:"service_cidr,omitempty"` VirtualNetworkId string `protobuf:"bytes,4,opt,name=virtual_network_id,json=virtualNetworkId,proto3" json:"virtual_network_id,omitempty"` DefaultNodePool *KubernetesNodePoolArgs `protobuf:"bytes,5,opt,name=default_node_pool,json=defaultNodePool,proto3" json:"default_node_pool,omitempty"` + GcpOverride *KubernetesClusterOverrides `protobuf:"bytes,6,opt,name=gcp_override,json=gcpOverride,proto3" json:"gcp_override,omitempty"` } func (x *KubernetesClusterArgs) Reset() { *x = KubernetesClusterArgs{} if protoimpl.UnsafeEnabled { - mi := &file_api_proto_resourcespb_kubernetes_cluster_proto_msgTypes[4] + mi := &file_api_proto_resourcespb_kubernetes_cluster_proto_msgTypes[5] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -245,7 +293,7 @@ func (x *KubernetesClusterArgs) String() string { func (*KubernetesClusterArgs) ProtoMessage() {} func (x *KubernetesClusterArgs) ProtoReflect() protoreflect.Message { - mi := &file_api_proto_resourcespb_kubernetes_cluster_proto_msgTypes[4] + mi := &file_api_proto_resourcespb_kubernetes_cluster_proto_msgTypes[5] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -258,7 +306,7 @@ func (x *KubernetesClusterArgs) ProtoReflect() protoreflect.Message { // Deprecated: Use KubernetesClusterArgs.ProtoReflect.Descriptor instead. func (*KubernetesClusterArgs) Descriptor() ([]byte, []int) { - return file_api_proto_resourcespb_kubernetes_cluster_proto_rawDescGZIP(), []int{4} + return file_api_proto_resourcespb_kubernetes_cluster_proto_rawDescGZIP(), []int{5} } func (x *KubernetesClusterArgs) GetCommonParameters() *commonpb.ResourceCommonArgs { @@ -296,6 +344,13 @@ func (x *KubernetesClusterArgs) GetDefaultNodePool() *KubernetesNodePoolArgs { return nil } +func (x *KubernetesClusterArgs) GetGcpOverride() *KubernetesClusterOverrides { + if x != nil { + return x.GcpOverride + } + return nil +} + type KubernetesClusterResource struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -306,6 +361,7 @@ type KubernetesClusterResource struct { ServiceCidr string `protobuf:"bytes,3,opt,name=service_cidr,json=serviceCidr,proto3" json:"service_cidr,omitempty"` DefaultNodePool *KubernetesNodePoolResource `protobuf:"bytes,4,opt,name=default_node_pool,json=defaultNodePool,proto3" json:"default_node_pool,omitempty"` VirtualNetworkId string `protobuf:"bytes,5,opt,name=virtual_network_id,json=virtualNetworkId,proto3" json:"virtual_network_id,omitempty"` + GcpOverride *KubernetesClusterOverrides `protobuf:"bytes,9,opt,name=gcp_override,json=gcpOverride,proto3" json:"gcp_override,omitempty"` // outputs Endpoint string `protobuf:"bytes,6,opt,name=endpoint,proto3" json:"endpoint,omitempty"` CaCertificate string `protobuf:"bytes,7,opt,name=ca_certificate,json=caCertificate,proto3" json:"ca_certificate,omitempty"` @@ -315,7 +371,7 @@ type KubernetesClusterResource struct { func (x *KubernetesClusterResource) Reset() { *x = KubernetesClusterResource{} if protoimpl.UnsafeEnabled { - mi := &file_api_proto_resourcespb_kubernetes_cluster_proto_msgTypes[5] + mi := &file_api_proto_resourcespb_kubernetes_cluster_proto_msgTypes[6] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -328,7 +384,7 @@ func (x *KubernetesClusterResource) String() string { func (*KubernetesClusterResource) ProtoMessage() {} func (x *KubernetesClusterResource) ProtoReflect() protoreflect.Message { - mi := &file_api_proto_resourcespb_kubernetes_cluster_proto_msgTypes[5] + mi := &file_api_proto_resourcespb_kubernetes_cluster_proto_msgTypes[6] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -341,7 +397,7 @@ func (x *KubernetesClusterResource) ProtoReflect() protoreflect.Message { // Deprecated: Use KubernetesClusterResource.ProtoReflect.Descriptor instead. func (*KubernetesClusterResource) Descriptor() ([]byte, []int) { - return file_api_proto_resourcespb_kubernetes_cluster_proto_rawDescGZIP(), []int{5} + return file_api_proto_resourcespb_kubernetes_cluster_proto_rawDescGZIP(), []int{6} } func (x *KubernetesClusterResource) GetCommonParameters() *commonpb.CommonResourceParameters { @@ -379,6 +435,13 @@ func (x *KubernetesClusterResource) GetVirtualNetworkId() string { return "" } +func (x *KubernetesClusterResource) GetGcpOverride() *KubernetesClusterOverrides { + if x != nil { + return x.GcpOverride + } + return nil +} + func (x *KubernetesClusterResource) GetEndpoint() string { if x != nil { return x.Endpoint @@ -436,45 +499,59 @@ var file_api_proto_resourcespb_kubernetes_cluster_proto_rawDesc = []byte{ 0x74, 0x65, 0x73, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x49, 0x64, 0x22, 0xa8, 0x02, 0x0a, 0x15, 0x4b, 0x75, 0x62, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x65, - 0x73, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x41, 0x72, 0x67, 0x73, 0x12, 0x51, 0x0a, 0x11, - 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, - 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x64, 0x65, 0x76, 0x2e, 0x6d, 0x75, - 0x6c, 0x74, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x41, 0x72, 0x67, 0x73, 0x52, 0x10, 0x63, - 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x12, - 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, - 0x61, 0x6d, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x63, - 0x69, 0x64, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x65, 0x72, 0x76, 0x69, - 0x63, 0x65, 0x43, 0x69, 0x64, 0x72, 0x12, 0x2c, 0x0a, 0x12, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, - 0x6c, 0x5f, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x10, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x4e, 0x65, 0x74, 0x77, 0x6f, - 0x72, 0x6b, 0x49, 0x64, 0x12, 0x57, 0x0a, 0x11, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, - 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x70, 0x6f, 0x6f, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x2b, 0x2e, 0x64, 0x65, 0x76, 0x2e, 0x6d, 0x75, 0x6c, 0x74, 0x79, 0x2e, 0x72, 0x65, 0x73, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x4b, 0x75, 0x62, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x65, 0x73, - 0x4e, 0x6f, 0x64, 0x65, 0x50, 0x6f, 0x6f, 0x6c, 0x41, 0x72, 0x67, 0x73, 0x52, 0x0f, 0x64, 0x65, - 0x66, 0x61, 0x75, 0x6c, 0x74, 0x4e, 0x6f, 0x64, 0x65, 0x50, 0x6f, 0x6f, 0x6c, 0x22, 0xa1, 0x03, - 0x0a, 0x19, 0x4b, 0x75, 0x62, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x65, 0x73, 0x43, 0x6c, 0x75, 0x73, - 0x74, 0x65, 0x72, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x57, 0x0a, 0x11, 0x63, - 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x64, 0x65, 0x76, 0x2e, 0x6d, 0x75, 0x6c, - 0x74, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, - 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, - 0x72, 0x73, 0x52, 0x10, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, - 0x74, 0x65, 0x72, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x65, 0x72, 0x76, - 0x69, 0x63, 0x65, 0x5f, 0x63, 0x69, 0x64, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, - 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x43, 0x69, 0x64, 0x72, 0x12, 0x5b, 0x0a, 0x11, 0x64, - 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x70, 0x6f, 0x6f, 0x6c, - 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x64, 0x65, 0x76, 0x2e, 0x6d, 0x75, 0x6c, - 0x74, 0x79, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x4b, 0x75, 0x62, - 0x65, 0x72, 0x6e, 0x65, 0x74, 0x65, 0x73, 0x4e, 0x6f, 0x64, 0x65, 0x50, 0x6f, 0x6f, 0x6c, 0x52, - 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x0f, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, - 0x4e, 0x6f, 0x64, 0x65, 0x50, 0x6f, 0x6f, 0x6c, 0x12, 0x2c, 0x0a, 0x12, 0x76, 0x69, 0x72, 0x74, - 0x75, 0x61, 0x6c, 0x5f, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x5f, 0x69, 0x64, 0x18, 0x05, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x4e, 0x65, 0x74, - 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, + 0x49, 0x64, 0x22, 0x36, 0x0a, 0x1a, 0x4b, 0x75, 0x62, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x65, 0x73, + 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x73, + 0x12, 0x18, 0x0a, 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x22, 0xfc, 0x02, 0x0a, 0x15, 0x4b, + 0x75, 0x62, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x65, 0x73, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, + 0x41, 0x72, 0x67, 0x73, 0x12, 0x51, 0x0a, 0x11, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x5f, 0x70, + 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x24, 0x2e, 0x64, 0x65, 0x76, 0x2e, 0x6d, 0x75, 0x6c, 0x74, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, + 0x6f, 0x6e, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, + 0x6e, 0x41, 0x72, 0x67, 0x73, 0x52, 0x10, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x50, 0x61, 0x72, + 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x73, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x63, 0x69, 0x64, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0b, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x43, 0x69, 0x64, 0x72, 0x12, 0x2c, + 0x0a, 0x12, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x5f, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, + 0x6b, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x76, 0x69, 0x72, 0x74, + 0x75, 0x61, 0x6c, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x12, 0x57, 0x0a, 0x11, + 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x70, 0x6f, 0x6f, + 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x64, 0x65, 0x76, 0x2e, 0x6d, 0x75, + 0x6c, 0x74, 0x79, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x4b, 0x75, + 0x62, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x65, 0x73, 0x4e, 0x6f, 0x64, 0x65, 0x50, 0x6f, 0x6f, 0x6c, + 0x41, 0x72, 0x67, 0x73, 0x52, 0x0f, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x4e, 0x6f, 0x64, + 0x65, 0x50, 0x6f, 0x6f, 0x6c, 0x12, 0x52, 0x0a, 0x0c, 0x67, 0x63, 0x70, 0x5f, 0x6f, 0x76, 0x65, + 0x72, 0x72, 0x69, 0x64, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x64, 0x65, + 0x76, 0x2e, 0x6d, 0x75, 0x6c, 0x74, 0x79, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x73, 0x2e, 0x4b, 0x75, 0x62, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x65, 0x73, 0x43, 0x6c, 0x75, 0x73, + 0x74, 0x65, 0x72, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x73, 0x52, 0x0b, 0x67, 0x63, + 0x70, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x22, 0xf5, 0x03, 0x0a, 0x19, 0x4b, 0x75, + 0x62, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x65, 0x73, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x52, + 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x57, 0x0a, 0x11, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, + 0x6e, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x64, 0x65, 0x76, 0x2e, 0x6d, 0x75, 0x6c, 0x74, 0x79, 0x2e, 0x63, + 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x52, 0x10, + 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, + 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, + 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, + 0x63, 0x69, 0x64, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x43, 0x69, 0x64, 0x72, 0x12, 0x5b, 0x0a, 0x11, 0x64, 0x65, 0x66, 0x61, 0x75, + 0x6c, 0x74, 0x5f, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x70, 0x6f, 0x6f, 0x6c, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x64, 0x65, 0x76, 0x2e, 0x6d, 0x75, 0x6c, 0x74, 0x79, 0x2e, 0x72, + 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x4b, 0x75, 0x62, 0x65, 0x72, 0x6e, 0x65, + 0x74, 0x65, 0x73, 0x4e, 0x6f, 0x64, 0x65, 0x50, 0x6f, 0x6f, 0x6c, 0x52, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x52, 0x0f, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x4e, 0x6f, 0x64, 0x65, + 0x50, 0x6f, 0x6f, 0x6c, 0x12, 0x2c, 0x0a, 0x12, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x5f, + 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x5f, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x10, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, + 0x49, 0x64, 0x12, 0x52, 0x0a, 0x0c, 0x67, 0x63, 0x70, 0x5f, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, + 0x64, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x64, 0x65, 0x76, 0x2e, 0x6d, + 0x75, 0x6c, 0x74, 0x79, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x4b, + 0x75, 0x62, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x65, 0x73, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, + 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x73, 0x52, 0x0b, 0x67, 0x63, 0x70, 0x4f, 0x76, + 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x25, 0x0a, 0x0e, 0x63, 0x61, 0x5f, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x63, 0x61, 0x43, 0x65, @@ -502,31 +579,34 @@ func file_api_proto_resourcespb_kubernetes_cluster_proto_rawDescGZIP() []byte { return file_api_proto_resourcespb_kubernetes_cluster_proto_rawDescData } -var file_api_proto_resourcespb_kubernetes_cluster_proto_msgTypes = make([]protoimpl.MessageInfo, 6) +var file_api_proto_resourcespb_kubernetes_cluster_proto_msgTypes = make([]protoimpl.MessageInfo, 7) var file_api_proto_resourcespb_kubernetes_cluster_proto_goTypes = []interface{}{ (*CreateKubernetesClusterRequest)(nil), // 0: dev.multy.resources.CreateKubernetesClusterRequest (*ReadKubernetesClusterRequest)(nil), // 1: dev.multy.resources.ReadKubernetesClusterRequest (*UpdateKubernetesClusterRequest)(nil), // 2: dev.multy.resources.UpdateKubernetesClusterRequest (*DeleteKubernetesClusterRequest)(nil), // 3: dev.multy.resources.DeleteKubernetesClusterRequest - (*KubernetesClusterArgs)(nil), // 4: dev.multy.resources.KubernetesClusterArgs - (*KubernetesClusterResource)(nil), // 5: dev.multy.resources.KubernetesClusterResource - (*commonpb.ResourceCommonArgs)(nil), // 6: dev.multy.common.ResourceCommonArgs - (*KubernetesNodePoolArgs)(nil), // 7: dev.multy.resources.KubernetesNodePoolArgs - (*commonpb.CommonResourceParameters)(nil), // 8: dev.multy.common.CommonResourceParameters - (*KubernetesNodePoolResource)(nil), // 9: dev.multy.resources.KubernetesNodePoolResource + (*KubernetesClusterOverrides)(nil), // 4: dev.multy.resources.KubernetesClusterOverrides + (*KubernetesClusterArgs)(nil), // 5: dev.multy.resources.KubernetesClusterArgs + (*KubernetesClusterResource)(nil), // 6: dev.multy.resources.KubernetesClusterResource + (*commonpb.ResourceCommonArgs)(nil), // 7: dev.multy.common.ResourceCommonArgs + (*KubernetesNodePoolArgs)(nil), // 8: dev.multy.resources.KubernetesNodePoolArgs + (*commonpb.CommonResourceParameters)(nil), // 9: dev.multy.common.CommonResourceParameters + (*KubernetesNodePoolResource)(nil), // 10: dev.multy.resources.KubernetesNodePoolResource } var file_api_proto_resourcespb_kubernetes_cluster_proto_depIdxs = []int32{ - 4, // 0: dev.multy.resources.CreateKubernetesClusterRequest.resource:type_name -> dev.multy.resources.KubernetesClusterArgs - 4, // 1: dev.multy.resources.UpdateKubernetesClusterRequest.resource:type_name -> dev.multy.resources.KubernetesClusterArgs - 6, // 2: dev.multy.resources.KubernetesClusterArgs.common_parameters:type_name -> dev.multy.common.ResourceCommonArgs - 7, // 3: dev.multy.resources.KubernetesClusterArgs.default_node_pool:type_name -> dev.multy.resources.KubernetesNodePoolArgs - 8, // 4: dev.multy.resources.KubernetesClusterResource.common_parameters:type_name -> dev.multy.common.CommonResourceParameters - 9, // 5: dev.multy.resources.KubernetesClusterResource.default_node_pool:type_name -> dev.multy.resources.KubernetesNodePoolResource - 6, // [6:6] is the sub-list for method output_type - 6, // [6:6] is the sub-list for method input_type - 6, // [6:6] is the sub-list for extension type_name - 6, // [6:6] is the sub-list for extension extendee - 0, // [0:6] is the sub-list for field type_name + 5, // 0: dev.multy.resources.CreateKubernetesClusterRequest.resource:type_name -> dev.multy.resources.KubernetesClusterArgs + 5, // 1: dev.multy.resources.UpdateKubernetesClusterRequest.resource:type_name -> dev.multy.resources.KubernetesClusterArgs + 7, // 2: dev.multy.resources.KubernetesClusterArgs.common_parameters:type_name -> dev.multy.common.ResourceCommonArgs + 8, // 3: dev.multy.resources.KubernetesClusterArgs.default_node_pool:type_name -> dev.multy.resources.KubernetesNodePoolArgs + 4, // 4: dev.multy.resources.KubernetesClusterArgs.gcp_override:type_name -> dev.multy.resources.KubernetesClusterOverrides + 9, // 5: dev.multy.resources.KubernetesClusterResource.common_parameters:type_name -> dev.multy.common.CommonResourceParameters + 10, // 6: dev.multy.resources.KubernetesClusterResource.default_node_pool:type_name -> dev.multy.resources.KubernetesNodePoolResource + 4, // 7: dev.multy.resources.KubernetesClusterResource.gcp_override:type_name -> dev.multy.resources.KubernetesClusterOverrides + 8, // [8:8] is the sub-list for method output_type + 8, // [8:8] is the sub-list for method input_type + 8, // [8:8] is the sub-list for extension type_name + 8, // [8:8] is the sub-list for extension extendee + 0, // [0:8] is the sub-list for field type_name } func init() { file_api_proto_resourcespb_kubernetes_cluster_proto_init() } @@ -585,7 +665,7 @@ func file_api_proto_resourcespb_kubernetes_cluster_proto_init() { } } file_api_proto_resourcespb_kubernetes_cluster_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*KubernetesClusterArgs); i { + switch v := v.(*KubernetesClusterOverrides); i { case 0: return &v.state case 1: @@ -597,6 +677,18 @@ func file_api_proto_resourcespb_kubernetes_cluster_proto_init() { } } file_api_proto_resourcespb_kubernetes_cluster_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*KubernetesClusterArgs); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_api_proto_resourcespb_kubernetes_cluster_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*KubernetesClusterResource); i { case 0: return &v.state @@ -615,7 +707,7 @@ func file_api_proto_resourcespb_kubernetes_cluster_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_api_proto_resourcespb_kubernetes_cluster_proto_rawDesc, NumEnums: 0, - NumMessages: 6, + NumMessages: 7, NumExtensions: 0, NumServices: 0, }, diff --git a/api/proto/resourcespb/kubernetes_cluster.proto b/api/proto/resourcespb/kubernetes_cluster.proto index fd7c1b4f..95761594 100644 --- a/api/proto/resourcespb/kubernetes_cluster.proto +++ b/api/proto/resourcespb/kubernetes_cluster.proto @@ -27,6 +27,10 @@ message DeleteKubernetesClusterRequest { string resource_id = 1; } +message KubernetesClusterOverrides { + string project = 1; +} + message KubernetesClusterArgs { common.ResourceCommonArgs common_parameters = 1; string name = 2; @@ -34,6 +38,7 @@ message KubernetesClusterArgs { string virtual_network_id = 4; KubernetesNodePoolArgs default_node_pool = 5; + KubernetesClusterOverrides gcp_override = 6; } message KubernetesClusterResource { @@ -42,6 +47,7 @@ message KubernetesClusterResource { string service_cidr = 3; KubernetesNodePoolResource default_node_pool = 4; string virtual_network_id = 5; + KubernetesClusterOverrides gcp_override = 9; // outputs string endpoint = 6; diff --git a/resources/common/helper.go b/resources/common/helper.go index bf4cc438..912f764b 100644 --- a/resources/common/helper.go +++ b/resources/common/helper.go @@ -39,13 +39,14 @@ func RandomString(n int) string { // Prefix can be any size but will be sliced if bigger than 16 chars. Suffix can have 4 chars at most. // Returns a string with at most 24 chars. func UniqueId(prefix string, suffix string, formatFunc FormatFunc) string { - if len(suffix) > 4 { - validate.LogInternalError("suffix must be shorter than 4 chars") + if len(suffix) > 10 { + validate.LogInternalError("suffix must be shorter than 10 chars") } result := "" formattedPrefix := formatFunc(prefix) - if len(formattedPrefix) > 16 { - result += formattedPrefix[:12] + generateHash(prefix) + maxPrefixLen := 20 - len(suffix) + if len(formattedPrefix) > maxPrefixLen { + result += formattedPrefix[:maxPrefixLen] + generateHash(prefix) } else { result += formattedPrefix } diff --git a/resources/output/iam/gcp_service_account.go b/resources/output/iam/gcp_service_account.go new file mode 100644 index 00000000..54f83c30 --- /dev/null +++ b/resources/output/iam/gcp_service_account.go @@ -0,0 +1,9 @@ +package iam + +import "github.com/multycloud/multy/resources/common" + +type GoogleServiceAccount struct { + *common.GcpResource `hcl:",squash" default:"name=google_service_account"` + AccountId string `hcl:"account_id"` + DisplayName string `hcl:"display_name"` +} diff --git a/resources/output/kubernetes_node_pool/gcp_gke_node_pool.go b/resources/output/kubernetes_node_pool/gcp_gke_node_pool.go index cac0636c..5bf7ba58 100644 --- a/resources/output/kubernetes_node_pool/gcp_gke_node_pool.go +++ b/resources/output/kubernetes_node_pool/gcp_gke_node_pool.go @@ -8,7 +8,7 @@ type GoogleContainerNodePool struct { InitialNodeCount int `hcl:"initial_node_count"` Autoscaling GoogleContainerNodePoolAutoScaling `hcl:"autoscaling"` NodeConfig GoogleContainerNodeConfig `hcl:"node_config"` - NetworkConfig GoogleContainerNetworkConfig `hcl:"network_config"` + NetworkConfig GoogleContainerNetworkConfig `hcl:"network_config" hcle:"omitempty"` } type GoogleContainerNodePoolAutoScaling struct { @@ -17,13 +17,16 @@ type GoogleContainerNodePoolAutoScaling struct { } type GoogleContainerNodeConfig struct { - DiskSizeGb int `hcl:"disk_size_gb"` + DiskSizeGb int `hcl:"disk_size_gb" hcle:"omitempty"` DiskType string `hcl:"disk_type" hcle:"omitempty"` - ImageType string `hcl:"image_type"` + ImageType string `hcl:"image_type" hcle:"omitempty"` Labels map[string]string `hcl:"labels" hcle:"omitempty"` MachineType string `hcl:"machine_type"` Metadata map[string]string `hcl:"metadata" hcle:"omitempty"` Tags []string `hcl:"tags" hcle:"omitempty"` + + ServiceAccount string `hcl:"service_account,expr"` + OAuthScopes []string `hcl:"oauth_scopes"` } type GoogleContainerNetworkConfig struct { diff --git a/resources/output/kubernetes_service/azure_aks.go b/resources/output/kubernetes_service/azure_aks.go index e9393c7e..1c49b836 100644 --- a/resources/output/kubernetes_service/azure_aks.go +++ b/resources/output/kubernetes_service/azure_aks.go @@ -20,8 +20,8 @@ type AzureEksCluster struct { NetworkProfile NetworkProfile `hcl:"network_profile"` // outputs - KubeConfigRaw string `json:"kube_config_raw" hcle:"omitempty"` - KubeConfig []KubeConfig `json:"kube_config" hcle:"omitempty"` + KubeConfigRaw string `json:"kube_config_raw" hcle:"omitempty"` + KubeConfig []AzureKubeConfig `json:"kube_config" hcle:"omitempty"` } type NetworkProfile struct { @@ -31,7 +31,7 @@ type NetworkProfile struct { ServiceCidr string `hcl:"service_cidr"` } -type KubeConfig struct { +type AzureKubeConfig struct { Host string `json:"host" hcle:"omitempty"` ClusterCaCertificate string `json:"cluster_ca_certificate" hcle:"omitempty"` } diff --git a/resources/output/kubernetes_service/gcp_gke.go b/resources/output/kubernetes_service/gcp_gke.go index 6f1b5de4..e40ca286 100644 --- a/resources/output/kubernetes_service/gcp_gke.go +++ b/resources/output/kubernetes_service/gcp_gke.go @@ -1,13 +1,19 @@ package kubernetes_service -import "github.com/multycloud/multy/resources/common" +import ( + "github.com/multycloud/multy/resources/common" + "github.com/multycloud/multy/resources/output/kubernetes_node_pool" +) type GoogleContainerCluster struct { *common.GcpResource `hcl:",squash" default:"name=google_container_cluster"` - RemoveDefaultNodePool bool `hcl:"remove_default_node_pool"` - InitialNodeCount int `hcl:"initial_node_count"` - Network string `hcl:"network,expr"` - IpAllocationPolicy GoogleContainerClusterIpAllocationPolicy `hcl:"ip_allocation_policy"` + RemoveDefaultNodePool bool `hcl:"remove_default_node_pool"` + InitialNodeCount int `hcl:"initial_node_count"` + Subnetwork string `hcl:"subnetwork,expr"` + Network string `hcl:"network,expr"` + IpAllocationPolicy GoogleContainerClusterIpAllocationPolicy `hcl:"ip_allocation_policy"` + Location string `hcl:"location"` + NodeConfig kubernetes_node_pool.GoogleContainerNodeConfig `hcl:"node_config"` // outputs Endpoint string `json:"endpoint" hcle:"omitempty"` @@ -22,5 +28,5 @@ type GoogleContainerClusterAuth struct { type GoogleContainerClusterIpAllocationPolicy struct { //ClusterIpv4CidrBlock string `hcl:"cluster_ipv_4_cidr_block"` - ServicesIpv4CidrBlock string `hcl:"services_ipv_4_cidr_block"` + ServicesIpv4CidrBlock string `hcl:"services_ipv4_cidr_block"` } diff --git a/resources/output/kubernetes_service/kube_config.go b/resources/output/kubernetes_service/kube_config.go new file mode 100644 index 00000000..f0b10852 --- /dev/null +++ b/resources/output/kubernetes_service/kube_config.go @@ -0,0 +1,46 @@ +package kubernetes_service + +type KubeConfig struct { + ApiVersion string `yaml:"apiVersion"` + Clusters []NamedKubeConfigCluster `yaml:"clusters"` + Contexts []NamedKubeConfigContext `yaml:"contexts"` + CurrentContext string `yaml:"current-context"` + Users []KubeConfigUser `yaml:"users"` + Kind string `yaml:"kind"` +} + +type NamedKubeConfigCluster struct { + Name string `yaml:"name"` + Cluster KubeConfigCluster `yaml:"cluster"` +} + +type KubeConfigCluster struct { + CertificateAuthorityData string `yaml:"certificate-authority-data"` + Server string `yaml:"server"` +} + +type NamedKubeConfigContext struct { + Name string `yaml:"name"` + Context KubeConfigContext `yaml:"context"` +} + +type KubeConfigContext struct { + User string `yaml:"user"` + Cluster string `yaml:"cluster"` +} + +type KubeConfigUser struct { + Name string `yaml:"name"` + User struct { + Exec KubeConfigExec `yaml:"exec"` + } `yaml:"user"` +} + +type KubeConfigExec struct { + ApiVersion string `yaml:"apiVersion"` + Command string `yaml:"command"` + Args []string `yaml:"args"` + InteractiveMode string `yaml:"interactiveMode"` + ProvideClusterInfo bool `yaml:"provideClusterInfo"` + InstallHint string `yaml:"installHint"` +} diff --git a/resources/types/aws/kubernetes_cluster.go b/resources/types/aws/kubernetes_cluster.go index ee9bbf4f..293854e4 100644 --- a/resources/types/aws/kubernetes_cluster.go +++ b/resources/types/aws/kubernetes_cluster.go @@ -30,83 +30,41 @@ func InitKubernetesCluster(r *types.KubernetesCluster) resources.ResourceTransla return AwsKubernetesCluster{r} } -type KubeConfig struct { - ApiVersion string `yaml:"apiVersion"` - Clusters []NamedKubeConfigCluster `yaml:"clusters"` - Contexts []NamedKubeConfigContext `yaml:"contexts"` - CurrentContext string `yaml:"current-context"` - Users []KubeConfigUser `yaml:"users"` - Kind string `yaml:"kind"` -} - -type NamedKubeConfigCluster struct { - Name string `yaml:"name"` - Cluster KubeConfigCluster `yaml:"cluster"` -} - -type KubeConfigCluster struct { - CertificateAuthorityData string `yaml:"certificate-authority-data"` - Server string `yaml:"server"` -} - -type NamedKubeConfigContext struct { - Name string `yaml:"name"` - Context KubeConfigContext `yaml:"context"` -} - -type KubeConfigContext struct { - User string `yaml:"user"` - Cluster string `yaml:"cluster"` -} - -type KubeConfigUser struct { - Name string `yaml:"name"` - User struct { - Exec KubeConfigExec `yaml:"exec"` - } `yaml:"user"` -} - -type KubeConfigExec struct { - ApiVersion string `yaml:"apiVersion"` - Command string `yaml:"command"` - Args []string `yaml:"args"` - InteractiveMode string `yaml:"interactiveMode"` -} - func createKubeConfig(clusterName string, certData string, endpoint string, awsRegion string) (string, error) { username := fmt.Sprintf("clusterUser_%s", clusterName) - kubeConfig := &KubeConfig{ + kubeConfig := &kubernetes_service.KubeConfig{ ApiVersion: "v1", Kind: "Config", - Clusters: []NamedKubeConfigCluster{ + Clusters: []kubernetes_service.NamedKubeConfigCluster{ { Name: clusterName, - Cluster: KubeConfigCluster{ + Cluster: kubernetes_service.KubeConfigCluster{ CertificateAuthorityData: certData, Server: endpoint, }, }, }, - Contexts: []NamedKubeConfigContext{ + Contexts: []kubernetes_service.NamedKubeConfigContext{ { Name: clusterName, - Context: KubeConfigContext{ + Context: kubernetes_service.KubeConfigContext{ User: username, Cluster: clusterName, }, }, }, - Users: []KubeConfigUser{ + Users: []kubernetes_service.KubeConfigUser{ { Name: username, User: struct { - Exec KubeConfigExec `yaml:"exec"` + Exec kubernetes_service.KubeConfigExec `yaml:"exec"` }{ - Exec: KubeConfigExec{ + Exec: kubernetes_service.KubeConfigExec{ ApiVersion: "client.authentication.k8s.io/v1beta1", Command: "aws", Args: []string{"--region", awsRegion, "eks", "get-token", "--cluster-name", clusterName}, InteractiveMode: "IfAvailable", + InstallHint: "Install aws cli for use with kubectl by following\n\t\t\t\thttps://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html", }, }, }, diff --git a/resources/types/gcp/kubernetes_cluster.go b/resources/types/gcp/kubernetes_cluster.go index d9218af8..5e4ea6ff 100644 --- a/resources/types/gcp/kubernetes_cluster.go +++ b/resources/types/gcp/kubernetes_cluster.go @@ -6,10 +6,15 @@ import ( "github.com/multycloud/multy/api/proto/resourcespb" "github.com/multycloud/multy/flags" "github.com/multycloud/multy/resources" + "github.com/multycloud/multy/resources/common" "github.com/multycloud/multy/resources/output" + "github.com/multycloud/multy/resources/output/iam" + "github.com/multycloud/multy/resources/output/kubernetes_node_pool" "github.com/multycloud/multy/resources/output/kubernetes_service" + "github.com/multycloud/multy/resources/output/subnet" "github.com/multycloud/multy/resources/output/virtual_network" "github.com/multycloud/multy/resources/types" + "gopkg.in/yaml.v3" ) type GcpKubernetesCluster struct { @@ -35,29 +40,115 @@ func (r GcpKubernetesCluster) FromState(state *output.TfState) (*resourcespb.Kub } result.Endpoint = "dryrun" if !flags.DryRun { - //cluster, err := output.GetParsedById[kubernetes_service.GoogleContainerCluster](state, r.ResourceId) - //if err != nil { - // return nil, err - //} - //result.Endpoint = cluster.KubeConfig[0].Host - //result.CaCertificate = cluster.KubeConfig[0].ClusterCaCertificate - //result.KubeConfigRaw = cluster.KubeConfigRaw + cluster, err := output.GetParsedById[kubernetes_service.GoogleContainerCluster](state, r.ResourceId) + if err != nil { + return nil, err + } + result.Endpoint = cluster.Endpoint + result.CaCertificate = cluster.MasterAuth[0].ClusterCaCertificate + + rawConfig, err := createKubeConfig(r.Args.Name, result.CaCertificate, result.Endpoint) + if err != nil { + return nil, err + } + + result.KubeConfigRaw = rawConfig } return result, nil } -func (r GcpKubernetesCluster) Translate(_ resources.MultyContext) ([]output.TfBlock, error) { - return []output.TfBlock{ - &kubernetes_service.GoogleContainerCluster{ - RemoveDefaultNodePool: true, - InitialNodeCount: 1, - Network: fmt.Sprintf("%s.%s.id", output.GetResourceName(virtual_network.GoogleComputeNetwork{}), r.VirtualNetwork.ResourceId), - IpAllocationPolicy: kubernetes_service.GoogleContainerClusterIpAllocationPolicy{ - ServicesIpv4CidrBlock: r.Args.ServiceCidr, +func createKubeConfig(clusterName string, certData string, endpoint string) (string, error) { + username := fmt.Sprintf("clusterUser_%s", clusterName) + kubeConfig := &kubernetes_service.KubeConfig{ + ApiVersion: "v1", + Kind: "Config", + Clusters: []kubernetes_service.NamedKubeConfigCluster{ + { + Name: clusterName, + Cluster: kubernetes_service.KubeConfigCluster{ + CertificateAuthorityData: certData, + Server: endpoint, + }, + }, + }, + Contexts: []kubernetes_service.NamedKubeConfigContext{ + { + Name: clusterName, + Context: kubernetes_service.KubeConfigContext{ + User: username, + Cluster: clusterName, + }, + }, + }, + Users: []kubernetes_service.KubeConfigUser{ + { + Name: username, + User: struct { + Exec kubernetes_service.KubeConfigExec `yaml:"exec"` + }{ + Exec: kubernetes_service.KubeConfigExec{ + ApiVersion: "client.authentication.k8s.io/v1beta1", + Command: "gke-gcloud-auth-plugin", + InteractiveMode: "IfAvailable", + ProvideClusterInfo: true, + InstallHint: "Install gke-gcloud-auth-plugin for use with kubectl by following\n https://cloud.google.com/blog/products/containers-kubernetes/kubectl-auth-changes-in-gke", + }, + }, }, - }}, nil + }, + CurrentContext: clusterName, + } + + s, err := yaml.Marshal(kubeConfig) + if err != nil { + return "", fmt.Errorf("unable to marshal kube config, %s", err) + } + + return string(s), nil } + +func (r GcpKubernetesCluster) Translate(ctx resources.MultyContext) ([]output.TfBlock, error) { + var outputs []output.TfBlock + + serviceAccountId := r.getServiceAccountId() + serviceAccount := &iam.GoogleServiceAccount{ + GcpResource: common.NewGcpResource(serviceAccountId, "", r.Args.GetGcpOverride().GetProject()), + AccountId: serviceAccountId, + DisplayName: fmt.Sprintf("Service Account for cluster %s - created by Multy", r.Args.Name), + } + outputs = append(outputs, serviceAccount) + + defaultNodePoolResources, err := GcpKubernetesNodePool{r.DefaultNodePool}.Translate(ctx) + if err != nil { + return nil, err + } + outputs = append(outputs, defaultNodePoolResources...) + outputs = append(outputs, &kubernetes_service.GoogleContainerCluster{ + GcpResource: common.NewGcpResource(r.ResourceId, r.Args.Name, r.Args.GetGcpOverride().GetProject()), + RemoveDefaultNodePool: true, + InitialNodeCount: 1, + Location: r.GetCloudSpecificLocation(), + Subnetwork: fmt.Sprintf("%s.%s.id", output.GetResourceName(subnet.GoogleComputeSubnetwork{}), r.DefaultNodePool.Subnet.ResourceId), + Network: fmt.Sprintf("%s.%s.id", output.GetResourceName(virtual_network.GoogleComputeNetwork{}), r.VirtualNetwork.ResourceId), + IpAllocationPolicy: kubernetes_service.GoogleContainerClusterIpAllocationPolicy{ + ServicesIpv4CidrBlock: r.Args.ServiceCidr, + }, + NodeConfig: kubernetes_node_pool.GoogleContainerNodeConfig{ + MachineType: "e2-micro", + Tags: []string{GcpSubnet{r.DefaultNodePool.Subnet}.getNetworkTag()}, + // Google recommends custom service accounts that have cloud-platform scope and permissions granted via IAM Roles. + ServiceAccount: fmt.Sprintf("%s.%s.email", output.GetResourceName(iam.GoogleServiceAccount{}), serviceAccountId), + OAuthScopes: []string{"https://www.googleapis.com/auth/cloud-platform"}, + }, + }) + return outputs, nil +} + +func (r GcpKubernetesCluster) getServiceAccountId() string { + return common.UniqueId(r.Args.Name, "-sa-", common.AlphanumericFormatFunc) +} + func (r GcpKubernetesCluster) GetMainResourceName() (string, error) { return output.GetResourceName(kubernetes_service.GoogleContainerCluster{}), nil } diff --git a/resources/types/gcp/kubernetes_node_pool.go b/resources/types/gcp/kubernetes_node_pool.go index 4fe7ca73..a258df28 100644 --- a/resources/types/gcp/kubernetes_node_pool.go +++ b/resources/types/gcp/kubernetes_node_pool.go @@ -35,69 +35,42 @@ func (r GcpKubernetesNodePool) FromState(state *output.TfState) (*resourcespb.Ku VmSize: r.Args.VmSize, DiskSizeGb: r.Args.DiskSizeGb, Labels: r.Args.Labels, - GcpOverride: r.Args.GcpOverride, AzureOverride: r.Args.AzureOverride, }, nil } func (r GcpKubernetesNodePool) Translate(_ resources.MultyContext) ([]output.TfBlock, error) { - subnetId, err := resources.GetMainOutputId(GcpSubnet{r.Subnet}) + clusterId, err := resources.GetMainOutputId(GcpKubernetesCluster{r.KubernetesCluster}) if err != nil { return nil, err } - - var instanceTypes []string - if r.Args.GcpOverride.GetInstanceTypes() != nil { - instanceTypes = r.Args.GcpOverride.GetInstanceTypes() - } else { - instanceTypes = []string{common.VMSIZE[r.Args.VmSize][r.GetCloud()]} - } - - roleName := fmt.Sprintf("multy-k8nodepool-%s-%s-role", r.KubernetesCluster.Args.Name, r.Args.Name) - role := iam.GcpIamRole{ - GcpResource: common.NewGcpResource(r.ResourceId, roleName), - Name: roleName, - AssumeRolePolicy: iam.NewAssumeRolePolicy("ec2.amazonGcp.com"), - } - clusterId, err := resources.GetMainOutputId(GcpKubernetesCluster{r.KubernetesCluster}) + size, err := common.GetVmSize(r.Args.VmSize, r.GetCloud()) if err != nil { return nil, err } - return []output.TfBlock{ - &role, - iam.GcpIamRolePolicyAttachment{ - GcpResource: common.NewGcpResourceWithIdOnly(fmt.Sprintf("%s_%s", r.ResourceId, "AmazonEKSWorkerNodePolicy")), - Role: fmt.Sprintf("Gcp_iam_role.%s.name", r.ResourceId), - PolicyArn: "arn:Gcp:iam::Gcp:policy/AmazonEKSWorkerNodePolicy", + nodePool := &kubernetes_node_pool.GoogleContainerNodePool{ + GcpResource: common.NewGcpResource(r.ResourceId, r.Args.Name, r.KubernetesCluster.Args.GetGcpOverride().GetProject()), + Cluster: clusterId, + InitialNodeCount: int(r.Args.StartingNodeCount), + Autoscaling: kubernetes_node_pool.GoogleContainerNodePoolAutoScaling{ + MinNodeCount: int(r.Args.MinNodeCount), + MaxNodeCount: int(r.Args.MaxNodeCount), }, - iam.GcpIamRolePolicyAttachment{ - GcpResource: common.NewGcpResourceWithIdOnly(fmt.Sprintf("%s_%s", r.ResourceId, "AmazonEKS_CNI_Policy")), - Role: fmt.Sprintf("Gcp_iam_role.%s.name", r.ResourceId), - PolicyArn: "arn:Gcp:iam::Gcp:policy/AmazonEKS_CNI_Policy", + NodeConfig: kubernetes_node_pool.GoogleContainerNodeConfig{ + DiskSizeGb: int(r.Args.DiskSizeGb), + Labels: r.Args.Labels, + MachineType: size, + Tags: []string{GcpSubnet{r.Subnet}.getNetworkTag()}, + // Google recommends custom service accounts that have cloud-platform scope and permissions granted via IAM Roles. + ServiceAccount: fmt.Sprintf("%s.%s.email", output.GetResourceName(iam.GoogleServiceAccount{}), GcpKubernetesCluster{r.KubernetesCluster}.getServiceAccountId()), + OAuthScopes: []string{"https://www.googleapis.com/auth/cloud-platform"}, }, - iam.GcpIamRolePolicyAttachment{ - GcpResource: common.NewGcpResourceWithIdOnly(fmt.Sprintf("%s_%s", r.ResourceId, "AmazonEC2ContainerRegistryReadOnly")), - Role: fmt.Sprintf("Gcp_iam_role.%s.name", r.ResourceId), - PolicyArn: "arn:Gcp:iam::Gcp:policy/AmazonEC2ContainerRegistryReadOnly", - }, - &kubernetes_node_pool.GcpKubernetesNodeGroup{ - GcpResource: common.NewGcpResourceWithIdOnly(r.ResourceId), - ClusterName: clusterId, - NodeGroupName: r.Args.Name, - NodeRoleArn: fmt.Sprintf("Gcp_iam_role.%s.arn", r.ResourceId), - SubnetIds: []string{subnetId}, - ScalingConfig: kubernetes_node_pool.ScalingConfig{ - DesiredSize: int(r.Args.StartingNodeCount), - MaxSize: int(r.Args.MaxNodeCount), - MinSize: int(r.Args.MinNodeCount), - }, - Labels: r.Args.Labels, - InstanceTypes: instanceTypes, - }, - }, nil + } + + return []output.TfBlock{nodePool}, nil } func (r GcpKubernetesNodePool) GetMainResourceName() (string, error) { - return output.GetResourceName(kubernetes_node_pool.GcpKubernetesNodeGroup{}), nil + return output.GetResourceName(kubernetes_node_pool.GoogleContainerNodePool{}), nil } diff --git a/resources/types/metadata/all_resources_metadata.go b/resources/types/metadata/all_resources_metadata.go index b15bcfbd..ce2943ce 100644 --- a/resources/types/metadata/all_resources_metadata.go +++ b/resources/types/metadata/all_resources_metadata.go @@ -71,6 +71,7 @@ var Metadatas = map[proto.Message]resources.ResourceMetadataInterface{ Translators: map[commonpb.CloudProvider]func(*types.KubernetesNodePool) resources.ResourceTranslator[*resourcespb.KubernetesNodePoolResource]{ commonpb.CloudProvider_AWS: aws_resources.InitKubernetesNodePool, commonpb.CloudProvider_AZURE: azure_resources.InitKubernetesNodePool, + commonpb.CloudProvider_GCP: gcp_resources.InitKubernetesNodePool, }, }, &resourcespb.KubernetesClusterArgs{}: &resources.ResourceMetadata[*resourcespb.KubernetesClusterArgs, *types.KubernetesCluster, *resourcespb.KubernetesClusterResource]{ @@ -79,6 +80,7 @@ var Metadatas = map[proto.Message]resources.ResourceMetadataInterface{ Translators: map[commonpb.CloudProvider]func(*types.KubernetesCluster) resources.ResourceTranslator[*resourcespb.KubernetesClusterResource]{ commonpb.CloudProvider_AWS: aws_resources.InitKubernetesCluster, commonpb.CloudProvider_AZURE: azure_resources.InitKubernetesCluster, + commonpb.CloudProvider_GCP: gcp_resources.InitKubernetesCluster, }, }, &resourcespb.NetworkInterfaceArgs{}: &resources.ResourceMetadata[*resourcespb.NetworkInterfaceArgs, *types.NetworkInterface, *resourcespb.NetworkInterfaceResource]{ diff --git a/resources/types/virtual_network.go b/resources/types/virtual_network.go index c8475848..6c41755f 100644 --- a/resources/types/virtual_network.go +++ b/resources/types/virtual_network.go @@ -72,7 +72,7 @@ func (r *VirtualNetwork) Validate(ctx resources.MultyContext) (errs []validate.V } /* -Virtual Network is a private address space when resources can be placed. +Virtual Subnetwork is a private address space when resources can be placed. By default, resources inside `virtual_network` cannot access the internet. To enable internet access look at`route_table` diff --git a/test/_configs/kubernetes/kubernetes/config.textproto b/test/_configs/kubernetes/kubernetes/config.textproto index 48f9c0f9..f90cb6db 100755 --- a/test/_configs/kubernetes/kubernetes/config.textproto +++ b/test/_configs/kubernetes/kubernetes/config.textproto @@ -1,3 +1,88 @@ +resources: { + resource_id: "example_vn_gcp" + resource_args: { + resource_args: { + [type.googleapis.com/dev.multy.resources.VirtualNetworkArgs]: { + common_parameters: { + resource_group_id: "rg1" + location: EU_WEST_1 + cloud_provider: GCP + } + name: "k8svn" + cidr_block: "10.0.0.0/16" + gcp_override: { + project: "multy-project" + } + } + } + } +} +resources: { + resource_id: "public_subnet_gcp" + resource_args: { + resource_args: { + [type.googleapis.com/dev.multy.resources.SubnetArgs]: { + name: "public-subnet" + cidr_block: "10.0.0.0/24" + virtual_network_id: "example_vn_gcp" + availability_zone: 2 + } + } + } +} +resources: { + resource_id: "rt_gcp" + resource_args: { + resource_args: { + [type.googleapis.com/dev.multy.resources.RouteTableArgs]: { + name: "test-rt" + virtual_network_id: "example_vn_gcp" + routes: { + cidr_block: "0.0.0.0/0" + destination: INTERNET + } + } + } + } +} +resources: { + resource_id: "rta_gcp" + resource_args: { + resource_args: { + [type.googleapis.com/dev.multy.resources.RouteTableAssociationArgs]: { + subnet_id: "public_subnet_gcp" + route_table_id: "rt_gcp" + } + } + } +} +resources: { + resource_id: "cluster_gcp" + resource_args: { + resource_args: { + [type.googleapis.com/dev.multy.resources.KubernetesClusterArgs]: { + common_parameters: { + resource_group_id: "rg1" + location: EU_WEST_1 + cloud_provider: GCP + } + name: "cluster" + service_cidr: "10.100.0.0/16" + virtual_network_id: "example_vn_gcp" + default_node_pool: { + name: "node-pool-gcp" + subnet_id: "public_subnet_gcp" + min_node_count: 1 + max_node_count: 1 + vm_size: GENERAL_MEDIUM + } + gcp_override: { + project: "multy-project" + } + } + } + } +} resources: { resource_id: "example_vn_aws" resource_args: { diff --git a/test/_configs/kubernetes/kubernetes/main.tf b/test/_configs/kubernetes/kubernetes/main.tf old mode 100644 new mode 100755 index 20f57d60..51a0f48e --- a/test/_configs/kubernetes/kubernetes/main.tf +++ b/test/_configs/kubernetes/kubernetes/main.tf @@ -23,9 +23,7 @@ resource "aws_eks_node_group" "cluster_aws_default_pool" { cluster_name = aws_eks_cluster.cluster_aws.id node_group_name = "node_pool_aws" node_role_arn = aws_iam_role.cluster_aws_default_pool.arn - subnet_ids = [ - aws_subnet.public_subnet_aws-1.id, aws_subnet.public_subnet_aws-2.id, aws_subnet.public_subnet_aws-3.id - ] + subnet_ids = [aws_subnet.public_subnet_aws-1.id, aws_subnet.public_subnet_aws-2.id, aws_subnet.public_subnet_aws-3.id] scaling_config { desired_size = 1 max_size = 1 @@ -79,14 +77,9 @@ resource "aws_iam_role_policy_attachment" "cluster_aws_AmazonEKSVPCResourceContr provider = "aws.eu-west-1" } resource "aws_eks_cluster" "cluster_aws" { - depends_on = [ - aws_subnet.cluster_aws_public_subnet, aws_subnet.cluster_aws_private_subnet, aws_route_table.cluster_aws_public_rt, - aws_route_table_association.cluster_aws_public_rta, - aws_iam_role_policy_attachment.cluster_aws_AmazonEKSClusterPolicy, - aws_iam_role_policy_attachment.cluster_aws_AmazonEKSVPCResourceController - ] - tags = { "Name" = "cluster_aws" } - role_arn = aws_iam_role.cluster_aws.arn + depends_on = [aws_subnet.cluster_aws_public_subnet, aws_subnet.cluster_aws_private_subnet, aws_route_table.cluster_aws_public_rt, aws_route_table_association.cluster_aws_public_rta, aws_iam_role_policy_attachment.cluster_aws_AmazonEKSClusterPolicy, aws_iam_role_policy_attachment.cluster_aws_AmazonEKSVPCResourceController] + tags = { "Name" = "cluster_aws" } + role_arn = aws_iam_role.cluster_aws.arn vpc_config { subnet_ids = [aws_subnet.cluster_aws_public_subnet.id, aws_subnet.cluster_aws_private_subnet.id] endpoint_private_access = true @@ -121,6 +114,48 @@ resource "azurerm_kubernetes_cluster" "cluster_azure" { service_cidr = "10.100.0.0/16" } } +resource "google_service_account" "cluster-sa-avg8" { + project = "multy-project" + account_id = "cluster-sa-avg8" + display_name = "Service Account for cluster cluster - created by Multy" + provider = "google.europe-west1" +} +resource "google_container_node_pool" "cluster_gcp_default_pool" { + name = "node-pool-gcp" + project = "multy-project" + cluster = google_container_cluster.cluster_gcp.id + initial_node_count = 1 + autoscaling { + min_node_count = 1 + max_node_count = 1 + } + node_config { + machine_type = "e2-medium" + tags = ["subnet-public-subnet"] + service_account = google_service_account.cluster-sa-avg8.email + oauth_scopes = ["https://www.googleapis.com/auth/cloud-platform"] + } + provider = "google.europe-west1" +} +resource "google_container_cluster" "cluster_gcp" { + name = "cluster" + project = "multy-project" + remove_default_node_pool = true + initial_node_count = 1 + subnetwork = google_compute_subnetwork.public_subnet_gcp.id + network = google_compute_network.example_vn_gcp.id + ip_allocation_policy { + services_ipv4_cidr_block = "10.100.0.0/16" + } + location = "europe-west1" + node_config { + machine_type = "e2-micro" + tags = ["subnet-public-subnet"] + service_account = google_service_account.cluster-sa-avg8.email + oauth_scopes = ["https://www.googleapis.com/auth/cloud-platform"] + } + provider = "google.europe-west1" +} resource "aws_vpc" "example_vn_aws" { tags = { "Name" = "example_vn" } cidr_block = "10.0.0.0/16" @@ -165,6 +200,15 @@ resource "azurerm_route_table" "example_vn_azure" { next_hop_type = "VnetLocal" } } +resource "google_compute_network" "example_vn_gcp" { + name = "k8svn" + project = "multy-project" + routing_mode = "REGIONAL" + description = "Managed by Multy" + auto_create_subnetworks = false + delete_default_routes_on_create = true + provider = "google.europe-west1" +} resource "aws_subnet" "public_subnet_aws-1" { tags = { "Name" = "public-subnet-1" } cidr_block = "10.0.0.0/25" @@ -195,6 +239,14 @@ resource "azurerm_subnet" "public_subnet_azure" { address_prefixes = ["10.0.0.0/24"] virtual_network_name = azurerm_virtual_network.example_vn_azure.name } +resource "google_compute_subnetwork" "public_subnet_gcp" { + name = "public-subnet" + project = "multy-project" + ip_cidr_range = "10.0.0.0/24" + network = google_compute_network.example_vn_gcp.id + private_ip_google_access = true + provider = "google.europe-west1" +} resource "azurerm_resource_group" "rg1" { name = "rg1" location = "northeurope" @@ -218,6 +270,16 @@ resource "azurerm_route_table" "rt_azure" { next_hop_type = "Internet" } } +resource "google_compute_route" "rt_gcp-0" { + name = "test-rt-0" + project = "multy-project" + dest_range = "0.0.0.0/0" + network = google_compute_network.example_vn_gcp.id + priority = 1000 + tags = ["subnet-public-subnet"] + next_hop_gateway = "default-internet-gateway" + provider = "google.europe-west1" +} resource "aws_route_table_association" "rta_aws-1" { subnet_id = aws_subnet.public_subnet_aws-1.id route_table_id = aws_route_table.rt_aws.id @@ -245,3 +307,7 @@ provider "azurerm" { features { } } +provider "google" { + region = "europe-west1" + alias = "europe-west1" +} From e3407e50d05b99ccf5a43601ad3fc1424d429b87 Mon Sep 17 00:00:00 2001 From: goncalo-rodrigues Date: Tue, 5 Jul 2022 10:18:35 +0200 Subject: [PATCH 3/6] add zones to kubernetes node pools --- .../resourcespb/kubernetes_node_pool.pb.go | 171 +++++----- .../resourcespb/kubernetes_node_pool.proto | 4 + .../azure_aks_node_pool.go | 1 + .../kubernetes_node_pool/gcp_gke_node_pool.go | 1 + .../output/kubernetes_service/kube_config.go | 6 +- resources/types/aws/kubernetes_node_pool.go | 16 +- resources/types/azure/kubernetes_node_pool.go | 11 + resources/types/gcp/kubernetes_cluster.go | 2 +- resources/types/gcp/kubernetes_node_pool.go | 12 + resources/types/kubernetes_node_pool.go | 3 + .../kubernetes_zones/config.textproto | 282 ++++++++++++++++ .../kubernetes/kubernetes_zones/main.tf | 315 ++++++++++++++++++ test/e2e/common.go | 2 +- test/e2e/e2e.go | 3 +- test/e2e/kubernetes_test.go | 13 +- test/e2e/nic_test.go | 8 +- test/e2e/rollback_test.go | 6 +- test/e2e/virtual_machine_test.go | 2 +- 18 files changed, 763 insertions(+), 95 deletions(-) create mode 100755 test/_configs/kubernetes/kubernetes_zones/config.textproto create mode 100755 test/_configs/kubernetes/kubernetes_zones/main.tf diff --git a/api/proto/resourcespb/kubernetes_node_pool.pb.go b/api/proto/resourcespb/kubernetes_node_pool.pb.go index f9093d81..0c166ba0 100644 --- a/api/proto/resourcespb/kubernetes_node_pool.pb.go +++ b/api/proto/resourcespb/kubernetes_node_pool.pb.go @@ -325,6 +325,7 @@ type KubernetesNodePoolArgs struct { MaxNodeCount int32 `protobuf:"varint,7,opt,name=max_node_count,json=maxNodeCount,proto3" json:"max_node_count,omitempty"` VmSize commonpb.VmSize_Enum `protobuf:"varint,8,opt,name=vm_size,json=vmSize,proto3,enum=dev.multy.common.VmSize_Enum" json:"vm_size,omitempty"` DiskSizeGb int64 `protobuf:"varint,9,opt,name=disk_size_gb,json=diskSizeGb,proto3" json:"disk_size_gb,omitempty"` + AvailabilityZone []int32 `protobuf:"varint,13,rep,packed,name=availability_zone,json=availabilityZone,proto3" json:"availability_zone,omitempty"` AwsOverride *KubernetesNodePoolAwsOverride `protobuf:"bytes,11,opt,name=aws_override,json=awsOverride,proto3" json:"aws_override,omitempty"` AzureOverride *KubernetesNodePoolAzureOverride `protobuf:"bytes,12,opt,name=azure_override,json=azureOverride,proto3" json:"azure_override,omitempty"` Labels map[string]string `protobuf:"bytes,10,rep,name=labels,proto3" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` @@ -425,6 +426,13 @@ func (x *KubernetesNodePoolArgs) GetDiskSizeGb() int64 { return 0 } +func (x *KubernetesNodePoolArgs) GetAvailabilityZone() []int32 { + if x != nil { + return x.AvailabilityZone + } + return nil +} + func (x *KubernetesNodePoolArgs) GetAwsOverride() *KubernetesNodePoolAwsOverride { if x != nil { return x.AwsOverride @@ -460,6 +468,7 @@ type KubernetesNodePoolResource struct { MaxNodeCount int32 `protobuf:"varint,7,opt,name=max_node_count,json=maxNodeCount,proto3" json:"max_node_count,omitempty"` VmSize commonpb.VmSize_Enum `protobuf:"varint,8,opt,name=vm_size,json=vmSize,proto3,enum=dev.multy.common.VmSize_Enum" json:"vm_size,omitempty"` DiskSizeGb int64 `protobuf:"varint,9,opt,name=disk_size_gb,json=diskSizeGb,proto3" json:"disk_size_gb,omitempty"` + AvailabilityZone []int32 `protobuf:"varint,13,rep,packed,name=availability_zone,json=availabilityZone,proto3" json:"availability_zone,omitempty"` AwsOverride *KubernetesNodePoolAwsOverride `protobuf:"bytes,11,opt,name=aws_override,json=awsOverride,proto3" json:"aws_override,omitempty"` AzureOverride *KubernetesNodePoolAzureOverride `protobuf:"bytes,12,opt,name=azure_override,json=azureOverride,proto3" json:"azure_override,omitempty"` Labels map[string]string `protobuf:"bytes,10,rep,name=labels,proto3" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` @@ -560,6 +569,13 @@ func (x *KubernetesNodePoolResource) GetDiskSizeGb() int64 { return 0 } +func (x *KubernetesNodePoolResource) GetAvailabilityZone() []int32 { + if x != nil { + return x.AvailabilityZone + } + return nil +} + func (x *KubernetesNodePoolResource) GetAwsOverride() *KubernetesNodePoolAwsOverride { if x != nil { return x.AwsOverride @@ -622,7 +638,7 @@ var file_api_proto_resourcespb_kubernetes_node_pool_proto_rawDesc = []byte{ 0x22, 0x3a, 0x0a, 0x1f, 0x4b, 0x75, 0x62, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x65, 0x73, 0x4e, 0x6f, 0x64, 0x65, 0x50, 0x6f, 0x6f, 0x6c, 0x41, 0x7a, 0x75, 0x72, 0x65, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x12, 0x17, 0x0a, 0x07, 0x76, 0x6d, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x76, 0x6d, 0x53, 0x69, 0x7a, 0x65, 0x22, 0xd6, 0x05, 0x0a, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x76, 0x6d, 0x53, 0x69, 0x7a, 0x65, 0x22, 0x83, 0x06, 0x0a, 0x16, 0x4b, 0x75, 0x62, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x65, 0x73, 0x4e, 0x6f, 0x64, 0x65, 0x50, 0x6f, 0x6f, 0x6c, 0x41, 0x72, 0x67, 0x73, 0x12, 0x56, 0x0a, 0x11, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x01, @@ -648,80 +664,85 @@ var file_api_proto_resourcespb_kubernetes_node_pool_proto_rawDesc = []byte{ 0x56, 0x6d, 0x53, 0x69, 0x7a, 0x65, 0x2e, 0x45, 0x6e, 0x75, 0x6d, 0x52, 0x06, 0x76, 0x6d, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x20, 0x0a, 0x0c, 0x64, 0x69, 0x73, 0x6b, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x5f, 0x67, 0x62, 0x18, 0x09, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x64, 0x69, 0x73, 0x6b, 0x53, - 0x69, 0x7a, 0x65, 0x47, 0x62, 0x12, 0x55, 0x0a, 0x0c, 0x61, 0x77, 0x73, 0x5f, 0x6f, 0x76, 0x65, - 0x72, 0x72, 0x69, 0x64, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x64, 0x65, - 0x76, 0x2e, 0x6d, 0x75, 0x6c, 0x74, 0x79, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x73, 0x2e, 0x4b, 0x75, 0x62, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x65, 0x73, 0x4e, 0x6f, 0x64, 0x65, - 0x50, 0x6f, 0x6f, 0x6c, 0x41, 0x77, 0x73, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x52, - 0x0b, 0x61, 0x77, 0x73, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x12, 0x5b, 0x0a, 0x0e, - 0x61, 0x7a, 0x75, 0x72, 0x65, 0x5f, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x18, 0x0c, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x34, 0x2e, 0x64, 0x65, 0x76, 0x2e, 0x6d, 0x75, 0x6c, 0x74, 0x79, - 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x4b, 0x75, 0x62, 0x65, 0x72, - 0x6e, 0x65, 0x74, 0x65, 0x73, 0x4e, 0x6f, 0x64, 0x65, 0x50, 0x6f, 0x6f, 0x6c, 0x41, 0x7a, 0x75, - 0x72, 0x65, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x52, 0x0d, 0x61, 0x7a, 0x75, 0x72, - 0x65, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x12, 0x4f, 0x0a, 0x06, 0x6c, 0x61, 0x62, - 0x65, 0x6c, 0x73, 0x18, 0x0a, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x37, 0x2e, 0x64, 0x65, 0x76, 0x2e, - 0x6d, 0x75, 0x6c, 0x74, 0x79, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, - 0x4b, 0x75, 0x62, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x65, 0x73, 0x4e, 0x6f, 0x64, 0x65, 0x50, 0x6f, - 0x6f, 0x6c, 0x41, 0x72, 0x67, 0x73, 0x2e, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x45, 0x6e, 0x74, - 0x72, 0x79, 0x52, 0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x1a, 0x39, 0x0a, 0x0b, 0x4c, 0x61, - 0x62, 0x65, 0x6c, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, - 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, - 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xe4, 0x05, 0x0a, 0x1a, 0x4b, 0x75, 0x62, 0x65, 0x72, 0x6e, - 0x65, 0x74, 0x65, 0x73, 0x4e, 0x6f, 0x64, 0x65, 0x50, 0x6f, 0x6f, 0x6c, 0x52, 0x65, 0x73, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x12, 0x5c, 0x0a, 0x11, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x5f, 0x70, - 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x2f, 0x2e, 0x64, 0x65, 0x76, 0x2e, 0x6d, 0x75, 0x6c, 0x74, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, - 0x6f, 0x6e, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x43, 0x68, 0x69, 0x6c, 0x64, 0x52, 0x65, - 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, - 0x52, 0x10, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, - 0x72, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, - 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, 0x75, 0x62, 0x6e, 0x65, - 0x74, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x69, - 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, - 0x49, 0x64, 0x12, 0x2e, 0x0a, 0x13, 0x73, 0x74, 0x61, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x5f, 0x6e, - 0x6f, 0x64, 0x65, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, - 0x11, 0x73, 0x74, 0x61, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x4e, 0x6f, 0x64, 0x65, 0x43, 0x6f, 0x75, - 0x6e, 0x74, 0x12, 0x24, 0x0a, 0x0e, 0x6d, 0x69, 0x6e, 0x5f, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x63, - 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x6d, 0x69, 0x6e, 0x4e, - 0x6f, 0x64, 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x24, 0x0a, 0x0e, 0x6d, 0x61, 0x78, 0x5f, - 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x05, - 0x52, 0x0c, 0x6d, 0x61, 0x78, 0x4e, 0x6f, 0x64, 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x36, - 0x0a, 0x07, 0x76, 0x6d, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0e, 0x32, - 0x1d, 0x2e, 0x64, 0x65, 0x76, 0x2e, 0x6d, 0x75, 0x6c, 0x74, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, - 0x6f, 0x6e, 0x2e, 0x56, 0x6d, 0x53, 0x69, 0x7a, 0x65, 0x2e, 0x45, 0x6e, 0x75, 0x6d, 0x52, 0x06, - 0x76, 0x6d, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x20, 0x0a, 0x0c, 0x64, 0x69, 0x73, 0x6b, 0x5f, 0x73, - 0x69, 0x7a, 0x65, 0x5f, 0x67, 0x62, 0x18, 0x09, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x64, 0x69, - 0x73, 0x6b, 0x53, 0x69, 0x7a, 0x65, 0x47, 0x62, 0x12, 0x55, 0x0a, 0x0c, 0x61, 0x77, 0x73, 0x5f, - 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x32, - 0x2e, 0x64, 0x65, 0x76, 0x2e, 0x6d, 0x75, 0x6c, 0x74, 0x79, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x73, 0x2e, 0x4b, 0x75, 0x62, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x65, 0x73, 0x4e, - 0x6f, 0x64, 0x65, 0x50, 0x6f, 0x6f, 0x6c, 0x41, 0x77, 0x73, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, - 0x64, 0x65, 0x52, 0x0b, 0x61, 0x77, 0x73, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x12, - 0x5b, 0x0a, 0x0e, 0x61, 0x7a, 0x75, 0x72, 0x65, 0x5f, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, - 0x65, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x34, 0x2e, 0x64, 0x65, 0x76, 0x2e, 0x6d, 0x75, - 0x6c, 0x74, 0x79, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x4b, 0x75, - 0x62, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x65, 0x73, 0x4e, 0x6f, 0x64, 0x65, 0x50, 0x6f, 0x6f, 0x6c, - 0x41, 0x7a, 0x75, 0x72, 0x65, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x52, 0x0d, 0x61, - 0x7a, 0x75, 0x72, 0x65, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x12, 0x53, 0x0a, 0x06, - 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x18, 0x0a, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3b, 0x2e, 0x64, - 0x65, 0x76, 0x2e, 0x6d, 0x75, 0x6c, 0x74, 0x79, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x73, 0x2e, 0x4b, 0x75, 0x62, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x65, 0x73, 0x4e, 0x6f, 0x64, - 0x65, 0x50, 0x6f, 0x6f, 0x6c, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x4c, 0x61, - 0x62, 0x65, 0x6c, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c, - 0x73, 0x1a, 0x39, 0x0a, 0x0b, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, - 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, - 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x5e, 0x0a, 0x17, - 0x64, 0x65, 0x76, 0x2e, 0x6d, 0x75, 0x6c, 0x74, 0x79, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x72, 0x65, - 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x42, 0x0e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x73, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x31, 0x67, 0x69, 0x74, 0x68, 0x75, - 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6d, 0x75, 0x6c, 0x74, 0x79, 0x63, 0x6c, 0x6f, 0x75, 0x64, - 0x2f, 0x6d, 0x75, 0x6c, 0x74, 0x79, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x33, + 0x69, 0x7a, 0x65, 0x47, 0x62, 0x12, 0x2b, 0x0a, 0x11, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, + 0x69, 0x6c, 0x69, 0x74, 0x79, 0x5f, 0x7a, 0x6f, 0x6e, 0x65, 0x18, 0x0d, 0x20, 0x03, 0x28, 0x05, + 0x52, 0x10, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x5a, 0x6f, + 0x6e, 0x65, 0x12, 0x55, 0x0a, 0x0c, 0x61, 0x77, 0x73, 0x5f, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, + 0x64, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x64, 0x65, 0x76, 0x2e, 0x6d, + 0x75, 0x6c, 0x74, 0x79, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x4b, + 0x75, 0x62, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x65, 0x73, 0x4e, 0x6f, 0x64, 0x65, 0x50, 0x6f, 0x6f, + 0x6c, 0x41, 0x77, 0x73, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x52, 0x0b, 0x61, 0x77, + 0x73, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x12, 0x5b, 0x0a, 0x0e, 0x61, 0x7a, 0x75, + 0x72, 0x65, 0x5f, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x18, 0x0c, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x34, 0x2e, 0x64, 0x65, 0x76, 0x2e, 0x6d, 0x75, 0x6c, 0x74, 0x79, 0x2e, 0x72, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x4b, 0x75, 0x62, 0x65, 0x72, 0x6e, 0x65, 0x74, + 0x65, 0x73, 0x4e, 0x6f, 0x64, 0x65, 0x50, 0x6f, 0x6f, 0x6c, 0x41, 0x7a, 0x75, 0x72, 0x65, 0x4f, + 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x52, 0x0d, 0x61, 0x7a, 0x75, 0x72, 0x65, 0x4f, 0x76, + 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x12, 0x4f, 0x0a, 0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, + 0x18, 0x0a, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x37, 0x2e, 0x64, 0x65, 0x76, 0x2e, 0x6d, 0x75, 0x6c, + 0x74, 0x79, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x4b, 0x75, 0x62, + 0x65, 0x72, 0x6e, 0x65, 0x74, 0x65, 0x73, 0x4e, 0x6f, 0x64, 0x65, 0x50, 0x6f, 0x6f, 0x6c, 0x41, + 0x72, 0x67, 0x73, 0x2e, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, + 0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x1a, 0x39, 0x0a, 0x0b, 0x4c, 0x61, 0x62, 0x65, 0x6c, + 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, + 0x38, 0x01, 0x22, 0x91, 0x06, 0x0a, 0x1a, 0x4b, 0x75, 0x62, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x65, + 0x73, 0x4e, 0x6f, 0x64, 0x65, 0x50, 0x6f, 0x6f, 0x6c, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x12, 0x5c, 0x0a, 0x11, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x5f, 0x70, 0x61, 0x72, 0x61, + 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x64, + 0x65, 0x76, 0x2e, 0x6d, 0x75, 0x6c, 0x74, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, + 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x43, 0x68, 0x69, 0x6c, 0x64, 0x52, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x52, 0x10, 0x63, + 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x12, + 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, + 0x61, 0x6d, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x5f, 0x69, 0x64, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x49, 0x64, + 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x49, 0x64, 0x12, + 0x2e, 0x0a, 0x13, 0x73, 0x74, 0x61, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x5f, 0x6e, 0x6f, 0x64, 0x65, + 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x11, 0x73, 0x74, + 0x61, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x4e, 0x6f, 0x64, 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, + 0x24, 0x0a, 0x0e, 0x6d, 0x69, 0x6e, 0x5f, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x63, 0x6f, 0x75, 0x6e, + 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x6d, 0x69, 0x6e, 0x4e, 0x6f, 0x64, 0x65, + 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x24, 0x0a, 0x0e, 0x6d, 0x61, 0x78, 0x5f, 0x6e, 0x6f, 0x64, + 0x65, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x6d, + 0x61, 0x78, 0x4e, 0x6f, 0x64, 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x36, 0x0a, 0x07, 0x76, + 0x6d, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1d, 0x2e, 0x64, + 0x65, 0x76, 0x2e, 0x6d, 0x75, 0x6c, 0x74, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, + 0x56, 0x6d, 0x53, 0x69, 0x7a, 0x65, 0x2e, 0x45, 0x6e, 0x75, 0x6d, 0x52, 0x06, 0x76, 0x6d, 0x53, + 0x69, 0x7a, 0x65, 0x12, 0x20, 0x0a, 0x0c, 0x64, 0x69, 0x73, 0x6b, 0x5f, 0x73, 0x69, 0x7a, 0x65, + 0x5f, 0x67, 0x62, 0x18, 0x09, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x64, 0x69, 0x73, 0x6b, 0x53, + 0x69, 0x7a, 0x65, 0x47, 0x62, 0x12, 0x2b, 0x0a, 0x11, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, + 0x69, 0x6c, 0x69, 0x74, 0x79, 0x5f, 0x7a, 0x6f, 0x6e, 0x65, 0x18, 0x0d, 0x20, 0x03, 0x28, 0x05, + 0x52, 0x10, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x5a, 0x6f, + 0x6e, 0x65, 0x12, 0x55, 0x0a, 0x0c, 0x61, 0x77, 0x73, 0x5f, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, + 0x64, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x64, 0x65, 0x76, 0x2e, 0x6d, + 0x75, 0x6c, 0x74, 0x79, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x4b, + 0x75, 0x62, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x65, 0x73, 0x4e, 0x6f, 0x64, 0x65, 0x50, 0x6f, 0x6f, + 0x6c, 0x41, 0x77, 0x73, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x52, 0x0b, 0x61, 0x77, + 0x73, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x12, 0x5b, 0x0a, 0x0e, 0x61, 0x7a, 0x75, + 0x72, 0x65, 0x5f, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x18, 0x0c, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x34, 0x2e, 0x64, 0x65, 0x76, 0x2e, 0x6d, 0x75, 0x6c, 0x74, 0x79, 0x2e, 0x72, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x4b, 0x75, 0x62, 0x65, 0x72, 0x6e, 0x65, 0x74, + 0x65, 0x73, 0x4e, 0x6f, 0x64, 0x65, 0x50, 0x6f, 0x6f, 0x6c, 0x41, 0x7a, 0x75, 0x72, 0x65, 0x4f, + 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x52, 0x0d, 0x61, 0x7a, 0x75, 0x72, 0x65, 0x4f, 0x76, + 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x12, 0x53, 0x0a, 0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, + 0x18, 0x0a, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3b, 0x2e, 0x64, 0x65, 0x76, 0x2e, 0x6d, 0x75, 0x6c, + 0x74, 0x79, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x4b, 0x75, 0x62, + 0x65, 0x72, 0x6e, 0x65, 0x74, 0x65, 0x73, 0x4e, 0x6f, 0x64, 0x65, 0x50, 0x6f, 0x6f, 0x6c, 0x52, + 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x45, 0x6e, + 0x74, 0x72, 0x79, 0x52, 0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x1a, 0x39, 0x0a, 0x0b, 0x4c, + 0x61, 0x62, 0x65, 0x6c, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, + 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x5e, 0x0a, 0x17, 0x64, 0x65, 0x76, 0x2e, 0x6d, 0x75, + 0x6c, 0x74, 0x79, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x73, 0x42, 0x0e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x50, 0x72, 0x6f, 0x74, + 0x6f, 0x50, 0x01, 0x5a, 0x31, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, + 0x6d, 0x75, 0x6c, 0x74, 0x79, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2f, 0x6d, 0x75, 0x6c, 0x74, 0x79, + 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x73, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/api/proto/resourcespb/kubernetes_node_pool.proto b/api/proto/resourcespb/kubernetes_node_pool.proto index 2440d667..b5d68dee 100644 --- a/api/proto/resourcespb/kubernetes_node_pool.proto +++ b/api/proto/resourcespb/kubernetes_node_pool.proto @@ -44,6 +44,8 @@ message KubernetesNodePoolArgs { int32 max_node_count = 7; common.VmSize.Enum vm_size = 8; int64 disk_size_gb = 9; + repeated int32 availability_zone = 13; + KubernetesNodePoolAwsOverride aws_override = 11; KubernetesNodePoolAzureOverride azure_override = 12; @@ -61,6 +63,8 @@ message KubernetesNodePoolResource { int32 max_node_count = 7; common.VmSize.Enum vm_size = 8; int64 disk_size_gb = 9; + repeated int32 availability_zone = 13; + KubernetesNodePoolAwsOverride aws_override = 11; KubernetesNodePoolAzureOverride azure_override = 12; diff --git a/resources/output/kubernetes_node_pool/azure_aks_node_pool.go b/resources/output/kubernetes_node_pool/azure_aks_node_pool.go index 417e8573..a0203c88 100644 --- a/resources/output/kubernetes_node_pool/azure_aks_node_pool.go +++ b/resources/output/kubernetes_node_pool/azure_aks_node_pool.go @@ -13,4 +13,5 @@ type AzureKubernetesNodePool struct { EnableAutoScaling bool `hcl:"enable_auto_scaling"` VmSize string `hcl:"vm_size"` VirtualNetworkSubnetId string `hcl:"vnet_subnet_id,expr"` + Zones []string `hcl:"zones" hcle:"omitempty"` } diff --git a/resources/output/kubernetes_node_pool/gcp_gke_node_pool.go b/resources/output/kubernetes_node_pool/gcp_gke_node_pool.go index 5bf7ba58..91c6e758 100644 --- a/resources/output/kubernetes_node_pool/gcp_gke_node_pool.go +++ b/resources/output/kubernetes_node_pool/gcp_gke_node_pool.go @@ -6,6 +6,7 @@ type GoogleContainerNodePool struct { *common.GcpResource `hcl:",squash" default:"name=google_container_node_pool"` Cluster string `hcl:"cluster,expr"` //expr InitialNodeCount int `hcl:"initial_node_count"` + NodeLocations []string `hcl:"node_locations" hcle:"omitempty"` Autoscaling GoogleContainerNodePoolAutoScaling `hcl:"autoscaling"` NodeConfig GoogleContainerNodeConfig `hcl:"node_config"` NetworkConfig GoogleContainerNetworkConfig `hcl:"network_config" hcle:"omitempty"` diff --git a/resources/output/kubernetes_service/kube_config.go b/resources/output/kubernetes_service/kube_config.go index f0b10852..9bf92018 100644 --- a/resources/output/kubernetes_service/kube_config.go +++ b/resources/output/kubernetes_service/kube_config.go @@ -39,8 +39,8 @@ type KubeConfigUser struct { type KubeConfigExec struct { ApiVersion string `yaml:"apiVersion"` Command string `yaml:"command"` - Args []string `yaml:"args"` + Args []string `yaml:"args,omitempty"` InteractiveMode string `yaml:"interactiveMode"` - ProvideClusterInfo bool `yaml:"provideClusterInfo"` - InstallHint string `yaml:"installHint"` + ProvideClusterInfo bool `yaml:"provideClusterInfo,omitempty"` + InstallHint string `yaml:"installHint,omitempty"` } diff --git a/resources/types/aws/kubernetes_node_pool.go b/resources/types/aws/kubernetes_node_pool.go index fe78d6d6..2cfb3c79 100644 --- a/resources/types/aws/kubernetes_node_pool.go +++ b/resources/types/aws/kubernetes_node_pool.go @@ -34,14 +34,26 @@ func (r AwsKubernetesNodePool) FromState(state *output.TfState) (*resourcespb.Ku MaxNodeCount: r.Args.MaxNodeCount, VmSize: r.Args.VmSize, DiskSizeGb: r.Args.DiskSizeGb, - Labels: r.Args.Labels, + AvailabilityZone: r.Args.AvailabilityZone, AwsOverride: r.Args.AwsOverride, AzureOverride: r.Args.AzureOverride, + Labels: r.Args.Labels, }, nil } func (r AwsKubernetesNodePool) Translate(_ resources.MultyContext) ([]output.TfBlock, error) { - subnetIds := AwsSubnet{r.Subnet}.GetSubnetIds() + var subnetIds []string + if len(r.Args.AvailabilityZone) == 0 { + subnetIds = AwsSubnet{r.Subnet}.GetSubnetIds() + } else { + for _, zone := range r.Args.AvailabilityZone { + id, err := AwsSubnet{r.Subnet}.GetSubnetId(zone) + if err != nil { + return nil, err + } + subnetIds = append(subnetIds, id) + } + } var instanceTypes []string if r.Args.AwsOverride.GetInstanceTypes() != nil { diff --git a/resources/types/azure/kubernetes_node_pool.go b/resources/types/azure/kubernetes_node_pool.go index 7be4e6a2..f52c425f 100644 --- a/resources/types/azure/kubernetes_node_pool.go +++ b/resources/types/azure/kubernetes_node_pool.go @@ -35,6 +35,7 @@ func (r AzureKubernetesNodePool) FromState(state *output.TfState) (*resourcespb. Labels: r.Args.Labels, AwsOverride: r.Args.AwsOverride, AzureOverride: r.Args.AzureOverride, + AvailabilityZone: r.Args.AvailabilityZone, }, nil } @@ -65,6 +66,15 @@ func (r AzureKubernetesNodePool) translateAzNodePool() (*kubernetes_node_pool.Az vmSize = common.VMSIZE[r.Args.VmSize][r.GetCloud()] } + var zones []string + for _, zone := range r.Args.AvailabilityZone { + availabilityZone, err := common.GetAvailabilityZone(r.KubernetesCluster.GetLocation(), int(zone), r.GetCloud()) + if err != nil { + return nil, err + } + zones = append(zones, availabilityZone) + } + return &kubernetes_node_pool.AzureKubernetesNodePool{ AzResource: &common.AzResource{ TerraformResource: output.TerraformResource{ResourceId: r.ResourceId}, @@ -78,6 +88,7 @@ func (r AzureKubernetesNodePool) translateAzNodePool() (*kubernetes_node_pool.Az EnableAutoScaling: true, VmSize: vmSize, VirtualNetworkSubnetId: subnetId, + Zones: zones, }, nil } diff --git a/resources/types/gcp/kubernetes_cluster.go b/resources/types/gcp/kubernetes_cluster.go index 5e4ea6ff..ab95962e 100644 --- a/resources/types/gcp/kubernetes_cluster.go +++ b/resources/types/gcp/kubernetes_cluster.go @@ -44,7 +44,7 @@ func (r GcpKubernetesCluster) FromState(state *output.TfState) (*resourcespb.Kub if err != nil { return nil, err } - result.Endpoint = cluster.Endpoint + result.Endpoint = fmt.Sprintf("https://%s", cluster.Endpoint) result.CaCertificate = cluster.MasterAuth[0].ClusterCaCertificate rawConfig, err := createKubeConfig(r.Args.Name, result.CaCertificate, result.Endpoint) diff --git a/resources/types/gcp/kubernetes_node_pool.go b/resources/types/gcp/kubernetes_node_pool.go index a258df28..ecc1081e 100644 --- a/resources/types/gcp/kubernetes_node_pool.go +++ b/resources/types/gcp/kubernetes_node_pool.go @@ -36,6 +36,7 @@ func (r GcpKubernetesNodePool) FromState(state *output.TfState) (*resourcespb.Ku DiskSizeGb: r.Args.DiskSizeGb, Labels: r.Args.Labels, AzureOverride: r.Args.AzureOverride, + AvailabilityZone: r.Args.AvailabilityZone, }, nil } @@ -48,9 +49,20 @@ func (r GcpKubernetesNodePool) Translate(_ resources.MultyContext) ([]output.TfB if err != nil { return nil, err } + + var zones []string + for _, zone := range r.Args.AvailabilityZone { + availabilityZone, err := common.GetAvailabilityZone(r.KubernetesCluster.GetLocation(), int(zone), r.GetCloud()) + if err != nil { + return nil, err + } + zones = append(zones, availabilityZone) + } + nodePool := &kubernetes_node_pool.GoogleContainerNodePool{ GcpResource: common.NewGcpResource(r.ResourceId, r.Args.Name, r.KubernetesCluster.Args.GetGcpOverride().GetProject()), Cluster: clusterId, + NodeLocations: zones, InitialNodeCount: int(r.Args.StartingNodeCount), Autoscaling: kubernetes_node_pool.GoogleContainerNodePoolAutoScaling{ MinNodeCount: int(r.Args.MinNodeCount), diff --git a/resources/types/kubernetes_node_pool.go b/resources/types/kubernetes_node_pool.go index 352e06e6..632a5a65 100644 --- a/resources/types/kubernetes_node_pool.go +++ b/resources/types/kubernetes_node_pool.go @@ -76,6 +76,9 @@ func (r *KubernetesNodePool) Validate(ctx resources.MultyContext) (errs []valida if r.Subnet.VirtualNetwork.ResourceId != r.KubernetesCluster.VirtualNetwork.ResourceId { errs = append(errs, r.NewValidationError(fmt.Errorf("subnet must be in the same virtual network as the cluster"), "subnet_id")) } + if r.Subnet != r.KubernetesCluster.DefaultNodePool.Subnet { + errs = append(errs, r.NewValidationError(fmt.Errorf("different subnets for node pools within the same cluster are not yet supported"), "subnet_id")) + } return errs } diff --git a/test/_configs/kubernetes/kubernetes_zones/config.textproto b/test/_configs/kubernetes/kubernetes_zones/config.textproto new file mode 100755 index 00000000..9d524474 --- /dev/null +++ b/test/_configs/kubernetes/kubernetes_zones/config.textproto @@ -0,0 +1,282 @@ +resources: { + resource_id: "example_vn_gcp" + resource_args: { + resource_args: { + [type.googleapis.com/dev.multy.resources.VirtualNetworkArgs]: { + common_parameters: { + resource_group_id: "rg1" + location: EU_WEST_1 + cloud_provider: GCP + } + name: "k8svn" + cidr_block: "10.0.0.0/16" + gcp_override: { + project: "multy-project" + } + } + } + } +} +resources: { + resource_id: "public_subnet_gcp" + resource_args: { + resource_args: { + [type.googleapis.com/dev.multy.resources.SubnetArgs]: { + name: "public-subnet" + cidr_block: "10.0.0.0/24" + virtual_network_id: "example_vn_gcp" + availability_zone: 2 + } + } + } +} +resources: { + resource_id: "rt_gcp" + resource_args: { + resource_args: { + [type.googleapis.com/dev.multy.resources.RouteTableArgs]: { + name: "test-rt" + virtual_network_id: "example_vn_gcp" + routes: { + cidr_block: "0.0.0.0/0" + destination: INTERNET + } + } + } + } +} +resources: { + resource_id: "rta_gcp" + resource_args: { + resource_args: { + [type.googleapis.com/dev.multy.resources.RouteTableAssociationArgs]: { + subnet_id: "public_subnet_gcp" + route_table_id: "rt_gcp" + } + } + } +} +resources: { + resource_id: "cluster_gcp" + resource_args: { + resource_args: { + [type.googleapis.com/dev.multy.resources.KubernetesClusterArgs]: { + common_parameters: { + resource_group_id: "rg1" + location: EU_WEST_1 + cloud_provider: GCP + } + name: "cluster" + service_cidr: "10.100.0.0/16" + virtual_network_id: "example_vn_gcp" + default_node_pool: { + name: "node-pool-gcp" + subnet_id: "public_subnet_gcp" + min_node_count: 1 + max_node_count: 1 + vm_size: GENERAL_MEDIUM + availability_zone: 1 + } + gcp_override: { + project: "multy-project" + } + } + } + } +} +resources: { + resource_id: "example_vn_aws" + resource_args: { + resource_args: { + [type.googleapis.com/dev.multy.resources.VirtualNetworkArgs]: { + common_parameters: { + resource_group_id: "rg1" + location: EU_WEST_1 + cloud_provider: AWS + } + name: "example_vn" + cidr_block: "10.0.0.0/16" + } + } + } +} +resources: { + resource_id: "example_vn_azure" + resource_args: { + resource_args: { + [type.googleapis.com/dev.multy.resources.VirtualNetworkArgs]: { + common_parameters: { + resource_group_id: "rg1" + location: EU_WEST_1 + cloud_provider: AZURE + } + name: "example_vn" + cidr_block: "10.0.0.0/16" + } + } + } +} +resources: { + resource_id: "public_subnet_aws" + resource_args: { + resource_args: { + [type.googleapis.com/dev.multy.resources.SubnetArgs]: { + name: "public-subnet" + cidr_block: "10.0.0.0/24" + virtual_network_id: "example_vn_aws" + availability_zone: 2 + } + } + } +} +resources: { + resource_id: "public_subnet_azure" + resource_args: { + resource_args: { + [type.googleapis.com/dev.multy.resources.SubnetArgs]: { + name: "public-subnet" + cidr_block: "10.0.0.0/24" + virtual_network_id: "example_vn_azure" + availability_zone: 2 + } + } + } +} +resources: { + resource_id: "rt_aws" + resource_args: { + resource_args: { + [type.googleapis.com/dev.multy.resources.RouteTableArgs]: { + name: "test-rt" + virtual_network_id: "example_vn_aws" + routes: { + cidr_block: "0.0.0.0/0" + destination: INTERNET + } + } + } + } +} +resources: { + resource_id: "rt_azure" + resource_args: { + resource_args: { + [type.googleapis.com/dev.multy.resources.RouteTableArgs]: { + name: "test-rt" + virtual_network_id: "example_vn_azure" + routes: { + cidr_block: "0.0.0.0/0" + destination: INTERNET + } + } + } + } +} +resources: { + resource_id: "rta_aws" + resource_args: { + resource_args: { + [type.googleapis.com/dev.multy.resources.RouteTableAssociationArgs]: { + subnet_id: "public_subnet_aws" + route_table_id: "rt_aws" + } + } + } +} +resources: { + resource_id: "rta_azure" + resource_args: { + resource_args: { + [type.googleapis.com/dev.multy.resources.RouteTableAssociationArgs]: { + subnet_id: "public_subnet_azure" + route_table_id: "rt_azure" + } + } + } +} +resources: { + resource_id: "cluster_aws" + resource_args: { + resource_args: { + [type.googleapis.com/dev.multy.resources.KubernetesClusterArgs]: { + common_parameters: { + resource_group_id: "rg1" + location: EU_WEST_1 + cloud_provider: AWS + } + name: "cluster_aws" + service_cidr: "10.100.0.0/16" + virtual_network_id: "example_vn_aws" + default_node_pool: { + name: "node_pool_aws" + subnet_id: "public_subnet_aws" + min_node_count: 1 + max_node_count: 1 + vm_size: GENERAL_MEDIUM + availability_zone: 1 + } + } + } + } +} +resources: { + resource_id: "cluster_azure" + resource_args: { + resource_args: { + [type.googleapis.com/dev.multy.resources.KubernetesClusterArgs]: { + common_parameters: { + resource_group_id: "rg1" + location: EU_WEST_1 + cloud_provider: AZURE + } + name: "cluster_azure" + service_cidr: "10.100.0.0/16" + virtual_network_id: "example_vn_azure" + default_node_pool: { + name: "default" + subnet_id: "public_subnet_azure" + min_node_count: 1 + max_node_count: 1 + vm_size: GENERAL_MEDIUM + availability_zone: 1 + } + } + } + } +} +resources: { + resource_id: "rg1" + resource_args: { + resource_args: { + [type.googleapis.com/dev.multy.resources.ResourceGroupArgs]: { + common_parameters: { + location: EU_WEST_1 + cloud_provider: AZURE + } + name: "rg1" + } + } + } +} + + +# proto-file: api/proto/configpb/config.proto +# proto-import: api/proto/resourcespb/database.proto +# proto-import: api/proto/resourcespb/kubernetes_cluster.proto +# proto-import: api/proto/resourcespb/kubernetes_node_pool.proto +# proto-import: api/proto/resourcespb/lambda.proto +# proto-import: api/proto/resourcespb/network_interface.proto +# proto-import: api/proto/resourcespb/network_security_group.proto +# proto-import: api/proto/resourcespb/public_ip.proto +# proto-import: api/proto/resourcespb/resource_group.proto +# proto-import: api/proto/resourcespb/route_table_association.proto +# proto-import: api/proto/resourcespb/object_storage.proto +# proto-import: api/proto/resourcespb/object_storage_object.proto +# proto-import: api/proto/resourcespb/route_table.proto +# proto-import: api/proto/resourcespb/subnet.proto +# proto-import: api/proto/resourcespb/vault.proto +# proto-import: api/proto/resourcespb/vault_access_policy.proto +# proto-import: api/proto/resourcespb/vault_secret.proto +# proto-import: api/proto/resourcespb/virtual_machine.proto +# proto-import: api/proto/resourcespb/virtual_network.proto +# proto-message: config.Config diff --git a/test/_configs/kubernetes/kubernetes_zones/main.tf b/test/_configs/kubernetes/kubernetes_zones/main.tf new file mode 100755 index 00000000..5a01d85f --- /dev/null +++ b/test/_configs/kubernetes/kubernetes_zones/main.tf @@ -0,0 +1,315 @@ +resource "aws_iam_role" "cluster_aws_default_pool" { + tags = { "Name" = "multy-k8nodepool-cluster_aws-node_pool_aws-role" } + name = "multy-k8nodepool-cluster_aws-node_pool_aws-role" + assume_role_policy = "{\"Statement\":[{\"Action\":[\"sts:AssumeRole\"],\"Effect\":\"Allow\",\"Principal\":{\"Service\":\"ec2.amazonaws.com\"}}],\"Version\":\"2012-10-17\"}" + provider = "aws.eu-west-1" +} +resource "aws_iam_role_policy_attachment" "cluster_aws_default_pool_AmazonEKSWorkerNodePolicy" { + role = aws_iam_role.cluster_aws_default_pool.name + policy_arn = "arn:aws:iam::aws:policy/AmazonEKSWorkerNodePolicy" + provider = "aws.eu-west-1" +} +resource "aws_iam_role_policy_attachment" "cluster_aws_default_pool_AmazonEKS_CNI_Policy" { + role = aws_iam_role.cluster_aws_default_pool.name + policy_arn = "arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy" + provider = "aws.eu-west-1" +} +resource "aws_iam_role_policy_attachment" "cluster_aws_default_pool_AmazonEC2ContainerRegistryReadOnly" { + role = aws_iam_role.cluster_aws_default_pool.name + policy_arn = "arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly" + provider = "aws.eu-west-1" +} +resource "aws_eks_node_group" "cluster_aws_default_pool" { + cluster_name = aws_eks_cluster.cluster_aws.id + node_group_name = "node_pool_aws" + node_role_arn = aws_iam_role.cluster_aws_default_pool.arn + subnet_ids = [aws_subnet.public_subnet_aws-1.id] + scaling_config { + desired_size = 1 + max_size = 1 + min_size = 1 + } + instance_types = ["t2.medium"] + provider = "aws.eu-west-1" +} +resource "aws_subnet" "cluster_aws_public_subnet" { + tags = { "Name" = "cluster_aws_public_subnet" } + cidr_block = "10.0.255.240/28" + vpc_id = aws_vpc.example_vn_aws.id + availability_zone = "eu-west-1a" + provider = "aws.eu-west-1" +} +resource "aws_subnet" "cluster_aws_private_subnet" { + tags = { "Name" = "cluster_aws_private_subnet" } + cidr_block = "10.0.255.224/28" + vpc_id = aws_vpc.example_vn_aws.id + availability_zone = "eu-west-1b" + provider = "aws.eu-west-1" +} +resource "aws_route_table" "cluster_aws_public_rt" { + tags = { "Name" = "cluster_aws_public_rt" } + vpc_id = aws_vpc.example_vn_aws.id + route { + cidr_block = "0.0.0.0/0" + gateway_id = aws_internet_gateway.example_vn_aws.id + } + provider = "aws.eu-west-1" +} +resource "aws_route_table_association" "cluster_aws_public_rta" { + subnet_id = aws_subnet.cluster_aws_public_subnet.id + route_table_id = aws_route_table.cluster_aws_public_rt.id + provider = "aws.eu-west-1" +} +resource "aws_iam_role" "cluster_aws" { + tags = { "Name" = "multy-k8cluster-cluster_aws-role" } + name = "multy-k8cluster-cluster_aws-role" + assume_role_policy = "{\"Statement\":[{\"Action\":[\"sts:AssumeRole\"],\"Effect\":\"Allow\",\"Principal\":{\"Service\":\"eks.amazonaws.com\"}}],\"Version\":\"2012-10-17\"}" + provider = "aws.eu-west-1" +} +resource "aws_iam_role_policy_attachment" "cluster_aws_AmazonEKSClusterPolicy" { + role = aws_iam_role.cluster_aws.name + policy_arn = "arn:aws:iam::aws:policy/AmazonEKSClusterPolicy" + provider = "aws.eu-west-1" +} +resource "aws_iam_role_policy_attachment" "cluster_aws_AmazonEKSVPCResourceController" { + role = aws_iam_role.cluster_aws.name + policy_arn = "arn:aws:iam::aws:policy/AmazonEKSVPCResourceController" + provider = "aws.eu-west-1" +} +resource "aws_eks_cluster" "cluster_aws" { + depends_on = [aws_subnet.cluster_aws_public_subnet, aws_subnet.cluster_aws_private_subnet, aws_route_table.cluster_aws_public_rt, aws_route_table_association.cluster_aws_public_rta, aws_iam_role_policy_attachment.cluster_aws_AmazonEKSClusterPolicy, aws_iam_role_policy_attachment.cluster_aws_AmazonEKSVPCResourceController] + tags = { "Name" = "cluster_aws" } + role_arn = aws_iam_role.cluster_aws.arn + vpc_config { + subnet_ids = [aws_subnet.cluster_aws_public_subnet.id, aws_subnet.cluster_aws_private_subnet.id] + endpoint_private_access = true + } + kubernetes_network_config { + service_ipv4_cidr = "10.100.0.0/16" + } + name = "cluster_aws" + provider = "aws.eu-west-1" +} +resource "azurerm_kubernetes_cluster" "cluster_azure" { + resource_group_name = azurerm_resource_group.rg1.name + name = "cluster_azure" + location = "northeurope" + default_node_pool { + name = "default" + node_count = 1 + max_count = 1 + min_count = 1 + enable_auto_scaling = true + vm_size = "Standard_B2s" + vnet_subnet_id = azurerm_subnet.public_subnet_azure.id + zones = ["1"] + } + dns_prefix = "clusterazureaks7hut" + identity { + type = "SystemAssigned" + } + network_profile { + network_plugin = "azure" + dns_service_ip = "10.100.0.10" + docker_bridge_cidr = "172.17.0.1/16" + service_cidr = "10.100.0.0/16" + } +} +resource "google_service_account" "cluster-sa-avg8" { + project = "multy-project" + account_id = "cluster-sa-avg8" + display_name = "Service Account for cluster cluster - created by Multy" + provider = "google.europe-west1" +} +resource "google_container_node_pool" "cluster_gcp_default_pool" { + name = "node-pool-gcp" + project = "multy-project" + cluster = google_container_cluster.cluster_gcp.id + initial_node_count = 1 + node_locations = ["europe-west1-b"] + autoscaling { + min_node_count = 1 + max_node_count = 1 + } + node_config { + machine_type = "e2-medium" + tags = ["subnet-public-subnet"] + service_account = google_service_account.cluster-sa-avg8.email + oauth_scopes = ["https://www.googleapis.com/auth/cloud-platform"] + } + provider = "google.europe-west1" +} +resource "google_container_cluster" "cluster_gcp" { + name = "cluster" + project = "multy-project" + remove_default_node_pool = true + initial_node_count = 1 + subnetwork = google_compute_subnetwork.public_subnet_gcp.id + network = google_compute_network.example_vn_gcp.id + ip_allocation_policy { + services_ipv4_cidr_block = "10.100.0.0/16" + } + location = "europe-west1" + node_config { + machine_type = "e2-micro" + tags = ["subnet-public-subnet"] + service_account = google_service_account.cluster-sa-avg8.email + oauth_scopes = ["https://www.googleapis.com/auth/cloud-platform"] + } + provider = "google.europe-west1" +} +resource "aws_vpc" "example_vn_aws" { + tags = { "Name" = "example_vn" } + cidr_block = "10.0.0.0/16" + enable_dns_hostnames = true + provider = "aws.eu-west-1" +} +resource "aws_internet_gateway" "example_vn_aws" { + tags = { "Name" = "example_vn" } + vpc_id = aws_vpc.example_vn_aws.id + provider = "aws.eu-west-1" +} +resource "aws_default_security_group" "example_vn_aws" { + tags = { "Name" = "example_vn" } + vpc_id = aws_vpc.example_vn_aws.id + ingress { + protocol = "-1" + from_port = 0 + to_port = 0 + self = true + } + egress { + protocol = "-1" + from_port = 0 + to_port = 0 + self = true + } + provider = "aws.eu-west-1" +} +resource "azurerm_virtual_network" "example_vn_azure" { + resource_group_name = azurerm_resource_group.rg1.name + name = "example_vn" + location = "northeurope" + address_space = ["10.0.0.0/16"] +} +resource "azurerm_route_table" "example_vn_azure" { + resource_group_name = azurerm_resource_group.rg1.name + name = "example_vn" + location = "northeurope" + route { + name = "local" + address_prefix = "0.0.0.0/0" + next_hop_type = "VnetLocal" + } +} +resource "google_compute_network" "example_vn_gcp" { + name = "k8svn" + project = "multy-project" + routing_mode = "REGIONAL" + description = "Managed by Multy" + auto_create_subnetworks = false + delete_default_routes_on_create = true + provider = "google.europe-west1" +} +resource "aws_subnet" "public_subnet_aws-1" { + tags = { "Name" = "public-subnet-1" } + cidr_block = "10.0.0.0/25" + vpc_id = aws_vpc.example_vn_aws.id + availability_zone = "eu-west-1a" + map_public_ip_on_launch = true + provider = "aws.eu-west-1" +} +resource "aws_subnet" "public_subnet_aws-2" { + tags = { "Name" = "public-subnet-2" } + cidr_block = "10.0.0.128/26" + vpc_id = aws_vpc.example_vn_aws.id + availability_zone = "eu-west-1b" + map_public_ip_on_launch = true + provider = "aws.eu-west-1" +} +resource "aws_subnet" "public_subnet_aws-3" { + tags = { "Name" = "public-subnet-3" } + cidr_block = "10.0.0.192/26" + vpc_id = aws_vpc.example_vn_aws.id + availability_zone = "eu-west-1c" + map_public_ip_on_launch = true + provider = "aws.eu-west-1" +} +resource "azurerm_subnet" "public_subnet_azure" { + resource_group_name = azurerm_resource_group.rg1.name + name = "public-subnet" + address_prefixes = ["10.0.0.0/24"] + virtual_network_name = azurerm_virtual_network.example_vn_azure.name +} +resource "google_compute_subnetwork" "public_subnet_gcp" { + name = "public-subnet" + project = "multy-project" + ip_cidr_range = "10.0.0.0/24" + network = google_compute_network.example_vn_gcp.id + private_ip_google_access = true + provider = "google.europe-west1" +} +resource "azurerm_resource_group" "rg1" { + name = "rg1" + location = "northeurope" +} +resource "aws_route_table" "rt_aws" { + tags = { "Name" = "test-rt" } + vpc_id = aws_vpc.example_vn_aws.id + route { + cidr_block = "0.0.0.0/0" + gateway_id = aws_internet_gateway.example_vn_aws.id + } + provider = "aws.eu-west-1" +} +resource "azurerm_route_table" "rt_azure" { + resource_group_name = azurerm_resource_group.rg1.name + name = "test-rt" + location = "northeurope" + route { + name = "internet" + address_prefix = "0.0.0.0/0" + next_hop_type = "Internet" + } +} +resource "google_compute_route" "rt_gcp-0" { + name = "test-rt-0" + project = "multy-project" + dest_range = "0.0.0.0/0" + network = google_compute_network.example_vn_gcp.id + priority = 1000 + tags = ["subnet-public-subnet"] + next_hop_gateway = "default-internet-gateway" + provider = "google.europe-west1" +} +resource "aws_route_table_association" "rta_aws-1" { + subnet_id = aws_subnet.public_subnet_aws-1.id + route_table_id = aws_route_table.rt_aws.id + provider = "aws.eu-west-1" +} +resource "aws_route_table_association" "rta_aws-2" { + subnet_id = aws_subnet.public_subnet_aws-2.id + route_table_id = aws_route_table.rt_aws.id + provider = "aws.eu-west-1" +} +resource "aws_route_table_association" "rta_aws-3" { + subnet_id = aws_subnet.public_subnet_aws-3.id + route_table_id = aws_route_table.rt_aws.id + provider = "aws.eu-west-1" +} +resource "azurerm_subnet_route_table_association" "public_subnet_azure" { + subnet_id = azurerm_subnet.public_subnet_azure.id + route_table_id = azurerm_route_table.rt_azure.id +} +provider "aws" { + region = "eu-west-1" + alias = "eu-west-1" +} +provider "azurerm" { + features { + } +} +provider "google" { + region = "europe-west1" + alias = "europe-west1" +} diff --git a/test/e2e/common.go b/test/e2e/common.go index fa947327..dde297a4 100644 --- a/test/e2e/common.go +++ b/test/e2e/common.go @@ -127,7 +127,7 @@ func cleanup[Arg proto.Message, OutT proto.Message](t *testing.T, ctx context.Co GetResourceId() string }).GetResourceId() t.Cleanup(func() { - if DestroyAfter { + if *destroyAfter { _, err := s.Delete(ctx, &resourcespb.DeleteVirtualNetworkRequest{ResourceId: resourceId}) if err != nil { logGrpcErrorDetails(t, err) diff --git a/test/e2e/e2e.go b/test/e2e/e2e.go index bfc3d420..feb8699d 100644 --- a/test/e2e/e2e.go +++ b/test/e2e/e2e.go @@ -5,6 +5,7 @@ package e2e import ( "context" + "flag" "fmt" "github.com/multycloud/multy/api" aws_client "github.com/multycloud/multy/api/aws" @@ -22,7 +23,7 @@ import ( "testing" ) -const DestroyAfter = true +var destroyAfter = flag.Bool("destroy_after", true, "If false, resources won't be destroyed after tests complete.") func getCtx(t *testing.T, cloud commonpb.CloudProvider, testName string) context.Context { credentials := &credspb.CloudCredentials{ diff --git a/test/e2e/kubernetes_test.go b/test/e2e/kubernetes_test.go index 3cae8e57..05d5a1dd 100644 --- a/test/e2e/kubernetes_test.go +++ b/test/e2e/kubernetes_test.go @@ -37,9 +37,9 @@ type Node struct { func testKubernetes(t *testing.T, cloud commonpb.CloudProvider) { ctx := getCtx(t, cloud, "k8s") - region := commonpb.Location_US_WEST_1 - if cloud == commonpb.CloudProvider_AZURE { - region = commonpb.Location_EU_WEST_2 + region := commonpb.Location_EU_WEST_2 + if cloud == commonpb.CloudProvider_AWS { + region = commonpb.Location_US_WEST_1 } createVnRequest := &resourcespb.CreateVirtualNetworkRequest{Resource: &resourcespb.VirtualNetworkArgs{ @@ -151,7 +151,7 @@ func testKubernetes(t *testing.T, cloud commonpb.CloudProvider) { t.Fatal(fmt.Errorf("output cant be parsed: %s", err)) } - assert.Len(t, o.Items, 1) + assert.Len(t, o.Items, 3) assert.Contains(t, o.Items[0].Status.Conditions, NodeStatusCondition{ Type: "Ready", Status: "True", @@ -170,3 +170,8 @@ func TestAzureKubernetes(t *testing.T) { t.Parallel() testKubernetes(t, commonpb.CloudProvider_AZURE) } + +func TestGcpKubernetes(t *testing.T) { + t.Parallel() + testKubernetes(t, commonpb.CloudProvider_GCP) +} diff --git a/test/e2e/nic_test.go b/test/e2e/nic_test.go index cdd1f32f..c09d0339 100644 --- a/test/e2e/nic_test.go +++ b/test/e2e/nic_test.go @@ -34,7 +34,7 @@ func testNetworkInterface(t *testing.T, cloud commonpb.CloudProvider) { t.Fatalf("unable to create public ip: %+v", err) } t.Cleanup(func() { - if DestroyAfter { + if *destroyAfter { _, err := server.PublicIpService.Delete(ctx, &resourcespb.DeletePublicIpRequest{ResourceId: pip.CommonParameters.ResourceId}) if err != nil { logGrpcErrorDetails(t, err) @@ -57,7 +57,7 @@ func testNetworkInterface(t *testing.T, cloud commonpb.CloudProvider) { t.Fatalf("unable to create network interface: %+v", err) } t.Cleanup(func() { - if DestroyAfter { + if *destroyAfter { _, err := server.NetworkInterfaceService.Delete(ctx, &resourcespb.DeleteNetworkInterfaceRequest{ResourceId: nic.CommonParameters.ResourceId}) if err != nil { logGrpcErrorDetails(t, err) @@ -75,7 +75,7 @@ func testNetworkInterface(t *testing.T, cloud commonpb.CloudProvider) { t.Fatalf("unable to create network interface nsg association: %+v", err) } t.Cleanup(func() { - if DestroyAfter { + if *destroyAfter { _, err := server.NetworkInterfaceSecurityGroupAssociationService.Delete(ctx, &resourcespb.DeleteNetworkInterfaceSecurityGroupAssociationRequest{ResourceId: nicNsgAssociation.CommonParameters.ResourceId}) if err != nil { logGrpcErrorDetails(t, err) @@ -110,7 +110,7 @@ sudo echo "hello world" > /tmp/test.txt`)), t.Fatalf("unable to create virtual machine: %+v", err) } t.Cleanup(func() { - if DestroyAfter { + if *destroyAfter { _, err := server.VirtualMachineService.Delete(ctx, &resourcespb.DeleteVirtualMachineRequest{ResourceId: vm.CommonParameters.ResourceId}) if err != nil { logGrpcErrorDetails(t, err) diff --git a/test/e2e/rollback_test.go b/test/e2e/rollback_test.go index 5cf978cd..d2e34036 100644 --- a/test/e2e/rollback_test.go +++ b/test/e2e/rollback_test.go @@ -32,7 +32,7 @@ func TestRollbackResourceGroup(t *testing.T) { t.Fatalf("unable to create vn: %+v", err) } t.Cleanup(func() { - if DestroyAfter && !rgDeleted { + if *destroyAfter && !rgDeleted { _, _ = server.VnService.Delete(ctx, &resourcespb.DeleteVirtualNetworkRequest{ResourceId: vn.CommonParameters.ResourceId}) } }) @@ -48,7 +48,7 @@ func TestRollbackResourceGroup(t *testing.T) { t.Fatalf("unable to create subnet: %+v", err) } t.Cleanup(func() { - if DestroyAfter && !rgDeleted { + if *destroyAfter && !rgDeleted { _, _ = server.SubnetService.Delete(ctx, &resourcespb.DeleteSubnetRequest{ResourceId: subnet.CommonParameters.ResourceId}) } }) @@ -76,7 +76,7 @@ func TestRollbackResourceGroup(t *testing.T) { ni, err := server.NetworkInterfaceService.Create(ctx, createNetworkInterfaceRequest) if err == nil { t.Cleanup(func() { - if DestroyAfter { + if *destroyAfter { _, err := server.NetworkInterfaceService.Delete(ctx, &resourcespb.DeleteNetworkInterfaceRequest{ResourceId: ni.CommonParameters.ResourceId}) if err != nil { logGrpcErrorDetails(t, err) diff --git a/test/e2e/virtual_machine_test.go b/test/e2e/virtual_machine_test.go index 8deeac9b..e8b8a556 100644 --- a/test/e2e/virtual_machine_test.go +++ b/test/e2e/virtual_machine_test.go @@ -109,7 +109,7 @@ sudo echo "hello world" > /tmp/test.txt`)), t.Fatalf("unable to create virtual machine: %+v", err) } t.Cleanup(func() { - if DestroyAfter { + if *destroyAfter { _, err := server.VirtualMachineService.Delete(ctx, &resourcespb.DeleteVirtualMachineRequest{ResourceId: vm.CommonParameters.ResourceId}) if err != nil { logGrpcErrorDetails(t, err) From 231b90e7dcaa58f2c22d99838df47500b1b8565f Mon Sep 17 00:00:00 2001 From: goncalo-rodrigues Date: Tue, 5 Jul 2022 10:32:05 +0200 Subject: [PATCH 4/6] change kuberentes e2e to work with multiple nodes --- test/e2e/kubernetes_test.go | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/test/e2e/kubernetes_test.go b/test/e2e/kubernetes_test.go index 05d5a1dd..bf55ce3e 100644 --- a/test/e2e/kubernetes_test.go +++ b/test/e2e/kubernetes_test.go @@ -151,15 +151,17 @@ func testKubernetes(t *testing.T, cloud commonpb.CloudProvider) { t.Fatal(fmt.Errorf("output cant be parsed: %s", err)) } - assert.Len(t, o.Items, 3) - assert.Contains(t, o.Items[0].Status.Conditions, NodeStatusCondition{ - Type: "Ready", - Status: "True", - }) - - labels := o.Items[0].Metadata.Labels - assert.Contains(t, maps.Keys(labels), "multy.dev/env") - assert.Equal(t, labels["multy.dev/env"], "test") + assert.Greater(t, len(o.Items), 0) + for _, item := range o.Items { + assert.Contains(t, item.Status.Conditions, NodeStatusCondition{ + Type: "Ready", + Status: "True", + }) + labels := item.Metadata.Labels + assert.Contains(t, maps.Keys(labels), "multy.dev/env") + assert.Equal(t, "test", labels["multy.dev/env"]) + } + } func TestAwsKubernetes(t *testing.T) { From b21eba1e82721e1888da4c6aa5c674d0c7b2821c Mon Sep 17 00:00:00 2001 From: goncalo-rodrigues Date: Tue, 5 Jul 2022 11:22:29 +0200 Subject: [PATCH 5/6] set gcp node count depending on the number of availability zones --- resources/types/gcp/kubernetes_node_pool.go | 11 ++++++--- resources/types/kubernetes_node_pool.go | 24 +++++++++++++++++++ resources/types/virtual_network.go | 2 +- .../kubernetes/kubernetes/config.textproto | 4 ++-- test/e2e/kubernetes_test.go | 1 + 5 files changed, 36 insertions(+), 6 deletions(-) diff --git a/resources/types/gcp/kubernetes_node_pool.go b/resources/types/gcp/kubernetes_node_pool.go index ecc1081e..53ccb983 100644 --- a/resources/types/gcp/kubernetes_node_pool.go +++ b/resources/types/gcp/kubernetes_node_pool.go @@ -50,6 +50,11 @@ func (r GcpKubernetesNodePool) Translate(_ resources.MultyContext) ([]output.TfB return nil, err } + numZones := 3 + if len(r.Args.AvailabilityZone) > 0 { + numZones = len(r.Args.AvailabilityZone) + } + var zones []string for _, zone := range r.Args.AvailabilityZone { availabilityZone, err := common.GetAvailabilityZone(r.KubernetesCluster.GetLocation(), int(zone), r.GetCloud()) @@ -63,10 +68,10 @@ func (r GcpKubernetesNodePool) Translate(_ resources.MultyContext) ([]output.TfB GcpResource: common.NewGcpResource(r.ResourceId, r.Args.Name, r.KubernetesCluster.Args.GetGcpOverride().GetProject()), Cluster: clusterId, NodeLocations: zones, - InitialNodeCount: int(r.Args.StartingNodeCount), + InitialNodeCount: int(r.Args.StartingNodeCount) / numZones, Autoscaling: kubernetes_node_pool.GoogleContainerNodePoolAutoScaling{ - MinNodeCount: int(r.Args.MinNodeCount), - MaxNodeCount: int(r.Args.MaxNodeCount), + MinNodeCount: int(r.Args.MinNodeCount) / numZones, + MaxNodeCount: int(r.Args.MaxNodeCount) / numZones, }, NodeConfig: kubernetes_node_pool.GoogleContainerNodeConfig{ DiskSizeGb: int(r.Args.DiskSizeGb), diff --git a/resources/types/kubernetes_node_pool.go b/resources/types/kubernetes_node_pool.go index 632a5a65..1d579f39 100644 --- a/resources/types/kubernetes_node_pool.go +++ b/resources/types/kubernetes_node_pool.go @@ -79,6 +79,30 @@ func (r *KubernetesNodePool) Validate(ctx resources.MultyContext) (errs []valida if r.Subnet != r.KubernetesCluster.DefaultNodePool.Subnet { errs = append(errs, r.NewValidationError(fmt.Errorf("different subnets for node pools within the same cluster are not yet supported"), "subnet_id")) } + if r.GetCloud() == commonpb.CloudProvider_GCP { + numZones := 3 + if len(r.Args.AvailabilityZone) > 0 { + numZones = len(r.Args.AvailabilityZone) + } + + if int(r.Args.StartingNodeCount)%numZones != 0 { + errs = append(errs, r.NewValidationError( + fmt.Errorf("for gcp, starting node count must be a multiple of the number of availability zones (%d, %d, %d, etc)", + numZones, numZones*2, numZones*3), "starting_node_count")) + } + + if int(r.Args.MinNodeCount)%numZones != 0 { + errs = append(errs, r.NewValidationError( + fmt.Errorf("for gcp, minimum number of nodes must be a multiple of the number of availability zones (%d, %d, %d, etc)", + numZones, numZones*2, numZones*3), "min_node_count")) + } + + if int(r.Args.MaxNodeCount)%numZones != 0 { + errs = append(errs, r.NewValidationError( + fmt.Errorf("for gcp, maximum number of nodes must be a multiple of the number of availability zones (%d, %d, %d, etc)", + numZones, numZones*2, numZones*3), "max_node_count")) + } + } return errs } diff --git a/resources/types/virtual_network.go b/resources/types/virtual_network.go index 6c41755f..e2e8f261 100644 --- a/resources/types/virtual_network.go +++ b/resources/types/virtual_network.go @@ -72,7 +72,7 @@ func (r *VirtualNetwork) Validate(ctx resources.MultyContext) (errs []validate.V } /* -Virtual Subnetwork is a private address space when resources can be placed. +Virtual network is a private address space when resources can be placed. By default, resources inside `virtual_network` cannot access the internet. To enable internet access look at`route_table` diff --git a/test/_configs/kubernetes/kubernetes/config.textproto b/test/_configs/kubernetes/kubernetes/config.textproto index f90cb6db..8704c855 100755 --- a/test/_configs/kubernetes/kubernetes/config.textproto +++ b/test/_configs/kubernetes/kubernetes/config.textproto @@ -72,8 +72,8 @@ resources: { default_node_pool: { name: "node-pool-gcp" subnet_id: "public_subnet_gcp" - min_node_count: 1 - max_node_count: 1 + min_node_count: 3 + max_node_count: 3 vm_size: GENERAL_MEDIUM } gcp_override: { diff --git a/test/e2e/kubernetes_test.go b/test/e2e/kubernetes_test.go index bf55ce3e..4a565de2 100644 --- a/test/e2e/kubernetes_test.go +++ b/test/e2e/kubernetes_test.go @@ -112,6 +112,7 @@ func testKubernetes(t *testing.T, cloud commonpb.CloudProvider) { MaxNodeCount: 3, VmSize: commonpb.VmSize_GENERAL_MEDIUM, DiskSizeGb: 20, + AvailabilityZone: []int32{2}, Labels: map[string]string{ "multy.dev/env": "test", }, From 8379c640262791b073598fe3c5e01e5815621cf3 Mon Sep 17 00:00:00 2001 From: goncalo-rodrigues Date: Tue, 5 Jul 2022 12:54:27 +0200 Subject: [PATCH 6/6] install gke auth plugin --- .github/workflows/e2e.yml | 7 +++++++ .github/workflows/pr-e2e.yml | 14 +++++++++++++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index 1a6d384e..b5e6057d 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -44,6 +44,13 @@ jobs: go vet . golint . + - name: Install gke-cloud-auth-plugin + run: | + echo "deb [signed-by=/usr/share/keyrings/cloud.google.gpg] https://packages.cloud.google.com/apt cloud-sdk main" | sudo tee -a /etc/apt/sources.list.d/google-cloud-sdk.list + curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key --keyring /usr/share/keyrings/cloud.google.gpg add - + sudo apt-get update && sudo apt-get install google-cloud-sdk-gke-gcloud-auth-plugin + gke-gcloud-auth-plugin --version + - name: Test run: go test ./test/e2e -tags=e2e -timeout=180m -parallel 10 env: diff --git a/.github/workflows/pr-e2e.yml b/.github/workflows/pr-e2e.yml index 45b9feb4..e0b3d6d0 100644 --- a/.github/workflows/pr-e2e.yml +++ b/.github/workflows/pr-e2e.yml @@ -46,6 +46,17 @@ jobs: go vet . golint . + - name: Set up Cloud SDK + uses: 'google-github-actions/setup-gcloud@v0' + + - name: Authenticate to Gcloud + uses: 'google-github-actions/auth@v0' + with: + credentials_json: '${{ secrets.GOOGLE_CREDENTIALS }}' + + - name: Install gke-cloud-auth-plugin + run: gcloud components install gke-gcloud-auth-plugin + - name: Test run: go test ./test/e2e -tags=e2e -timeout=180m -parallel 10 env: @@ -56,4 +67,5 @@ jobs: ARM_CLIENT_SECRET: ${{ secrets.ARM_CLIENT_SECRET_E2E }} ARM_SUBSCRIPTION_ID: ${{ secrets.ARM_SUBSCRIPTION_ID }} ARM_TENANT_ID: ${{ secrets.ARM_TENANT_ID }} - GOOGLE_CREDENTIALS: ${{ secrets.GOOGLE_CREDENTIALS }} \ No newline at end of file + GOOGLE_CREDENTIALS: ${{ secrets.GOOGLE_CREDENTIALS }} + GOOGLE_APPLICATION_CREDENTIALS: ${{ secrets.GOOGLE_APPLICATION_CREDENTIALS }} \ No newline at end of file