github.com/olli-ai/jx/v2@v2.0.400-0.20210921045218-14731b4dd448/pkg/cmd/create/create_addon_flagger.go (about) 1 package create 2 3 import ( 4 "fmt" 5 "strings" 6 7 "github.com/olli-ai/jx/v2/pkg/cmd/create/options" 8 9 "github.com/olli-ai/jx/v2/pkg/cmd/helper" 10 11 "github.com/olli-ai/jx/v2/pkg/helm" 12 13 "github.com/jenkins-x/jx-logging/pkg/log" 14 networkingv1alpha3 "istio.io/api/networking/v1alpha3" 15 istiov1alpha3 "istio.io/client-go/pkg/apis/networking/v1alpha3" 16 17 "github.com/olli-ai/jx/v2/pkg/kube" 18 "github.com/pkg/errors" 19 20 "github.com/olli-ai/jx/v2/pkg/cmd/opts" 21 "github.com/olli-ai/jx/v2/pkg/cmd/templates" 22 "github.com/olli-ai/jx/v2/pkg/util" 23 "github.com/spf13/cobra" 24 apierrors "k8s.io/apimachinery/pkg/api/errors" 25 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 26 "k8s.io/apimachinery/pkg/types" 27 ) 28 29 const ( 30 DefaultFlaggerNamespace = DefaultIstioNamespace 31 defaultFlaggerReleaseName = kube.DefaultFlaggerReleaseName 32 defaultFlaggerVersion = "" 33 defaultFlaggerRepo = "https://flagger.app" 34 optionGrafanaChart = "grafana-chart" 35 optionGrafanaVersion = "grafana-version" 36 defaultFlaggerProductionEnvironment = "production" 37 defaultIstioGateway = "jx-gateway" 38 ) 39 40 var ( 41 createAddonFlaggerLong = templates.LongDesc(` 42 Creates the Flagger addon 43 `) 44 45 createAddonFlaggerExample = templates.Examples(` 46 # Create the Flagger addon 47 jx create addon flagger 48 `) 49 ) 50 51 type CreateAddonFlaggerOptions struct { 52 CreateAddonOptions 53 Chart string 54 GrafanaChart string 55 GrafanaVersion string 56 ProductionEnvironment string 57 IstioGateway string 58 } 59 60 func NewCmdCreateAddonFlagger(commonOpts *opts.CommonOptions) *cobra.Command { 61 options := &CreateAddonFlaggerOptions{ 62 CreateAddonOptions: CreateAddonOptions{ 63 CreateOptions: options.CreateOptions{ 64 CommonOptions: commonOpts, 65 }, 66 }, 67 } 68 69 cmd := &cobra.Command{ 70 Use: "flagger", 71 Short: "Create the Flagger addon for Canary deployments", 72 Long: createAddonFlaggerLong, 73 Example: createAddonFlaggerExample, 74 Run: func(cmd *cobra.Command, args []string) { 75 err := options.Run() 76 helper.CheckErr(err) 77 }, 78 } 79 80 options.addFlags(cmd, DefaultFlaggerNamespace, defaultFlaggerReleaseName, defaultFlaggerVersion) 81 82 cmd.Flags().StringVarP(&options.Chart, optionChart, "c", kube.ChartFlagger, "The name of the chart to use") 83 cmd.Flags().StringVarP(&options.GrafanaChart, optionGrafanaChart, "", kube.ChartFlaggerGrafana, "The name of the Flagger Grafana chart to use") 84 cmd.Flags().StringVarP(&options.GrafanaVersion, optionGrafanaVersion, "", "", "The version of the Flagger Grafana chart") 85 cmd.Flags().StringVarP(&options.ProductionEnvironment, "environment", "e", defaultFlaggerProductionEnvironment, "The name of the production environment where Istio will be enabled") 86 cmd.Flags().StringVarP(&options.IstioGateway, "istio-gateway", "", defaultIstioGateway, "The name of the Istio Gateway that will be created if it does not exist") 87 return cmd 88 } 89 90 // Create the addon 91 func (o *CreateAddonFlaggerOptions) Run() error { 92 if o.ReleaseName == "" { 93 return util.MissingOption(optionRelease) 94 } 95 if o.Chart == "" { 96 return util.MissingOption(optionChart) 97 } 98 if o.GrafanaChart == "" { 99 return util.MissingOption(optionGrafanaChart) 100 } 101 err := o.EnsureHelm() 102 if err != nil { 103 return errors.Wrap(err, "failed to ensure that Helm is present") 104 } 105 106 values := []string{} 107 setValues := strings.Split(o.SetValues, ",") 108 values = append(values, setValues...) 109 _, err = o.AddHelmBinaryRepoIfMissing(defaultFlaggerRepo, "flagger", "", "") 110 if err != nil { 111 return errors.Wrap(err, "Flagger deployment failed") 112 } 113 helmOptions := helm.InstallChartOptions{ 114 Chart: o.Chart, 115 ReleaseName: o.ReleaseName, 116 Version: o.Version, 117 Ns: o.Namespace, 118 SetValues: values, 119 } 120 err = o.InstallChartWithOptions(helmOptions) 121 if err != nil { 122 return errors.Wrap(err, "Flagger deployment failed") 123 } 124 helmOptions = helm.InstallChartOptions{ 125 Chart: o.GrafanaChart, 126 ReleaseName: o.ReleaseName + "-grafana", 127 Version: o.GrafanaVersion, 128 Ns: o.Namespace, 129 SetValues: values, 130 } 131 err = o.InstallChartWithOptions(helmOptions) 132 if err != nil { 133 return errors.Wrap(err, "Flagger Grafana deployment failed") 134 } 135 136 // Enable Istio in production namespace 137 if o.ProductionEnvironment != "" { 138 client, err := o.KubeClient() 139 if err != nil { 140 return errors.Wrap(err, "error enabling Istio in production namespace") 141 } 142 var ns string 143 ns, err = o.FindEnvironmentNamespace(o.ProductionEnvironment) 144 if err != nil { 145 return errors.Wrap(err, fmt.Sprintf("error enabling Istio for environment %s", o.ProductionEnvironment)) 146 } 147 log.Logger().Infof("Enabling Istio in namespace %s", ns) 148 patch := []byte(`{"metadata":{"labels":{"istio-injection":"enabled"}}}`) 149 _, err = client.CoreV1().Namespaces().Patch(ns, types.MergePatchType, patch) 150 if err != nil { 151 return errors.Wrap(err, fmt.Sprintf("error enabling Istio in namespace %s", ns)) 152 } 153 } 154 155 // Create the Istio gateway 156 if o.IstioGateway != "" { 157 istioClient, err := o.IstioClient() 158 if err != nil { 159 return errors.Wrap(err, "error building Istio client") 160 } 161 gateway, err := istioClient.NetworkingV1alpha3().Gateways(DefaultIstioNamespace).Get(o.IstioGateway, metav1.GetOptions{}) 162 if apierrors.IsNotFound(err) { 163 gateway = &istiov1alpha3.Gateway{ 164 ObjectMeta: metav1.ObjectMeta{ 165 Name: o.IstioGateway, 166 Namespace: DefaultIstioNamespace, 167 }, 168 Spec: networkingv1alpha3.Gateway{ 169 Selector: map[string]string{"istio": "ingressgateway"}, 170 Servers: []*networkingv1alpha3.Server{ 171 // TODO add https port if enabled 172 { 173 Port: &networkingv1alpha3.Port{ 174 Number: 80, 175 Name: "http", 176 Protocol: "HTTP", 177 }, 178 Hosts: []string{"*"}, 179 }, 180 }, 181 }, 182 } 183 184 log.Logger().Infof("Creating Istio gateway: %s", o.IstioGateway) 185 gateway, err = istioClient.NetworkingV1alpha3().Gateways(DefaultIstioNamespace).Create(gateway) 186 if err != nil { 187 return errors.Wrap(err, "error creating Istio gateway") 188 } 189 } else { 190 log.Logger().Infof("Istio gateway already exists: %s", o.IstioGateway) 191 } 192 } 193 return nil 194 }