diff --git a/cli/cmd/lib_cluster_config.go b/cli/cmd/lib_cluster_config.go index 97a9b86058..edd6cd7732 100644 --- a/cli/cmd/lib_cluster_config.go +++ b/cli/cmd/lib_cluster_config.go @@ -281,6 +281,10 @@ func confirmInstallClusterConfig(clusterConfig *clusterconfig.Config, awsClient func confirmConfigureClusterConfig(configureChanges clusterconfig.ConfigureChanges, oldCc, newCc clusterconfig.Config, disallowPrompt bool) { fmt.Printf("your %s cluster in region %s will be updated as follows:\n\n", newCc.ClusterName, newCc.Region) + for _, fieldToUpdate := range configureChanges.FieldsToUpdate { + fmt.Printf("○ %s will be updated\n", fieldToUpdate) + } + for _, ngName := range configureChanges.NodeGroupsToScale { ngOld := oldCc.GetNodeGroupByName(ngName) ngScaled := newCc.GetNodeGroupByName(ngName) diff --git a/manager/install.sh b/manager/install.sh index 204e1c63b0..8d42997637 100755 --- a/manager/install.sh +++ b/manager/install.sh @@ -90,6 +90,8 @@ function cluster_configure() { add_nodegroups remove_nodegroups + update_networking + echo -n "○ updating cluster configuration " setup_configmap echo "✓" @@ -365,6 +367,51 @@ function setup_istio() { output_if_error istio-${ISTIO_VERSION}/bin/istioctl install --skip-confirmation --filename /workspace/istio.yaml } +function update_networking() { + prev_ssl_certificate_arn=$(kubectl get svc ingressgateway-apis -n=istio-system -o json | jq -r '.metadata.annotations."service.beta.kubernetes.io/aws-load-balancer-ssl-cert"') + + if [ "$prev_ssl_certificate_arn" = "null" ]; then + prev_ssl_certificate_arn="" + fi + + new_ssl_certificate_arn=$(cat $CORTEX_CLUSTER_CONFIG_FILE | yq -r .ssl_certificate_arn) + + if [ "$new_ssl_certificate_arn" = "null" ]; then + new_ssl_certificate_arn="" + fi + + prev_api_whitelist_ip_address=$(kubectl get svc ingressgateway-apis -n=istio-system -o yaml | yq -r -c ".spec.loadBalancerSourceRanges") + prev_operator_whitelist_ip_address=$(kubectl get svc ingressgateway-operator -n=istio-system -o yaml | yq -r -c ".spec.loadBalancerSourceRanges") + + new_api_whitelist_ip_address=$(cat $CORTEX_CLUSTER_CONFIG_FILE | yq -r -c ".api_load_balancer_cidr_white_list") + new_operator_whitelist_ip_address=$(cat $CORTEX_CLUSTER_CONFIG_FILE | yq -r -c ".operator_load_balancer_cidr_white_list") + + if [ "$prev_ssl_certificate_arn" = "$new_ssl_certificate_arn" ] && [ "$prev_api_whitelist_ip_address" = "$new_api_whitelist_ip_address" ] && [ "$prev_operator_whitelist_ip_address" = "$new_operator_whitelist_ip_address" ] ; then + return + fi + + echo -n "○ updating networking configuration " + + if [ "$new_ssl_certificate_arn" != "$prev_ssl_certificate_arn" ] ; then + # there is a bug where changing the certificate annotation will not cause the HTTPS listener in the NLB to update + # the current workaround is to delete the HTTPS listener and have it recreated with istioctl + if [ "$prev_ssl_certificate_arn" != "" ] ; then + kubectl patch svc ingressgateway-apis -n=istio-system --type=json -p="[{'op': 'remove', 'path': '/metadata/annotations/service.beta.kubernetes.io~1aws-load-balancer-ssl-cert'}]" >/dev/null + fi + https_index=$(kubectl get svc ingressgateway-apis -n=istio-system -o json | jq '.spec.ports | map(.name == "https") | index(true)') + if [ "$https_index" != "null" ] ; then + kubectl patch svc ingressgateway-apis -n=istio-system --type=json -p="[{'op': 'remove', 'path': '/spec/ports/$https_index'}]" >/dev/null + fi + fi + + python render_template.py $CORTEX_CLUSTER_CONFIG_FILE manifests/istio.yaml.j2 > /workspace/istio.yaml + output_if_error istio-${ISTIO_VERSION}/bin/istioctl install --skip-confirmation --filename /workspace/istio.yaml + python render_template.py $CORTEX_CLUSTER_CONFIG_FILE manifests/apis.yaml.j2 > /workspace/apis.yaml + kubectl apply -f /workspace/apis.yaml >/dev/null + + echo "✓" +} + function validate_cortex() { set +e diff --git a/manager/manifests/istio.yaml.j2 b/manager/manifests/istio.yaml.j2 index bf0a60af41..9df2d198a5 100644 --- a/manager/manifests/istio.yaml.j2 +++ b/manager/manifests/istio.yaml.j2 @@ -50,9 +50,7 @@ spec: service: type: LoadBalancer externalTrafficPolicy: Cluster # https://medium.com/pablo-perez/k8s-externaltrafficpolicy-local-or-cluster-40b259a19404, https://www.asykim.com/blog/deep-dive-into-kubernetes-external-traffic-policies - {% if config.get('operator_load_balancer_cidr_white_list', [])|length > 0 %} - loadBalancerSourceRanges: {{ config['operator_load_balancer_cidr_white_list'] }} - {% endif %} + loadBalancerSourceRanges: {{ config.get('operator_load_balancer_cidr_white_list', ['0.0.0.0/0']) }} selector: app: operator-istio-gateway istio: ingressgateway-operator @@ -110,9 +108,7 @@ spec: {% endif %} service: type: LoadBalancer - {% if config.get('api_load_balancer_cidr_white_list', [])|length > 0 %} - loadBalancerSourceRanges: {{ config['api_load_balancer_cidr_white_list'] }} - {% endif %} + loadBalancerSourceRanges: {{ config.get('api_load_balancer_cidr_white_list', ['0.0.0.0/0']) }} externalTrafficPolicy: Cluster # https://medium.com/pablo-perez/k8s-externaltrafficpolicy-local-or-cluster-40b259a19404, https://www.asykim.com/blog/deep-dive-into-kubernetes-external-traffic-policies selector: app: apis-istio-gateway diff --git a/pkg/types/clusterconfig/cluster_config.go b/pkg/types/clusterconfig/cluster_config.go index b48f9e403a..0029acfe3b 100644 --- a/pkg/types/clusterconfig/cluster_config.go +++ b/pkg/types/clusterconfig/cluster_config.go @@ -39,6 +39,7 @@ import ( "github.com/cortexlabs/cortex/pkg/lib/pointer" "github.com/cortexlabs/cortex/pkg/lib/sets/strset" "github.com/cortexlabs/cortex/pkg/lib/slices" + libstr "github.com/cortexlabs/cortex/pkg/lib/strings" "github.com/cortexlabs/cortex/pkg/lib/structs" "github.com/cortexlabs/yaml" ) @@ -191,10 +192,11 @@ type ConfigureChanges struct { NodeGroupsToRemove []string NodeGroupsToScale []string EKSNodeGroupsToRemove []string // EKS node group names of (NodeGroupsToRemove ∩ Cortex-converted EKS node groups) ∪ (Cortex-converted EKS node groups - the new cluster config's nodegroups) + FieldsToUpdate []string } func (c *ConfigureChanges) HasChanges() bool { - return len(c.NodeGroupsToAdd) != 0 || len(c.NodeGroupsToRemove) != 0 || len(c.NodeGroupsToScale) != 0 || len(c.EKSNodeGroupsToRemove) != 0 + return len(c.NodeGroupsToAdd)+len(c.NodeGroupsToRemove)+len(c.NodeGroupsToScale)+len(c.EKSNodeGroupsToRemove)+len(c.FieldsToUpdate) != 0 } // GetGhostEKSNodeGroups returns the set difference between EKSNodeGroupsToRemove and the EKS-converted NodeGroupsToRemove @@ -1029,43 +1031,54 @@ func (cc *Config) validate(awsClient *aws.Client) error { return nil } -func (cc *Config) validateConfigDiff(oldConfig Config) error { - err := cc.validateTopLevelSectionDiff(oldConfig) - if err != nil { - return err - } - - return cc.validateSharedNodeGroupsDiff(oldConfig) -} - -func (cc *Config) validateTopLevelSectionDiff(oldConfig Config) error { +func (cc *Config) validateTopLevelSectionDiff(oldConfig Config) ([]string, error) { + var fieldsToUpdate []string // validate actionable changes newClusterConfigCopy, err := cc.DeepCopy() if err != nil { - return err + return nil, err } oldClusterConfigCopy, err := oldConfig.DeepCopy() if err != nil { - return err + return nil, err + } + + if libstr.Obj(newClusterConfigCopy.SSLCertificateARN) != libstr.Obj(oldClusterConfigCopy.SSLCertificateARN) { + fieldsToUpdate = append(fieldsToUpdate, SSLCertificateARNKey) } - newClusterConfigCopy.NodeGroups = []*NodeGroup{} - oldClusterConfigCopy.NodeGroups = []*NodeGroup{} + if libstr.Obj(newClusterConfigCopy.APILoadBalancerCIDRWhiteList) != libstr.Obj(oldClusterConfigCopy.APILoadBalancerCIDRWhiteList) { + fieldsToUpdate = append(fieldsToUpdate, APILoadBalancerCIDRWhiteListKey) + } + + if libstr.Obj(newClusterConfigCopy.OperatorLoadBalancerCIDRWhiteList) != libstr.Obj(oldClusterConfigCopy.OperatorLoadBalancerCIDRWhiteList) { + fieldsToUpdate = append(fieldsToUpdate, OperatorLoadBalancerCIDRWhiteListKey) + } + + clearUpdatableFields(&newClusterConfigCopy) + clearUpdatableFields(&oldClusterConfigCopy) h1, err := newClusterConfigCopy.Hash() if err != nil { - return err + return nil, err } h2, err := oldClusterConfigCopy.Hash() if err != nil { - return err + return nil, err } if h1 != h2 { - return ErrorConfigCannotBeChangedOnConfigure() + return nil, ErrorConfigCannotBeChangedOnConfigure() } - return nil + return fieldsToUpdate, nil +} + +func clearUpdatableFields(clusterConfig *Config) { + clusterConfig.SSLCertificateARN = nil + clusterConfig.APILoadBalancerCIDRWhiteList = nil + clusterConfig.OperatorLoadBalancerCIDRWhiteList = nil + clusterConfig.NodeGroups = []*NodeGroup{} } func (cc *Config) validateSharedNodeGroupsDiff(oldConfig Config) error { @@ -1139,7 +1152,12 @@ func (cc *Config) ValidateOnConfigure(awsClient *aws.Client, oldConfig Config, e return ConfigureChanges{}, err } - err = cc.validateConfigDiff(oldConfig) + fieldsToUpdate, err := cc.validateTopLevelSectionDiff(oldConfig) + if err != nil { + return ConfigureChanges{}, err + } + + err = cc.validateSharedNodeGroupsDiff(oldConfig) if err != nil { return ConfigureChanges{}, err } @@ -1170,6 +1188,7 @@ func (cc *Config) ValidateOnConfigure(awsClient *aws.Client, oldConfig Config, e NodeGroupsToRemove: GetNodeGroupNames(ngsToBeRemoved), NodeGroupsToScale: GetNodeGroupNames(ngNamesToBeScaled), EKSNodeGroupsToRemove: getStaleEksNodeGroups(cc.ClusterName, eksNodeGroupStacks, cc.NodeGroups, ngsToBeRemoved), + FieldsToUpdate: fieldsToUpdate, }, nil } diff --git a/pkg/types/clusterconfig/config_key.go b/pkg/types/clusterconfig/config_key.go index 19df34d3f2..bbb7e6dc15 100644 --- a/pkg/types/clusterconfig/config_key.go +++ b/pkg/types/clusterconfig/config_key.go @@ -53,6 +53,8 @@ const ( NATGatewayKey = "nat_gateway" APILoadBalancerSchemeKey = "api_load_balancer_scheme" OperatorLoadBalancerSchemeKey = "operator_load_balancer_scheme" + APILoadBalancerCIDRWhiteListKey = "api_load_balancer_cidr_white_list" + OperatorLoadBalancerCIDRWhiteListKey = "operator_load_balancer_cidr_white_list" VPCCIDRKey = "vpc_cidr" AccountIDKey = "account_id" TelemetryKey = "telemetry" diff --git a/pkg/types/clusterconfig/errors.go b/pkg/types/clusterconfig/errors.go index b5126d94bc..5c00328654 100644 --- a/pkg/types/clusterconfig/errors.go +++ b/pkg/types/clusterconfig/errors.go @@ -280,7 +280,7 @@ func ErrorNoNATGatewayWithSubnets() error { func ErrorConfigCannotBeChangedOnConfigure() error { return errors.WithStack(&errors.Error{ Kind: ErrConfigCannotBeChangedOnConfigure, - Message: fmt.Sprintf("in a running cluster, only the %s field can be modified", NodeGroupsKey), + Message: fmt.Sprintf("in a running cluster, only %s can be modified", s.StrsAnd([]string{NodeGroupsKey, SSLCertificateARNKey, OperatorLoadBalancerCIDRWhiteListKey, APILoadBalancerCIDRWhiteListKey})), }) }