func deployFabric8SASSecurityContextConstraints(c *k8sclient.Client, f *cmdutil.Factory, ns string) (Result, error) { name := Fabric8SASSCC scc := kapi.SecurityContextConstraints{ ObjectMeta: kapi.ObjectMeta{ Name: name, }, SELinuxContext: kapi.SELinuxContextStrategyOptions{ Type: kapi.SELinuxStrategyRunAsAny, }, RunAsUser: kapi.RunAsUserStrategyOptions{ Type: kapi.RunAsUserStrategyRunAsAny, }, Groups: []string{"system:serviceaccounts"}, Volumes: []kapi.FSType{kapi.FSTypeGitRepo, kapi.FSTypeConfigMap, kapi.FSTypeSecret, kapi.FSTypeEmptyDir}, } _, err := c.SecurityContextConstraints().Get(name) if err == nil { err = c.SecurityContextConstraints().Delete(name) if err != nil { return Failure, err } } _, err = c.SecurityContextConstraints().Create(&scc) if err != nil { util.Fatalf("Cannot create SecurityContextConstraints: %v\n", err) util.Fatalf("Failed to create SecurityContextConstraints %v in namespace %s: %v\n", scc, ns, err) return Failure, err } util.Infof("SecurityContextConstraints %s is setup correctly\n", name) return Success, err }
// NewCmdDockerEnv sets the current func NewCmdDockerEnv(f *cmdutil.Factory) *cobra.Command { cmd := &cobra.Command{ Use: "docker-env", Short: "Sets up docker env variables; Usage 'eval $(gofabric8 docker-env)'", Long: `Sets up docker env variables; Usage 'eval $(gofabric8 docker-env)'`, Run: func(cmd *cobra.Command, args []string) { c, _ := client.NewClient(f) nodes, err := c.Nodes().List(api.ListOptions{}) if err != nil { util.Errorf("Unable to find any nodes: %s\n", err) } if len(nodes.Items) == 1 { node := nodes.Items[0] var command string var args []string if node.Name == minikubeNodeName { command = "minikube" args = []string{"docker-env"} } else if node.Name == minishiftNodeName { command = "minishift" args = []string{"docker-env"} } else if node.Name == rhelcdk { command = "vagrant" args = []string{"service-manager", "env", "docker"} } if command == "" { util.Fatalf("Unrecognised cluster environment for node %s\n", node.Name) util.Fatalf("docker-env support is currently only for CDK, Minishift and Minikube\n") } e := exec.Command(command, args...) e.Stdout = os.Stdout e.Stderr = os.Stderr err = e.Run() if err != nil { util.Fatalf("Unable to set the docker environment %v", err) } } else { util.Fatalf("docker-env is only available to run on clusters of 1 node") } }, } return cmd }
func generateSshKeyPair(logGeneratedKeys string) Keypair { priv, err := rsa.GenerateKey(rand.Reader, 2014) if err != nil { util.Fatalf("Error generating key", err) } err = priv.Validate() if err != nil { util.Fatalf("Validation failed.", err) } // Get der format. priv_der []byte priv_der := x509.MarshalPKCS1PrivateKey(priv) // pem.Block // blk pem.Block priv_blk := pem.Block{ Type: "RSA PRIVATE KEY", Headers: nil, Bytes: priv_der, } // Resultant private key in PEM format. // priv_pem string priv_pem := string(pem.EncodeToMemory(&priv_blk)) if logGeneratedKeys == "true" { util.Infof(priv_pem) } // Public Key generation pub := priv.PublicKey pub_der, err := x509.MarshalPKIXPublicKey(&pub) if err != nil { util.Fatalf("Failed to get der format for PublicKey.", err) } pub_blk := pem.Block{ Type: "PUBLIC KEY", Headers: nil, Bytes: pub_der, } pub_pem := string(pem.EncodeToMemory(&pub_blk)) if logGeneratedKeys == "true" { util.Infof(pub_pem) } return Keypair{ pub: []byte(pub_pem), priv: []byte(priv_pem), } }
func NewClient(f *cmdutil.Factory) (*client.Client, *restclient.Config) { var err error cfg, err := f.ClientConfig() if err != nil { util.Error("Could not initialise a client - is your server setting correct?\n\n") util.Fatalf("%v", err) } c, err := client.New(cfg) if err != nil { util.Fatalf("Could not initialise a client: %v", err) } return c, cfg }
func deployFabric8SecurityContextConstraints(c *k8sclient.Client, f *cmdutil.Factory, ns string) (Result, error) { name := Fabric8SCC if ns != "default" { name += "-" + ns } scc := kapi.SecurityContextConstraints{ ObjectMeta: kapi.ObjectMeta{ Name: name, }, Priority: &[]int{10}[0], AllowPrivilegedContainer: true, AllowHostNetwork: true, AllowHostPorts: true, Volumes: []kapi.FSType{kapi.FSTypeAll}, SELinuxContext: kapi.SELinuxContextStrategyOptions{ Type: kapi.SELinuxStrategyRunAsAny, }, RunAsUser: kapi.RunAsUserStrategyOptions{ Type: kapi.RunAsUserStrategyRunAsAny, }, Users: []string{ "system:serviceaccount:openshift-infra:build-controller", "system:serviceaccount:" + ns + ":default", "system:serviceaccount:" + ns + ":fabric8", "system:serviceaccount:" + ns + ":gerrit", "system:serviceaccount:" + ns + ":jenkins", "system:serviceaccount:" + ns + ":router", "system:serviceaccount:" + ns + ":registry", "system:serviceaccount:" + ns + ":gogs", "system:serviceaccount:" + ns + ":fluentd", }, Groups: []string{bootstrappolicy.ClusterAdminGroup, bootstrappolicy.NodesGroup}, } _, err := c.SecurityContextConstraints().Get(name) if err == nil { err = c.SecurityContextConstraints().Delete(name) if err != nil { return Failure, err } } _, err = c.SecurityContextConstraints().Create(&scc) if err != nil { util.Fatalf("Cannot create SecurityContextConstraints: %v\n", err) util.Fatalf("Failed to create SecurityContextConstraints %v in namespace %s: %v\n", scc, ns, err) return Failure, err } util.Infof("SecurityContextConstraints %s is setup correctly\n", name) return Success, err }
func NewCmdCopyEndpoints(f *cmdutil.Factory) *cobra.Command { cmd := &cobra.Command{ Use: "copy-endpoints", Short: "Copies endpoints from the current namespace to a target namespace", Long: `Copies endpoints from the current namespace to a target namespace`, PreRun: func(cmd *cobra.Command, args []string) { showBanner() }, Run: func(cmd *cobra.Command, args []string) { if len(args) == 0 { util.Info("Please specify one or more endpoint names to copy as arguments!\n") return } c, cfg := client.NewClient(f) oc, _ := client.NewOpenShiftClient(cfg) initSchema() toNamespace := cmd.Flags().Lookup(toNamespaceFlag).Value.String() fromNamespace := cmd.Flags().Lookup(fromNamespaceFlag).Value.String() if len(fromNamespace) == 0 { ns, _, err := f.DefaultNamespace() if err != nil { util.Fatal("No default namespace") } fromNamespace = ns } if len(toNamespace) == 0 { util.Fatal("No target namespace specified!") } util.Infof("Copying endpoints from namespace: %s to namespace: %s\n", fromNamespace, toNamespace) err := ensureNamespaceExists(c, oc, toNamespace) if err != nil { util.Fatalf("Failed to copy endpoints %v", err) } err = copyEndpoints(c, fromNamespace, toNamespace, args) if err != nil { util.Fatalf("Failed to copy endpoints %v", err) } }, } cmd.PersistentFlags().StringP(fromNamespaceFlag, "f", "", "the source namespace or uses the default namespace") cmd.PersistentFlags().StringP(toNamespaceFlag, "t", "", "the destination namespace") return cmd }
func getFabric8BinLocation() string { home := homedir.HomeDir() if home == "" { util.Fatalf("No user home environment variable found for OS %s", runtime.GOOS) } return filepath.Join(home, ".fabric8", "bin") }
// NewCmdService looks up the external service address and opens the URL // Credits: https://github.com/kubernetes/minikube/blob/v0.9.0/cmd/minikube/cmd/service.go func NewCmdService(f *cmdutil.Factory) *cobra.Command { cmd := &cobra.Command{ Use: "service", Short: "Opens the specified Kubernetes service in your browser", Long: `Opens the specified Kubernetes service in your browser`, Run: func(cmd *cobra.Command, args []string) { c, _ := client.NewClient(f) ns := cmd.Flags().Lookup(namespaceCommandFlag).Value.String() if ns == "" { ns, _, _ = f.DefaultNamespace() } printURL := cmd.Flags().Lookup(urlCommandFlag).Value.String() == "true" retry := cmd.Flags().Lookup(retryFlag).Value.String() == "true" if len(args) == 1 { openService(ns, args[0], c, printURL, retry) } else { util.Fatalf("Please choose a service, found %v arguments\n", len(args)) } }, } cmd.PersistentFlags().StringP(namespaceCommandFlag, "n", "default", "The service namespace") cmd.PersistentFlags().BoolP(urlCommandFlag, "u", false, "Display the kubernetes service exposed URL in the CLI instead of opening it in the default browser") cmd.PersistentFlags().Bool(retryFlag, true, "Retries to find the service if its not available just yet") return cmd }
func generateSshKeyPair() Keypair { priv, err := rsa.GenerateKey(rand.Reader, 2014) if err != nil { util.Fatalf("Error generating key", err) } // Get der format. priv_der []byte priv_der := x509.MarshalPKCS1PrivateKey(priv) // pem.Block // blk pem.Block priv_blk := pem.Block{ Type: "RSA PRIVATE KEY", Headers: nil, Bytes: priv_der, } // Resultant private key in PEM format. // priv_pem string priv_pem := string(pem.EncodeToMemory(&priv_blk)) // Public Key generation sshPublicKey, err := ssh.NewPublicKey(&priv.PublicKey) pubBytes := ssh.MarshalAuthorizedKey(sshPublicKey) return Keypair{ pub: []byte(pubBytes), priv: []byte(priv_pem), } }
func loadJsonDataAndAdaptFabric8Images(uri string, dockerRegistry string, arch string) ([]byte, error) { 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) } jsonData, err = adaptFabric8ImagesInResourceDescriptor(jsonData, dockerRegistry, arch) if err != nil { util.Fatalf("Cannot append docker registry: %v", err) } return jsonData, nil }
func getTemplates(c *oclient.Client, ns string) *tapi.TemplateList { templates, err := c.Templates(ns).List(api.ListOptions{}) if err != nil { util.Fatalf("No Templates found in namespace %s\n", ns) } return templates }
// NewCmdCleanUp delete all fabric8 apps, environments and configurations func NewCmdCleanUp(f *cmdutil.Factory) *cobra.Command { cmd := &cobra.Command{ Use: "cleanup", Short: "Hard delete all fabric8 apps, environments and configurations", Long: `Hard delete all fabric8 apps, environments and configurations`, Run: func(cmd *cobra.Command, args []string) { currentContext, err := util.GetCurrentContext() if err != nil { util.Fatalf("%s", err) } fmt.Fprintf(os.Stdout, `WARNING this is destructive and will remove ALL fabric8 apps, environments and configuration from cluster %s. Continue? [y/N] `, currentContext) var confirm string fmt.Scanln(&confirm) if confirm == "y" { util.Info("Removing...\n") cleanUp(f) return } util.Info("Cancelled") }, } return cmd }
func validateRouter(c *k8sclient.Client, f *cmdutil.Factory) (Result, error) { ns, _, err := f.DefaultNamespace() if err != nil { return Failure, err } requirement, err := labels.NewRequirement("router", labels.EqualsOperator, kutil.NewStringSet("router")) if err != nil { return Failure, err } label := labels.LabelSelector{*requirement} rc, err := c.ReplicationControllers(ns).List(label) if err != nil { util.Fatalf("Failed to get PersistentVolumeClaims, %s in namespace %s\n", err, ns) } if rc != nil { items := rc.Items if len(items) > 0 { return Success, err } } //util.Fatalf("No router running in namespace %s\n", ns) // TODO lets create a router return Failure, err }
func getTemplates(c *oclient.Client, ns string) *tapi.TemplateList { rc, err := c.Templates(ns).List(labels.Everything(), fields.Everything()) if err != nil { util.Fatalf("No Templates found in namespace %s\n", ns) } return rc }
// NewCmdStop stops the current local cluster func NewCmdStop(f *cmdutil.Factory) *cobra.Command { cmd := &cobra.Command{ Use: "stop", Short: "Stops a running local cluster", Long: `Stops a running local cluster`, Run: func(cmd *cobra.Command, args []string) { context, err := util.GetCurrentContext() if err != nil { util.Fatalf("Error getting current context %s", err) } var command string var cargs []string if context == util.Minikube { command = "minikube" cargs = []string{"stop"} } else if util.IsMiniShift(context) { command = "minishift" cargs = []string{"stop"} } else if context == util.CDK { command = "vagrant" cargs = []string{"halt"} } if command == "" { util.Fatalf("Context %s not supported. Currently only CDK, Minishift and Minikube are supported by this command\n", context) } e := exec.Command(command, cargs...) e.Stdout = os.Stdout e.Stderr = os.Stderr err = e.Run() if err != nil { util.Fatalf("Unable to stop the cluster %s", err) } }, } return cmd }
func NewOpenShiftClient(cfg *restclient.Config) (*oclient.Client, *restclient.Config) { ocfg := *cfg ocfg.APIPath = "" c, err := oclient.New(&ocfg) if err != nil { util.Fatalf("Could not initialise an OpenShift client: %v", err) } return c, cfg }
func f8Version(v string, typeOfMaster util.MasterType) string { metadataUrl := consoleMetadataUrl if typeOfMaster == util.Kubernetes { metadataUrl = consoleKubernetesMetadataUrl } resp, err := http.Get(metadataUrl) if err != nil { util.Fatalf("Cannot get fabric8 version to deploy: %v", err) } defer resp.Body.Close() // read xml http response xmlData, err := ioutil.ReadAll(resp.Body) if err != nil { util.Fatalf("Cannot get fabric8 version to deploy: %v", err) } type Metadata struct { Release string `xml:"versioning>release"` Versions []string `xml:"versioning>versions>version"` } var m Metadata err = xml.Unmarshal(xmlData, &m) if err != nil { util.Fatalf("Cannot get fabric8 version to deploy: %v", err) } if v == "latest" { return m.Release } for _, version := range m.Versions { if v == version { return version } } util.Errorf("\nUnknown version: %s\n", v) util.Fatalf("Valid versions: %v\n", append(m.Versions, "latest")) return "" }
func deployFabric8SecurityContextConstraints(c *k8sclient.Client, f *cmdutil.Factory) (Result, error) { name := Fabric8SCC scc := kapi.SecurityContextConstraints{ ObjectMeta: kapi.ObjectMeta{ Name: name, }, AllowPrivilegedContainer: true, AllowHostNetwork: true, AllowHostPorts: true, AllowHostDirVolumePlugin: true, SELinuxContext: kapi.SELinuxContextStrategyOptions{ Type: kapi.SELinuxStrategyRunAsAny, }, RunAsUser: kapi.RunAsUserStrategyOptions{ Type: kapi.RunAsUserStrategyRunAsAny, }, Users: []string{"system:serviceaccount:openshift-infra:build-controller", "system:serviceaccount:default:default", "system:serviceaccount:default:fabric8", "system:serviceaccount:default:gerrit", "system:serviceaccount:default:jenkins", "system:serviceaccount:default:router"}, Groups: []string{bootstrappolicy.ClusterAdminGroup, bootstrappolicy.NodesGroup}, } ns, _, err := f.DefaultNamespace() if err != nil { util.Fatal("No default namespace") return Failure, err } _, err = c.SecurityContextConstraints().Get(name) if err == nil { err = c.SecurityContextConstraints().Delete(name) if err != nil { return Failure, err } } _, err = c.SecurityContextConstraints().Create(&scc) if err != nil { util.Fatalf("Cannot create SecurityContextConstraints: %v\n", err) util.Fatalf("Failed to create SecurityContextConstraints %v in namespace %s: %v\n", scc, ns, err) return Failure, err } util.Infof("SecurityContextConstraints %s is setup correctly\n", name) return Success, err }
func validatePersistenceVolumeClaims(c *k8sclient.Client, f *cmdutil.Factory) (Result, error) { ns, _, err := f.DefaultNamespace() if err != nil { return Failure, err } rc, err := c.PersistentVolumeClaims(ns).List(api.ListOptions{}) if err != nil { util.Fatalf("Failed to get PersistentVolumeClaims, %s in namespace %s\n", err, ns) } if rc != nil { items := rc.Items pendingClaimNames := make([]string, 0, len(items)) for _, item := range items { status := item.Status.Phase if status != "Bound" { pendingClaimNames = append(pendingClaimNames, item.ObjectMeta.Name) } } if len(pendingClaimNames) > 0 { util.Failuref("PersistentVolumeClaim not Bound for: %s. You need to create a PersistentVolume!\n", strings.Join(pendingClaimNames, ", ")) util.Info(` You can enable dynamic PersistentVolume creation with Kubernetes 1.4 or later. Or to get gofabric8 to create HostPath based PersistentVolume resources for you on minikube and minishift type: gofabric8 volumes For other clusters you could do something like this - though ideally with a persistent volume implementation other than hostPath: cat <<EOF | oc create -f - --- kind: PersistentVolume apiVersion: v1 metadata: name: fabric8 spec: accessModes: - ReadWrite capacity: storage: 1000 hostPath: path: /opt/fabric8-data EOF `) return Failure, err } return Success, err } return Failure, err }
func cleanUpOpenshiftResources(c *k8sclient.Client, oc *oclient.Client, ns string, selector labels.Selector) { err := deleteDeploymentConfigs(oc, ns, selector) if err != nil { util.Fatalf("%s", err) } err = deleteBuilds(oc, ns, selector) if err != nil { util.Fatalf("%s", err) } err = deleteBuildConfigs(oc, ns, selector) if err != nil { util.Fatalf("%s", err) } err = deleteRoutes(oc, ns, selector) if err != nil { util.Fatalf("%s", err) } }
func validateSecurityContextConstraints(c *k8sclient.Client, f *cmdutil.Factory) (Result, error) { ns, _, err := f.DefaultNamespace() if err != nil { return Failure, err } rc, err := c.SecurityContextConstraints().Get("fabric8") if err != nil { util.Fatalf("Failed to get SecurityContextConstraints, %s in namespace %s\n", err, ns) } if rc != nil { return Success, err } return Failure, err }
func versionForUrl(v string, metadataUrl string) string { resp, err := http.Get(metadataUrl) if err != nil { util.Fatalf("Cannot get fabric8 version to deploy: %v", err) } defer resp.Body.Close() // read xml http response xmlData, err := ioutil.ReadAll(resp.Body) if err != nil { util.Fatalf("Cannot get fabric8 version to deploy: %v", err) } type Metadata struct { Release string `xml:"versioning>release"` Versions []string `xml:"versioning>versions>version"` } var m Metadata err = xml.Unmarshal(xmlData, &m) if err != nil { util.Fatalf("Cannot get fabric8 version to deploy: %v", err) } if v == "latest" { return m.Release } for _, version := range m.Versions { if v == version { return version } } util.Errorf("\nUnknown version %s for %s\n", v, metadataUrl) util.Fatalf("Valid versions: %v\n", append(m.Versions, "latest")) return "" }
func validatePersistenceVolumeClaims(c *k8sclient.Client, f *cmdutil.Factory) (Result, error) { ns, _, err := f.DefaultNamespace() if err != nil { return Failure, err } rc, err := c.PersistentVolumeClaims(ns).List(labels.Everything(), fields.Everything()) if err != nil { util.Fatalf("Failed to get PersistentVolumeClaims, %s in namespace %s\n", err, ns) } if rc != nil { items := rc.Items pendingClaimNames := make([]string, 0, len(items)) for _, item := range items { status := item.Status.Phase if status != "Bound" { pendingClaimNames = append(pendingClaimNames, item.ObjectMeta.Name) } } if len(pendingClaimNames) > 0 { util.Failuref("PersistentVolumeClaim not Bound for: %s. You need to create a PersistentVolume!\n", strings.Join(pendingClaimNames, ", ")) util.Info(` to generate a single node PersistentVolume then type something like this: cat <<EOF | oc create -f - --- kind: PersistentVolume apiVersion: v1 metadata: name: fabric8 spec: accessModes: - ReadWrite capacity: storage: 1000 hostPath: path: /opt/fabric8-data EOF `) return Failure, err } return Success, err } return Failure, err }
// Ensure that the `restricted` SecurityContextConstraints has the RunAsUser set to RunAsAny // // if `restricted does not exist lets create it // otherwise if needed lets modify the RunAsUser func verifyRestrictedSecurityContextConstraints(c *k8sclient.Client, f *cmdutil.Factory) (Result, error) { name := RestrictedSCC ns, _, e := f.DefaultNamespace() if e != nil { util.Fatal("No default namespace") return Failure, e } rc, err := c.SecurityContextConstraints().Get(name) if err != nil { scc := kapi.SecurityContextConstraints{ ObjectMeta: kapi.ObjectMeta{ Name: RestrictedSCC, }, SELinuxContext: kapi.SELinuxContextStrategyOptions{ Type: kapi.SELinuxStrategyMustRunAs, }, RunAsUser: kapi.RunAsUserStrategyOptions{ Type: kapi.RunAsUserStrategyRunAsAny, }, Groups: []string{bootstrappolicy.AuthenticatedGroup}, } _, err = c.SecurityContextConstraints().Create(&scc) if err != nil { return Failure, err } else { util.Infof("SecurityContextConstraints %s created\n", name) return Success, err } } // lets check that the restricted is configured correctly if kapi.RunAsUserStrategyRunAsAny != rc.RunAsUser.Type { rc.RunAsUser.Type = kapi.RunAsUserStrategyRunAsAny _, err = c.SecurityContextConstraints().Update(rc) if err != nil { util.Fatalf("Failed to update SecurityContextConstraints %v in namespace %s: %v\n", rc, ns, err) return Failure, err } util.Infof("SecurityContextConstraints %s is updated to enable fabric8\n", name) } else { util.Infof("SecurityContextConstraints %s is configured correctly\n", name) } return Success, err }
func downloadTemplateDockerImages(cmd *cobra.Command, ns string, c *oclient.Client, fac *cmdutil.Factory, name string) (Result, error) { rc, err := c.Templates(ns).Get(name) if err != nil { util.Fatalf("No Template %s found in namespace %s\n", name, ns) } // convert Template.Objects to Kubernetes resources _ = runtime.DecodeList(rc.Objects, api.Scheme, runtime.UnstructuredJSONScheme) for _, rc := range rc.Objects { switch rc := rc.(type) { case *api.ReplicationController: for _, container := range rc.Spec.Template.Spec.Containers { err = downloadDockerImage(container.Image) if err != nil { return Failure, err } } } } return Success, nil }
func isInstalled(isMinishift bool) bool { home := homedir.HomeDir() if home == "" { util.Fatalf("No user home environment variable found for OS %s", runtime.GOOS) } // check if we can find a local kube config file if _, err := os.Stat(home + "/.kube/config"); os.IsNotExist(err) { return false } // check for kubectl _, err := exec.LookPath(kubectl) if err != nil { return false } if isMinishift { // check for minishift _, err = exec.LookPath(minishift) if err != nil { return false } // check for oc client _, err = exec.LookPath(oc) if err != nil { return false } } else { // check for minikube _, err = exec.LookPath(minikube) if err != nil { return false } } return true }
func processTemplate(tmpl *tapi.Template, ns string, domain string, apiserver string) { generators := map[string]generator.Generator{ "expression": generator.NewExpressionValueGenerator(rand.New(rand.NewSource(time.Now().UnixNano()))), } p := template.NewProcessor(generators) ip, port, err := net.SplitHostPort(apiserver) if err != nil && !strings.Contains(err.Error(), "missing port in address") { util.Fatalf("%s", err) } namespaceIdx := -1 for i, param := range tmpl.Parameters { if param.Name == "NAMESPACE" { namespaceIdx = i } } if namespaceIdx >= 0 { tmpl.Parameters[namespaceIdx].Value = ns } tmpl.Parameters = append(tmpl.Parameters, tapi.Parameter{ Name: "DOMAIN", Value: ns + "." + domain, }, tapi.Parameter{ Name: "APISERVER", Value: ip, }, tapi.Parameter{ Name: "OAUTH_AUTHORIZE_PORT", Value: port, }) errorList := p.Process(tmpl) for _, errInfo := range errorList { util.Errorf("Processing template field %s got error %s\n", errInfo.Field, errInfo.Detail) } }
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 }
func installTemplates(kc *k8sclient.Client, c *oclient.Client, fac *cmdutil.Factory, v string, templateUrl string, dockerRegistry string, arch string, domain string) error { ns, _, err := fac.DefaultNamespace() if err != nil { util.Fatal("No default namespace") return err } templates := c.Templates(ns) util.Infof("Downloading templates for version %v\n", v) uri := fmt.Sprintf(templateUrl, v) resp, err := http.Get(uri) if err != nil { util.Fatalf("Cannot get fabric8 template to deploy: %v", err) } defer resp.Body.Close() tmpFileName := "/tmp/fabric8-template-distros.tar.gz" t, err := os.OpenFile(tmpFileName, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0777) if err != nil { return err } defer t.Close() _, err = io.Copy(t, resp.Body) if err != nil { return err } r, err := zip.OpenReader(tmpFileName) if err != nil { return err } defer r.Close() typeOfMaster := util.TypeOfMaster(kc) for _, f := range r.File { mode := f.FileHeader.Mode() if mode.IsDir() { continue } rc, err := f.Open() if err != nil { return err } defer rc.Close() util.Infof("Loading template %s\n", f.Name) jsonData, err := ioutil.ReadAll(rc) if err != nil { util.Fatalf("Cannot get fabric8 template to deploy: %v", err) } jsonData, err = adaptFabric8ImagesInResourceDescriptor(jsonData, dockerRegistry, arch) if err != nil { util.Fatalf("Cannot append docker registry: %v", err) } jsonData = replaceDomain(jsonData, domain, ns, typeOfMaster) 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) return err } name := tmpl.ObjectMeta.Name if typeOfMaster == util.Kubernetes { appName := name name = "catalog-" + appName // lets install ConfigMaps for the templates // TODO should the name have a prefix? configmap := api.ConfigMap{ ObjectMeta: api.ObjectMeta{ Name: name, Namespace: ns, Labels: map[string]string{ "name": appName, "provider": "fabric8.io", "kind": "catalog", }, }, Data: map[string]string{ name + ".json": string(jsonData), }, } configmaps := kc.ConfigMaps(ns) _, err = configmaps.Get(name) if err == nil { err = configmaps.Delete(name) if err != nil { util.Errorf("Could not delete configmap %s due to: %v\n", name, err) } } _, err = configmaps.Create(&configmap) if err != nil { util.Fatalf("Failed to create configmap %v", err) return err } } else { // lets install the OpenShift templates _, err = templates.Get(name) if err == nil { err = templates.Delete(name) if err != nil { util.Errorf("Could not delete template %s due to: %v\n", name, err) } } _, err = templates.Create(&tmpl) if err != nil { util.Fatalf("Failed to create template %v", err) return err } } } return nil }
func createTemplate(jsonData []byte, templateName string, ns string, domain string, apiserver string, c *k8sclient.Client) { var v1tmpl tapiv1.Template err := json.Unmarshal(jsonData, &v1tmpl) if err != nil { util.Fatalf("Cannot get %s template to deploy. error: %v\ntemplate: %s", templateName, err, string(jsonData)) } var tmpl tapi.Template err = api.Scheme.Convert(&v1tmpl, &tmpl) if err != nil { util.Fatalf("Cannot convert %s template to deploy: %v", templateName, 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: domain, }, tapi.Parameter{ Name: "APISERVER", Value: apiserver, }) p.Process(&tmpl) objectCount := len(tmpl.Objects) if objectCount == 0 { // can't be a template so lets try just process it directly var v1List v1.List err = json.Unmarshal(jsonData, &v1List) if err != nil { util.Fatalf("Cannot unmarshal List %s to deploy. error: %v\ntemplate: %s", templateName, err, string(jsonData)) } if len(v1List.Items) == 0 { // lets check if its an RC / ReplicaSet or something _, groupVersionKind, err := api.Codecs.UniversalDeserializer().Decode(jsonData, nil, nil) if err != nil { printResult(templateName, Failure, err) } else { kind := groupVersionKind.Kind util.Infof("Processing resource of kind: %s version: %s\n", kind, groupVersionKind.Version) if len(kind) <= 0 { printResult(templateName, Failure, fmt.Errorf("Could not find kind from json %s", string(jsonData))) } else { processResource(c, jsonData, ns, kind) } } } else { var kubeList api.List err = api.Scheme.Convert(&v1List, &kubeList) if err != nil { util.Fatalf("Cannot convert %s List to deploy: %v", templateName, err) } util.Infof("Converted json to list with %d items with json %s\n", len(kubeList.Items), string(jsonData)) util.Infof("Creating "+templateName+" list resources from %d objects\n", len(kubeList.Items)) for _, o := range kubeList.Items { err = processItem(c, &o, ns) } } } else { util.Infof("Creating "+templateName+" template resources from %d objects\n", objectCount) for _, o := range tmpl.Objects { err = processItem(c, &o, ns) } } if err != nil { printResult(templateName, Failure, err) } else { printResult(templateName, Success, nil) } }