From ef571a9b1bb5a53cd0d866f7b054664cafe3196b Mon Sep 17 00:00:00 2001 From: Stefan Prodan Date: Fri, 26 Oct 2018 12:09:21 +0300 Subject: [PATCH] Add initialize podinfo code repo command --- cmd/podcli/code.go | 283 ++++++++++++++++++ .../chartmuseum-virtual-service.yaml | 32 ++ 2 files changed, 315 insertions(+) create mode 100644 cmd/podcli/code.go create mode 100644 deploy/istio-system/chartmuseum-virtual-service.yaml diff --git a/cmd/podcli/code.go b/cmd/podcli/code.go new file mode 100644 index 0000000..b4c05f8 --- /dev/null +++ b/cmd/podcli/code.go @@ -0,0 +1,283 @@ +package main + +import ( + "fmt" + "io" + "io/ioutil" + "log" + "os" + "path" + "path/filepath" + "regexp" + "strings" + + "github.com/hashicorp/go-getter" + "github.com/spf13/cobra" +) + +var ( + codeProjectName string + codeGitUser string + codeVersion string + codeProjectPath string +) + +var codeCmd = &cobra.Command{ + Use: `code`, + Short: "Code commands", +} + +var codeInitCmd = &cobra.Command{ + Use: `init [name]`, + Short: "initialize podinfo code repo", + Example: ` code init demo-app --version=v1.2.0 --git-user=stefanprodan`, + RunE: runCodeInit, +} + +func init() { + codeInitCmd.Flags().StringVar(&codeGitUser, "git-user", "", "GitHub user or org") + codeInitCmd.Flags().StringVar(&codeVersion, "version", "master", "podinfo repo tag or branch name") + codeInitCmd.Flags().StringVar(&codeProjectPath, "path", ".", "destination repo") + + codeCmd.AddCommand(codeInitCmd) + + rootCmd.AddCommand(codeCmd) +} + +func runCodeInit(cmd *cobra.Command, args []string) error { + if len(codeGitUser) < 0 { + return fmt.Errorf("--git-user is required") + } + if len(args) < 1 { + return fmt.Errorf("project name is required") + } + + codeProjectName = args[0] + + pwd, err := os.Getwd() + if err != nil { + log.Fatalf("Error getting pwd: %s", err) + os.Exit(1) + } + + tmpPath := "/tmp/k8s-podinfo" + versionName := fmt.Sprintf("k8s-podinfo-%s", codeVersion) + + downloadURL := fmt.Sprintf("https://github.com/stefanprodan/k8s-podinfo/archive/%s.zip", codeVersion) + client := &getter.Client{ + Src: downloadURL, + Dst: tmpPath, + Pwd: pwd, + Mode: getter.ClientModeAny, + } + + fmt.Printf("Downloading %s\n", downloadURL) + + if err := client.Get(); err != nil { + log.Fatalf("Error downloading: %s", err) + os.Exit(1) + } + + pkgFrom := "github.com/stefanprodan/k8s-podinfo" + pkgTo := fmt.Sprintf("github.com/%s/%s", codeGitUser, codeProjectName) + + if err := replaceImports(tmpPath, pkgFrom, pkgTo); err != nil { + log.Fatalf("Error parsing imports: %s", err) + os.Exit(1) + } + + dirs := []string{"pkg", "cmd", "ui", "vendor", "charts/podinfo", ".github"} + for _, dir := range dirs { + + err = os.MkdirAll(path.Join(codeProjectPath, dir), os.ModePerm) + if err != nil { + log.Fatalf("Error: %s", err) + os.Exit(1) + } + if err := copyDir(path.Join(tmpPath, versionName, dir), path.Join(codeProjectPath, dir)); err != nil { + log.Fatalf("Error: %s", err) + os.Exit(1) + } + } + + files := []string{"Gopkg.toml", "Gopkg.lock", "Dockerfile.ci"} + for _, file := range files { + + if err := copyFile(path.Join(tmpPath, versionName, file), path.Join(codeProjectPath, file)); err != nil { + log.Fatalf("Error: %s", err) + os.Exit(1) + } + + fileContent, err := ioutil.ReadFile(path.Join(codeProjectPath, file)) + if err != nil { + log.Fatalf("Error: %s", err) + os.Exit(1) + } + + newContent := strings.Replace(string(fileContent), pkgFrom, pkgTo, -1) + err = ioutil.WriteFile(path.Join(codeProjectPath, file), []byte(newContent), os.ModePerm) + if err != nil { + log.Fatalf("Error: %s", err) + os.Exit(1) + } + } + + fmt.Printf("Done %s\n", codeProjectPath) + + return nil +} + +func replaceImports(projectPath string, pkgFrom string, pkgTo string) error { + regexImport, err := regexp.Compile(`(?s)(import(.*?)\)|import.*$)`) + if err != nil { + return err + } + + regexImportedPackage, err := regexp.Compile(`"(.*?)"`) + if err != nil { + return err + } + + found := []string{} + + err = filepath.Walk(projectPath, func(path string, info os.FileInfo, err error) error { + if filepath.Ext(path) == ".go" { + bts, err := ioutil.ReadFile(path) + if err != nil { + return err + } + + content := string(bts) + matches := regexImport.FindAllString(content, -1) + isExists := false + + isReplacable: + for _, each := range matches { + for _, eachLine := range strings.Split(each, "\n") { + matchesInline := regexImportedPackage.FindAllString(eachLine, -1) + if err != nil { + return err + } + + for _, eachSubline := range matchesInline { + if strings.Contains(eachSubline, pkgFrom) { + isExists = true + break isReplacable + } + } + } + } + + if isExists { + content = strings.Replace(content, `"`+pkgFrom+`"`, `"`+pkgTo+`"`, -1) + content = strings.Replace(content, `"`+pkgFrom+`/`, `"`+pkgTo+`/`, -1) + found = append(found, path) + } + + err = ioutil.WriteFile(path, []byte(content), info.Mode()) + if err != nil { + return err + } + } + + return nil + }) + + if err != nil { + fmt.Println("ERROR", err.Error()) + } + + //for _, path := range found { + // fmt.Printf("found in %s\n", path) + //} + + if len(found) == 0 { + fmt.Println("Nothing replaced") + } else { + fmt.Printf("Go imports total %d file replaced\n", len(found)) + } + + return nil +} + +func copyDir(src string, dst string) error { + si, err := os.Stat(src) + if err != nil { + return err + } + if !si.IsDir() { + return fmt.Errorf("source is not a directory") + } + + err = os.MkdirAll(dst, si.Mode()) + if err != nil { + return err + } + + entries, err := ioutil.ReadDir(src) + if err != nil { + return err + } + + for _, entry := range entries { + srcPath := filepath.Join(src, entry.Name()) + dstPath := filepath.Join(dst, entry.Name()) + + if entry.IsDir() { + err = copyDir(srcPath, dstPath) + if err != nil { + return err + } + } else { + // Skip symlinks. + if entry.Mode()&os.ModeSymlink != 0 { + continue + } + + err = copyFile(srcPath, dstPath) + if err != nil { + return err + } + } + } + return nil +} + +func copyFile(src, dst string) (err error) { + in, err := os.Open(src) + if err != nil { + return + } + defer in.Close() + + out, err := os.Create(dst) + if err != nil { + return + } + defer func() { + if e := out.Close(); e != nil { + err = e + } + }() + + _, err = io.Copy(out, in) + if err != nil { + return + } + + err = out.Sync() + if err != nil { + return + } + + si, err := os.Stat(src) + if err != nil { + return + } + err = os.Chmod(dst, si.Mode()) + if err != nil { + return + } + + return +} diff --git a/deploy/istio-system/chartmuseum-virtual-service.yaml b/deploy/istio-system/chartmuseum-virtual-service.yaml new file mode 100644 index 0000000..ff16b49 --- /dev/null +++ b/deploy/istio-system/chartmuseum-virtual-service.yaml @@ -0,0 +1,32 @@ +--- +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: grafana + namespace: adm +spec: + hosts: + - "helm.iowa.weavedx.com" + gateways: + - public-gateway.istio-system.svc.cluster.local + http: + - route: + - destination: + host: chartmuseum-chartmuseum + timeout: 30s +--- +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: kubeapps + namespace: adm +spec: + hosts: + - "kubeapps.iowa.weavedx.com" + gateways: + - public-gateway.istio-system.svc.cluster.local + http: + - route: + - destination: + host: kubeapps + timeout: 30s