From 44bd29a7feffb3a930b7d5f4ec015c0df8778843 Mon Sep 17 00:00:00 2001 From: bobmex <38759636+bobmex@users.noreply.github.com> Date: Sat, 26 Jan 2019 18:03:23 -0800 Subject: [PATCH] part of issue 373 (#29) * nginx rev proxy for kubectl proxy to plug security holes, wip * htpasswd location * certificate,key location * mexctl handle kubectl and bypass kubectl proxy complications --- mexos/agent.go | 7 +- mexos/cluster.go | 55 ++-- mexos/flavor.go | 2 +- mexos/ip.go | 8 +- mexos/kubeconfig.go | 15 +- mexos/kubectl.go | 29 +- mexos/kubeproxy.go | 91 +++--- mexos/kubernetes.go | 1 + mexos/kvm.go | 9 +- mexos/manifest.go | 3 + mexos/mexctl/main.go | 18 +- mexos/misc.go | 17 ++ mexos/network.go | 2 +- mexos/nginx.go | 55 +++- mexos/oscli.go | 12 +- mexos/rootlb.go | 6 +- mexos/valid.go | 6 +- mexos/vault.go | 5 +- openstack-tenant/agent/README.md | 151 ---------- openstack-tenant/agent/api/mexosagent.pb.go | 264 +++++++++++++----- .../agent/api/mexosagent.pb.gw.go | 46 +++ openstack-tenant/agent/api/mexosagent.proto | 18 ++ .../agent/api/mexosagent.swagger.json | 66 ++++- openstack-tenant/agent/server/handlers.go | 197 ++++++++++++- openstack-tenant/agent/server/server.go | 3 + 25 files changed, 744 insertions(+), 342 deletions(-) delete mode 100644 openstack-tenant/agent/README.md diff --git a/mexos/agent.go b/mexos/agent.go index c2d2577ab..323342043 100644 --- a/mexos/agent.go +++ b/mexos/agent.go @@ -86,13 +86,17 @@ func RunMEXAgentManifest(mf *Manifest) error { return fmt.Errorf("can't acquire certificate for %s, %v", rootLB.Name, err) } log.DebugLog(log.DebugLevelMexos, "acquired certificates from letsencrypt", "name", rootLB.Name) + err = GetHTPassword(mf, rootLB) + if err != nil { + return fmt.Errorf("can't download htpassword %v", err) + } //return RunMEXOSAgentContainer(mf, rootLB) return RunMEXOSAgentService(mf, rootLB) } func RunMEXOSAgentService(mf *Manifest, rootLB *MEXRootLB) error { //TODO check if agent is running before restarting again. - log.DebugLog(log.DebugLevelMexos, "will run new mexosagent service") + log.DebugLog(log.DebugLevelMexos, "run mexosagent service") client, err := GetSSHClient(mf, rootLB.Name, mf.Values.Network.External, sshUser) if err != nil { return err @@ -104,6 +108,7 @@ func RunMEXOSAgentService(mf *Manifest, rootLB *MEXRootLB) error { } } log.DebugLog(log.DebugLevelMexos, "copying new mexosagent service") + //TODO name should come from mf.Values and allow versioning for _, dest := range []struct{ path, name string }{ {"/usr/local/bin", "mexosagent"}, {"/lib/systemd/system", "mexosagent.service"}, diff --git a/mexos/cluster.go b/mexos/cluster.go index cbc1fd984..133540cd8 100644 --- a/mexos/cluster.go +++ b/mexos/cluster.go @@ -3,7 +3,6 @@ package mexos import ( "encoding/json" "fmt" - "os" "strings" "time" @@ -73,7 +72,7 @@ type ClusterMasterFlavor struct { //mexCreateClusterKubernetes creates a cluster of nodes. It can take a while, so call from a goroutine. func mexCreateClusterKubernetes(mf *Manifest) error { //func mexCreateClusterKubernetes(mf *Manifest) (*string, error) { - log.DebugLog(log.DebugLevelMexos, "create kubernetes cluster", "cluster metadata", mf.Metadata, "spec", mf.Spec) + //log.DebugLog(log.DebugLevelMexos, "create kubernetes cluster", "cluster metadata", mf.Metadata, "spec", mf.Spec) rootLB, err := getRootLB(mf.Spec.RootLB) if err != nil { return err @@ -215,7 +214,11 @@ func mexDeleteClusterKubernetes(mf *Manifest) error { if err != nil { return err } - log.DebugLog(log.DebugLevelMexos, "looking for server", "name", name, "servers", srvs) + // clname, err := FindClusterWithKey(mf, mf.Spec.Key) + // if err != nil { + // return fmt.Errorf("can't find cluster with key %s, %v", mf.Spec.Key, err) + // } + //log.DebugLog(log.DebugLevelMexos, "looking for server", "name", name, "servers", srvs) force := strings.Contains(mf.Spec.Flags, "force") serverDeleted := false for _, s := range srvs { @@ -245,11 +248,11 @@ func mexDeleteClusterKubernetes(mf *Manifest) error { } serverDeleted = true //kconfname := fmt.Sprintf("%s.kubeconfig", s.Name[strings.LastIndex(s.Name, "-")+1:]) - kconfname := GetLocalKconfName(mf) - rerr := os.Remove(kconfname) - if rerr != nil { - log.DebugLog(log.DebugLevelMexos, "error can't remove file", "name", kconfname, "error", rerr) - } + // kconfname := GetLocalKconfName(mf) + // rerr := os.Remove(kconfname) + // if rerr != nil { + // log.DebugLog(log.DebugLevelMexos, "error can't remove file", "name", kconfname, "error", rerr) + // } } } if !serverDeleted { @@ -271,37 +274,17 @@ func mexDeleteClusterKubernetes(mf *Manifest) error { } err = DeleteSubnet(mf, s.Name) if err != nil { - log.DebugLog(log.DebugLevelMexos, "warning, error while deleting subnet", "error", err) + log.DebugLog(log.DebugLevelMexos, "warning, problems deleting subnet", "error", err) } break } } //XXX tell agent to remove the route //XXX remove kubectl proxy instance - client, err := GetSSHClient(mf, rootLB.Name, mf.Values.Network.External, sshUser) - if err != nil { - return err - } - cmd := "sudo ps wwh -C kubectl -o pid,args" - out, err := client.Output(cmd) - if err != nil || out == "" { - return nil // no kubectl running - } - lines := strings.Split(out, "\n") - for _, ln := range lines { - pidnum := parseKCPid(ln, mf.Spec.Key) - if pidnum == 0 { - continue - } - cmd = fmt.Sprintf("sudo kill -9 %d", pidnum) - out, err = client.Output(cmd) - if err != nil { - log.InfoLog("error killing kubectl proxy", "command", cmd, "out", out, "error", err) - } else { - log.DebugLog(log.DebugLevelMexos, "killed kubectl proxy", "line", ln, "cmd", cmd) - } - return nil - } + // if err = DeleteNginxKCProxy(mf, rootLB.Name, clname); err != nil { + // log.DebugLog(log.DebugLevelMexos, "warning,cannot clean nginx kubectl proxy", "error", err) + // //return err + // } return nil } @@ -333,7 +316,7 @@ func IsClusterReady(mf *Manifest, rootLB *MEXRootLB) (bool, error) { } log.DebugLog(log.DebugLevelMexos, "checking master k8s node for available nodes", "ipaddr", ipaddr) cmd := fmt.Sprintf("ssh -o %s -o %s -o %s -i id_rsa_mex %s@%s kubectl get nodes -o json", sshOpts[0], sshOpts[1], sshOpts[2], sshUser, ipaddr) - log.DebugLog(log.DebugLevelMexos, "running kubectl get nodes", "cmd", cmd) + //log.DebugLog(log.DebugLevelMexos, "running kubectl get nodes", "cmd", cmd) out, err := client.Output(cmd) if err != nil { log.DebugLog(log.DebugLevelMexos, "error checking for kubernetes nodes", "out", out, "err", err) @@ -361,7 +344,7 @@ func IsClusterReady(mf *Manifest, rootLB *MEXRootLB) (bool, error) { //FindClusterWithKey finds cluster given a key string func FindClusterWithKey(mf *Manifest, key string) (string, error) { - log.DebugLog(log.DebugLevelMexos, "find cluster with key", "key", key) + //log.DebugLog(log.DebugLevelMexos, "find cluster with key", "key", key) if key == "" { return "", fmt.Errorf("empty key") } @@ -371,7 +354,7 @@ func FindClusterWithKey(mf *Manifest, key string) (string, error) { } for _, s := range srvs { if s.Status == "ACTIVE" && strings.HasSuffix(s.Name, key) && strings.HasPrefix(s.Name, "mex-k8s-master") { - log.DebugLog(log.DebugLevelMexos, "find cluster with key", "key", key, "found", s.Name) + //log.DebugLog(log.DebugLevelMexos, "find cluster with key", "key", key, "found", s.Name) return s.Name, nil } } diff --git a/mexos/flavor.go b/mexos/flavor.go index f6724c2cc..e6e2ffd64 100644 --- a/mexos/flavor.go +++ b/mexos/flavor.go @@ -76,7 +76,7 @@ func GetClusterFlavor(flavor string) (*ClusterFlavor, error) { log.DebugLog(log.DebugLevelMexos, "get cluster flavor details", "cluster flavor", flavor) for _, af := range AvailableClusterFlavors { if af.Name == flavor { - log.DebugLog(log.DebugLevelMexos, "using cluster flavor", "cluster flavor", af) + //log.DebugLog(log.DebugLevelMexos, "using cluster flavor", "cluster flavor", af) return af, nil } } diff --git a/mexos/ip.go b/mexos/ip.go index ad43b9651..bf9615b25 100644 --- a/mexos/ip.go +++ b/mexos/ip.go @@ -42,7 +42,7 @@ func GetAllowedClientCIDR() string { //GetServerIPAddr gets the server IP func GetServerIPAddr(mf *Manifest, networkName, serverName string) (string, error) { //TODO: mexosagent cache - log.DebugLog(log.DebugLevelMexos, "get server ip addr", "networkname", networkName, "servername", serverName) + //log.DebugLog(log.DebugLevelMexos, "get server ip addr", "networkname", networkName, "servername", serverName) //sd, err := GetServerDetails(rootLB) sd, err := GetServerDetails(mf, serverName) if err != nil { @@ -76,13 +76,13 @@ func GetServerIPAddr(mf *Manifest, networkName, serverName string) (string, erro return "", fmt.Errorf("invalid network name in server detail address, %s", sd.Addresses) } addr := its[1] - log.DebugLog(log.DebugLevelMexos, "got server ip addr", "ipaddr", addr, "netname", networkName, "servername", serverName) + //log.DebugLog(log.DebugLevelMexos, "got server ip addr", "ipaddr", addr, "netname", networkName, "servername", serverName) return addr, nil } //FindNodeIP finds IP for the given node func FindNodeIP(mf *Manifest, name string) (string, error) { - log.DebugLog(log.DebugLevelMexos, "find node ip", "name", name) + //log.DebugLog(log.DebugLevelMexos, "find node ip", "name", name) if name == "" { return "", fmt.Errorf("empty name") } @@ -96,7 +96,7 @@ func FindNodeIP(mf *Manifest, name string) (string, error) { if err != nil { return "", fmt.Errorf("can't get IP for %s, %v", s.Name, err) } - log.DebugLog(log.DebugLevelMexos, "found node ip", "name", name, "ipaddr", ipaddr) + //log.DebugLog(log.DebugLevelMexos, "found node ip", "name", name, "ipaddr", ipaddr) return ipaddr, nil } } diff --git a/mexos/kubeconfig.go b/mexos/kubeconfig.go index da8bb9dd4..c735eadf5 100644 --- a/mexos/kubeconfig.go +++ b/mexos/kubeconfig.go @@ -125,11 +125,13 @@ func CopyKubeConfig(mf *Manifest, rootLB *MEXRootLB, name string) error { if err != nil { return fmt.Errorf("can't cat %s, %s, %v", kconfname, out, err) } - port, serr := StartKubectlProxy(mf, rootLB, kconfname) - if serr != nil { - return serr - } - return ProcessKubeconfig(mf, rootLB, name, port, []byte(out)) + //TODO generate per proxy password and record in vault + //port, serr := StartKubectlProxy(mf, rootLB, name, kconfname) + //if serr != nil { + // return serr + //} + //return ProcessKubeconfig(mf, rootLB, name, port, []byte(out)) + return nil } //ProcessKubeconfig validates kubeconfig and saves it and creates a copy for proxy access @@ -148,7 +150,8 @@ func ProcessKubeconfig(mf *Manifest, rootLB *MEXRootLB, name string, port int, d } kconfname := GetLocalKconfName(mf) log.DebugLog(log.DebugLevelMexos, "writing local kubeconfig file", "name", kconfname) - kc.Clusters[0].Cluster.Server = fmt.Sprintf("http://%s:%d", rootLB.Name, port) + //TODO per cluster password has to come from vault + kc.Clusters[0].Cluster.Server = fmt.Sprintf("https://testuser314159:testpassword271828@%s:%d", rootLB.Name, port) dat, err = yaml.Marshal(kc) if err != nil { return fmt.Errorf("can't marshal kubeconfig proxy edit %s, %v", name, err) diff --git a/mexos/kubectl.go b/mexos/kubectl.go index c0a5338f3..3e00dd40f 100644 --- a/mexos/kubectl.go +++ b/mexos/kubectl.go @@ -14,6 +14,31 @@ import ( "github.com/mobiledgex/edge-cloud/log" ) +func RunKubectl(mf *Manifest, params string) (*string, error) { + log.DebugLog(log.DebugLevelMexos, "run kubectl", "params", params) + rootLB, err := getRootLB(mf.Spec.RootLB) + if err != nil { + return nil, err + } + if rootLB == nil { + return nil, fmt.Errorf("failed to create docker registry secret, rootLB is null") + } + //name, err := FindClusterWithKey(mf, mf.Spec.Key) + //if err != nil { + // return nil, fmt.Errorf("can't find cluster with key %s, %v", mf.Spec.Key, err) + //} + client, err := GetSSHClient(mf, rootLB.Name, mf.Values.Network.External, sshUser) + if err != nil { + return nil, fmt.Errorf("can't get ssh client, %v", err) + } + cmd := fmt.Sprintf("kubectl --kubeconfig %s.kubeconfig %s", rootLB.Name, params) + out, err := client.Output(cmd) + if err != nil { + return nil, fmt.Errorf("kubectl failed, %v, %s", err, out) + } + return &out, nil +} + func CreateDockerRegistrySecret(mf *Manifest) error { log.DebugLog(log.DebugLevelMexos, "creating docker registry secret in kubernetes") rootLB, err := getRootLB(mf.Spec.RootLB) @@ -25,8 +50,8 @@ func CreateDockerRegistrySecret(mf *Manifest) error { } var out string - log.DebugLog(log.DebugLevelMexos, "CreateDockerRegistrySecret", "mf", mf) - + //log.DebugLog(log.DebugLevelMexos, "CreateDockerRegistrySecret", "mf", mf) + log.DebugLog(log.DebugLevelMexos, "creating docker registry secret in kubernetes cluster") if IsLocalDIND(mf) || mf.Metadata.Operator == "gcp" || mf.Metadata.Operator == "azure" { log.DebugLog(log.DebugLevelMexos, "CreateDockerRegistrySecret locally non OpenStack case") var o []byte diff --git a/mexos/kubeproxy.go b/mexos/kubeproxy.go index b87e9f839..044341718 100644 --- a/mexos/kubeproxy.go +++ b/mexos/kubeproxy.go @@ -2,16 +2,18 @@ package mexos import ( "fmt" + "strconv" "strings" - "time" "github.com/mobiledgex/edge-cloud/log" ) +var kcproxySuffix = "-kcproxy" + //StartKubectlProxy starts kubectl proxy on the rootLB to handle kubectl commands remotely. // To be called after copying over the kubeconfig file from cluster to rootLB. -func StartKubectlProxy(mf *Manifest, rootLB *MEXRootLB, kubeconfig string) (int, error) { - log.DebugLog(log.DebugLevelMexos, "start kubectl proxy", "kubeconfig", kubeconfig) +func StartKubectlProxy(mf *Manifest, rootLB *MEXRootLB, name, kubeconfig string) (int, error) { + log.DebugLog(log.DebugLevelMexos, "start kubectl proxy", "name", name, "kubeconfig", kubeconfig) if rootLB == nil { return 0, fmt.Errorf("cannot kubectl proxy, rootLB is null") } @@ -22,52 +24,53 @@ func StartKubectlProxy(mf *Manifest, rootLB *MEXRootLB, kubeconfig string) (int, if err != nil { return 0, err } - maxPort := 8000 - cmd := "sudo ps wwh -C kubectl -o args" + //TODO check /home/ubuntu/.docker-pass file + cmd := fmt.Sprintf("echo %s | docker login -u mobiledgex --password-stdin %s", mexEnv(mf, "MEX_DOCKER_REG_PASS"), mf.Spec.DockerRegistry) out, err := client.Output(cmd) - if err == nil && out != "" { - lines := strings.Split(out, "\n") - for _, ln := range lines { - portnum := parseKCPort(ln) - if portnum > maxPort { - maxPort = portnum - } - } + if err != nil { + return 0, fmt.Errorf("can't docker login, %s, %v", out, err) } - maxPort++ - log.DebugLog(log.DebugLevelMexos, "port for kubectl proxy", "maxport", maxPort) - cmd = fmt.Sprintf("kubectl proxy --port %d --accept-hosts='.*' --address='0.0.0.0' --kubeconfig=%s ", maxPort, kubeconfig) - //Use .Start() because we don't want to hang - cl1, cl2, err := client.Start(cmd) + cmd = fmt.Sprintf("docker pull registry.mobiledgex.net:5000/mobiledgex/mobiledgex") + res, err := client.Output(cmd) if err != nil { - return 0, fmt.Errorf("error running kubectl proxy, %s, %v", cmd, err) + return 0, fmt.Errorf("cannot pull mobiledgex image, %v, %s", err, res) } - cl1.Close() //nolint - cl2.Close() //nolint - err = AddSecurityRuleCIDR(mf, GetAllowedClientCIDR(), "tcp", GetMEXSecurityRule(mf), maxPort) - log.DebugLog(log.DebugLevelMexos, "adding external ingress security rule for kubeproxy", "port", maxPort) + //TODO verify existence of kubeconfig file + containerName := name + kcproxySuffix + cmd = fmt.Sprintf("docker run --net host -d --rm -it -v /home:/home --name %s registry.mobiledgex.net:5000/mobiledgex/mobiledgex kubectl proxy --port 0 --accept-hosts '^127.0.0.1$' --address 127.0.0.1 --kubeconfig /home/ubuntu/%s", containerName, kubeconfig) + res, err = client.Output(cmd) if err != nil { - log.DebugLog(log.DebugLevelMexos, "warning, error while adding external ingress security rule for kubeproxy", "error", err, "port", maxPort) + return 0, fmt.Errorf("error running kubectl proxy, %s, %v, %s", cmd, err, res) } - - cmd = "sudo ps wwh -C kubectl -o args" - for i := 0; i < 5; i++ { - //verify - out, outerr := client.Output(cmd) - if outerr == nil { - if out == "" { - continue - } - lines := strings.Split(out, "\n") - for _, ln := range lines { - if parseKCPort(ln) == maxPort { - log.DebugLog(log.DebugLevelMexos, "kubectl confirmed running with port", "port", maxPort) - } - } - return maxPort, nil - } - log.DebugLog(log.DebugLevelMexos, "waiting for kubectl proxy...") - time.Sleep(3 * time.Second) + res, err = client.Output(fmt.Sprintf("docker logs %s", containerName)) + if err != nil { + return 0, fmt.Errorf("cannot get logs for container %s", containerName) + } + items := strings.Split(res, " ") + if len(items) < 5 { + return 0, fmt.Errorf("insufficient address info in log output, %s", res) + } + addr := items[4] + addr = strings.TrimSpace(addr) + items = strings.Split(addr, ":") + if len(items) < 2 { + return 0, fmt.Errorf("cannot get port from %s", addr) + } + port := items[1] + portnum, aerr := strconv.Atoi(port) + if aerr != nil { + return 0, fmt.Errorf("cannot convert port %v, %s", aerr, port) + } + log.DebugLog(log.DebugLevelMexos, "adding external ingress security rule for kubeproxy", "port", port) + err = AddSecurityRuleCIDR(mf, GetAllowedClientCIDR(), "tcp", GetMEXSecurityRule(mf), portnum+1) //XXX + if err != nil { + log.DebugLog(log.DebugLevelMexos, "warning, error while adding external ingress security rule for kubeproxy", "error", err, "port", port) + } + portnum++ + //TODO delete security rule when kubectl proxy container deleted + if err := AddNginxKubectlProxy(mf, rootLB.Name, name, portnum); err != nil { + return 0, fmt.Errorf("cannot add nginx kubectl proxy, %v", err) } - return 0, fmt.Errorf("timeout error verifying kubectl proxy") + log.DebugLog(log.DebugLevelMexos, "nginx kubectl proxy", "port", portnum) + return portnum, nil } diff --git a/mexos/kubernetes.go b/mexos/kubernetes.go index afca01ef8..ef74e1da3 100644 --- a/mexos/kubernetes.go +++ b/mexos/kubernetes.go @@ -36,6 +36,7 @@ func CreateKubernetesAppManifest(mf *Manifest, kubeManifest string) error { //if err := CreateDockerRegistrySecret(mf); err != nil { // return err //} + //TODO do not create yaml file but use remote yaml file over https cmd = fmt.Sprintf("cat <<'EOF'> %s.yaml \n%s\nEOF", mf.Metadata.Name, kubeManifest) out, err := kp.client.Output(cmd) if err != nil { diff --git a/mexos/kvm.go b/mexos/kvm.go index 86ccf6b1b..d3df9a350 100644 --- a/mexos/kvm.go +++ b/mexos/kvm.go @@ -185,7 +185,8 @@ func CreateFlavorMEXVM(mf *Manifest, name, image, flavor, netID, userdata, role, props = append(props, "update="+mf.Values.Registry.Update) } opts.Properties = props - log.DebugLog(log.DebugLevelMexos, "create flavor MEX KVM", "flavor", flavor, "server opts", opts) + //log.DebugLog(log.DebugLevelMexos, "create flavor MEX KVM", "flavor", flavor, "server opts", opts) + log.DebugLog(log.DebugLevelMexos, "create flavor MEX KVM", "flavor", flavor) err = CreateServer(mf, opts) if err != nil { log.DebugLog(log.DebugLevelMexos, "error creating flavor MEX KVM", "server opts", opts) @@ -317,7 +318,8 @@ func CreateMEXKVM(mf *Manifest, name, role, netSpec, tags, tenant string, id int maxoct++ ni.CIDR = fmt.Sprintf("%s.%s.%d.%d/%s", its[0], its[1], maxoct, id, sits[1]) } else { - log.DebugLog(log.DebugLevelMexos, "subnet for this cluster existed", "subnet detail", snd) + //log.DebugLog(log.DebugLevelMexos, "subnet for this cluster existed", "subnet detail", snd) + log.DebugLog(log.DebugLevelMexos, "subnet for this cluster existed", "name", snd.Name) ni.CIDR = snd.CIDR } log.DebugLog(log.DebugLevelMexos, "allocated CIDR", "cidr", ni.CIDR) @@ -391,7 +393,8 @@ func CreateMEXKVM(mf *Manifest, name, role, netSpec, tags, tenant string, id int return fmt.Errorf("cannot add router %s to subnet %s, %v", mexRouter, sn, err) } } else { - log.DebugLog(log.DebugLevelMexos, "will not create subnet since it exists", "name", snd) + //log.DebugLog(log.DebugLevelMexos, "will not create subnet since it exists", "name", snd) + log.DebugLog(log.DebugLevelMexos, "will not create subnet since it exists", "name", snd.Name) } ipaddr = net.IPv4(v4[0], v4[1], v4[2], byte(2)) } diff --git a/mexos/manifest.go b/mexos/manifest.go index 65112a938..e7833f26c 100644 --- a/mexos/manifest.go +++ b/mexos/manifest.go @@ -272,6 +272,9 @@ func FillManifestValues(mf *Manifest, kind, base string) error { base = GetDefaultRegistryBase(mf, base) var uri string switch kind { + case "kubectl": + kind = "platform" + fallthrough case "openstack": kind = "platform" fallthrough diff --git a/mexos/mexctl/main.go b/mexos/mexctl/main.go index f505d6b9d..e539f1e61 100644 --- a/mexos/mexctl/main.go +++ b/mexos/mexctl/main.go @@ -27,12 +27,14 @@ var applicationOps = map[string]func(*mexos.Manifest) error{ } var openstackOps = map[string]func(*mexos.Manifest) error{} +var kubectlOps = map[string]func(*mexos.Manifest) error{} var categories = map[string]map[string]func(*mexos.Manifest) error{ "cluster": clusterOps, "platform": platformOps, "application": applicationOps, "openstack": openstackOps, + "kubectl": kubectlOps, } var mainflag = flag.NewFlagSet(os.Args[0], flag.ExitOnError) @@ -124,13 +126,25 @@ func callOps(mf *mexos.Manifest, kind string, ops ...string) error { for i, v := range ops { vs[i] = v } - out, err := sh.Command("openstack", vs...).Output() + out, err := sh.Command(kind, vs...).Output() if err != nil { - return fmt.Errorf("error, openstack %v, %v", ops, err) + return fmt.Errorf("error, %s %v, %v, %s", kind, ops, err, out) } fmt.Println(string(out)) return nil } + if kind == "kubectl" { + vs := "" + for _, v := range ops { + vs = vs + v + " " + } + out, err := mexos.RunKubectl(mf, vs) + if err != nil { + return fmt.Errorf("error, %s %v, %v", kind, ops, err) + } + fmt.Println(string(*out)) + return nil + } if _, ok := categories[kind]; !ok { return fmt.Errorf("invalid category %s", kind) } diff --git a/mexos/misc.go b/mexos/misc.go index d9478051d..6234ff652 100644 --- a/mexos/misc.go +++ b/mexos/misc.go @@ -9,6 +9,8 @@ import ( "github.com/mobiledgex/edge-cloud/util" ) +const HTPasswdFile = "nginx.htpasswd" + func PrivateSSHKey() string { return MEXDir() + "/id_rsa_mex" } @@ -89,3 +91,18 @@ func SeedDockerSecret(mf *Manifest, rootLB *MEXRootLB) error { log.DebugLog(log.DebugLevelMexos, "docker login ok") return nil } + +func GetHTPassword(mf *Manifest, rootLB *MEXRootLB) error { + log.DebugLog(log.DebugLevelMexos, "get htpasswd") + client, err := GetSSHClient(mf, rootLB.Name, mf.Values.Network.External, sshUser) + if err != nil { + return fmt.Errorf("can't get ssh client for docker swarm, %v", err) + } + cmd := fmt.Sprintf("scp -o %s -o %s -i id_rsa_mex mobiledgex@%s:files-repo/mobiledgex/%s .", sshOpts[0], sshOpts[1], mf.Values.Registry.Name, HTPasswdFile) + out, err := client.Output(cmd) + if err != nil { + return fmt.Errorf("can't get htpasswd file, %v, %s", err, out) + } + log.DebugLog(log.DebugLevelMexos, "downloaded htpasswd") + return nil +} diff --git a/mexos/network.go b/mexos/network.go index 88ea3446b..dacd8a5cc 100644 --- a/mexos/network.go +++ b/mexos/network.go @@ -79,7 +79,7 @@ func GetRouterDetailExternalGateway(mf *Manifest, rd *OSRouterDetail) (*OSExtern if err != nil { return nil, fmt.Errorf("can't get unmarshal external gateway info, %v", err) } - log.DebugLog(log.DebugLevelMexos, "get router detail external gateway", "external gateway", externalGateway) + //log.DebugLog(log.DebugLevelMexos, "get router detail external gateway", "external gateway", externalGateway) return externalGateway, nil } diff --git a/mexos/nginx.go b/mexos/nginx.go index 802c94b57..b60813880 100644 --- a/mexos/nginx.go +++ b/mexos/nginx.go @@ -31,6 +31,11 @@ func AddNginxProxy(mf *Manifest, rootLBName, name, ipaddr string, ports []PortDe return fmt.Errorf("cannot add nginx proxy, resp %v", resp) } +func FormNginxKCProxyRequest(name string, portnum int) (*string, error) { + pl := fmt.Sprintf(`{"message":"add","name": "%s","port": "%d"}`, name, portnum) + return &pl, nil +} + func FormNginxProxyRequest(ports []PortDetail, ipaddr string, name string, network string) (*string, error) { portstrs := []string{} for _, p := range ports { @@ -61,7 +66,7 @@ func FormNginxProxyRequest(ports []PortDetail, ipaddr string, name string, netwo } pl := fmt.Sprintf(`{ "message":"add", "name": "%s", "network": "%s", "ports": %s }`, name, network, "["+portspec+"]") - if network != "" { + if network != "" { //TODO: network is not handled right, and also incorrect in mexosagent handler } @@ -85,3 +90,51 @@ func DeleteNginxProxy(mf *Manifest, rootLBName, name string) error { log.DebugLog(log.DebugLevelMexos, "error while deleting nginx proxy", "resp", resp, "body", body) return fmt.Errorf("cannot delete nginx proxy, resp %v", resp) } + +func AddNginxKubectlProxy(mf *Manifest, rootLBName, name string, portnum int) error { + log.DebugLog(log.DebugLevelMexos, "add nginx kubectl proxy", "name", name) + request := gorequest.New() + npURI := fmt.Sprintf("http://%s:%s/v1/nginx-kcp", rootLBName, mf.Values.Agent.Port) + pl, err := FormNginxKCProxyRequest(name, portnum) + if err != nil { + log.DebugLog(log.DebugLevelMexos, "cannot form nginx kubectl proxy request") + return err + } + log.DebugLog(log.DebugLevelMexos, "nginx kubectl proxy add request post", "request", *pl) + resp, body, errs := request.Post(npURI).Set("Content-Type", "application/json").Send(pl).End() + if errs != nil { + return fmt.Errorf("error, can't request nginx kubectl proxy add, %v", errs) + } + if strings.Contains(body, "OK") { + log.DebugLog(log.DebugLevelMexos, "ok, nginx kubectl proxy add request post") + return nil + } + log.DebugLog(log.DebugLevelMexos, "warning, error while adding nginx kubectl proxy", "resp", resp, "body", body) + return fmt.Errorf("cannot add nginx kubectl proxy, resp %v", resp) +} + +func DeleteNginxKCProxy(mf *Manifest, rootLBName, name string) error { + log.DebugLog(log.DebugLevelMexos, "deleting nginx kubectl proxy", "name", name) + client, err := GetSSHClient(mf, rootLBName, mf.Values.Network.External, sshUser) + if err != nil { + return err + } + out, err := client.Output("docker kill " + name + kcproxySuffix) + if err != nil { + log.DebugLog(log.DebugLevelMexos, "warning, cannot delete container", "name", name+kcproxySuffix, "error", err, "out", out) + } + request := gorequest.New() + npURI := fmt.Sprintf("http://%s:%s/v1/nginx-kcp", rootLBName, mf.Values.Agent.Port) + pl := fmt.Sprintf(`{"message":"delete","name":"%s"}`, name) + log.DebugLog(log.DebugLevelMexos, "nginx kubectl proxy delete request post", "request", pl) + resp, body, errs := request.Post(npURI).Set("Content-Type", "application/json").Send(pl).End() + if errs != nil { + return fmt.Errorf("error, can't request nginx kubectl proxy delete, %v", errs) + } + if strings.Contains(body, "OK") { + log.DebugLog(log.DebugLevelMexos, "deleted nginx kubectl proxy OK") + return nil + } + log.DebugLog(log.DebugLevelMexos, "error while deleting nginx kubectl proxy", "resp", resp, "body", body) + return fmt.Errorf("cannot delete nginx kubectl proxy, resp %v", resp) +} diff --git a/mexos/oscli.go b/mexos/oscli.go index 99daaf667..6e85269f8 100644 --- a/mexos/oscli.go +++ b/mexos/oscli.go @@ -23,7 +23,7 @@ func ListServers(mf *Manifest) ([]OSServer, error) { err = fmt.Errorf("cannot unmarshal, %v", err) return nil, err } - log.DebugLog(log.DebugLevelMexos, "list servers", "servers", servers) + //log.DebugLog(log.DebugLevelMexos, "list servers", "servers", servers) return servers, nil } @@ -102,7 +102,7 @@ func CreateServer(mf *Manifest, opts *OSServerOpt) error { for i, v := range args { iargs[i] = v } - log.DebugLog(log.DebugLevelMexos, "openstack create server", "opts", opts, "iargs", iargs) + //log.DebugLog(log.DebugLevelMexos, "openstack create server", "opts", opts, "iargs", iargs) out, err := sh.Command("openstack", iargs...).Output() if err != nil { err = fmt.Errorf("cannot create server, %v, '%s'", err, out) @@ -137,7 +137,7 @@ func GetServerDetails(mf *Manifest, name string) (*OSServerDetail, error) { if !active { return nil, fmt.Errorf("while getting server detail, waited but server %s is too slow getting to active state", name) } - log.DebugLog(log.DebugLevelMexos, "server detail", "server detail", srvDetail) + //log.DebugLog(log.DebugLevelMexos, "server detail", "server detail", srvDetail) return srvDetail, nil } @@ -306,7 +306,7 @@ func ListSubnets(mf *Manifest, netName string) ([]OSSubnet, error) { err = fmt.Errorf("can't unmarshal subnets, %v", err) return nil, err } - log.DebugLog(log.DebugLevelMexos, "list subnets", "subnets", subnets) + //log.DebugLog(log.DebugLevelMexos, "list subnets", "subnets", subnets) return subnets, nil } @@ -340,7 +340,7 @@ func GetRouterDetail(mf *Manifest, routerName string) (*OSRouterDetail, error) { err = fmt.Errorf("can't unmarshal router detail, %v", err) return nil, err } - log.DebugLog(log.DebugLevelMexos, "router detail", "router detail", routerDetail) + //log.DebugLog(log.DebugLevelMexos, "router detail", "router detail", routerDetail) return routerDetail, nil } @@ -411,7 +411,7 @@ func GetSubnetDetail(mf *Manifest, subnetName string) (*OSSubnetDetail, error) { if err != nil { return nil, fmt.Errorf("can't unmarshal subnet detail, %v", err) } - log.DebugLog(log.DebugLevelMexos, "get subnet detail", "subnet detail", subnetDetail) + //log.DebugLog(log.DebugLevelMexos, "get subnet detail", "subnet detail", subnetDetail) return subnetDetail, nil } diff --git a/mexos/rootlb.go b/mexos/rootlb.go index 8f8ec2514..665d63c55 100644 --- a/mexos/rootlb.go +++ b/mexos/rootlb.go @@ -61,9 +61,9 @@ var rootLBPorts = []int{ 18889, //mexosagent HTTP server 18888, //mexosagent GRPC server 443, //mexosagent reverse proxy HTTPS - 8001, //kubectl proxy - 6443, //kubernetes control - 8000, //mex k8s join token server + //8001, //kubectl proxy + 6443, //kubernetes control + //8000, //mex k8s join token server } //TODO more than one kubectl proxy, one per hosted cluster diff --git a/mexos/valid.go b/mexos/valid.go index 77d9013d0..a8aa25a99 100644 --- a/mexos/valid.go +++ b/mexos/valid.go @@ -32,16 +32,16 @@ func CheckVals(vals interface{}) error { return nil } for i := 0; i < m.NumField(); i++ { - n := m.Type().Field(i).Name + //n := m.Type().Field(i).Name t := m.Type().Field(i).Type v := m.Field(i).Interface() - log.DebugLog(log.DebugLevelMexos, "checkvals", "name", n, "type", m.Type(), "field type", t, "value", v) + //log.DebugLog(log.DebugLevelMexos, "checkvals", "name", n, "type", m.Type(), "field type", t, "value", v) if t.String() == "[]mexos.PortDetail" { // XXX skip ports, TODO check !nil and validate continue } if t.String() == "string" { if v == "" { - log.DebugLog(log.DebugLevelMexos, "checkvals, warning, empty field", "name", n, "type", m.Type(), "field type", t, "value", v) + //log.DebugLog(log.DebugLevelMexos, "checkvals, warning, empty field", "name", n, "type", m.Type(), "field type", t, "value", v) } //log.DebugLog(log.DebugLevelMexos, "ok", "name", n, "type", t, "value", v) } else { diff --git a/mexos/vault.go b/mexos/vault.go index 460b37fe0..a9433ae1f 100644 --- a/mexos/vault.go +++ b/mexos/vault.go @@ -8,7 +8,6 @@ import ( "strings" "github.com/ghodss/yaml" - "github.com/mobiledgex/edge-cloud/log" ) func GetVaultData(url string) ([]byte, error) { @@ -94,7 +93,7 @@ func InternVaultEnv(mf *Manifest) error { return err } } - log.DebugLog(log.DebugLevelMexos, "vault env var map", "vault env map", mf.Values.VaultEnvMap) + //log.DebugLog(log.DebugLevelMexos, "vault env var map", "vault env map", mf.Values.VaultEnvMap) return nil } @@ -137,7 +136,7 @@ func GetVaultEnv(mf *Manifest, uri string) error { if err != nil { return err } - log.DebugLog(log.DebugLevelMexos, "about to intern vault env", "mf", mf) + //log.DebugLog(log.DebugLevelMexos, "about to intern vault env", "mf", mf) if err := InternVaultEnv(mf); err != nil { return err } diff --git a/openstack-tenant/agent/README.md b/openstack-tenant/agent/README.md deleted file mode 100644 index 7bcce4795..000000000 --- a/openstack-tenant/agent/README.md +++ /dev/null @@ -1,151 +0,0 @@ -# Agent for Openstack platform hosting Kubernetes cluster - -This is an agent that will create a kubernetes cluster in openstack for a tenant, perform reverse proxy, and other functions. -There can be one or more agent nodes and services per cloudlet. A given tenant may have one or more agents. An agent can manage one or more kubernetes clusters. A kubernetes cluster per tenant can host one or more tenant apps. A tenant may have one or more kubernetes clusters. - -The kubernetes clusters per tenant can be created based on `flavors`. The `flavors` are abstractions similiar to `m1.small` or `m1.large` in openstack or AWS and other cloud platforms. The `flavors` for the `mexosagent` are different. They are not merely for descriptions required for provisioning a single virtual machine instance resources. The `mexosagent` extends this idea to cluster configuration and resource descriptions. A `flavor` therefore can include such things as the number of machine instances, the type of networks, the number of master nodes vs. worker nodes, how the agents interact with the cluster, etc. The `flavors` can be defined and created on the fly. Although typically a set of useful `flavors` are created beforehand. This is typically done by the Controller as needed. - -The agent supports GRPC as well HTTP REST API. Swagger json under api/ directory for API documentation. - -The program requires platform environment, which can be set up by sourcing `k8sopenstack.env` located under `k8s-prov` directory or the equivalent. Please refer to README.md under `k8s-prov` directory for further information. - -## building - -You may need to set environment variable for docker builds: - -``` -export DOCKER_ID_USER=yourusername -``` - -Adjust the values of the DOCKER API version and docker hub user ID. DOCKER_API_VERSION may or may not need to be set. -If you have multiple docker binaries, you may check by doing `docker version`. We are compatible with API version 1.37. -The build process builds the container image and pushes to the repo. The target machine can pull the image and run. - -TODO: establish a private docker repo. Automate push and pull and relaunch. - -## Running the Agent - -The agent runs on a node with sufficient access to the Internet and the internal network in which kubernetes cluster and containers are hosted. The openstack network has to be setup properly for this. An instance of openstack router has to be created and directed to route between the public and private network. Typically a private network is created for the kubernetes cluster which is isolated from the internet. The traffic from the private network has to be NAT'ed and routed via a router. - -The agent is deployed as a docker container image. *NOTE THAT WE NO LONGER DEPLOY AGENT AS DOCKER. WE USE SERVICES. SEE BELOW* - -Pull the image on the agent node: - - -``` -docker pull mobiledgex/mexosagent -``` - -Some preparations are needed. The agent needs proper CA issued certificates as it runs `https` service as well as `grpc` and `rest api`. See the README.md under `acme` directory for more information. The `https` service is reverse proxy for the internal services hosted inside kubernetes clusters in the private network. The `TLS` is terminated at the proxy. This allows for simpler certificate management. Only one certificate is needed for the reverse proxy. The rest of the origin services can run without `TLS` and securely. - -Partly due to the above, the agent needs a proper FQDN in the public DNS service. The code here uses `cloudflare` API to register the FQDN for the agent service. This also simplifies the DNS management. All internal kubernetes DNS names are still available within the kubernetes cluster. There is no need to register individual internal origin services behind the reverse proxy. The reverse proxy allows for path name based routing to backend origin services. This allows for limiting the number of dedicated public IP addresses that are routable on the Internet. Only the reverse proxy needs to have the reserved IP externally exposed. One IP address can be shared among many services. - -Once certficate and key PEM files are available, place them under `certs` directory which should be in the working directory where you run the container. - -``` -$ ls certs -cert.pem key.pem -``` - -Also create a sub directory called `k8sopenstack` and place some environment variables files as described before. -``` -$ ls -a k8sopenstack/ -. .. .k8sopenstack.env .k8sopenstack.os.env .k8sopenstack.toml .k8sopenstack.userdata -``` - - -The agent can then be run as: - -``` -docker run --rm --name proxy -v `pwd`/certs:/var/www/.cache -v /etc/ssl/certs:/etc/ssl/certs -v `pwd`/k8sopenstack:/k8sopenstack --network host -e MEX_K8SOS_ENV=/k8sopenstack/.k8sopenstack.os.env -e MEX_K8SOS_CONFIG=/k8sopenstack/.k8sopenstack.toml -e MEX_K8SOS_USERDATA=/k8sopenstack/.k8sopenstack.userdata --name agent1.medge.gq mobiledgex/mexosagent -debug -``` - -The environment variables `MEX_K8SOS_ENV`, `MEX_K8SOS_CONFIG` and `MEX_K8SOS_USERDATA` are used for provisioning API. - -The `certs` directory is mounted as `/var/www/.cache` inside container. The `k8sopenstack` is mounted inside the container as `/k8sopenstack` to give access to the environment variables to the `mexosagent` running inside the container. - - -## Examples using curl - -The APIs can be accessed via `GRPC` or `HTTP REST API`. Here `curl` based examples are shown. - - -### Cluster provisioning - -To create a kubernetes `mini` cluster for a tenant consisting of total three VM nodes running one k8s master and two k8s nodes: - -``` -curl -sv http://localhost:18889/v1/provision -H "Content-Type: application/json" -d '{"provisions": [{"name":"test-1", "tenant":"tenant-1", "kind":"kubernetes-mini-openstack"}]}' -``` - -This will create three new VMs via openstack nova. The VM instances will boot up and start installation of kubernetes cluster. -You may need to wait a few minutes to see the cluster form. - -To see the VM instances: - -``` -openstack server list -``` - -If the instances are up then you can use ssh to each node to see the progress. Once kubernetes cluster is formed, you can ssh into master node and do: - -``` -kubectl get nodes -``` - - -To destroy the above cluster: - -``` -curl -sv http://localhost:18889/v1/destroy -H "Content-Type: application/json" -d '{"provisions": [{"name":"test-1", "tenant":"tenant-1", "kind":"kubernetes-mini-openstack"}]}' -``` - -### Reverse Proxy - -The agent implements dynamic reverse proxy that can be programmed on the fly via API. - -For example, - -``` -curl http://agent1.medge.gq:18889/v1/proxy -H "Content-Type: application/json" -d '{ "message": "add", "proxies": [ {"path": "/test2", "origin":"http://10.101.101.202:8081" } ] }' -``` - -When this is run from any `curl` enabled machine on Internet, it will direct the agent running on `agent1.medge.gq` machine in the cloudlet to add a reverse proxy for the origin server specified. The origin server here is running inside a kubernetes cluster on a private network. - -This is assuming that there is a HTTP service at port 8081 on node with IP address, within private network, set to 10.101.101.202. -The specifics of the private network settings are known to the client of the Agent. The calling side had previously already requested creation of the cluster with specific parameters. Subseqeuent calls are based on knowledge of the cluster on the caller's side. - -TODO: APIs to query the state of the Agent side, details of clusters, networking setup, current conditions, etc. Helpful when the calling side has to restart or lose all the information on its side. - -After this, another `curl` command can be used to access the origin server via the agent reverse proxy. - -``` -curl https://agent1.medge.gq/test2 -``` - -The origin server is hosted in kubernetes which exposes the service. The service itself may be behind kubernetes internal load balancer which can direct traffic to multiple instances of app deployment (pods). If there is a service running on the origin URL, in this case `http://10.101.101.202:8081`, the response from the origin will be returned to the requester. - - -### Nginx reverse proxy - -Nginx container based L7 and L4 proxy support is available at v1/nginx. - -For example, - -``` -curl http://hawkins.mex-gddt.mobiledgex.net:18889/v1/nginx -d '{"message":"add","name":"test1","ports":[{"mexproto":"LProtoHTTP","external":"8888","internal":"8888","origin":"127.0.0.1:8888","path":"/hello"},{"mexproto":"LProtoTCP","external":"7777","origin":"127.0.0.1:777"},{"mexproto":"LProtoUDP","external":"6666","origin":"127.0.0.1:6666"}]}' -``` - -adds one HTTP proxy which is terminated at port 8888 on the rootLB TLS. Users will access the service at https://example.com:8888. It also adds TCP proxy at 7777 and UDP proxy at 6666. - -``` -curl http://hawkins.mex-gddt.mobiledgex.net:18889/v1/nginx -d '{"message":"list"}' -``` - -Lists currently available nginx proxy container instances. - -``` -curl http://hawkins.mex-gddt.mobiledgex.net:18889/v1/nginx -d '{"message":"delete","name":"test1"}' -``` - -Deletes the nginx proxy instance named tested1. diff --git a/openstack-tenant/agent/api/mexosagent.pb.go b/openstack-tenant/agent/api/mexosagent.pb.go index 4f4515813..3663e9e5c 100644 --- a/openstack-tenant/agent/api/mexosagent.pb.go +++ b/openstack-tenant/agent/api/mexosagent.pb.go @@ -45,7 +45,7 @@ func (m *Provision) Reset() { *m = Provision{} } func (m *Provision) String() string { return proto.CompactTextString(m) } func (*Provision) ProtoMessage() {} func (*Provision) Descriptor() ([]byte, []int) { - return fileDescriptor_mexosagent_5395812191b92a69, []int{0} + return fileDescriptor_mexosagent_9eb18d75628383d9, []int{0} } func (m *Provision) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_Provision.Unmarshal(m, b) @@ -154,7 +154,7 @@ func (m *ProvisionRequest) Reset() { *m = ProvisionRequest{} } func (m *ProvisionRequest) String() string { return proto.CompactTextString(m) } func (*ProvisionRequest) ProtoMessage() {} func (*ProvisionRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_mexosagent_5395812191b92a69, []int{1} + return fileDescriptor_mexosagent_9eb18d75628383d9, []int{1} } func (m *ProvisionRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ProvisionRequest.Unmarshal(m, b) @@ -200,7 +200,7 @@ func (m *ProvisionResponse) Reset() { *m = ProvisionResponse{} } func (m *ProvisionResponse) String() string { return proto.CompactTextString(m) } func (*ProvisionResponse) ProtoMessage() {} func (*ProvisionResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_mexosagent_5395812191b92a69, []int{2} + return fileDescriptor_mexosagent_9eb18d75628383d9, []int{2} } func (m *ProvisionResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ProvisionResponse.Unmarshal(m, b) @@ -245,7 +245,7 @@ func (m *StatusRequest) Reset() { *m = StatusRequest{} } func (m *StatusRequest) String() string { return proto.CompactTextString(m) } func (*StatusRequest) ProtoMessage() {} func (*StatusRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_mexosagent_5395812191b92a69, []int{3} + return fileDescriptor_mexosagent_9eb18d75628383d9, []int{3} } func (m *StatusRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_StatusRequest.Unmarshal(m, b) @@ -286,7 +286,7 @@ func (m *StatusResponse) Reset() { *m = StatusResponse{} } func (m *StatusResponse) String() string { return proto.CompactTextString(m) } func (*StatusResponse) ProtoMessage() {} func (*StatusResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_mexosagent_5395812191b92a69, []int{4} + return fileDescriptor_mexosagent_9eb18d75628383d9, []int{4} } func (m *StatusResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_StatusResponse.Unmarshal(m, b) @@ -347,7 +347,7 @@ func (m *Proxy) Reset() { *m = Proxy{} } func (m *Proxy) String() string { return proto.CompactTextString(m) } func (*Proxy) ProtoMessage() {} func (*Proxy) Descriptor() ([]byte, []int) { - return fileDescriptor_mexosagent_5395812191b92a69, []int{5} + return fileDescriptor_mexosagent_9eb18d75628383d9, []int{5} } func (m *Proxy) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_Proxy.Unmarshal(m, b) @@ -400,7 +400,7 @@ func (m *ProxyRequest) Reset() { *m = ProxyRequest{} } func (m *ProxyRequest) String() string { return proto.CompactTextString(m) } func (*ProxyRequest) ProtoMessage() {} func (*ProxyRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_mexosagent_5395812191b92a69, []int{6} + return fileDescriptor_mexosagent_9eb18d75628383d9, []int{6} } func (m *ProxyRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ProxyRequest.Unmarshal(m, b) @@ -452,7 +452,7 @@ func (m *NginxPort) Reset() { *m = NginxPort{} } func (m *NginxPort) String() string { return proto.CompactTextString(m) } func (*NginxPort) ProtoMessage() {} func (*NginxPort) Descriptor() ([]byte, []int) { - return fileDescriptor_mexosagent_5395812191b92a69, []int{7} + return fileDescriptor_mexosagent_9eb18d75628383d9, []int{7} } func (m *NginxPort) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_NginxPort.Unmarshal(m, b) @@ -542,7 +542,7 @@ func (m *NginxRequest) Reset() { *m = NginxRequest{} } func (m *NginxRequest) String() string { return proto.CompactTextString(m) } func (*NginxRequest) ProtoMessage() {} func (*NginxRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_mexosagent_5395812191b92a69, []int{8} + return fileDescriptor_mexosagent_9eb18d75628383d9, []int{8} } func (m *NginxRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_NginxRequest.Unmarshal(m, b) @@ -602,7 +602,7 @@ func (m *NginxResponse) Reset() { *m = NginxResponse{} } func (m *NginxResponse) String() string { return proto.CompactTextString(m) } func (*NginxResponse) ProtoMessage() {} func (*NginxResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_mexosagent_5395812191b92a69, []int{9} + return fileDescriptor_mexosagent_9eb18d75628383d9, []int{9} } func (m *NginxResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_NginxResponse.Unmarshal(m, b) @@ -636,6 +636,106 @@ func (m *NginxResponse) GetStatus() string { return "" } +type NginxKCPRequest struct { + Message string `protobuf:"bytes,1,opt,name=message" json:"message,omitempty"` + Name string `protobuf:"bytes,2,opt,name=name" json:"name,omitempty"` + Port string `protobuf:"bytes,3,opt,name=port" json:"port,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *NginxKCPRequest) Reset() { *m = NginxKCPRequest{} } +func (m *NginxKCPRequest) String() string { return proto.CompactTextString(m) } +func (*NginxKCPRequest) ProtoMessage() {} +func (*NginxKCPRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_mexosagent_9eb18d75628383d9, []int{10} +} +func (m *NginxKCPRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_NginxKCPRequest.Unmarshal(m, b) +} +func (m *NginxKCPRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_NginxKCPRequest.Marshal(b, m, deterministic) +} +func (dst *NginxKCPRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_NginxKCPRequest.Merge(dst, src) +} +func (m *NginxKCPRequest) XXX_Size() int { + return xxx_messageInfo_NginxKCPRequest.Size(m) +} +func (m *NginxKCPRequest) XXX_DiscardUnknown() { + xxx_messageInfo_NginxKCPRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_NginxKCPRequest proto.InternalMessageInfo + +func (m *NginxKCPRequest) GetMessage() string { + if m != nil { + return m.Message + } + return "" +} + +func (m *NginxKCPRequest) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +func (m *NginxKCPRequest) GetPort() string { + if m != nil { + return m.Port + } + return "" +} + +type NginxKCPResponse struct { + Message string `protobuf:"bytes,1,opt,name=message" json:"message,omitempty"` + Status string `protobuf:"bytes,2,opt,name=status" json:"status,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *NginxKCPResponse) Reset() { *m = NginxKCPResponse{} } +func (m *NginxKCPResponse) String() string { return proto.CompactTextString(m) } +func (*NginxKCPResponse) ProtoMessage() {} +func (*NginxKCPResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_mexosagent_9eb18d75628383d9, []int{11} +} +func (m *NginxKCPResponse) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_NginxKCPResponse.Unmarshal(m, b) +} +func (m *NginxKCPResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_NginxKCPResponse.Marshal(b, m, deterministic) +} +func (dst *NginxKCPResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_NginxKCPResponse.Merge(dst, src) +} +func (m *NginxKCPResponse) XXX_Size() int { + return xxx_messageInfo_NginxKCPResponse.Size(m) +} +func (m *NginxKCPResponse) XXX_DiscardUnknown() { + xxx_messageInfo_NginxKCPResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_NginxKCPResponse proto.InternalMessageInfo + +func (m *NginxKCPResponse) GetMessage() string { + if m != nil { + return m.Message + } + return "" +} + +func (m *NginxKCPResponse) GetStatus() string { + if m != nil { + return m.Status + } + return "" +} + type ProxyResponse struct { Message string `protobuf:"bytes,1,opt,name=message" json:"message,omitempty"` Status string `protobuf:"bytes,2,opt,name=status" json:"status,omitempty"` @@ -648,7 +748,7 @@ func (m *ProxyResponse) Reset() { *m = ProxyResponse{} } func (m *ProxyResponse) String() string { return proto.CompactTextString(m) } func (*ProxyResponse) ProtoMessage() {} func (*ProxyResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_mexosagent_5395812191b92a69, []int{10} + return fileDescriptor_mexosagent_9eb18d75628383d9, []int{12} } func (m *ProxyResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ProxyResponse.Unmarshal(m, b) @@ -695,7 +795,7 @@ func (m *Route) Reset() { *m = Route{} } func (m *Route) String() string { return proto.CompactTextString(m) } func (*Route) ProtoMessage() {} func (*Route) Descriptor() ([]byte, []int) { - return fileDescriptor_mexosagent_5395812191b92a69, []int{11} + return fileDescriptor_mexosagent_9eb18d75628383d9, []int{13} } func (m *Route) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_Route.Unmarshal(m, b) @@ -748,7 +848,7 @@ func (m *RouteRequest) Reset() { *m = RouteRequest{} } func (m *RouteRequest) String() string { return proto.CompactTextString(m) } func (*RouteRequest) ProtoMessage() {} func (*RouteRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_mexosagent_5395812191b92a69, []int{12} + return fileDescriptor_mexosagent_9eb18d75628383d9, []int{14} } func (m *RouteRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_RouteRequest.Unmarshal(m, b) @@ -794,7 +894,7 @@ func (m *RouteResponse) Reset() { *m = RouteResponse{} } func (m *RouteResponse) String() string { return proto.CompactTextString(m) } func (*RouteResponse) ProtoMessage() {} func (*RouteResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_mexosagent_5395812191b92a69, []int{13} + return fileDescriptor_mexosagent_9eb18d75628383d9, []int{15} } func (m *RouteResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_RouteResponse.Unmarshal(m, b) @@ -839,6 +939,8 @@ func init() { proto.RegisterType((*NginxPort)(nil), "api.NginxPort") proto.RegisterType((*NginxRequest)(nil), "api.NginxRequest") proto.RegisterType((*NginxResponse)(nil), "api.NginxResponse") + proto.RegisterType((*NginxKCPRequest)(nil), "api.NginxKCPRequest") + proto.RegisterType((*NginxKCPResponse)(nil), "api.NginxKCPResponse") proto.RegisterType((*ProxyResponse)(nil), "api.ProxyResponse") proto.RegisterType((*Route)(nil), "api.Route") proto.RegisterType((*RouteRequest)(nil), "api.RouteRequest") @@ -862,6 +964,7 @@ type MexOSAgentClient interface { Route(ctx context.Context, in *RouteRequest, opts ...grpc.CallOption) (*RouteResponse, error) Status(ctx context.Context, in *StatusRequest, opts ...grpc.CallOption) (*StatusResponse, error) Nginx(ctx context.Context, in *NginxRequest, opts ...grpc.CallOption) (*NginxResponse, error) + NginxKCP(ctx context.Context, in *NginxKCPRequest, opts ...grpc.CallOption) (*NginxKCPResponse, error) } type mexOSAgentClient struct { @@ -926,6 +1029,15 @@ func (c *mexOSAgentClient) Nginx(ctx context.Context, in *NginxRequest, opts ... return out, nil } +func (c *mexOSAgentClient) NginxKCP(ctx context.Context, in *NginxKCPRequest, opts ...grpc.CallOption) (*NginxKCPResponse, error) { + out := new(NginxKCPResponse) + err := grpc.Invoke(ctx, "/api.MexOSAgent/NginxKCP", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // Server API for MexOSAgent service type MexOSAgentServer interface { @@ -935,6 +1047,7 @@ type MexOSAgentServer interface { Route(context.Context, *RouteRequest) (*RouteResponse, error) Status(context.Context, *StatusRequest) (*StatusResponse, error) Nginx(context.Context, *NginxRequest) (*NginxResponse, error) + NginxKCP(context.Context, *NginxKCPRequest) (*NginxKCPResponse, error) } func RegisterMexOSAgentServer(s *grpc.Server, srv MexOSAgentServer) { @@ -1049,6 +1162,24 @@ func _MexOSAgent_Nginx_Handler(srv interface{}, ctx context.Context, dec func(in return interceptor(ctx, in, info, handler) } +func _MexOSAgent_NginxKCP_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(NginxKCPRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MexOSAgentServer).NginxKCP(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/api.MexOSAgent/NginxKCP", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MexOSAgentServer).NginxKCP(ctx, req.(*NginxKCPRequest)) + } + return interceptor(ctx, in, info, handler) +} + var _MexOSAgent_serviceDesc = grpc.ServiceDesc{ ServiceName: "api.MexOSAgent", HandlerType: (*MexOSAgentServer)(nil), @@ -1077,58 +1208,65 @@ var _MexOSAgent_serviceDesc = grpc.ServiceDesc{ MethodName: "Nginx", Handler: _MexOSAgent_Nginx_Handler, }, + { + MethodName: "NginxKCP", + Handler: _MexOSAgent_NginxKCP_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "api/mexosagent.proto", } -func init() { proto.RegisterFile("api/mexosagent.proto", fileDescriptor_mexosagent_5395812191b92a69) } - -var fileDescriptor_mexosagent_5395812191b92a69 = []byte{ - // 715 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x55, 0xc1, 0x6e, 0x13, 0x3d, - 0x10, 0x56, 0xb2, 0xcd, 0xa6, 0x99, 0x36, 0xfd, 0x5b, 0xff, 0x6d, 0x64, 0x45, 0x1c, 0x2a, 0xab, - 0x87, 0xd2, 0x43, 0x22, 0xca, 0xad, 0xb7, 0x4a, 0x45, 0x20, 0x01, 0xa5, 0x4a, 0x39, 0x72, 0x71, - 0x89, 0xbb, 0x58, 0x4d, 0xec, 0xc5, 0xeb, 0xa4, 0x5b, 0xc4, 0x89, 0x17, 0xe0, 0xc0, 0x85, 0xc7, - 0x42, 0xe2, 0xc0, 0x0b, 0xf0, 0x20, 0xc8, 0xf6, 0xec, 0xb2, 0x1b, 0x01, 0x11, 0xe1, 0xe6, 0xcf, - 0x33, 0xfe, 0xfc, 0xcd, 0x78, 0xbe, 0x5d, 0xd8, 0xe5, 0xa9, 0x1c, 0x4e, 0x45, 0xae, 0x33, 0x9e, - 0x08, 0x65, 0x07, 0xa9, 0xd1, 0x56, 0x93, 0x88, 0xa7, 0xb2, 0x7f, 0x2f, 0xd1, 0x3a, 0x99, 0x88, - 0xa1, 0xcb, 0xe0, 0x4a, 0x69, 0xcb, 0xad, 0xd4, 0x2a, 0x0b, 0x29, 0xec, 0x63, 0x13, 0x3a, 0x17, - 0x46, 0xcf, 0x65, 0x26, 0xb5, 0x22, 0x04, 0xd6, 0x14, 0x9f, 0x0a, 0xda, 0xd8, 0x6f, 0x1c, 0x76, - 0x46, 0x7e, 0x4d, 0x76, 0xa1, 0x25, 0xa7, 0x3c, 0x11, 0xb4, 0xe9, 0x37, 0x03, 0x20, 0x3d, 0x88, - 0xaf, 0x27, 0x7c, 0xae, 0x0d, 0x8d, 0xfc, 0x36, 0x22, 0x42, 0xa1, 0xad, 0x84, 0xbd, 0xd5, 0xe6, - 0x86, 0xae, 0xf9, 0x40, 0x01, 0x5d, 0xe4, 0x5a, 0xe6, 0x62, 0x2c, 0x53, 0xda, 0x0a, 0x11, 0x84, - 0x2e, 0x92, 0x59, 0x6d, 0xdc, 0x1d, 0x71, 0x88, 0x20, 0x74, 0x7a, 0xde, 0x69, 0x25, 0x68, 0x3b, - 0xe8, 0x71, 0x6b, 0x77, 0xb3, 0x15, 0x8a, 0x2b, 0x4b, 0xd7, 0xc3, 0xcd, 0x01, 0x91, 0x3e, 0xac, - 0x4f, 0x85, 0xe5, 0x63, 0x6e, 0x39, 0xed, 0xf8, 0x48, 0x89, 0xdd, 0x19, 0x23, 0x12, 0xa9, 0x15, - 0x85, 0x70, 0x26, 0x20, 0xc7, 0x7f, 0x23, 0xd5, 0x98, 0x6e, 0x04, 0x7e, 0xb7, 0x66, 0xaf, 0x60, - 0xbb, 0x6c, 0xc8, 0x48, 0xbc, 0x9d, 0x89, 0xcc, 0x3a, 0x85, 0x53, 0x91, 0xb9, 0xde, 0x62, 0x6b, - 0x0a, 0x48, 0x06, 0x00, 0x69, 0x91, 0x9d, 0xd1, 0xe6, 0x7e, 0x74, 0xb8, 0x71, 0xbc, 0x35, 0xe0, - 0xa9, 0x1c, 0xfc, 0x24, 0xa9, 0x64, 0xb0, 0x47, 0xb0, 0x53, 0x61, 0xcf, 0x52, 0xad, 0x32, 0xf1, - 0x07, 0xfa, 0x1e, 0xc4, 0x99, 0xe5, 0x76, 0x96, 0x61, 0xf7, 0x11, 0xb1, 0xfb, 0xd0, 0xbd, 0xf4, - 0xab, 0xa5, 0x0a, 0xd9, 0xe7, 0x06, 0x6c, 0x15, 0xb9, 0xab, 0xde, 0x47, 0x0e, 0xa0, 0x9d, 0x1a, - 0x9d, 0x4b, 0x91, 0xd1, 0xc8, 0xd7, 0x08, 0x45, 0x8d, 0xf9, 0xdd, 0xa8, 0x08, 0x2d, 0x34, 0x63, - 0x6d, 0x69, 0x33, 0x1e, 0x43, 0xcb, 0x33, 0xfc, 0x72, 0xee, 0x7a, 0x10, 0x6b, 0x23, 0x13, 0xa9, - 0x0a, 0x29, 0x01, 0xb9, 0xdc, 0x94, 0xdb, 0x37, 0x38, 0x77, 0x7e, 0xcd, 0xce, 0x61, 0x33, 0x48, - 0x59, 0xfa, 0x5e, 0x95, 0x42, 0x9a, 0xbf, 0x2d, 0x84, 0x7d, 0x6b, 0x40, 0xe7, 0x3c, 0x91, 0x2a, - 0xbf, 0xd0, 0xc6, 0xfe, 0xab, 0x3a, 0x37, 0x99, 0x22, 0xb7, 0xc2, 0x28, 0x3e, 0x41, 0x53, 0x94, - 0xd8, 0xc5, 0xbc, 0x11, 0x5f, 0xeb, 0x09, 0xda, 0xa2, 0xc4, 0x61, 0xa2, 0x73, 0x0f, 0xd1, 0x18, - 0x25, 0x76, 0x31, 0x23, 0xa6, 0xda, 0x0a, 0x99, 0xa2, 0x3b, 0x4a, 0xec, 0x62, 0x52, 0xe1, 0x7d, - 0xc1, 0x23, 0x25, 0x66, 0xef, 0x61, 0xd3, 0x17, 0xb6, 0xbc, 0x53, 0x45, 0xd5, 0xcd, 0x4a, 0xd5, - 0x15, 0x77, 0x47, 0x75, 0x77, 0x1f, 0x40, 0x2b, 0xd5, 0xc6, 0xd6, 0x5f, 0xbd, 0x6c, 0xe1, 0x28, - 0x04, 0xd9, 0x29, 0x74, 0xf1, 0xf6, 0x95, 0x27, 0xff, 0x14, 0xba, 0xf8, 0xd4, 0x2b, 0x53, 0x3c, - 0x85, 0xd6, 0x48, 0xcf, 0x6c, 0x48, 0x98, 0x5d, 0x29, 0x61, 0xf1, 0x24, 0x22, 0x47, 0x99, 0x70, - 0x2b, 0x6e, 0xf9, 0x1d, 0x9e, 0x2c, 0x20, 0xd9, 0x86, 0x68, 0x2c, 0xe6, 0x58, 0xbc, 0x5b, 0xb2, - 0x67, 0xb0, 0xe9, 0xc9, 0x96, 0x37, 0x94, 0x41, 0x6c, 0x5c, 0x66, 0x7d, 0xf2, 0xc2, 0x61, 0x8c, - 0xb8, 0xea, 0x90, 0x6d, 0xd5, 0xea, 0x8e, 0xbf, 0x44, 0x00, 0xcf, 0x45, 0xfe, 0xe2, 0xf2, 0xd4, - 0xfd, 0x09, 0xc8, 0xcb, 0xea, 0xf7, 0x7d, 0x6f, 0xc1, 0x8c, 0x41, 0x73, 0xbf, 0xb7, 0xb8, 0x1d, - 0x2e, 0x67, 0xf4, 0xc3, 0xd7, 0xef, 0x9f, 0x9a, 0x84, 0x75, 0x87, 0xf3, 0x07, 0xc3, 0xd2, 0xb7, - 0x27, 0x8d, 0x23, 0x72, 0x01, 0xed, 0x33, 0x91, 0x59, 0xa3, 0xef, 0xfe, 0x96, 0xb3, 0xe7, 0x39, - 0xb7, 0xd9, 0x86, 0xe3, 0x1c, 0x07, 0x0e, 0xc7, 0x78, 0x56, 0x7c, 0x0b, 0x76, 0x2a, 0x86, 0x44, - 0x2e, 0x52, 0xdd, 0x42, 0x9e, 0x5d, 0xcf, 0xb3, 0xc5, 0x3a, 0xa8, 0x2d, 0x2f, 0x58, 0xc2, 0xd3, - 0xee, 0x54, 0x9a, 0x5b, 0x63, 0xa9, 0xb5, 0xb7, 0xce, 0xe2, 0xdf, 0xc0, 0xb1, 0x3c, 0x81, 0x38, - 0x7c, 0x31, 0x49, 0x38, 0x53, 0xfb, 0xd4, 0xf6, 0xff, 0xaf, 0xed, 0x21, 0xd1, 0x9e, 0x27, 0xfa, - 0x8f, 0x81, 0x23, 0x0a, 0x2f, 0x81, 0x7a, 0xfc, 0xc0, 0xa3, 0x9e, 0xaa, 0xf5, 0x50, 0x4f, 0xcd, - 0x0f, 0x75, 0x3d, 0xca, 0x85, 0x4e, 0x1a, 0x47, 0x57, 0xb1, 0xf7, 0xfc, 0xc3, 0x1f, 0x01, 0x00, - 0x00, 0xff, 0xff, 0x71, 0x56, 0xaa, 0x68, 0xe6, 0x07, 0x00, 0x00, +func init() { proto.RegisterFile("api/mexosagent.proto", fileDescriptor_mexosagent_9eb18d75628383d9) } + +var fileDescriptor_mexosagent_9eb18d75628383d9 = []byte{ + // 768 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x95, 0xcd, 0x6e, 0x13, 0x3b, + 0x14, 0xc7, 0x95, 0xef, 0xe6, 0xb4, 0x69, 0x53, 0xdf, 0x34, 0x1a, 0x45, 0x77, 0x51, 0x59, 0x5d, + 0xf4, 0x56, 0xba, 0x89, 0x6e, 0xef, 0xae, 0xbb, 0x8a, 0x22, 0x90, 0x0a, 0x25, 0xa4, 0x2c, 0xd9, + 0xb8, 0x8d, 0x3b, 0x58, 0x4d, 0xec, 0xc1, 0xe3, 0xa4, 0x53, 0xc4, 0x8a, 0x17, 0x60, 0xc1, 0x86, + 0x3d, 0x8f, 0xc4, 0x82, 0x17, 0xe0, 0x41, 0xd0, 0xb1, 0x3d, 0x93, 0x99, 0xa8, 0x10, 0x11, 0x76, + 0xfe, 0xfb, 0xd8, 0x3f, 0x9f, 0x0f, 0x1f, 0x1b, 0x3a, 0x2c, 0x12, 0x83, 0x29, 0x4f, 0x54, 0xcc, + 0x42, 0x2e, 0x4d, 0x3f, 0xd2, 0xca, 0x28, 0x52, 0x61, 0x91, 0xe8, 0xfd, 0x1d, 0x2a, 0x15, 0x4e, + 0xf8, 0x00, 0x57, 0x30, 0x29, 0x95, 0x61, 0x46, 0x28, 0x19, 0xbb, 0x25, 0xf4, 0x63, 0x19, 0x9a, + 0x43, 0xad, 0xe6, 0x22, 0x16, 0x4a, 0x12, 0x02, 0x55, 0xc9, 0xa6, 0x3c, 0x28, 0xed, 0x97, 0x0e, + 0x9b, 0x23, 0x3b, 0x26, 0x1d, 0xa8, 0x89, 0x29, 0x0b, 0x79, 0x50, 0xb6, 0x93, 0x4e, 0x90, 0x2e, + 0xd4, 0x6f, 0x26, 0x6c, 0xae, 0x74, 0x50, 0xb1, 0xd3, 0x5e, 0x91, 0x00, 0x1a, 0x92, 0x9b, 0x3b, + 0xa5, 0x6f, 0x83, 0xaa, 0x35, 0xa4, 0x12, 0x2d, 0x37, 0x22, 0xe1, 0x63, 0x11, 0x05, 0x35, 0x67, + 0xf1, 0x12, 0x2d, 0xb1, 0x51, 0x1a, 0xcf, 0xa8, 0x3b, 0x8b, 0x97, 0xe8, 0xcf, 0x3b, 0x25, 0x79, + 0xd0, 0x70, 0xfe, 0xe0, 0x18, 0x4f, 0x36, 0x5c, 0x32, 0x69, 0x82, 0x0d, 0x77, 0xb2, 0x53, 0xa4, + 0x07, 0x1b, 0x53, 0x6e, 0xd8, 0x98, 0x19, 0x16, 0x34, 0xad, 0x25, 0xd3, 0xb8, 0x47, 0xf3, 0x50, + 0x28, 0x19, 0x80, 0xdb, 0xe3, 0x14, 0xf2, 0x6f, 0x85, 0x1c, 0x07, 0x9b, 0x8e, 0x8f, 0x63, 0xfa, + 0x1a, 0xda, 0x59, 0x42, 0x46, 0xfc, 0xed, 0x8c, 0xc7, 0x06, 0x3d, 0x9c, 0xf2, 0x18, 0x73, 0xeb, + 0x53, 0x93, 0x4a, 0xd2, 0x07, 0x88, 0xd2, 0xd5, 0x71, 0x50, 0xde, 0xaf, 0x1c, 0x6e, 0x1e, 0x6f, + 0xf7, 0x59, 0x24, 0xfa, 0x0b, 0x48, 0x6e, 0x05, 0x7d, 0x0c, 0xbb, 0x39, 0x7a, 0x1c, 0x29, 0x19, + 0xf3, 0x5f, 0xe0, 0xbb, 0x50, 0x8f, 0x0d, 0x33, 0xb3, 0xd8, 0x67, 0xdf, 0x2b, 0xfa, 0x0f, 0xb4, + 0x2e, 0xed, 0x68, 0xa5, 0x87, 0xf4, 0x73, 0x09, 0xb6, 0xd3, 0xb5, 0xeb, 0x9e, 0x47, 0x0e, 0xa0, + 0x11, 0x69, 0x95, 0x08, 0x1e, 0x07, 0x15, 0x1b, 0x23, 0xa4, 0x31, 0x26, 0xf7, 0xa3, 0xd4, 0xb4, + 0x94, 0x8c, 0xea, 0xca, 0x64, 0x3c, 0x81, 0x9a, 0x25, 0x3c, 0x78, 0xef, 0xba, 0x50, 0x57, 0x5a, + 0x84, 0x42, 0xa6, 0xae, 0x38, 0x85, 0x6b, 0x23, 0x66, 0xde, 0xf8, 0x7b, 0x67, 0xc7, 0xf4, 0x02, + 0xb6, 0x9c, 0x2b, 0x2b, 0xeb, 0x95, 0x0b, 0xa4, 0xfc, 0xd3, 0x40, 0xe8, 0xb7, 0x12, 0x34, 0x2f, + 0x42, 0x21, 0x93, 0xa1, 0xd2, 0xe6, 0x4f, 0xbd, 0xc3, 0x9b, 0xc9, 0x13, 0xc3, 0xb5, 0x64, 0x13, + 0xdf, 0x14, 0x99, 0x46, 0x9b, 0x6d, 0xc4, 0x6b, 0x35, 0xf1, 0x6d, 0x91, 0x69, 0x77, 0xa3, 0x13, + 0x2b, 0x7d, 0x63, 0x64, 0x1a, 0x6d, 0x9a, 0x4f, 0x95, 0xe1, 0x22, 0xf2, 0xdd, 0x91, 0x69, 0xb4, + 0x09, 0xe9, 0xcf, 0x73, 0x3d, 0x92, 0x69, 0xfa, 0x1e, 0xb6, 0x6c, 0x60, 0xab, 0x33, 0x95, 0x46, + 0x5d, 0xce, 0x45, 0x9d, 0xeb, 0xee, 0x4a, 0xb1, 0xbb, 0x0f, 0xa0, 0x16, 0x29, 0x6d, 0x8a, 0x55, + 0xcf, 0x52, 0x38, 0x72, 0x46, 0x7a, 0x0a, 0x2d, 0x7f, 0xfa, 0xda, 0x37, 0xff, 0x12, 0x76, 0x2c, + 0xe2, 0xfc, 0xd1, 0x70, 0xbd, 0x18, 0xb0, 0x42, 0x4a, 0x9b, 0xac, 0x42, 0x4a, 0x1b, 0x7a, 0x06, + 0xed, 0x05, 0x74, 0x6d, 0xd7, 0x4e, 0xa1, 0xe5, 0x6f, 0xe1, 0xda, 0x88, 0x73, 0xa8, 0x8d, 0xd4, + 0xcc, 0xb8, 0x05, 0xb3, 0x2b, 0xc9, 0x8d, 0xdf, 0xe9, 0x15, 0x22, 0x43, 0x66, 0xf8, 0x1d, 0xbb, + 0xf7, 0x3b, 0x53, 0x49, 0xda, 0x50, 0x19, 0xf3, 0xb9, 0x0f, 0x0b, 0x87, 0xf4, 0x19, 0x6c, 0x59, + 0xd8, 0xea, 0x3c, 0x51, 0xa8, 0x6b, 0x5c, 0x59, 0x6c, 0x0a, 0xb7, 0xd9, 0x5b, 0x30, 0x3a, 0x4f, + 0x5b, 0x37, 0xba, 0xe3, 0x2f, 0x55, 0x80, 0xe7, 0x3c, 0x79, 0x71, 0x79, 0x8a, 0x9f, 0x14, 0x79, + 0x95, 0xff, 0x7a, 0xf6, 0x96, 0xde, 0x09, 0xe7, 0x73, 0xaf, 0xbb, 0x3c, 0xed, 0x0e, 0xa7, 0xc1, + 0x87, 0xaf, 0xdf, 0x3f, 0x95, 0x09, 0x6d, 0x0d, 0xe6, 0xff, 0x0d, 0xb2, 0x27, 0xe5, 0xa4, 0x74, + 0x44, 0x86, 0xd0, 0x38, 0xe3, 0xb1, 0xd1, 0xea, 0xfe, 0x77, 0x99, 0x5d, 0xcb, 0x6c, 0xd3, 0x4d, + 0x64, 0x8e, 0x1d, 0x03, 0x89, 0x67, 0xe9, 0x33, 0xb5, 0x9b, 0x7b, 0x2b, 0x3c, 0x8b, 0xe4, 0xa7, + 0x3c, 0xa7, 0x63, 0x39, 0xdb, 0xb4, 0xe9, 0x7d, 0x4b, 0x52, 0x8a, 0x2b, 0xed, 0x6e, 0x2e, 0xb9, + 0x05, 0x4a, 0x21, 0xbd, 0x45, 0x8a, 0xad, 0x01, 0x52, 0x9e, 0x42, 0xdd, 0x3d, 0xe6, 0xc4, 0xed, + 0x29, 0xfc, 0x02, 0xbd, 0xbf, 0x0a, 0x73, 0x1e, 0xb4, 0x67, 0x41, 0x3b, 0x14, 0x10, 0xe4, 0x2a, + 0xe1, 0xfd, 0xb1, 0x77, 0xde, 0xfb, 0x93, 0x7f, 0x15, 0xbc, 0x3f, 0x85, 0x56, 0x2d, 0xfa, 0x23, + 0xd1, 0x84, 0x94, 0x97, 0xb0, 0x91, 0x76, 0x0e, 0xe9, 0x2c, 0x76, 0x2d, 0xba, 0xb3, 0xb7, 0xb7, + 0x34, 0xfb, 0x50, 0x01, 0x2d, 0xee, 0xdf, 0xdb, 0xeb, 0xe8, 0xa4, 0x74, 0x74, 0x55, 0xb7, 0x2f, + 0xdc, 0xff, 0x3f, 0x02, 0x00, 0x00, 0xff, 0xff, 0xc3, 0x44, 0x72, 0xaa, 0xd4, 0x08, 0x00, 0x00, } diff --git a/openstack-tenant/agent/api/mexosagent.pb.gw.go b/openstack-tenant/agent/api/mexosagent.pb.gw.go index d827ea526..c305bf658 100644 --- a/openstack-tenant/agent/api/mexosagent.pb.gw.go +++ b/openstack-tenant/agent/api/mexosagent.pb.gw.go @@ -106,6 +106,19 @@ func request_MexOSAgent_Nginx_0(ctx context.Context, marshaler runtime.Marshaler } +func request_MexOSAgent_NginxKCP_0(ctx context.Context, marshaler runtime.Marshaler, client MexOSAgentClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq NginxKCPRequest + var metadata runtime.ServerMetadata + + if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.NginxKCP(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + // RegisterMexOSAgentHandlerFromEndpoint is same as RegisterMexOSAgentHandler but // automatically dials to "endpoint" and closes the connection when "ctx" gets done. func RegisterMexOSAgentHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) { @@ -318,6 +331,35 @@ func RegisterMexOSAgentHandlerClient(ctx context.Context, mux *runtime.ServeMux, }) + mux.Handle("POST", pattern_MexOSAgent_NginxKCP_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + 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, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_MexOSAgent_NginxKCP_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_MexOSAgent_NginxKCP_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + return nil } @@ -333,6 +375,8 @@ var ( pattern_MexOSAgent_Status_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "status"}, "")) pattern_MexOSAgent_Nginx_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "nginx"}, "")) + + pattern_MexOSAgent_NginxKCP_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "nginx-kcp"}, "")) ) var ( @@ -347,4 +391,6 @@ var ( forward_MexOSAgent_Status_0 = runtime.ForwardResponseMessage forward_MexOSAgent_Nginx_0 = runtime.ForwardResponseMessage + + forward_MexOSAgent_NginxKCP_0 = runtime.ForwardResponseMessage ) diff --git a/openstack-tenant/agent/api/mexosagent.proto b/openstack-tenant/agent/api/mexosagent.proto index 5c39e1e59..d18741104 100644 --- a/openstack-tenant/agent/api/mexosagent.proto +++ b/openstack-tenant/agent/api/mexosagent.proto @@ -45,6 +45,13 @@ service MexOSAgent { body: "*" }; } + + rpc NginxKCP(NginxKCPRequest) returns (NginxKCPResponse) { + option (google.api.http) = { + post: "/v1/nginx-kcp", + body: "*" + }; + } } message Provision { @@ -116,6 +123,17 @@ message NginxResponse { string status = 2; } +message NginxKCPRequest { + string message = 1; + string name = 2; + string port = 3; +} + +message NginxKCPResponse { + string message = 1; + string status = 2; +} + message ProxyResponse { string message = 1; string status = 2; diff --git a/openstack-tenant/agent/api/mexosagent.swagger.json b/openstack-tenant/agent/api/mexosagent.swagger.json index f2d7b0669..7e6201377 100644 --- a/openstack-tenant/agent/api/mexosagent.swagger.json +++ b/openstack-tenant/agent/api/mexosagent.swagger.json @@ -20,7 +20,7 @@ "operationId": "Destroy", "responses": { "200": { - "description": "", + "description": "A successful response.", "schema": { "$ref": "#/definitions/apiProvisionResponse" } @@ -46,7 +46,7 @@ "operationId": "Nginx", "responses": { "200": { - "description": "", + "description": "A successful response.", "schema": { "$ref": "#/definitions/apiNginxResponse" } @@ -67,12 +67,38 @@ ] } }, + "/v1/nginx-kcp": { + "post": { + "operationId": "NginxKCP", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/apiNginxKCPResponse" + } + } + }, + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/apiNginxKCPRequest" + } + } + ], + "tags": [ + "MexOSAgent" + ] + } + }, "/v1/provision": { "post": { "operationId": "Provision", "responses": { "200": { - "description": "", + "description": "A successful response.", "schema": { "$ref": "#/definitions/apiProvisionResponse" } @@ -98,7 +124,7 @@ "operationId": "Proxy", "responses": { "200": { - "description": "", + "description": "A successful response.", "schema": { "$ref": "#/definitions/apiProxyResponse" } @@ -124,7 +150,7 @@ "operationId": "Route", "responses": { "200": { - "description": "", + "description": "A successful response.", "schema": { "$ref": "#/definitions/apiRouteResponse" } @@ -150,7 +176,7 @@ "operationId": "Status", "responses": { "200": { - "description": "", + "description": "A successful response.", "schema": { "$ref": "#/definitions/apiStatusResponse" } @@ -173,6 +199,31 @@ } }, "definitions": { + "apiNginxKCPRequest": { + "type": "object", + "properties": { + "message": { + "type": "string" + }, + "name": { + "type": "string" + }, + "port": { + "type": "string" + } + } + }, + "apiNginxKCPResponse": { + "type": "object", + "properties": { + "message": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, "apiNginxPort": { "type": "object", "properties": { @@ -211,6 +262,9 @@ "name": { "type": "string" }, + "network": { + "type": "string" + }, "ports": { "type": "array", "items": { diff --git a/openstack-tenant/agent/server/handlers.go b/openstack-tenant/agent/server/handlers.go index eda80c6e1..4fc119a59 100644 --- a/openstack-tenant/agent/server/handlers.go +++ b/openstack-tenant/agent/server/handlers.go @@ -8,11 +8,12 @@ import ( "net/http/httputil" "net/url" "os" + "strconv" "strings" "text/template" "time" - "github.com/codeskyblue/go-sh" + sh "github.com/codeskyblue/go-sh" "github.com/julienschmidt/httprouter" "github.com/mobiledgex/edge-cloud-infra/k8s-prov/k8sopenstack" "github.com/mobiledgex/edge-cloud-infra/openstack-tenant/agent/api" @@ -27,6 +28,9 @@ type Server struct{} var proxyMap = make(map[string]string) +const lbproxySuffix = "-nginx-lbproxy" +const kcproxySuffix = "-nginx-kcproxy" + var supportProvisioning = false func init() { @@ -220,7 +224,7 @@ func delOrigin(path, origin string) error { //Status returns status information of the kubernetes cluster on openstack for a given tenant func (srv *Server) Status(ctx context.Context, req *api.StatusRequest) (res *api.StatusResponse, err error) { res = &api.StatusResponse{ - Message: "OK", + Message: "OK, version January, 2019", } return res, nil @@ -327,6 +331,7 @@ func GetNewRouter() *httprouter.Router { func (srv *Server) Nginx(ctx context.Context, req *api.NginxRequest) (res *api.NginxResponse, err error) { log.Debugln("Received Nginx request", "name", req.Name, "network", req.Network, "ports", req.Ports) if req.Message == "add" { + //TODO more req.XXX validation if len(req.Ports) < 1 { res = &api.NginxResponse{Message: fmt.Sprintf("Error, missing ports"), Status: "Error"} return res, fmt.Errorf("missing ports definitions") @@ -380,6 +385,7 @@ func CreateNginx(name string, network string, ports []*api.NginxPort) error { log.Debugln("can't get cwd", err) return err } + name = name + lbproxySuffix dir := pwd + "/nginx/" + name err = os.MkdirAll(dir, 0755) if err != nil { @@ -427,6 +433,7 @@ func CreateNginx(name string, network string, ports []*api.NginxPort) error { } cmdArgs := []string{"run", "-d", "--rm", "--name", name} + //TODO fix bad network handling if network != "" { // when runnning in DIND it cannot use host mode and so must expose the ports cmdArgs = append(cmdArgs, "--network", network) @@ -438,7 +445,6 @@ func CreateNginx(name string, network string, ports []*api.NginxPort) error { cmdArgs = append(cmdArgs, "--net=host") } cmdArgs = append(cmdArgs, []string{"-v", defaultConf + ":/etc/nginx/conf.d/default.conf", "-v", dir + ":/var/www/.cache", "-v", "/etc/ssl/certs:/etc/ssl/certs", "-v", pwd + "/cert.pem:/etc/ssl/certs/server.crt", "-v", pwd + "/key.pem:/etc/ssl/certs/server.key", "-v", errlogFile + ":/var/log/nginx/error.log", "-v", nconfName + ":/etc/nginx/nginx.conf", "nginx"}...) - fmt.Printf("Nginx command args %+v\n", cmdArgs) out, err := sh.Command("docker", cmdArgs).CombinedOutput() if err != nil { @@ -573,7 +579,7 @@ func createNginxDefaultConf(confname, name string, ports []*api.NginxPort) (*str return nil, fmt.Errorf("cannot reserve nginx http port") } dc := &DefaultConf{Port: port, Name: name} - tmpl, err := template.New("defaultnginxconf").Parse(nginxDefaultConfTmpl) + tmpl, err := template.New("defaultnginxconf").Parse(nginxDefaultConfTmpl) //TODO consider removing this if err != nil { return nil, err } @@ -653,6 +659,8 @@ func writeFile(confname string, confbytes []byte) error { } func DeleteNginx(name string) error { + log.Debugln("deleting nginx containers", name) + name = name + lbproxySuffix out, err := sh.Command("docker", "kill", name).Output() if err != nil { return fmt.Errorf("can't kill nginx container %s, %s, %v", name, out, err) @@ -662,12 +670,189 @@ func DeleteNginx(name string) error { } func ListNginx() ([]string, error) { - out, err := sh.Command("docker", "ps", "--format", "'{{.Names}}'").Output() + log.Debugln("listing nginx containers") + out, err := sh.Command("docker", "ps", "--filter", "name="+lbproxySuffix, "--format", "'{{.Names}}'").Output() //TODO filter on name pattern if err != nil { - return nil, fmt.Errorf("can't list nginx container %s, %v", out, err) + return nil, fmt.Errorf("can't list nginx containers, %s, %v", out, err) } outstr := string(out) log.Debugln("list of nginx containers", outstr) names := strings.Split(outstr, "\n") return names, nil } + +func (srv *Server) NginxKCP(ctx context.Context, req *api.NginxKCPRequest) (res *api.NginxKCPResponse, err error) { + log.Debugln("Received Nginx KCP request", "name", req.Name, "port", req.Port) + if req.Message == "add" { + if req.Name == "" { + res = &api.NginxKCPResponse{Message: fmt.Sprintf("Error, missing name"), Status: "Error"} + return res, fmt.Errorf("missing name") + } + if req.Port == "" { + res = &api.NginxKCPResponse{Message: fmt.Sprintf("Error, missing port"), Status: "Error"} + return res, fmt.Errorf("missing port") + } + aerr := CreateNginxKCP(req.Name, req.Port) + if aerr != nil { + res = &api.NginxKCPResponse{Message: fmt.Sprintf("Error, cannot create Nginx KCP, name %s, port %s", req.Name, req.Port), Status: "Error"} + return res, aerr + } + } else if req.Message == "list" { + names, err := ListNginxKCP() + if err != nil { + res = &api.NginxKCPResponse{Message: fmt.Sprintf("cannot get list of nginx KCP instances, %v", err), Status: "Error"} + return res, err + } + res = &api.NginxKCPResponse{Message: req.Message, Status: fmt.Sprintf("%v", names)} + return res, nil + } else if req.Message == "delete" { + berr := DeleteNginxKCP(req.Name) + if berr != nil { + res = &api.NginxKCPResponse{Message: fmt.Sprintf("Error, cannot delete Nginx KCP, name %s, port %s", req.Name, req.Port), Status: "Error"} + return res, berr + } + } else { + //TODO + res = &api.NginxKCPResponse{Message: fmt.Sprintf("Error, invalid request %s", req.Message), Status: "Error"} + return res, fmt.Errorf("invalid request") + } + + res = &api.NginxKCPResponse{ + Message: "OK", + } + return res, nil +} + +func CreateNginxKCP(name string, port string) error { + log.Debugln("create nginx kubectl proxy", "name", name, "port", port) + pwd, err := os.Getwd() + if err != nil { + log.Debugln("can't get cwd", err) + return err + } + name = name + kcproxySuffix + dir := pwd + "/nginx/" + name + err = os.MkdirAll(dir, 0755) + if err != nil { + log.Debugln("can't create dir", dir, err) + return err + } + + if !fileExists(pwd + "/cert.pem") { + log.Debugln("cert.pem does not exist") + return fmt.Errorf("while creating nginx kubectl proxy %s, cert.pem does not exist", name) + } + if !fileExists(pwd + "/key.pem") { + log.Debugln("key.pem does not exist") + return fmt.Errorf("while creating nginx kubectl proxy %s, key.pem does not exist", name) + } + htpasswdFn := "/nginx.htpasswd" + nginxHTPasswd := pwd + htpasswdFn + if !fileExists(nginxHTPasswd) { + nginxHTPasswd = "/home/ubuntu" + htpasswdFn + if !fileExists(nginxHTPasswd) { + return fmt.Errorf("no htpasswd file") + } + } + //TODO generate htpasswd file with contents from vault per cluster + nconfName := dir + "/nginx.conf" + portnum, err := strconv.Atoi(port) + if err != nil { + log.Debugln("invalid port", port) + return err + } + _, err = createNginxKCPConf(nconfName, name, portnum) + if err != nil { + log.Debugln("while creating nginx proxy, can't create conf", name) + return err + } + log.Debugln("created nginx conf", nconfName) + + cmdArgs := []string{"run", "-d", "--rm", "--net", "host", "--name", name} + cmdArgs = append(cmdArgs, []string{"-v", dir + ":/var/www/.cache", "-v", nginxHTPasswd + ":/etc/nginx/conf.d" + htpasswdFn, "-v", "/etc/ssl/certs:/etc/ssl/certs", "-v", pwd + "/cert.pem:/etc/nginx/conf.d/cert.pem", "-v", pwd + "/key.pem:/etc/nginx/conf.d/key.pem", "-v", dir + ":/var/log/nginx", "-v", nconfName + ":/etc/nginx/nginx.conf", "nginx:alpine"}...) + log.Debugln("cmdArgs", cmdArgs) + //XXX nginx:alpine for htpasswd to work + out, err := sh.Command("docker", cmdArgs).CombinedOutput() + if err != nil { + return fmt.Errorf("can't create nginx kubectl proxy container %s, %s, %v", name, out, err) + } + //TODO check vitality of the created container instance + log.Debugln("created nginx kubectl proxy container", name) + return nil +} + +func DeleteNginxKCP(name string) error { + name = name + kcproxySuffix + log.Debugln("deleting nginx kubectl proxy container", name) + out, err := sh.Command("docker", "kill", name).Output() + if err != nil { + return fmt.Errorf("can't kill nginx kubectl proxy container %s, %s, %v", name, out, err) + } + log.Debugln("deleted nginx kubectl proxy container", name) + return nil +} + +func ListNginxKCP() ([]string, error) { + log.Debugln("listing nginx kubectl proxy containers") + out, err := sh.Command("docker", "ps", "--filter", "name="+kcproxySuffix, "--format", "'{{.Names}}'").Output() //TODO filter on name pattern + if err != nil { + return nil, fmt.Errorf("can't list nginx KCP containers, %s, %v", out, err) + } + outstr := string(out) + log.Debugln("list of nginx kubectl proxy containers", outstr) + names := strings.Split(outstr, "\n") + return names, nil +} + +var nginxKCPConfTmpl = ` +worker_processes 2; + +events { + worker_connections 100; +} + +error_log /var/log/nginx/error.log debug; + +http { + server { + listen {{.Port}} ssl; + server_name {{.Name}}; + + ssl_certificate /etc/nginx/conf.d/cert.pem; + ssl_certificate_key /etc/nginx/conf.d/key.pem; + + auth_basic "restricted"; + auth_basic_user_file /etc/nginx/conf.d/nginx.htpasswd; + + location / { + proxy_pass http://127.0.0.1:{{.PortKCP}}/; + } + } +} +` + +type nginxKCPSpec struct { + Name string + Port int + PortKCP int +} + +func createNginxKCPConf(confname, name string, port int) (*string, error) { + log.Debugln("create nginx kubectl proxy conf", confname, name, port) + tmpl, err := template.New("nginxconf").Parse(nginxKCPConfTmpl) + if err != nil { + return nil, err + } + var outbuffer bytes.Buffer + err = tmpl.Execute(&outbuffer, &nginxKCPSpec{Name: name, Port: port, PortKCP: port - 1}) + if err != nil { + return nil, err + } + confbytes := outbuffer.Bytes() + err = writeFile(confname, confbytes) + if err != nil { + return nil, err + } + confstr := string(confbytes) + return &confstr, nil +} diff --git a/openstack-tenant/agent/server/server.go b/openstack-tenant/agent/server/server.go index e411e4e47..9a897060c 100644 --- a/openstack-tenant/agent/server/server.go +++ b/openstack-tenant/agent/server/server.go @@ -17,6 +17,7 @@ import ( func ListenAndServeGRPC(address string) error { opts := []grpc.ServerOption{} grpcServer := grpc.NewServer(opts...) + //s := api.MexOSAgentServer{} s := Server{} api.RegisterMexOSAgentServer(grpcServer, &s) @@ -32,6 +33,8 @@ func headerMatcher(headerName string) (string, bool) { return strings.ToLower(headerName), true } +//TODO need a separate service that monitors mexosagent and revives it + //ListenAndServeREST serves HTTP/REST API via GRPC mux func ListenAndServeREST(restAddress, grpcAddress string) error { ctx := context.Background()