From 599d2cfde3054fe0a08fdc35e5a0df934cecda52 Mon Sep 17 00:00:00 2001 From: Christine Dodrill Date: Fri, 27 Jan 2017 01:52:24 -0800 Subject: do more work on svc --- svc/cmd/svc/main.go | 214 +++++++++++ svc/cmd/svcd/dockerswarm-svcd/.gitignore | 3 + svc/cmd/svcd/dockerswarm-svcd/main.go | 253 +++++++++++++ svc/credentials/jwt/jwt.go | 24 ++ svc/proto/regen.sh | 19 + svc/proto/svc.pb.go | 598 +++++++++++++++++++++++++++++++ svc/proto/svc.pb.gw.go | 348 ++++++++++++++++++ svc/proto/svc.proto | 92 +++++ svc/proto/svc.swagger.json | 309 ++++++++++++++++ 9 files changed, 1860 insertions(+) create mode 100644 svc/cmd/svc/main.go create mode 100644 svc/cmd/svcd/dockerswarm-svcd/.gitignore create mode 100644 svc/cmd/svcd/dockerswarm-svcd/main.go create mode 100644 svc/credentials/jwt/jwt.go create mode 100755 svc/proto/regen.sh create mode 100644 svc/proto/svc.pb.go create mode 100644 svc/proto/svc.pb.gw.go create mode 100644 svc/proto/svc.proto create mode 100644 svc/proto/svc.swagger.json diff --git a/svc/cmd/svc/main.go b/svc/cmd/svc/main.go new file mode 100644 index 0000000..3a7b30d --- /dev/null +++ b/svc/cmd/svc/main.go @@ -0,0 +1,214 @@ +package main + +import ( + "context" + "encoding/json" + "fmt" + "log" + "os" + "path/filepath" + "time" + + "github.com/Bowery/prompt" + jwtcreds "github.com/Xe/tools/svc/credentials/jwt" + svc "github.com/Xe/tools/svc/proto" + "github.com/Xe/uuid" + jwt "github.com/dgrijalva/jwt-go" + "github.com/olekukonko/tablewriter" + "google.golang.org/grpc" + kingpin "gopkg.in/alecthomas/kingpin.v1" +) + +var ( + app = kingpin.New("svc", "A simple service manager") + debug = app.Flag("debug", "print debugging logs?").Bool() + host = app.Flag("host", "host to do these changes to").String() + dataDir = app.Flag("data-dir", "place for svc to store data").Default("/home/xena/.local/within/svc").String() + + createToken = app.Command("create-token", "Creates the initial server control token") + createTokenJwtSecret = createToken.Flag("jwt-secret", "jwt secret used on the server").Required().String() + createTokenUsername = createToken.Arg("username", "username to create token for").Required().String() + + list = app.Command("list", "List apps running with this backend") + listLabelKey = list.Flag("labelKey", "label key to match for").String() + listLabelValue = list.Flag("labelValue", "label value to match for (with labelKey)").String() + + create = app.Command("create", "Create a new application") + createName = create.Flag("name", "name of the application").Required().String() + createEnvFile = create.Flag("env-file", "file with key->value envvars").String() + createEnvironment = create.Flag("env", "environment variables for the program").StringMap() + createLabels = create.Flag("label", "additional labels to attach to the service").StringMap() + createAuthorizedUsers = create.Flag("authorized-user", "additional user to allow modification access to").Strings() + createExclusive = create.Flag("exclusive", "can this only ever have one copy running at once?").Bool() + createInstances = create.Flag("instances", "number of instances of the backend service").Default("1").Int() + createDockerImage = create.Arg("docker image", "docker image to execute for this service").Required().String() + + update = app.Command("update", "Update an application") + updateImage = update.Flag("image", "new docker image to use for this service").String() + updateEnvAdd = update.Flag("env-add", "new environment variables to set").StringMap() + updateEnvRm = update.Flag("env-rm", "environment variables to remove").StringMap() + updateLabelAdd = update.Flag("label-add", "container labels to addB").StringMap() + updateLabelRm = update.Flag("label-rm", "container labels to remove").StringMap() + updateGrantUsers = update.Flag("grant-user", "grant a user permission to this service").Strings() + updateRevokeUsers = update.Flag("revoke-user", "revoke a user's permission to this service").Strings() + updateInstanceCount = update.Flag("instances", "updates the instance count of the service").Int() + + inspect = app.Command("inspect", "Inspect an application") + inspectName = inspect.Arg("name", "name of the service").String() + + deleteCmd = app.Command("delete", "Deletes an application by name") + deleteName = deleteCmd.Arg("name", "name of the service").String() + + hostCmd = app.Command("host", "Host management") + hostAdd = hostCmd.Command("add", "Add a host to the state file") + hostAddTor = hostAdd.Flag("tor", "connect to this over tor?").Bool() + hostAddName = hostAdd.Arg("name", "name of host to add").Required().String() + hostAddAddr = hostAdd.Arg("addr", "address of taget server (host:port)").Required().String() + hostRemove = hostCmd.Command("remove", "Remove a host from the state file") + hostRemoveName = hostRemove.Arg("name", "name of host to remove").Required().String() +) + +func main() { + cmdline := kingpin.MustParse(app.Parse(os.Args[1:])) + + state, err := readState() + if err != nil { + if os.IsNotExist(err) { + log.Println("Host file does not exist, please add a host with `svc host add`.") + } + + log.Fatal(err) + } + writeState(state) + + switch cmdline { + case "host add": + token, err := prompt.Basic("token: ", true) + if err != nil { + log.Fatal(err) + } + + h := &Host{ + Name: *hostAddName, + Addr: *hostAddAddr, + Token: token, + Tor: *hostAddTor, + } + + state.Hosts[h.Name] = h + writeState(state) + + log.Println("Host added to hosts file.") + return + case "host remove": + log.Println("removing host not yet implemented") + os.Exit(1) + case "create-token": + now := time.Now() + nva := now.AddDate(0, 1, 0) // Expiry time of this token + nb4 := now.AddDate(0, 0, -1) // Not before then is this token valid + + hostname, _ := os.Hostname() + tid := uuid.New() + + token := jwt.NewWithClaims(jwt.SigningMethodHS512, &jwt.StandardClaims{ + IssuedAt: now.Unix(), + NotBefore: nb4.Unix(), + ExpiresAt: nva.Unix(), + Issuer: hostname, + Subject: *createTokenUsername, + Id: tid, + }) + + tokenString, err := token.SignedString([]byte(*createTokenJwtSecret)) + if err != nil { + log.Fatal(err) + } + + fmt.Println(tokenString) + + os.Exit(0) + } + + if *host == "" { + log.Fatal("--host must be supplied") + } + + hostInfo, ok := state.Hosts[*host] + if !ok { + log.Fatalf("Requested host %q that doesn't exist in state", *host) + } + + creds := jwtcreds.NewFromToken(hostInfo.Token) + conn, err := grpc.Dial(hostInfo.Addr, grpc.WithInsecure(), + grpc.WithPerRPCCredentials(creds)) + if err != nil { + log.Fatal(err) + } + + c := svc.NewAppsClient(conn) + + // RPC commands + switch cmdline { + case list.FullCommand(): + apps, err := c.List(context.Background(), &svc.AppsListParams{}) + if err != nil { + log.Fatal(err) + } + + table := tablewriter.NewWriter(os.Stdout) + + table.SetHeader([]string{"ID", "Name", "Image", "Users"}) + + for _, app := range apps.Apps { + table.Append([]string{app.Id, app.Name, app.DockerImage, fmt.Sprintf("%v", app.AuthorizedUsers)}) + } + table.Render() + + case create.FullCommand(): + log.Println("create not implemented") + case update.FullCommand(): + log.Println("update not implemented") + case inspect.FullCommand(): + log.Println("inspect not implemented") + case deleteCmd.FullCommand(): + log.Println("delete not implemented") + } +} + +type state struct { + Hosts map[string]*Host +} + +type Host struct { + Name string + Addr string + Token string + Tor bool +} + +func readState() (*state, error) { + s := &state{} + + fname := filepath.Join(*dataDir, "state.json") + fin, err := os.Open(fname) + if err != nil { + return nil, err + } + defer fin.Close() + + err = json.NewDecoder(fin).Decode(s) + + return s, err +} + +func writeState(s *state) error { + fname := filepath.Join(*dataDir, "state.json") + fout, err := os.Create(fname) + if err != nil { + return err + } + defer fout.Close() + + return json.NewEncoder(fout).Encode(s) +} diff --git a/svc/cmd/svcd/dockerswarm-svcd/.gitignore b/svc/cmd/svcd/dockerswarm-svcd/.gitignore new file mode 100644 index 0000000..39305f0 --- /dev/null +++ b/svc/cmd/svcd/dockerswarm-svcd/.gitignore @@ -0,0 +1,3 @@ +state.json +dockerswarm-svcd +*.pem diff --git a/svc/cmd/svcd/dockerswarm-svcd/main.go b/svc/cmd/svcd/dockerswarm-svcd/main.go new file mode 100644 index 0000000..724e7c9 --- /dev/null +++ b/svc/cmd/svcd/dockerswarm-svcd/main.go @@ -0,0 +1,253 @@ +package main + +import ( + "encoding/json" + "errors" + "flag" + "fmt" + "log" + "net" + "os" + "strings" + "sync" + + svc "github.com/Xe/tools/svc/proto" + jwt "github.com/dgrijalva/jwt-go" + "github.com/docker/docker/api/types" + "github.com/docker/docker/api/types/swarm" + "github.com/docker/docker/client" + "github.com/facebookgo/flagenv" + _ "github.com/joho/godotenv/autoload" + "golang.org/x/net/context" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" +) + +var ( + listenAddress = flag.String("listen", "127.0.0.1:23142", "tcp host:port to listen on") + sslCert = flag.String("tls-cert", "cert.pem", "tls certificate to read from") + sslKey = flag.String("tls-key", "key.pem", "tls private key") + jwtSecret = flag.String("jwt-secret", "hunter2", "secret used to sign jwt's") +) + +const admin = "xena" + +type server struct { + docker *client.Client + + sync.Mutex + state map[string][]string +} + +func (s *server) LoadState(fname string) error { + s.Lock() + defer s.Unlock() + + fin, err := os.Open(fname) + if err != nil { + return err + } + defer fin.Close() + + return json.NewDecoder(fin).Decode(&s.state) +} + +func (s *server) SaveState(fname string) error { + s.Lock() + defer s.Unlock() + + fout, err := os.Create(fname) + if err != nil { + return err + } + defer fout.Close() + + return json.NewEncoder(fout).Encode(&s.state) +} + +func (s *server) List(ctx context.Context, params *svc.AppsListParams) (*svc.AppsList, error) { + user, err := s.checkAuth(ctx) + if err != nil { + return nil, err + } + + svcs, err := s.docker.ServiceList(ctx, types.ServiceListOptions{}) + if err != nil { + return nil, err + } + + result := &svc.AppsList{} + + for _, ssvc := range svcs { + env := func(kv []string) map[string]string { + result := map[string]string{} + + for _, pair := range kv { + split := strings.SplitN(pair, "=", 2) + result[split[0]] = split[1] + } + + return result + }(ssvc.Spec.TaskTemplate.ContainerSpec.Env) + + au := s.state[ssvc.Spec.Name] + if au == nil { + s.state[ssvc.Spec.Name] = []string{admin} + s.SaveState("state.json") + } + + allowed := false + + if user == admin { + allowed = true + } + + for _, allowedUser := range au { + if user == allowedUser { + allowed = true + } + } + + if !allowed { + continue + } + + result.Apps = append(result.Apps, &svc.App{ + Id: ssvc.ID, + Name: ssvc.Spec.Name, + DockerImage: ssvc.Spec.TaskTemplate.ContainerSpec.Image, + Environment: env, + Labels: ssvc.Spec.Labels, + AuthorizedUsers: au, + }) + } + + return result, nil +} + +func (s *server) Create(ctx context.Context, manifest *svc.Manifest) (*svc.App, error) { + user, err := s.checkAuth(ctx) + if err != nil { + return nil, err + } + + env := []string{} + + for key, val := range manifest.Environment { + env = append(env, fmt.Sprintf("%s=%s", key, val)) + } + + spec := swarm.ServiceSpec{ + Annotations: swarm.Annotations{ + Name: manifest.Name, + Labels: manifest.Labels, + }, + + TaskTemplate: swarm.TaskSpec{ + ContainerSpec: swarm.ContainerSpec{ + Image: manifest.DockerImage, + Env: env, + }, + }, + + Mode: swarm.ServiceMode{ + Replicated: &swarm.ReplicatedService{}, + }, + } + + resp, err := s.docker.ServiceCreate(ctx, spec, types.ServiceCreateOptions{}) + if err != nil { + return nil, err + } + + ssvc, _, err := s.docker.ServiceInspectWithRaw(ctx, resp.ID) + if err != nil { + return nil, err + } + + app := &svc.App{ + Id: ssvc.ID, + Name: ssvc.Spec.Name, + DockerImage: ssvc.Spec.TaskTemplate.ContainerSpec.Image, + Environment: manifest.Environment, + Labels: ssvc.Spec.Labels, + AuthorizedUsers: []string{user}, + } + + return app, nil +} + +func (s *server) Update(ctx context.Context, params *svc.AppUpdate) (*svc.App, error) { + return nil, errors.New("not implemented") +} + +func (s *server) Inspect(ctx context.Context, params *svc.AppInspect) (*svc.App, error) { + return nil, errors.New("not implemented") +} + +func (s *server) Delete(ctx context.Context, params *svc.AppDelete) (*svc.Ok, error) { + return nil, errors.New("not implemented") +} + +func main() { + flag.Parse() + flagenv.Parse() + + gs := grpc.NewServer() + + defaultHeaders := map[string]string{"User-Agent": "dockerswarm-svcd"} + cli, err := client.NewClient(client.DefaultDockerHost, client.DefaultVersion, nil, defaultHeaders) + if err != nil { + log.Fatal(err) + } + + s := &server{ + docker: cli, + state: map[string][]string{}, + } + + err = s.LoadState("state.json") + if err != nil { + log.Fatal(err) + } + + svc.RegisterAppsServer(gs, s) + + l, err := net.Listen("tcp", *listenAddress) + if err != nil { + log.Fatal(err) + } + + err = gs.Serve(l) + if err != nil { + log.Fatal(err) + } +} + +func (s *server) checkAuth(ctx context.Context) (string, error) { + var err error + + md, ok := metadata.FromContext(ctx) + if !ok { + return "", grpc.Errorf(codes.Unauthenticated, "valid token required.") + } + + jwtToken, ok := md["authorization"] + if !ok { + return "", grpc.Errorf(codes.Unauthenticated, "valid token required.") + } + + clms := &jwt.StandardClaims{} + + p := &jwt.Parser{} + _, err = p.ParseWithClaims(jwtToken[0], clms, jwt.Keyfunc(func(t *jwt.Token) (interface{}, error) { + return []byte(*jwtSecret), nil + })) + if err != nil { + log.Printf("rpc error: %v", err) + return "", grpc.Errorf(codes.Unauthenticated, "valid token requried.") + } + + return clms.Subject, nil +} diff --git a/svc/credentials/jwt/jwt.go b/svc/credentials/jwt/jwt.go new file mode 100644 index 0000000..978c880 --- /dev/null +++ b/svc/credentials/jwt/jwt.go @@ -0,0 +1,24 @@ +package jwt + +import ( + "golang.org/x/net/context" + "google.golang.org/grpc/credentials" +) + +type jwt struct { + token string +} + +func NewFromToken(token string) credentials.PerRPCCredentials { + return jwt{token: token} +} + +func (j jwt) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) { + return map[string]string{ + "authorization": j.token, + }, nil +} + +func (j jwt) RequireTransportSecurity() bool { + return false +} diff --git a/svc/proto/regen.sh b/svc/proto/regen.sh new file mode 100755 index 0000000..cb20e86 --- /dev/null +++ b/svc/proto/regen.sh @@ -0,0 +1,19 @@ +#!/bin/bash + +protoc -I/usr/local/include -I. \ + -I$GOPATH/src \ + -I$GOPATH/src/github.com/grpc-ecosystem/grpc-gateway/third_party/googleapis \ + --go_out=Mgoogle/api/annotations.proto=github.com/grpc-ecosystem/grpc-gateway/third_party/googleapis/google/api,plugins=grpc:. \ + svc.proto + +protoc -I/usr/local/include -I. \ + -I$GOPATH/src \ + -I$GOPATH/src/github.com/grpc-ecosystem/grpc-gateway/third_party/googleapis \ + --grpc-gateway_out=logtostderr=true:. \ + svc.proto + +protoc -I/usr/local/include -I. \ + -I$GOPATH/src \ + -I$GOPATH/src/github.com/grpc-ecosystem/grpc-gateway/third_party/googleapis \ + --swagger_out=logtostderr=true:. \ + svc.proto diff --git a/svc/proto/svc.pb.go b/svc/proto/svc.pb.go new file mode 100644 index 0000000..445c1ba --- /dev/null +++ b/svc/proto/svc.pb.go @@ -0,0 +1,598 @@ +// Code generated by protoc-gen-go. +// source: svc.proto +// DO NOT EDIT! + +/* +Package svc is a generated protocol buffer package. + +It is generated from these files: + svc.proto + +It has these top-level messages: + AppsListParams + AppsList + Manifest + App + AppUpdate + AppInspect + AppDelete + Ok +*/ +package svc + +import proto "github.com/golang/protobuf/proto" +import fmt "fmt" +import math "math" +import _ "github.com/grpc-ecosystem/grpc-gateway/third_party/googleapis/google/api" + +import ( + context "golang.org/x/net/context" + grpc "google.golang.org/grpc" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package + +type AppsListParams struct { + LabelKey string `protobuf:"bytes,1,opt,name=labelKey" json:"labelKey,omitempty"` + LabelVal string `protobuf:"bytes,2,opt,name=labelVal" json:"labelVal,omitempty"` + // will be matched to app names + Name string `protobuf:"bytes,3,opt,name=name" json:"name,omitempty"` +} + +func (m *AppsListParams) Reset() { *m = AppsListParams{} } +func (m *AppsListParams) String() string { return proto.CompactTextString(m) } +func (*AppsListParams) ProtoMessage() {} +func (*AppsListParams) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } + +func (m *AppsListParams) GetLabelKey() string { + if m != nil { + return m.LabelKey + } + return "" +} + +func (m *AppsListParams) GetLabelVal() string { + if m != nil { + return m.LabelVal + } + return "" +} + +func (m *AppsListParams) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +type AppsList struct { + Message string `protobuf:"bytes,1,opt,name=message" json:"message,omitempty"` + Apps []*App `protobuf:"bytes,2,rep,name=apps" json:"apps,omitempty"` +} + +func (m *AppsList) Reset() { *m = AppsList{} } +func (m *AppsList) String() string { return proto.CompactTextString(m) } +func (*AppsList) ProtoMessage() {} +func (*AppsList) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} } + +func (m *AppsList) GetMessage() string { + if m != nil { + return m.Message + } + return "" +} + +func (m *AppsList) GetApps() []*App { + if m != nil { + return m.Apps + } + return nil +} + +type Manifest struct { + Environment map[string]string `protobuf:"bytes,1,rep,name=environment" json:"environment,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` + Labels map[string]string `protobuf:"bytes,2,rep,name=labels" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` + DockerImage string `protobuf:"bytes,3,opt,name=dockerImage" json:"dockerImage,omitempty"` + Name string `protobuf:"bytes,4,opt,name=name" json:"name,omitempty"` +} + +func (m *Manifest) Reset() { *m = Manifest{} } +func (m *Manifest) String() string { return proto.CompactTextString(m) } +func (*Manifest) ProtoMessage() {} +func (*Manifest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} } + +func (m *Manifest) GetEnvironment() map[string]string { + if m != nil { + return m.Environment + } + return nil +} + +func (m *Manifest) GetLabels() map[string]string { + if m != nil { + return m.Labels + } + return nil +} + +func (m *Manifest) GetDockerImage() string { + if m != nil { + return m.DockerImage + } + return "" +} + +func (m *Manifest) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +type App struct { + Id string `protobuf:"bytes,1,opt,name=id" json:"id,omitempty"` + Name string `protobuf:"bytes,2,opt,name=name" json:"name,omitempty"` + DockerImage string `protobuf:"bytes,3,opt,name=dockerImage" json:"dockerImage,omitempty"` + Environment map[string]string `protobuf:"bytes,4,rep,name=environment" json:"environment,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` + Labels map[string]string `protobuf:"bytes,5,rep,name=labels" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` + AuthorizedUsers []string `protobuf:"bytes,6,rep,name=authorizedUsers" json:"authorizedUsers,omitempty"` + Instances int32 `protobuf:"varint,7,opt,name=instances" json:"instances,omitempty"` +} + +func (m *App) Reset() { *m = App{} } +func (m *App) String() string { return proto.CompactTextString(m) } +func (*App) ProtoMessage() {} +func (*App) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{3} } + +func (m *App) GetId() string { + if m != nil { + return m.Id + } + return "" +} + +func (m *App) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +func (m *App) GetDockerImage() string { + if m != nil { + return m.DockerImage + } + return "" +} + +func (m *App) GetEnvironment() map[string]string { + if m != nil { + return m.Environment + } + return nil +} + +func (m *App) GetLabels() map[string]string { + if m != nil { + return m.Labels + } + return nil +} + +func (m *App) GetAuthorizedUsers() []string { + if m != nil { + return m.AuthorizedUsers + } + return nil +} + +func (m *App) GetInstances() int32 { + if m != nil { + return m.Instances + } + return 0 +} + +type AppUpdate struct { + Name string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` + NewImage string `protobuf:"bytes,2,opt,name=newImage" json:"newImage,omitempty"` + EnvAdd map[string]string `protobuf:"bytes,3,rep,name=envAdd" json:"envAdd,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` + EnvRm map[string]string `protobuf:"bytes,4,rep,name=envRm" json:"envRm,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` + LabelAdd map[string]string `protobuf:"bytes,5,rep,name=labelAdd" json:"labelAdd,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` + LabelRm map[string]string `protobuf:"bytes,6,rep,name=labelRm" json:"labelRm,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` + GrantUsers []string `protobuf:"bytes,7,rep,name=grantUsers" json:"grantUsers,omitempty"` + RevokeUsers []string `protobuf:"bytes,8,rep,name=revokeUsers" json:"revokeUsers,omitempty"` + NewInstanceCount int32 `protobuf:"varint,9,opt,name=newInstanceCount" json:"newInstanceCount,omitempty"` +} + +func (m *AppUpdate) Reset() { *m = AppUpdate{} } +func (m *AppUpdate) String() string { return proto.CompactTextString(m) } +func (*AppUpdate) ProtoMessage() {} +func (*AppUpdate) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{4} } + +func (m *AppUpdate) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +func (m *AppUpdate) GetNewImage() string { + if m != nil { + return m.NewImage + } + return "" +} + +func (m *AppUpdate) GetEnvAdd() map[string]string { + if m != nil { + return m.EnvAdd + } + return nil +} + +func (m *AppUpdate) GetEnvRm() map[string]string { + if m != nil { + return m.EnvRm + } + return nil +} + +func (m *AppUpdate) GetLabelAdd() map[string]string { + if m != nil { + return m.LabelAdd + } + return nil +} + +func (m *AppUpdate) GetLabelRm() map[string]string { + if m != nil { + return m.LabelRm + } + return nil +} + +func (m *AppUpdate) GetGrantUsers() []string { + if m != nil { + return m.GrantUsers + } + return nil +} + +func (m *AppUpdate) GetRevokeUsers() []string { + if m != nil { + return m.RevokeUsers + } + return nil +} + +func (m *AppUpdate) GetNewInstanceCount() int32 { + if m != nil { + return m.NewInstanceCount + } + return 0 +} + +type AppInspect struct { + Name string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` +} + +func (m *AppInspect) Reset() { *m = AppInspect{} } +func (m *AppInspect) String() string { return proto.CompactTextString(m) } +func (*AppInspect) ProtoMessage() {} +func (*AppInspect) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{5} } + +func (m *AppInspect) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +type AppDelete struct { + Name string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` +} + +func (m *AppDelete) Reset() { *m = AppDelete{} } +func (m *AppDelete) String() string { return proto.CompactTextString(m) } +func (*AppDelete) ProtoMessage() {} +func (*AppDelete) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{6} } + +func (m *AppDelete) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +type Ok struct { + Message string `protobuf:"bytes,1,opt,name=message" json:"message,omitempty"` +} + +func (m *Ok) Reset() { *m = Ok{} } +func (m *Ok) String() string { return proto.CompactTextString(m) } +func (*Ok) ProtoMessage() {} +func (*Ok) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{7} } + +func (m *Ok) GetMessage() string { + if m != nil { + return m.Message + } + return "" +} + +func init() { + proto.RegisterType((*AppsListParams)(nil), "AppsListParams") + proto.RegisterType((*AppsList)(nil), "AppsList") + proto.RegisterType((*Manifest)(nil), "Manifest") + proto.RegisterType((*App)(nil), "App") + proto.RegisterType((*AppUpdate)(nil), "AppUpdate") + proto.RegisterType((*AppInspect)(nil), "AppInspect") + proto.RegisterType((*AppDelete)(nil), "AppDelete") + proto.RegisterType((*Ok)(nil), "Ok") +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// Client API for Apps service + +type AppsClient interface { + List(ctx context.Context, in *AppsListParams, opts ...grpc.CallOption) (*AppsList, error) + Create(ctx context.Context, in *Manifest, opts ...grpc.CallOption) (*App, error) + Update(ctx context.Context, in *AppUpdate, opts ...grpc.CallOption) (*App, error) + Inspect(ctx context.Context, in *AppInspect, opts ...grpc.CallOption) (*App, error) + Delete(ctx context.Context, in *AppDelete, opts ...grpc.CallOption) (*Ok, error) +} + +type appsClient struct { + cc *grpc.ClientConn +} + +func NewAppsClient(cc *grpc.ClientConn) AppsClient { + return &appsClient{cc} +} + +func (c *appsClient) List(ctx context.Context, in *AppsListParams, opts ...grpc.CallOption) (*AppsList, error) { + out := new(AppsList) + err := grpc.Invoke(ctx, "/Apps/List", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *appsClient) Create(ctx context.Context, in *Manifest, opts ...grpc.CallOption) (*App, error) { + out := new(App) + err := grpc.Invoke(ctx, "/Apps/Create", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *appsClient) Update(ctx context.Context, in *AppUpdate, opts ...grpc.CallOption) (*App, error) { + out := new(App) + err := grpc.Invoke(ctx, "/Apps/Update", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *appsClient) Inspect(ctx context.Context, in *AppInspect, opts ...grpc.CallOption) (*App, error) { + out := new(App) + err := grpc.Invoke(ctx, "/Apps/Inspect", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *appsClient) Delete(ctx context.Context, in *AppDelete, opts ...grpc.CallOption) (*Ok, error) { + out := new(Ok) + err := grpc.Invoke(ctx, "/Apps/Delete", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// Server API for Apps service + +type AppsServer interface { + List(context.Context, *AppsListParams) (*AppsList, error) + Create(context.Context, *Manifest) (*App, error) + Update(context.Context, *AppUpdate) (*App, error) + Inspect(context.Context, *AppInspect) (*App, error) + Delete(context.Context, *AppDelete) (*Ok, error) +} + +func RegisterAppsServer(s *grpc.Server, srv AppsServer) { + s.RegisterService(&_Apps_serviceDesc, srv) +} + +func _Apps_List_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(AppsListParams) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AppsServer).List(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/Apps/List", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AppsServer).List(ctx, req.(*AppsListParams)) + } + return interceptor(ctx, in, info, handler) +} + +func _Apps_Create_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(Manifest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AppsServer).Create(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/Apps/Create", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AppsServer).Create(ctx, req.(*Manifest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Apps_Update_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(AppUpdate) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AppsServer).Update(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/Apps/Update", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AppsServer).Update(ctx, req.(*AppUpdate)) + } + return interceptor(ctx, in, info, handler) +} + +func _Apps_Inspect_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(AppInspect) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AppsServer).Inspect(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/Apps/Inspect", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AppsServer).Inspect(ctx, req.(*AppInspect)) + } + return interceptor(ctx, in, info, handler) +} + +func _Apps_Delete_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(AppDelete) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AppsServer).Delete(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/Apps/Delete", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AppsServer).Delete(ctx, req.(*AppDelete)) + } + return interceptor(ctx, in, info, handler) +} + +var _Apps_serviceDesc = grpc.ServiceDesc{ + ServiceName: "Apps", + HandlerType: (*AppsServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "List", + Handler: _Apps_List_Handler, + }, + { + MethodName: "Create", + Handler: _Apps_Create_Handler, + }, + { + MethodName: "Update", + Handler: _Apps_Update_Handler, + }, + { + MethodName: "Inspect", + Handler: _Apps_Inspect_Handler, + }, + { + MethodName: "Delete", + Handler: _Apps_Delete_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "svc.proto", +} + +func init() { proto.RegisterFile("svc.proto", fileDescriptor0) } + +var fileDescriptor0 = []byte{ + // 728 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xc4, 0x55, 0xcd, 0x6e, 0xd3, 0x40, + 0x10, 0x56, 0x1c, 0xe7, 0xc7, 0x13, 0x68, 0xc3, 0x96, 0x82, 0x71, 0x4b, 0x89, 0xcc, 0x25, 0x2a, + 0xc2, 0x51, 0x0b, 0x82, 0x52, 0x68, 0x25, 0xab, 0xf4, 0x50, 0x51, 0x54, 0x64, 0xa9, 0x3d, 0x71, + 0xd9, 0xc6, 0x4b, 0xb0, 0x62, 0xaf, 0x57, 0x5e, 0x27, 0xa8, 0x20, 0x2e, 0xbc, 0x02, 0x2f, 0xc1, + 0x5b, 0xf0, 0x10, 0x9c, 0xb9, 0xf1, 0x02, 0xbc, 0x01, 0xf2, 0xee, 0xfa, 0x27, 0x25, 0x08, 0x72, + 0xe2, 0xb6, 0x3b, 0xf3, 0x7d, 0xe3, 0x99, 0x6f, 0x66, 0xc7, 0x60, 0xf0, 0xe9, 0xd0, 0x61, 0x49, + 0x9c, 0xc6, 0xd6, 0xfa, 0x28, 0x8e, 0x47, 0x21, 0x19, 0x60, 0x16, 0x0c, 0x30, 0xa5, 0x71, 0x8a, + 0xd3, 0x20, 0xa6, 0x5c, 0x7a, 0xed, 0xd7, 0xb0, 0xe4, 0x32, 0xc6, 0x8f, 0x03, 0x9e, 0xbe, 0xc2, + 0x09, 0x8e, 0x38, 0xb2, 0xa0, 0x1d, 0xe2, 0x73, 0x12, 0xbe, 0x20, 0x17, 0x66, 0xad, 0x57, 0xeb, + 0x1b, 0x5e, 0x71, 0x2f, 0x7c, 0x67, 0x38, 0x34, 0xb5, 0x8a, 0xef, 0x0c, 0x87, 0x08, 0x81, 0x4e, + 0x71, 0x44, 0xcc, 0xba, 0xb0, 0x8b, 0xb3, 0xbd, 0x0f, 0xed, 0x3c, 0x3a, 0x32, 0xa1, 0x15, 0x11, + 0xce, 0xf1, 0x88, 0xa8, 0xb0, 0xf9, 0x15, 0x99, 0xa0, 0x63, 0xc6, 0xb8, 0xa9, 0xf5, 0xea, 0xfd, + 0xce, 0xb6, 0xee, 0xb8, 0x8c, 0x79, 0xc2, 0x62, 0x7f, 0xd1, 0xa0, 0xfd, 0x12, 0xd3, 0xe0, 0x0d, + 0xe1, 0x29, 0x7a, 0x06, 0x1d, 0x42, 0xa7, 0x41, 0x12, 0xd3, 0x88, 0xd0, 0xd4, 0xac, 0x09, 0xb4, + 0xe5, 0xe4, 0x7e, 0xe7, 0xb0, 0x74, 0x1e, 0xd2, 0x34, 0xb9, 0xf0, 0xaa, 0x70, 0x74, 0x1f, 0x9a, + 0x22, 0xd5, 0xfc, 0x33, 0xab, 0x25, 0xf1, 0x58, 0xd8, 0x25, 0x47, 0x81, 0x50, 0x0f, 0x3a, 0x7e, + 0x3c, 0x1c, 0x93, 0xe4, 0x28, 0xca, 0x32, 0x96, 0x45, 0x55, 0x4d, 0x45, 0xbd, 0x7a, 0x59, 0xaf, + 0xb5, 0x0f, 0xdd, 0xcb, 0x59, 0xa0, 0x2e, 0xd4, 0xc7, 0x85, 0x94, 0xd9, 0x11, 0x5d, 0x87, 0xc6, + 0x14, 0x87, 0x13, 0xa2, 0x24, 0x94, 0x97, 0x5d, 0x6d, 0xa7, 0x66, 0x3d, 0x81, 0x4e, 0x25, 0x99, + 0x45, 0xa8, 0xf6, 0x4f, 0x0d, 0xea, 0x2e, 0x63, 0x68, 0x09, 0xb4, 0xc0, 0x57, 0x14, 0x2d, 0xf0, + 0x8b, 0x34, 0xb5, 0x32, 0xcd, 0x7f, 0x28, 0xee, 0xf1, 0xac, 0xd6, 0xba, 0x92, 0xcc, 0x65, 0xec, + 0x2f, 0x32, 0xf7, 0x0b, 0x99, 0x1b, 0x82, 0xd3, 0x15, 0x9c, 0x79, 0x0a, 0xf7, 0x61, 0x19, 0x4f, + 0xd2, 0xb7, 0x71, 0x12, 0xbc, 0x27, 0xfe, 0x29, 0x27, 0x09, 0x37, 0x9b, 0xbd, 0x7a, 0xdf, 0xf0, + 0x2e, 0x9b, 0xd1, 0x3a, 0x18, 0x01, 0xe5, 0x29, 0xa6, 0x43, 0xc2, 0xcd, 0x56, 0xaf, 0xd6, 0x6f, + 0x78, 0xa5, 0xe1, 0x7f, 0x6a, 0xfe, 0x5d, 0x07, 0xc3, 0x65, 0xec, 0x94, 0xf9, 0x38, 0x2d, 0x07, + 0xa2, 0x56, 0x51, 0xda, 0x82, 0x36, 0x25, 0xef, 0xa4, 0xcc, 0xea, 0xc1, 0xe4, 0x77, 0xe4, 0x40, + 0x93, 0xd0, 0xa9, 0xeb, 0xfb, 0x66, 0x5d, 0x48, 0x75, 0xc3, 0x29, 0x62, 0x65, 0x22, 0xbb, 0xbe, + 0xaf, 0x04, 0x93, 0x28, 0x74, 0x0f, 0x1a, 0x84, 0x4e, 0xbd, 0xa8, 0xda, 0x8d, 0x12, 0xee, 0x45, + 0x12, 0x2d, 0x31, 0xe8, 0xa1, 0x7a, 0xa9, 0x59, 0x78, 0xd9, 0x09, 0xb3, 0x82, 0x3f, 0x56, 0x2e, + 0x49, 0x29, 0x90, 0x68, 0x0b, 0x5a, 0xe2, 0xec, 0x45, 0xa2, 0x17, 0x9d, 0xed, 0x9b, 0x97, 0x49, + 0xf9, 0x67, 0x72, 0x1c, 0xda, 0x00, 0x18, 0x25, 0x98, 0xa6, 0xb2, 0x83, 0x2d, 0xd1, 0xc1, 0x8a, + 0x25, 0x9b, 0xb5, 0x84, 0x4c, 0xe3, 0x31, 0x91, 0x80, 0xb6, 0x00, 0x54, 0x4d, 0x68, 0x13, 0xba, + 0x99, 0x26, 0xaa, 0xa1, 0x07, 0xf1, 0x84, 0xa6, 0xa6, 0x21, 0xba, 0xfc, 0x9b, 0x3d, 0x6b, 0x56, + 0x45, 0x9a, 0x85, 0xfa, 0xbc, 0x03, 0x50, 0xca, 0xb4, 0x10, 0xf3, 0x29, 0x5c, 0x9d, 0x11, 0x6c, + 0x21, 0xf2, 0x2e, 0x5c, 0xa9, 0x0a, 0xb7, 0xd0, 0x7c, 0xf5, 0x00, 0x5c, 0xc6, 0x8e, 0x28, 0x67, + 0x64, 0x98, 0xce, 0x9b, 0x2f, 0xfb, 0x8e, 0x18, 0xc0, 0xe7, 0x24, 0x24, 0xf3, 0x07, 0xd0, 0xde, + 0x00, 0xed, 0x64, 0xfc, 0xe7, 0xdd, 0xbb, 0xfd, 0x55, 0x03, 0x3d, 0x5b, 0xd1, 0x68, 0x0f, 0x74, + 0xb1, 0xa6, 0x97, 0x9d, 0xd9, 0xff, 0x81, 0x65, 0x14, 0x06, 0xfb, 0xd6, 0xa7, 0x6f, 0x3f, 0x3e, + 0x6b, 0x2b, 0xe8, 0x9a, 0xf8, 0x99, 0x4c, 0xb7, 0x06, 0xd9, 0x92, 0x1e, 0x84, 0x19, 0xed, 0x11, + 0x34, 0x0f, 0x12, 0x92, 0x3d, 0x03, 0xa3, 0x58, 0xac, 0x96, 0x58, 0xe5, 0xf6, 0x9a, 0x60, 0xad, + 0xda, 0x2b, 0x33, 0xac, 0xa1, 0x44, 0xef, 0x43, 0x53, 0x3d, 0x1f, 0x28, 0x47, 0x4d, 0x11, 0x6d, + 0x41, 0x5c, 0xb7, 0xad, 0x19, 0xe2, 0x87, 0xac, 0xae, 0x8f, 0x83, 0x89, 0x64, 0xb9, 0xd0, 0xca, + 0xf5, 0xe9, 0x38, 0xa5, 0x58, 0x2a, 0xc2, 0x5d, 0x11, 0xe1, 0x36, 0x5a, 0x9b, 0x17, 0x21, 0x50, + 0xbc, 0x3d, 0x68, 0x2a, 0x01, 0x45, 0x0a, 0xf2, 0x6c, 0xd5, 0x9d, 0x93, 0x71, 0x9e, 0xc1, 0xe6, + 0xdc, 0x0c, 0x7c, 0x01, 0x3c, 0x6f, 0x8a, 0x1f, 0xe9, 0x83, 0x5f, 0x01, 0x00, 0x00, 0xff, 0xff, + 0xab, 0xa9, 0xbb, 0x45, 0x73, 0x07, 0x00, 0x00, +} diff --git a/svc/proto/svc.pb.gw.go b/svc/proto/svc.pb.gw.go new file mode 100644 index 0000000..62fba24 --- /dev/null +++ b/svc/proto/svc.pb.gw.go @@ -0,0 +1,348 @@ +// Code generated by protoc-gen-grpc-gateway +// source: svc.proto +// DO NOT EDIT! + +/* +Package svc is a reverse proxy. + +It translates gRPC into RESTful JSON APIs. +*/ +package svc + +import ( + "io" + "net/http" + + "github.com/golang/protobuf/proto" + "github.com/grpc-ecosystem/grpc-gateway/runtime" + "github.com/grpc-ecosystem/grpc-gateway/utilities" + "golang.org/x/net/context" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/grpclog" +) + +var _ codes.Code +var _ io.Reader +var _ = runtime.String +var _ = utilities.NewDoubleArray + +var ( + filter_Apps_List_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} +) + +func request_Apps_List_0(ctx context.Context, marshaler runtime.Marshaler, client AppsClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq AppsListParams + var metadata runtime.ServerMetadata + + if err := runtime.PopulateQueryParameters(&protoReq, req.URL.Query(), filter_Apps_List_0); err != nil { + return nil, metadata, grpc.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.List(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +var ( + filter_Apps_Create_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} +) + +func request_Apps_Create_0(ctx context.Context, marshaler runtime.Marshaler, client AppsClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq Manifest + var metadata runtime.ServerMetadata + + if err := runtime.PopulateQueryParameters(&protoReq, req.URL.Query(), filter_Apps_Create_0); err != nil { + return nil, metadata, grpc.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.Create(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +var ( + filter_Apps_Update_0 = &utilities.DoubleArray{Encoding: map[string]int{"name": 0}, Base: []int{1, 1, 0}, Check: []int{0, 1, 2}} +) + +func request_Apps_Update_0(ctx context.Context, marshaler runtime.Marshaler, client AppsClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq AppUpdate + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["name"] + if !ok { + return nil, metadata, grpc.Errorf(codes.InvalidArgument, "missing parameter %s", "name") + } + + protoReq.Name, err = runtime.String(val) + + if err != nil { + return nil, metadata, err + } + + if err := runtime.PopulateQueryParameters(&protoReq, req.URL.Query(), filter_Apps_Update_0); err != nil { + return nil, metadata, grpc.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.Update(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func request_Apps_Inspect_0(ctx context.Context, marshaler runtime.Marshaler, client AppsClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq AppInspect + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["name"] + if !ok { + return nil, metadata, grpc.Errorf(codes.InvalidArgument, "missing parameter %s", "name") + } + + protoReq.Name, err = runtime.String(val) + + if err != nil { + return nil, metadata, err + } + + msg, err := client.Inspect(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func request_Apps_Delete_0(ctx context.Context, marshaler runtime.Marshaler, client AppsClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq AppDelete + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["name"] + if !ok { + return nil, metadata, grpc.Errorf(codes.InvalidArgument, "missing parameter %s", "name") + } + + protoReq.Name, err = runtime.String(val) + + if err != nil { + return nil, metadata, err + } + + msg, err := client.Delete(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +// RegisterAppsHandlerFromEndpoint is same as RegisterAppsHandler but +// automatically dials to "endpoint" and closes the connection when "ctx" gets done. +func RegisterAppsHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) { + conn, err := grpc.Dial(endpoint, opts...) + if err != nil { + return err + } + defer func() { + if err != nil { + if cerr := conn.Close(); cerr != nil { + grpclog.Printf("Failed to close conn to %s: %v", endpoint, cerr) + } + return + } + go func() { + <-ctx.Done() + if cerr := conn.Close(); cerr != nil { + grpclog.Printf("Failed to close conn to %s: %v", endpoint, cerr) + } + }() + }() + + return RegisterAppsHandler(ctx, mux, conn) +} + +// RegisterAppsHandler registers the http handlers for service Apps to "mux". +// The handlers forward requests to the grpc endpoint over "conn". +func RegisterAppsHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error { + client := NewAppsClient(conn) + + mux.Handle("GET", pattern_Apps_List_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(ctx) + defer cancel() + if cn, ok := w.(http.CloseNotifier); ok { + go func(done <-chan struct{}, closed <-chan bool) { + select { + case <-done: + case <-closed: + cancel() + } + }(ctx.Done(), cn.CloseNotify()) + } + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, req) + if err != nil { + runtime.HTTPError(ctx, outboundMarshaler, w, req, err) + } + resp, md, err := request_Apps_List_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, outboundMarshaler, w, req, err) + return + } + + forward_Apps_List_0(ctx, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("POST", pattern_Apps_Create_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(ctx) + defer cancel() + if cn, ok := w.(http.CloseNotifier); ok { + go func(done <-chan struct{}, closed <-chan bool) { + select { + case <-done: + case <-closed: + cancel() + } + }(ctx.Done(), cn.CloseNotify()) + } + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, req) + if err != nil { + runtime.HTTPError(ctx, outboundMarshaler, w, req, err) + } + resp, md, err := request_Apps_Create_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, outboundMarshaler, w, req, err) + return + } + + forward_Apps_Create_0(ctx, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("POST", pattern_Apps_Update_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(ctx) + defer cancel() + if cn, ok := w.(http.CloseNotifier); ok { + go func(done <-chan struct{}, closed <-chan bool) { + select { + case <-done: + case <-closed: + cancel() + } + }(ctx.Done(), cn.CloseNotify()) + } + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, req) + if err != nil { + runtime.HTTPError(ctx, outboundMarshaler, w, req, err) + } + resp, md, err := request_Apps_Update_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, outboundMarshaler, w, req, err) + return + } + + forward_Apps_Update_0(ctx, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Apps_Inspect_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(ctx) + defer cancel() + if cn, ok := w.(http.CloseNotifier); ok { + go func(done <-chan struct{}, closed <-chan bool) { + select { + case <-done: + case <-closed: + cancel() + } + }(ctx.Done(), cn.CloseNotify()) + } + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, req) + if err != nil { + runtime.HTTPError(ctx, outboundMarshaler, w, req, err) + } + resp, md, err := request_Apps_Inspect_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, outboundMarshaler, w, req, err) + return + } + + forward_Apps_Inspect_0(ctx, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("DELETE", pattern_Apps_Delete_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(ctx) + defer cancel() + if cn, ok := w.(http.CloseNotifier); ok { + go func(done <-chan struct{}, closed <-chan bool) { + select { + case <-done: + case <-closed: + cancel() + } + }(ctx.Done(), cn.CloseNotify()) + } + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, req) + if err != nil { + runtime.HTTPError(ctx, outboundMarshaler, w, req, err) + } + resp, md, err := request_Apps_Delete_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, outboundMarshaler, w, req, err) + return + } + + forward_Apps_Delete_0(ctx, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + +var ( + pattern_Apps_List_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"api", "v1", "apps", "list"}, "")) + + pattern_Apps_Create_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"api", "v1", "apps", "create"}, "")) + + pattern_Apps_Update_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 2, 4}, []string{"api", "v1", "apps", "name", "update"}, "")) + + pattern_Apps_Inspect_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 2, 4}, []string{"api", "v1", "apps", "name", "inspect"}, "")) + + pattern_Apps_Delete_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 2, 4}, []string{"api", "v1", "apps", "name", "delete"}, "")) +) + +var ( + forward_Apps_List_0 = runtime.ForwardResponseMessage + + forward_Apps_Create_0 = runtime.ForwardResponseMessage + + forward_Apps_Update_0 = runtime.ForwardResponseMessage + + forward_Apps_Inspect_0 = runtime.ForwardResponseMessage + + forward_Apps_Delete_0 = runtime.ForwardResponseMessage +) diff --git a/svc/proto/svc.proto b/svc/proto/svc.proto new file mode 100644 index 0000000..65f373f --- /dev/null +++ b/svc/proto/svc.proto @@ -0,0 +1,92 @@ +syntax = "proto3"; + +import "google/api/annotations.proto"; + +// Apps is the master service that svc provides. It allows a user to list, create, update +service Apps { + rpc List(AppsListParams) returns (AppsList) { + option (google.api.http) = { + get: "/api/v1/apps/list" + }; + } + + rpc Create(Manifest) returns (App) { + option (google.api.http) = { + post: "/api/v1/apps/create" + }; + } + + rpc Update(AppUpdate) returns (App) { + option (google.api.http) = { + post: "/api/v1/apps/{name}/update" + }; + } + + rpc Inspect(AppInspect) returns (App) { + option (google.api.http) = { + get: "/api/v1/apps/{name}/inspect" + }; + } + + rpc Delete(AppDelete) returns(Ok) { + option (google.api.http) = { + delete: "/api/v1/apps/{name}/delete" + }; + } +} + +message AppsListParams { + string labelKey = 1; + string labelVal = 2; + + // will be matched to app names + string name = 3; +} + +message AppsList { + string message = 1; + repeated App apps = 2; +} + +message Manifest { + map environment = 1; + map labels = 2; + string dockerImage = 3; + string name = 4; +} + +message App { + string id = 1; + string name = 2; + string dockerImage = 3; + map environment = 4; + map labels = 5; + repeated string authorizedUsers = 6; + int32 instances = 7; +} + +message AppUpdate { + string name = 1; + + string newImage = 2; + map envAdd = 3; + map envRm = 4; + map labelAdd = 5; + map labelRm = 6; + + repeated string grantUsers = 7; + repeated string revokeUsers = 8; + int32 newInstanceCount = 9; +} + +message AppInspect { + string name = 1; +} + +message AppDelete { + string name = 1; +} + +message Ok { + string message = 1; +} diff --git a/svc/proto/svc.swagger.json b/svc/proto/svc.swagger.json new file mode 100644 index 0000000..6b49f3d --- /dev/null +++ b/svc/proto/svc.swagger.json @@ -0,0 +1,309 @@ +{ + "swagger": "2.0", + "info": { + "title": "svc.proto", + "version": "version not set" + }, + "schemes": [ + "http", + "https" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "paths": { + "/api/v1/apps/create": { + "post": { + "operationId": "Create", + "responses": { + "200": { + "description": "", + "schema": { + "$ref": "#/definitions/App" + } + } + }, + "tags": [ + "Apps" + ] + } + }, + "/api/v1/apps/list": { + "get": { + "operationId": "List", + "responses": { + "200": { + "description": "", + "schema": { + "$ref": "#/definitions/AppsList" + } + } + }, + "parameters": [ + { + "name": "labelKey", + "in": "query", + "required": false, + "type": "string" + }, + { + "name": "labelVal", + "in": "query", + "required": false, + "type": "string" + }, + { + "name": "name", + "description": "will be matched to app names.", + "in": "query", + "required": false, + "type": "string" + } + ], + "tags": [ + "Apps" + ] + } + }, + "/api/v1/apps/{name}/delete": { + "delete": { + "operationId": "Delete", + "responses": { + "200": { + "description": "", + "schema": { + "$ref": "#/definitions/Ok" + } + } + }, + "parameters": [ + { + "name": "name", + "in": "path", + "required": true, + "type": "string" + } + ], + "tags": [ + "Apps" + ] + } + }, + "/api/v1/apps/{name}/inspect": { + "get": { + "operationId": "Inspect", + "responses": { + "200": { + "description": "", + "schema": { + "$ref": "#/definitions/App" + } + } + }, + "parameters": [ + { + "name": "name", + "in": "path", + "required": true, + "type": "string" + } + ], + "tags": [ + "Apps" + ] + } + }, + "/api/v1/apps/{name}/update": { + "post": { + "operationId": "Update", + "responses": { + "200": { + "description": "", + "schema": { + "$ref": "#/definitions/App" + } + } + }, + "parameters": [ + { + "name": "name", + "in": "path", + "required": true, + "type": "string" + } + ], + "tags": [ + "Apps" + ] + } + } + }, + "definitions": { + "App": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "dockerImage": { + "type": "string" + }, + "environment": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "labels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "authorizedUsers": { + "type": "array", + "items": { + "type": "string" + } + }, + "instances": { + "type": "integer", + "format": "int32" + } + } + }, + "AppDelete": { + "type": "object", + "properties": { + "name": { + "type": "string" + } + } + }, + "AppInspect": { + "type": "object", + "properties": { + "name": { + "type": "string" + } + } + }, + "AppUpdate": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "newImage": { + "type": "string" + }, + "envAdd": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "envRm": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "labelAdd": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "labelRm": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "grantUsers": { + "type": "array", + "items": { + "type": "string" + } + }, + "revokeUsers": { + "type": "array", + "items": { + "type": "string" + } + }, + "newInstanceCount": { + "type": "integer", + "format": "int32" + } + } + }, + "AppsList": { + "type": "object", + "properties": { + "message": { + "type": "string" + }, + "apps": { + "type": "array", + "items": { + "$ref": "#/definitions/App" + } + } + } + }, + "AppsListParams": { + "type": "object", + "properties": { + "labelKey": { + "type": "string" + }, + "labelVal": { + "type": "string" + }, + "name": { + "type": "string", + "title": "will be matched to app names" + } + } + }, + "Manifest": { + "type": "object", + "properties": { + "environment": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "labels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "dockerImage": { + "type": "string" + }, + "name": { + "type": "string" + } + } + }, + "Ok": { + "type": "object", + "properties": { + "message": { + "type": "string" + } + } + } + } +} -- cgit v1.2.3