diff --git a/cmd/gomu/cmd/cli/new/new.go b/cmd/gomu/cmd/cli/new/new.go index 1e569e84..ac0db61e 100644 --- a/cmd/gomu/cmd/cli/new/new.go +++ b/cmd/gomu/cmd/cli/new/new.go @@ -37,6 +37,102 @@ type file struct { Tmpl string } +// NewCommand returns a new new cli command. +func NewCommand() *cli.Command { + return &cli.Command{ + Name: "new", + Usage: "Create a project template", + Subcommands: []*cli.Command{ + { + Name: "function", + Usage: "Create a function template, e.g. " + cmd.App().Name + " new function greeter", + Action: Function, + Flags: flags, + }, + { + Name: "service", + Usage: "Create a service template, e.g. " + cmd.App().Name + " new service greeter", + Action: Service, + Flags: flags, + }, + }, + } +} + +// Function creates a new function project template. Exits on error. +func Function(ctx *cli.Context) error { + return createProject(ctx, true) +} + +// Service creates a new service project template. Exits on error. +func Service(ctx *cli.Context) error { + return createProject(ctx, false) +} + +func createProject(ctx *cli.Context, fn bool) error { + name := ctx.Args().First() + if len(name) == 0 { + return cli.ShowSubcommandHelp(ctx) + } + + if path.IsAbs(name) { + fmt.Println("must provide a relative path as service name") + return nil + } + + if _, err := os.Stat(name); !os.IsNotExist(err) { + return fmt.Errorf("%s already exists", name) + } + + if fn { + fmt.Printf("creating function %s\n", name) + } else { + fmt.Printf("creating service %s\n", name) + } + + files := []file{ + {".dockerignore", tmpl.DockerIgnore}, + {".gitignore", tmpl.GitIgnore}, + {"Dockerfile", tmpl.Dockerfile}, + {"Makefile", tmpl.Makefile}, + {"go.mod", tmpl.Module}, + } + if fn { + files = append(files, []file{ + {"handler/" + name + ".go", tmpl.HandlerFNC}, + {"main.go", tmpl.MainFNC}, + {"proto/" + name + ".proto", tmpl.ProtoFNC}, + }...) + } else { + files = append(files, []file{ + {"handler/" + name + ".go", tmpl.HandlerSRV}, + {"main.go", tmpl.MainSRV}, + {"proto/" + name + ".proto", tmpl.ProtoSRV}, + }...) + } + + if ctx.Bool("skaffold") { + files = append(files, []file{ + {"plugins.go", tmpl.Plugins}, + {"resources/clusterrole.yaml", tmpl.KubernetesClusterRole}, + {"resources/configmap.yaml", tmpl.KubernetesEnv}, + {"resources/deployment.yaml", tmpl.KubernetesDeployment}, + {"resources/rolebinding.yaml", tmpl.KubernetesRoleBinding}, + {"skaffold.yaml", tmpl.SkaffoldCFG}, + }...) + } + + c := config{ + Alias: name, + Comments: protoComments(name), + Dir: name, + Jaeger: ctx.Bool("jaeger"), + Skaffold: ctx.Bool("skaffold"), + } + + return create(files, c) +} + func protoComments(alias string) []string { return []string{ "\ndownload protoc zip packages (protoc-$VERSION-$PLATFORM.zip) and install:\n", @@ -93,115 +189,3 @@ func create(files []file, c config) error { return nil } - -// NewCommand returns a new new cli command. -func NewCommand() *cli.Command { - return &cli.Command{ - Name: "new", - Usage: "Create a project template", - Subcommands: []*cli.Command{ - { - Name: "function", - Usage: "Create a function template, e.g. " + cmd.App().Name + " new function greeter", - Action: Function, - Flags: flags, - }, - { - Name: "service", - Usage: "Create a service template, e.g. " + cmd.App().Name + " new service greeter", - Action: Service, - Flags: flags, - }, - }, - } -} - -// Function creates a new function project template. Exits on error. -func Function(ctx *cli.Context) error { - function := ctx.Args().First() - if len(function) == 0 { - return cli.ShowSubcommandHelp(ctx) - } - - if path.IsAbs(function) { - fmt.Println("must provide a relative path as function name") - return nil - } - - if _, err := os.Stat(function); !os.IsNotExist(err) { - return fmt.Errorf("%s already exists", function) - } - - fmt.Printf("creating function %s\n", function) - - files := []file{ - {".gitignore", tmpl.GitIgnore}, - {"Dockerfile", tmpl.Dockerfile}, - {"Makefile", tmpl.Makefile}, - {"go.mod", tmpl.Module}, - {"handler/" + function + ".go", tmpl.HandlerFNC}, - {"main.go", tmpl.MainFNC}, - {"proto/" + function + ".proto", tmpl.ProtoFNC}, - } - if ctx.Bool("skaffold") { - files = append(files, []file{ - {"skaffold.yaml", tmpl.SkaffoldCFG}, - {"resources/deployment.yaml", tmpl.SkaffoldDEP}, - }...) - } - - c := config{ - Alias: function, - Comments: protoComments(function), - Dir: function, - Jaeger: ctx.Bool("jaeger"), - } - - return create(files, c) -} - -// Service creates a new service project template. Exits on error. -func Service(ctx *cli.Context) error { - service := ctx.Args().First() - if len(service) == 0 { - return cli.ShowSubcommandHelp(ctx) - } - - if path.IsAbs(service) { - fmt.Println("must provide a relative path as service name") - return nil - } - - if _, err := os.Stat(service); !os.IsNotExist(err) { - return fmt.Errorf("%s already exists", service) - } - - fmt.Printf("creating service %s\n", service) - - files := []file{ - {".dockerignore", tmpl.DockerIgnore}, - {".gitignore", tmpl.GitIgnore}, - {"Dockerfile", tmpl.Dockerfile}, - {"Makefile", tmpl.Makefile}, - {"go.mod", tmpl.Module}, - {"handler/" + service + ".go", tmpl.HandlerSRV}, - {"main.go", tmpl.MainSRV}, - {"proto/" + service + ".proto", tmpl.ProtoSRV}, - } - if ctx.Bool("skaffold") { - files = append(files, []file{ - {"skaffold.yaml", tmpl.SkaffoldCFG}, - {"resources/deployment.yaml", tmpl.SkaffoldDEP}, - }...) - } - - c := config{ - Alias: service, - Comments: protoComments(service), - Dir: service, - Jaeger: ctx.Bool("jaeger"), - Skaffold: ctx.Bool("skaffold"), - } - - return create(files, c) -} diff --git a/cmd/gomu/cmd/cli/new/template/kubernetes.go b/cmd/gomu/cmd/cli/new/template/kubernetes.go new file mode 100644 index 00000000..aabcf171 --- /dev/null +++ b/cmd/gomu/cmd/cli/new/template/kubernetes.go @@ -0,0 +1,78 @@ +package template + +// KubernetesEnv is a Kubernetes configmap manifest template used for +// environment variables in new projects. +var KubernetesEnv = `--- + +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{.Alias}}-env +data: + MICRO_REGISTRY: kubernetes +` + +// KubernetesClusterRole is a Kubernetes cluster role manifest template +// required for the Kubernetes registry plugin to function correctly. +var KubernetesClusterRole = `--- + +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: micro-registry +rules: +- apiGroups: + - "" + resources: + - pods + verbs: + - list + - patch + - watch +` + +// KubernetesRoleBinding is a Kubernetes role binding manifest template +// required for the Kubernetes registry plugin to function correctly. +var KubernetesRoleBinding = `--- + +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: micro-registry +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: micro-registry +subjects: +- kind: ServiceAccount + name: default + namespace: default +` + +// KubernetesDeployment is a Kubernetes deployment manifest template used for +// new projects. +var KubernetesDeployment = `--- + +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{.Alias}} + labels: + app: {{.Alias}} +spec: + replicas: 1 + selector: + matchLabels: + app: {{.Alias}} + template: + metadata: + labels: + app: {{.Alias}} + spec: + containers: + - name: {{.Alias}} + image: {{.Alias}}:latest + envFrom: + - configMapRef: + name: {{.Alias}}-env +` diff --git a/cmd/gomu/cmd/cli/new/template/plugins.go b/cmd/gomu/cmd/cli/new/template/plugins.go new file mode 100644 index 00000000..40309405 --- /dev/null +++ b/cmd/gomu/cmd/cli/new/template/plugins.go @@ -0,0 +1,9 @@ +package template + +// Plugins is the plugins template used for new projects. +var Plugins = `package main + +import ( + _ "github.com/asim/go-micro/plugins/registry/kubernetes/v3" +) +` diff --git a/cmd/gomu/cmd/cli/new/template/skaffold.go b/cmd/gomu/cmd/cli/new/template/skaffold.go index 8efe9558..ffa257d5 100644 --- a/cmd/gomu/cmd/cli/new/template/skaffold.go +++ b/cmd/gomu/cmd/cli/new/template/skaffold.go @@ -15,28 +15,3 @@ deploy: manifests: - resources/*.yaml ` - -// SkaffoldDEP is the Kubernetes deployment manifest template used for new -// projects. -var SkaffoldDEP = `--- - -apiVersion: apps/v1 -kind: Deployment -metadata: - name: {{.Alias}} - labels: - app: {{.Alias}} -spec: - replicas: 1 - selector: - matchLabels: - app: {{.Alias}} - template: - metadata: - labels: - app: {{.Alias}} - spec: - containers: - - name: {{.Alias}} - image: {{.Alias}}:latest -`