Skip to content

Commit

Permalink
Adding InstallIngressControllerActivity
Browse files Browse the repository at this point in the history
  • Loading branch information
janosSarusiKis committed Feb 26, 2021
1 parent 4c3002f commit 411076e
Show file tree
Hide file tree
Showing 4 changed files with 223 additions and 0 deletions.
8 changes: 8 additions & 0 deletions cmd/worker/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,14 @@ func main() {

deployClusterAutoscalerActivity := autoscaler.NewDeployClusterAutoscalerActivity(clusterManager, unifiedHelmReleaser)
worker.RegisterActivityWithOptions(deployClusterAutoscalerActivity.Execute, activity.RegisterOptions{Name: clustersetup.DeployClusterAutoscalerActivityName})

installIngressControllerActivity := clustersetup.NewInstallIngressControllerActivity(
config.Cluster.Labels,
unifiedHelmReleaser,
)
worker.RegisterActivityWithOptions(
installIngressControllerActivity.Execute,
activity.RegisterOptions{Name: clustersetup.InstallIngressControllerActivityName})
}

worker.RegisterWorkflowWithOptions(cluster.CreateClusterWorkflow, workflow.RegisterOptions{Name: cluster.CreateClusterWorkflowName})
Expand Down
192 changes: 192 additions & 0 deletions internal/cluster/clustersetup/activity_install_ingress_controller.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
// Copyright © 2019 Banzai Cloud
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package clustersetup

import (
"context"
"encoding/json"
"fmt"
"strings"

"emperror.dev/errors"
"github.com/aws/aws-sdk-go/aws"

"github.com/banzaicloud/pipeline/internal/cluster/clusterconfig"
"github.com/banzaicloud/pipeline/internal/global"
"github.com/banzaicloud/pipeline/internal/providers/amazon"
"github.com/banzaicloud/pipeline/pkg/any"
pkgCluster "github.com/banzaicloud/pipeline/pkg/cluster"
"github.com/banzaicloud/pipeline/pkg/jsonstructure"
"github.com/banzaicloud/pipeline/src/auth"
"github.com/banzaicloud/pipeline/src/dns"
)

const InstallIngressControllerActivityName = "install-ingress-controller"

type InstallIngressControllerActivity struct {
config clusterconfig.LabelConfig
helmService HelmService
}

// NewInstallIngressControllerActivity returns a new InstallIngressControllerActivity.
func NewInstallIngressControllerActivity(
config clusterconfig.LabelConfig,
helmService HelmService,
) InstallIngressControllerActivity {
return InstallIngressControllerActivity{
config: config,
helmService: helmService,
}
}

type InstallIngressControllerActivityInput struct {
ClusterID, OrgID uint
Distribution string
}

type ingressControllerValues struct {
Traefik traefikValues `json:"traefik"`
}

type sslTraefikValues struct {
Enabled bool `json:"enabled"`
GenerateTLS bool `json:"generateTLS"`
DefaultCN string `json:"defaultCN,omitempty"`
DefaultSANList []string `json:"defaultSANList,omitempty"`
DefaultCert string `json:"defaultCert,omitempty"`
DefaultKey string `json:"defaultKey,omitempty"`
}

type serviceTraefikValues struct {
Annotations map[string]string `json:"annotations,omitempty"`
}

type traefikValues struct {
SSL sslTraefikValues `json:"ssl"`
Service serviceTraefikValues `json:"service,omitempty"`
}

func (a InstallIngressControllerActivity) Execute(ctx context.Context, input InstallIngressControllerActivityInput) error {
if a.helmService == nil {
return errors.New("missing helm service dependency")
}
config := global.Config.Cluster.PostHook
if !config.Ingress.Enabled {
return nil
}

organization, err := auth.GetOrganizationById(input.OrgID)
if err != nil {
return errors.WrapIfWithDetails(err, "failed to get organization", "organizationId", input.OrgID)
}

var orgDomainName string
var wildcardOrgDomainName string
baseDomain := strings.ToLower(global.Config.Cluster.DNS.BaseDomain)
if baseDomain != "" {
orgDomainName = strings.ToLower(fmt.Sprintf("%s.%s", organization.NormalizedName, baseDomain))
err = dns.ValidateSubdomain(orgDomainName)
if err != nil {
return errors.WrapIf(err, "invalid domain for TLS cert")
}

wildcardOrgDomainName = fmt.Sprintf("*.%s", orgDomainName)
err = dns.ValidateWildcardSubdomain(wildcardOrgDomainName)
if err != nil {
return errors.WrapIf(err, "invalid wildcard domain for TLS cert")
}
}

defaultCN := orgDomainName
var defaultSANList []string
if orgDomainName != "" {
defaultSANList = append(defaultSANList, orgDomainName)
}

if wildcardOrgDomainName != "" {
defaultSANList = append(defaultSANList, wildcardOrgDomainName)
}

if values, ok := config.Ingress.Values["traefik"].(map[string]interface{}); ok {
if sslV, ok := values["ssl"].(map[string]interface{}); ok {
if sanList, ok := sslV["defaultSANList"].([]interface{}); ok {
for _, san := range sanList {
if s, ok := san.(string); ok {
defaultSANList = append(defaultSANList, s)
}
}
}
}
}

ingressValues := ingressControllerValues{
Traefik: traefikValues{
SSL: sslTraefikValues{
Enabled: true,
GenerateTLS: true,
DefaultCN: defaultCN,
DefaultSANList: defaultSANList,
},
},
}

// TODO: once we move this to an integrated service we must find a way to append tags to user configured annotations
if input.Distribution == pkgCluster.EKS || input.Distribution == pkgCluster.PKE {
var tags []string

for _, tag := range amazon.PipelineTags() {
tags = append(tags, fmt.Sprintf("%s=%s", aws.StringValue(tag.Key), aws.StringValue(tag.Value)))
}

ingressValues.Traefik.Service.Annotations = map[string]string{
"service.beta.kubernetes.io/aws-load-balancer-additional-resource-tags": strings.Join(tags, ","),
}
}

valuesBytes, err := mergeValues(ingressValues, config.Ingress.Values)
if err != nil {
return errors.WrapIf(err, "failed to merge treafik values with config")
}

namespace := global.Config.Cluster.Namespace

err = a.helmService.ApplyDeployment(
context.Background(),
input.ClusterID,
namespace, config.Ingress.Chart,
"ingress",
valuesBytes,
config.Ingress.Version)

if err != nil {
return errors.WrapIf(err, "failed to merge treafik values with config")
}

return nil
}

func mergeValues(chartValues interface{}, configValues interface{}) ([]byte, error) {
out, err := jsonstructure.Encode(chartValues)
if err != nil {
return nil, errors.WrapIf(err, "failed to encode chart values")
}

result, err := any.Merge(configValues, out, jsonstructure.DefaultMergeOptions())
if err != nil {
return nil, errors.WrapIf(err, "failed to merge values")
}

return json.Marshal(result)
}
10 changes: 10 additions & 0 deletions internal/cluster/clustersetup/helm.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,16 @@ type HelmService interface {
wait bool,
) error

ApplyDeployment(
ctx context.Context,
clusterID uint,
namespace string,
chartName string,
releaseName string,
values []byte,
chartVersion string,
) error

ApplyDeploymentReuseValues(
ctx context.Context,
clusterID uint,
Expand Down
13 changes: 13 additions & 0 deletions internal/cluster/clustersetup/workflow.go
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,19 @@ func (w Workflow) Execute(ctx workflow.Context, input WorkflowInput) error {
}
}

{
activityInput := InstallIngressControllerActivityInput{
ClusterID: input.Cluster.ID,
OrgID: input.Organization.ID,
Distribution: input.Cluster.Distribution,
}

err := workflow.ExecuteActivity(ctx, InstallIngressControllerActivityName, activityInput).Get(ctx, nil)
if err != nil {
return err
}
}

{
if w.IsIntegratedServicesV2 {
// install / upgrade the integrated service operator
Expand Down

0 comments on commit 411076e

Please sign in to comment.