Beispiel #1
0
func NewCmdDeploy(f *cmdutil.Factory) *cobra.Command {
	cmd := &cobra.Command{
		Use:   "deploy",
		Short: "Deploy fabric8 to your Kubernetes or OpenShift environment",
		Long:  `deploy fabric8 to your Kubernetes or OpenShift environment`,
		PreRun: func(cmd *cobra.Command, args []string) {
			showBanner()
		},
		Run: func(cmd *cobra.Command, args []string) {
			c, cfg := client.NewClient(f)
			ns, _, _ := f.DefaultNamespace()
			util.Info("Deploying fabric8 to your ")
			util.Success(string(util.TypeOfMaster(c)))
			util.Info(" installation at ")
			util.Success(cfg.Host)
			util.Info(" in namespace ")
			util.Successf("%s\n\n", ns)

			if confirmAction(cmd.Flags()) {
				v := cmd.Flags().Lookup("version").Value.String()

				typeOfMaster := util.TypeOfMaster(c)
				v = f8Version(v, typeOfMaster)

				versioniPaaS := cmd.Flags().Lookup(versioniPaaSFlag).Value.String()
				versioniPaaS = versionForUrl(versioniPaaS, iPaaSMetadataUrl)

				util.Warnf("\nStarting deployment of %s...\n\n", v)

				if typeOfMaster == util.Kubernetes {
					uri := fmt.Sprintf(baseConsoleKubernetesUrl, v)
					filenames := []string{uri}

					createCmd := cobra.Command{}
					createCmd.Flags().StringSlice("filename", filenames, "")
					err := kcmd.RunCreate(f, &createCmd, ioutil.Discard)
					if err != nil {
						printResult("fabric8 console", Failure, err)
					} else {
						printResult("fabric8 console", Success, nil)
					}
				} else {
					oc, _ := client.NewOpenShiftClient(cfg)

					r, err := verifyRestrictedSecurityContextConstraints(c, f)
					printResult("SecurityContextConstraints restricted", r, err)
					r, err = deployFabric8SecurityContextConstraints(c, f, ns)
					printResult("SecurityContextConstraints fabric8", r, err)

					printAddClusterRoleToUser(oc, f, "cluster-admin", "system:serviceaccount:"+ns+":fabric8")
					printAddClusterRoleToUser(oc, f, "cluster-admin", "system:serviceaccount:"+ns+":jenkins")
					printAddClusterRoleToUser(oc, f, "cluster-reader", "system:serviceaccount:"+ns+":metrics")

					printAddServiceAccount(c, f, "metrics")
					printAddServiceAccount(c, f, "router")

					if cmd.Flags().Lookup(templatesFlag).Value.String() == "true" {
						uri := fmt.Sprintf(baseConsoleUrl, v)
						resp, err := http.Get(uri)
						if err != nil {
							util.Fatalf("Cannot get fabric8 template to deploy: %v", err)
						}
						defer resp.Body.Close()
						jsonData, err := ioutil.ReadAll(resp.Body)
						if err != nil {
							util.Fatalf("Cannot get fabric8 template to deploy: %v", err)
						}
						var v1tmpl tapiv1.Template
						err = json.Unmarshal(jsonData, &v1tmpl)
						if err != nil {
							util.Fatalf("Cannot get fabric8 template to deploy: %v", err)
						}
						var tmpl tapi.Template

						err = api.Scheme.Convert(&v1tmpl, &tmpl)
						if err != nil {
							util.Fatalf("Cannot get fabric8 template to deploy: %v", err)
						}

						generators := map[string]generator.Generator{
							"expression": generator.NewExpressionValueGenerator(rand.New(rand.NewSource(time.Now().UnixNano()))),
						}
						p := template.NewProcessor(generators)

						tmpl.Parameters = append(tmpl.Parameters, tapi.Parameter{
							Name:  "DOMAIN",
							Value: cmd.Flags().Lookup("domain").Value.String(),
						})

						p.Process(&tmpl)

						for _, o := range tmpl.Objects {
							switch o := o.(type) {
							case *runtime.Unstructured:
								var b []byte
								b, err = json.Marshal(o.Object)
								if err != nil {
									break
								}
								req := c.Post().Body(b)
								if o.Kind != "OAuthClient" {
									req.Namespace(ns).Resource(strings.ToLower(o.TypeMeta.Kind + "s"))
								} else {
									req.AbsPath("oapi", "v1", strings.ToLower(o.TypeMeta.Kind+"s"))
								}
								res := req.Do()
								if res.Error() != nil {
									err = res.Error()
									break
								}
								var statusCode int
								res.StatusCode(&statusCode)
								if statusCode != http.StatusCreated {
									err = fmt.Errorf("Failed to create %s: %d", o.TypeMeta.Kind, statusCode)
									break
								}
							}
						}

						if err != nil {
							printResult("fabric8 console", Failure, err)
						} else {
							printResult("fabric8 console", Success, nil)
						}
					} else {
						printError("Ignoring the deploy of the fabric8 console", nil)
					}

					if cmd.Flags().Lookup(templatesFlag).Value.String() == "true" {
						printError("Install DevOps templates", installTemplates(oc, f, v, templatesDistroUrl))
						printError("Install iPaaS templates", installTemplates(oc, f, versioniPaaS, iPaaSTemplatesDistroUrl))
					} else {
						printError("Ignoring the deploy of templates", nil)
					}

					domain := cmd.Flags().Lookup(domainFlag).Value.String()

					printError("Create routes", createRoutesForDomain(ns, domain, c, oc, f))
				}
			}
		},
	}
	cmd.PersistentFlags().StringP("domain", "d", defaultDomain(), "The domain name to append to the service name to access web applications")
	cmd.PersistentFlags().StringP(versioniPaaSFlag, "", "latest", "The version to use for the Fabric8 iPaaS templates")
	cmd.PersistentFlags().Bool(templatesFlag, true, "Should the standard Fabric8 templates be installed?")
	cmd.PersistentFlags().Bool(consoleFlag, true, "Should the Fabric8 console be deployed?")
	return cmd
}
Beispiel #2
0
func NewCmdDeploy(f *cmdutil.Factory) *cobra.Command {
	cmd := &cobra.Command{
		Use:   "deploy",
		Short: "Deploy fabric8 to your Kubernetes or OpenShift environment",
		Long:  `deploy fabric8 to your Kubernetes or OpenShift environment`,
		PreRun: func(cmd *cobra.Command, args []string) {
			showBanner()
		},
		Run: func(cmd *cobra.Command, args []string) {
			c, cfg := client.NewClient(f)
			ns, _, _ := f.DefaultNamespace()

			domain := cmd.Flags().Lookup(domainFlag).Value.String()
			apiserver := cmd.Flags().Lookup(apiServerFlag).Value.String()
			arch := cmd.Flags().Lookup(archFlag).Value.String()

			typeOfMaster := util.TypeOfMaster(c)

			util.Info("Deploying fabric8 to your ")
			util.Success(string(typeOfMaster))
			util.Info(" installation at ")
			util.Success(cfg.Host)
			util.Info(" for domain ")
			util.Success(domain)
			util.Info(" in namespace ")
			util.Successf("%s\n\n", ns)

			useIngress := cmd.Flags().Lookup(useIngressFlag).Value.String() == "true"
			deployConsole := cmd.Flags().Lookup(consoleFlag).Value.String() == "true"

			mavenRepo := cmd.Flags().Lookup(mavenRepoFlag).Value.String()
			if !strings.HasSuffix(mavenRepo, "/") {
				mavenRepo = mavenRepo + "/"
			}
			util.Info("Loading fabric8 releases from maven repository:")
			util.Successf("%s\n", mavenRepo)

			dockerRegistry := cmd.Flags().Lookup(dockerRegistryFlag).Value.String()
			if len(dockerRegistry) > 0 {
				util.Infof("Loading fabric8 docker images from docker registry: %s\n", dockerRegistry)
			}

			if len(apiserver) == 0 {
				apiserver = domain
			}

			if strings.Contains(domain, "=") {
				util.Warnf("\nInvalid domain: %s\n\n", domain)
			} else if confirmAction(cmd.Flags()) {
				v := cmd.Flags().Lookup("fabric8-version").Value.String()

				consoleVersion := f8ConsoleVersion(mavenRepo, v, typeOfMaster)

				versioniPaaS := cmd.Flags().Lookup(versioniPaaSFlag).Value.String()
				versioniPaaS = versionForUrl(versioniPaaS, urlJoin(mavenRepo, iPaaSMetadataUrl))

				versionDevOps := cmd.Flags().Lookup(versionDevOpsFlag).Value.String()
				versionDevOps = versionForUrl(versionDevOps, urlJoin(mavenRepo, devOpsMetadataUrl))

				versionKubeflix := cmd.Flags().Lookup(versionKubeflixFlag).Value.String()
				versionKubeflix = versionForUrl(versionKubeflix, urlJoin(mavenRepo, kubeflixMetadataUrl))

				versionZipkin := cmd.Flags().Lookup(versionZipkinFlag).Value.String()
				versionZipkin = versionForUrl(versionZipkin, urlJoin(mavenRepo, zipkinMetadataUrl))

				util.Warnf("\nStarting fabric8 console deployment using %s...\n\n", consoleVersion)

				oc, _ := client.NewOpenShiftClient(cfg)

				aapi.AddToScheme(api.Scheme)
				aapiv1.AddToScheme(api.Scheme)
				tapi.AddToScheme(api.Scheme)
				tapiv1.AddToScheme(api.Scheme)

				if typeOfMaster == util.Kubernetes {
					uri := fmt.Sprintf(urlJoin(mavenRepo, baseConsoleKubernetesUrl), consoleVersion)
					if fabric8ImageAdaptionNeeded(dockerRegistry, arch) {
						jsonData, err := loadJsonDataAndAdaptFabric8Images(uri, dockerRegistry, arch)
						if err == nil {
							tmpFileName := "/tmp/fabric8-console.json"
							t, err := os.OpenFile(tmpFileName, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0777)
							if err != nil {
								util.Fatalf("Cannot open the converted fabric8 console template file: %v", err)
							}
							defer t.Close()

							_, err = io.Copy(t, bytes.NewReader(jsonData))
							if err != nil {
								util.Fatalf("Cannot write the converted fabric8 console template file: %v", err)
							}
							uri = tmpFileName
						}
					}
					filenames := []string{uri}

					if deployConsole {
						createCmd := &cobra.Command{}
						cmdutil.AddValidateFlags(createCmd)
						cmdutil.AddOutputFlagsForMutation(createCmd)
						cmdutil.AddApplyAnnotationFlags(createCmd)
						cmdutil.AddRecordFlag(createCmd)
						err := kcmd.RunCreate(f, createCmd, ioutil.Discard, &kcmd.CreateOptions{Filenames: filenames})
						if err != nil {
							printResult("fabric8 console", Failure, err)
						} else {
							printResult("fabric8 console", Success, nil)
						}
					}
					printAddServiceAccount(c, f, "fluentd")
					printAddServiceAccount(c, f, "registry")
				} else {
					r, err := verifyRestrictedSecurityContextConstraints(c, f)
					printResult("SecurityContextConstraints restricted", r, err)
					r, err = deployFabric8SecurityContextConstraints(c, f, ns)
					printResult("SecurityContextConstraints fabric8", r, err)
					r, err = deployFabric8SASSecurityContextConstraints(c, f, ns)
					printResult("SecurityContextConstraints "+Fabric8SASSCC, r, err)

					printAddClusterRoleToUser(oc, f, "cluster-admin", "system:serviceaccount:"+ns+":fabric8")
					printAddClusterRoleToUser(oc, f, "cluster-admin", "system:serviceaccount:"+ns+":jenkins")
					printAddClusterRoleToUser(oc, f, "cluster-reader", "system:serviceaccount:"+ns+":metrics")
					printAddClusterRoleToUser(oc, f, "cluster-reader", "system:serviceaccount:"+ns+":fluentd")

					printAddServiceAccount(c, f, "fluentd")
					printAddServiceAccount(c, f, "registry")
					printAddServiceAccount(c, f, "router")

					if cmd.Flags().Lookup(templatesFlag).Value.String() == "true" {
						if deployConsole {
							uri := fmt.Sprintf(urlJoin(mavenRepo, baseConsoleUrl), consoleVersion)
							jsonData, err := loadJsonDataAndAdaptFabric8Images(uri, dockerRegistry, arch)
							if err != nil {
								printError("failed to apply docker registry prefix", err)
							}

							// lets delete the OAuthClient first as the domain may have changed
							oc.OAuthClients().Delete("fabric8")
							createTemplate(jsonData, "fabric8 console", ns, domain, apiserver, c)
						}
					} else {
						printError("Ignoring the deploy of the fabric8 console", nil)
					}
				}
				if deployConsole {
					println("Created fabric8 console")
				}

				if cmd.Flags().Lookup(templatesFlag).Value.String() == "true" {
					println("Installing templates!")
					printError("Install DevOps templates", installTemplates(c, oc, f, versionDevOps, urlJoin(mavenRepo, devopsTemplatesDistroUrl), dockerRegistry, arch, domain))
					printError("Install iPaaS templates", installTemplates(c, oc, f, versioniPaaS, urlJoin(mavenRepo, iPaaSTemplatesDistroUrl), dockerRegistry, arch, domain))
					printError("Install Kubeflix templates", installTemplates(c, oc, f, versionKubeflix, urlJoin(mavenRepo, kubeflixTemplatesDistroUrl), dockerRegistry, arch, domain))
					printError("Install Zipkin templates", installTemplates(c, oc, f, versionZipkin, urlJoin(mavenRepo, zipkinTemplatesDistroUrl), dockerRegistry, arch, domain))
				} else {
					printError("Ignoring the deploy of templates", nil)
				}

				appToRun := cmd.Flags().Lookup(runFlag).Value.String()
				if len(appToRun) > 0 {
					runTemplate(c, oc, appToRun, ns, domain, apiserver)
				}

				if typeOfMaster == util.Kubernetes {
					if useIngress {
						runTemplate(c, oc, "ingress-nginx", ns, domain, apiserver)

						printError("Create ingress resources", createIngressForDomain(ns, domain, c, f))
					}
				} else {
					printError("Create route resources", createRoutesForDomain(ns, domain, c, oc, f))
				}

				// lets label the namespace/project as a developer team
				nss := c.Namespaces()
				namespace, err := nss.Get(ns)
				if err != nil {
					printError("Failed to load namespace", err)
				} else {
					if addLabelIfNotxisEt(&namespace.ObjectMeta, typeLabel, teamTypeLabelValue) {
						_, err = nss.Update(namespace)
						if err != nil {
							printError("Failed to label namespace", err)
						}
					}
				}
			}
		},
	}
	cmd.PersistentFlags().StringP("domain", "d", defaultDomain(), "The domain name to append to the service name to access web applications")
	cmd.PersistentFlags().String("api-server", "", "overrides the api server url")
	cmd.PersistentFlags().String(archFlag, goruntime.GOARCH, "CPU architecture for referencing Docker images with this as a name suffix")
	cmd.PersistentFlags().String(versioniPaaSFlag, "latest", "The version to use for the Fabric8 iPaaS templates")
	cmd.PersistentFlags().String(versionDevOpsFlag, "latest", "The version to use for the Fabric8 DevOps templates")
	cmd.PersistentFlags().String(versionKubeflixFlag, "latest", "The version to use for the Kubeflix templates")
	cmd.PersistentFlags().String(versionZipkinFlag, "latest", "The version to use for the Zipkin templates")
	cmd.PersistentFlags().String(mavenRepoFlag, "https://repo1.maven.org/maven2/", "The maven repo used to find releases of fabric8")
	cmd.PersistentFlags().String(dockerRegistryFlag, "", "The docker registry used to download fabric8 images. Typically used to point to a staging registry")
	cmd.PersistentFlags().String(runFlag, "", "The name of the fabric8 app to startup. e.g. use `--app=cd-pipeline` to run the main CI/CD pipeline app")
	cmd.PersistentFlags().Bool(templatesFlag, true, "Should the standard Fabric8 templates be installed?")
	cmd.PersistentFlags().Bool(consoleFlag, true, "Should the Fabric8 console be deployed?")
	cmd.PersistentFlags().Bool(useIngressFlag, true, "Should Ingress be enabled by default?")
	return cmd
}
Beispiel #3
0
func NewCmdDeploy(f *cmdutil.Factory) *cobra.Command {
	cmd := &cobra.Command{
		Use:   "deploy",
		Short: "Deploy fabric8 to your Kubernetes or OpenShift environment",
		Long:  `deploy fabric8 to your Kubernetes or OpenShift environment`,
		PreRun: func(cmd *cobra.Command, args []string) {
			showBanner()
		},
		Run: func(cmd *cobra.Command, args []string) {
			c, cfg := client.NewClient(f)
			ns, _, _ := f.DefaultNamespace()

			domain := cmd.Flags().Lookup(domainFlag).Value.String()
			apiserver := cmd.Flags().Lookup(apiServerFlag).Value.String()
			arch := cmd.Flags().Lookup(archFlag).Value.String()
			mini := isMini(c, ns)
			typeOfMaster := util.TypeOfMaster(c)

			// extract the ip address from the URL
			ip := strings.Split(cfg.Host, ":")[1]
			ip = strings.Replace(ip, "/", "", 2)

			if mini && typeOfMaster == util.OpenShift {
				domain = ip + ".xip.io"
				apiserver = ip
			}

			util.Info("Deploying fabric8 to your ")
			util.Success(string(typeOfMaster))
			util.Info(" installation at ")
			util.Success(cfg.Host)
			util.Info(" for domain ")
			util.Success(domain)
			util.Info(" in namespace ")
			util.Successf("%s\n\n", ns)

			useIngress := cmd.Flags().Lookup(useIngressFlag).Value.String() == "true"
			deployConsole := cmd.Flags().Lookup(consoleFlag).Value.String() == "true"

			pv, err := shouldEnablePV(c, cmd.Flags())
			if err != nil {
				util.Fatalf("No nodes available, something bad has happened: %v", err)
			}

			mavenRepo := cmd.Flags().Lookup(mavenRepoFlag).Value.String()
			if !strings.HasSuffix(mavenRepo, "/") {
				mavenRepo = mavenRepo + "/"
			}
			util.Info("Loading fabric8 releases from maven repository:")
			util.Successf("%s\n", mavenRepo)

			dockerRegistry := cmd.Flags().Lookup(dockerRegistryFlag).Value.String()
			if len(dockerRegistry) > 0 {
				util.Infof("Loading fabric8 docker images from docker registry: %s\n", dockerRegistry)
			}

			if len(apiserver) == 0 {
				apiserver = domain
			}

			if strings.Contains(domain, "=") {
				util.Warnf("\nInvalid domain: %s\n\n", domain)
			} else if confirmAction(cmd.Flags()) {
				v := cmd.Flags().Lookup("fabric8-version").Value.String()

				consoleVersion := f8ConsoleVersion(mavenRepo, v, typeOfMaster)

				versioniPaaS := cmd.Flags().Lookup(versioniPaaSFlag).Value.String()
				versioniPaaS = versionForUrl(versioniPaaS, urlJoin(mavenRepo, iPaaSMetadataUrl))

				versionDevOps := cmd.Flags().Lookup(versionDevOpsFlag).Value.String()
				versionDevOps = versionForUrl(versionDevOps, urlJoin(mavenRepo, devOpsMetadataUrl))

				versionKubeflix := cmd.Flags().Lookup(versionKubeflixFlag).Value.String()
				versionKubeflix = versionForUrl(versionKubeflix, urlJoin(mavenRepo, kubeflixMetadataUrl))

				versionZipkin := cmd.Flags().Lookup(versionZipkinFlag).Value.String()
				versionZipkin = versionForUrl(versionZipkin, urlJoin(mavenRepo, zipkinMetadataUrl))

				util.Warnf("\nStarting fabric8 console deployment using %s...\n\n", consoleVersion)

				oc, _ := client.NewOpenShiftClient(cfg)

				initSchema()

				if typeOfMaster == util.Kubernetes {
					uri := fmt.Sprintf(urlJoin(mavenRepo, baseConsoleKubernetesUrl), consoleVersion)
					if fabric8ImageAdaptionNeeded(dockerRegistry, arch) {
						jsonData, err := loadJsonDataAndAdaptFabric8Images(uri, dockerRegistry, arch)
						if err == nil {
							tmpFileName := path.Join(os.TempDir(), "fabric8-console.json")
							t, err := os.OpenFile(tmpFileName, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0777)
							if err != nil {
								util.Fatalf("Cannot open the converted fabric8 console template file: %v", err)
							}
							defer t.Close()

							_, err = io.Copy(t, bytes.NewReader(jsonData))
							if err != nil {
								util.Fatalf("Cannot write the converted fabric8 console template file: %v", err)
							}
							uri = tmpFileName
						}
					}
					filenames := []string{uri}

					if deployConsole {
						createCmd := &cobra.Command{}
						cmdutil.AddValidateFlags(createCmd)
						cmdutil.AddOutputFlagsForMutation(createCmd)
						cmdutil.AddApplyAnnotationFlags(createCmd)
						cmdutil.AddRecordFlag(createCmd)
						err := kcmd.RunCreate(f, createCmd, ioutil.Discard, &kcmd.CreateOptions{Filenames: filenames})
						if err != nil {
							printResult("fabric8 console", Failure, err)
						} else {
							printResult("fabric8 console", Success, nil)
						}
					}
					printAddServiceAccount(c, f, "fluentd")
					printAddServiceAccount(c, f, "registry")
				} else {
					r, err := verifyRestrictedSecurityContextConstraints(c, f)
					printResult("SecurityContextConstraints restricted", r, err)
					r, err = deployFabric8SecurityContextConstraints(c, f, ns)
					printResult("SecurityContextConstraints fabric8", r, err)
					r, err = deployFabric8SASSecurityContextConstraints(c, f, ns)
					printResult("SecurityContextConstraints "+Fabric8SASSCC, r, err)

					printAddClusterRoleToUser(oc, f, "cluster-admin", "system:serviceaccount:"+ns+":fabric8")
					printAddClusterRoleToUser(oc, f, "cluster-admin", "system:serviceaccount:"+ns+":jenkins")
					printAddClusterRoleToUser(oc, f, "cluster-admin", "system:serviceaccount:"+ns+":exposecontroller")
					printAddClusterRoleToUser(oc, f, "cluster-reader", "system:serviceaccount:"+ns+":metrics")
					printAddClusterRoleToUser(oc, f, "cluster-reader", "system:serviceaccount:"+ns+":fluentd")

					printAddClusterRoleToGroup(oc, f, "cluster-reader", "system:serviceaccounts")

					printAddServiceAccount(c, f, "fluentd")
					printAddServiceAccount(c, f, "registry")
					printAddServiceAccount(c, f, "router")

					if cmd.Flags().Lookup(templatesFlag).Value.String() == "true" {
						if deployConsole {
							uri := fmt.Sprintf(urlJoin(mavenRepo, baseConsoleUrl), consoleVersion)
							format := "json"
							jsonData, err := loadJsonDataAndAdaptFabric8Images(uri, dockerRegistry, arch)
							if err != nil {
								printError("failed to apply docker registry prefix", err)
							}

							// lets delete the OAuthClient first as the domain may have changed
							oc.OAuthClients().Delete("fabric8")
							createTemplate(jsonData, format, "fabric8 console", ns, domain, apiserver, c, oc, pv)

							oac, err := oc.OAuthClients().Get("fabric8")
							if err != nil {
								printError("failed to get the OAuthClient called fabric8", err)
							}

							// lets add the nodePort URL to the OAuthClient
							service, err := c.Services(ns).Get("fabric8")
							if err != nil {
								printError("failed to get the Service called fabric8", err)
							}
							port := 0
							for _, p := range service.Spec.Ports {
								port = p.NodePort
							}
							if port == 0 {
								printError("failed to find nodePort on the Service called fabric8", err)
							}
							ip := apiserver
							redirectURL := fmt.Sprintf("http://%s:%d", ip, port)
							println("Adding OAuthClient redirectURL: " + redirectURL)
							oac.RedirectURIs = append(oac.RedirectURIs, redirectURL)
							oac.ResourceVersion = ""
							oc.OAuthClients().Delete("fabric8")
							_, err = oc.OAuthClients().Create(oac)
							if err != nil {
								printError("failed to create the OAuthClient called fabric8", err)
							}

						}
					} else {
						printError("Ignoring the deploy of the fabric8 console", nil)
					}
				}
				if deployConsole {
					println("Created fabric8 console")
				}

				if cmd.Flags().Lookup(templatesFlag).Value.String() == "true" {
					println("Installing templates!")
					printError("Install DevOps templates", installTemplates(c, oc, f, versionDevOps, urlJoin(mavenRepo, devopsTemplatesDistroUrl), dockerRegistry, arch, domain))
					printError("Install iPaaS templates", installTemplates(c, oc, f, versioniPaaS, urlJoin(mavenRepo, iPaaSTemplatesDistroUrl), dockerRegistry, arch, domain))
					printError("Install Kubeflix templates", installTemplates(c, oc, f, versionKubeflix, urlJoin(mavenRepo, kubeflixTemplatesDistroUrl), dockerRegistry, arch, domain))
					printError("Install Zipkin templates", installTemplates(c, oc, f, versionZipkin, urlJoin(mavenRepo, zipkinTemplatesDistroUrl), dockerRegistry, arch, domain))
				} else {
					printError("Ignoring the deploy of templates", nil)
				}

				runTemplate(c, oc, "exposecontroller", ns, domain, apiserver, pv)
				externalNodeName := ""
				if typeOfMaster == util.Kubernetes {
					if useIngress && !mini {
						runTemplate(c, oc, "ingress-nginx", ns, domain, apiserver, pv)
						externalNodeName = addIngressInfraLabel(c, ns)
					}
				}

				// create a populate the exposecontroller config map
				cfgms := c.ConfigMaps(ns)
				useLoadBalancer := cmd.Flags().Lookup(useLoadbalancerFlag).Value.String() == "true"
				_, err := cfgms.Get(exposecontrollerCM)
				if err == nil {
					util.Infof("\nRecreating configmap %s \n", exposecontrollerCM)
					err = cfgms.Delete(exposecontrollerCM)
					if err != nil {
						printError("\nError deleting ConfigMap: "+exposecontrollerCM, err)
					}
				}

				configMap := kapi.ConfigMap{
					ObjectMeta: kapi.ObjectMeta{
						Name: exposecontrollerCM,
						Labels: map[string]string{
							"provider": "fabric8.io",
						},
					},
					Data: map[string]string{
						"domain":   domain,
						exposeRule: defaultExposeRule(c, mini, useLoadBalancer),
					},
				}
				_, err = cfgms.Create(&configMap)
				if err != nil {
					printError("Failed to create ConfigMap: "+exposecontrollerCM, err)
				}

				appToRun := cmd.Flags().Lookup(runFlag).Value.String()
				if len(appToRun) > 0 {
					runTemplate(c, oc, appToRun, ns, domain, apiserver, pv)

					// lets create any missing PVs if on minikube or minishift
					found, pendingClaimNames := findPendingPVS(c, ns)
					if found {
						createPV(c, ns, pendingClaimNames, cmd)
					}
				}

				// lets label the namespace/project as a developer team
				nss := c.Namespaces()
				namespace, err := nss.Get(ns)
				if err != nil {
					printError("Failed to load namespace", err)
				} else {
					changed := addLabelIfNotExist(&namespace.ObjectMeta, typeLabel, teamTypeLabelValue)
					if len(domain) > 0 {
						if addAnnotationIfNotExist(&namespace.ObjectMeta, domainAnnotation, domain) {
							changed = true
						}
					}
					if changed {
						_, err = nss.Update(namespace)
						if err != nil {
							printError("Failed to label and annotate namespace", err)
						}
					}
				}

				// lets ensure that there is a `fabric8-environments` ConfigMap so that the current namespace
				// shows up as a Team page in the console
				_, err = cfgms.Get(fabric8Environments)
				if err != nil {
					configMap := kapi.ConfigMap{
						ObjectMeta: kapi.ObjectMeta{
							Name: fabric8Environments,
							Labels: map[string]string{
								"provider": "fabric8.io",
								"kind":     "environments",
							},
						},
					}
					_, err = cfgms.Create(&configMap)
					if err != nil {
						printError("Failed to create ConfigMap: "+fabric8Environments, err)
					}
				}

				nodeClient := c.Nodes()
				nodes, err := nodeClient.List(api.ListOptions{})
				changed := false

				for _, node := range nodes.Items {
					// if running on a single node then we can use node ports to access kubernetes services
					if len(nodes.Items) == 1 {
						changed = addAnnotationIfNotExist(&node.ObjectMeta, externalIPNodeLabel, ip)
					}
					changed = addAnnotationIfNotExist(&node.ObjectMeta, externalAPIServerAddressLabel, cfg.Host)
					if changed {
						_, err = nodeClient.Update(&node)
						if err != nil {
							printError("Failed to annotate node with ", err)
						}
					}
				}
				printSummary(typeOfMaster, externalNodeName, mini, ns, domain)

				openService(ns, "fabric8", c, false)
			}
		},
	}
	cmd.PersistentFlags().StringP(domainFlag, "d", defaultDomain(), "The domain name to append to the service name to access web applications")
	cmd.PersistentFlags().String(apiServerFlag, "", "overrides the api server url")
	cmd.PersistentFlags().String(archFlag, goruntime.GOARCH, "CPU architecture for referencing Docker images with this as a name suffix")
	cmd.PersistentFlags().String(versioniPaaSFlag, "latest", "The version to use for the Fabric8 iPaaS templates")
	cmd.PersistentFlags().String(versionDevOpsFlag, "latest", "The version to use for the Fabric8 DevOps templates")
	cmd.PersistentFlags().String(versionKubeflixFlag, "latest", "The version to use for the Kubeflix templates")
	cmd.PersistentFlags().String(versionZipkinFlag, "latest", "The version to use for the Zipkin templates")
	cmd.PersistentFlags().String(mavenRepoFlag, "https://repo1.maven.org/maven2/", "The maven repo used to find releases of fabric8")
	cmd.PersistentFlags().String(dockerRegistryFlag, "", "The docker registry used to download fabric8 images. Typically used to point to a staging registry")
	cmd.PersistentFlags().String(runFlag, "cd-pipeline", "The name of the fabric8 app to startup. e.g. use `--app=cd-pipeline` to run the main CI/CD pipeline app")
	cmd.PersistentFlags().Bool(pvFlag, true, "Enable the use of persistence (Not currently supported on the CDK)")
	cmd.PersistentFlags().Bool(noPVFlag, false, "(Deprecated use --pv=false to disable instead) Disable the use of persistence (disabling the PersistentVolumeClaims)?")
	cmd.PersistentFlags().Bool(templatesFlag, true, "Should the standard Fabric8 templates be installed?")
	cmd.PersistentFlags().Bool(consoleFlag, true, "Should the Fabric8 console be deployed?")
	cmd.PersistentFlags().Bool(useIngressFlag, true, "Should Ingress NGINX controller be enabled by default when deploying to Kubernetes?")
	cmd.PersistentFlags().Bool(useLoadbalancerFlag, false, "Should Cloud Provider LoadBalancer be used to expose services when running to Kubernetes? (overrides ingress)")

	return cmd
}