From e0c9da5d959336bc43127433c7ad712e83d8bd57 Mon Sep 17 00:00:00 2001 From: Rita Zhang Date: Mon, 11 Dec 2017 20:25:54 -0800 Subject: [PATCH 01/18] Enable kubectl logs po --- providers/azure/aci.go | 50 +++++++++++++++++++++++++++++++++++- providers/hypersh/hypersh.go | 11 ++++++++ vkubelet/apiserver.go | 50 ++++++++++++++++++++++++++++++++++++ vkubelet/provider.go | 9 ++++++- vkubelet/vkubelet.go | 6 ++++- 5 files changed, 123 insertions(+), 3 deletions(-) create mode 100644 vkubelet/apiserver.go diff --git a/providers/azure/aci.go b/providers/azure/aci.go index 76c3038a3..ef2301419 100644 --- a/providers/azure/aci.go +++ b/providers/azure/aci.go @@ -31,6 +31,7 @@ type ACIProvider struct { cpu string memory string pods string + internalIP string } // AuthConfig is the secret returned from an ImageRegistryCredential @@ -45,7 +46,7 @@ type AuthConfig struct { } // NewACIProvider creates a new ACIProvider. -func NewACIProvider(config string, rm *manager.ResourceManager, nodeName, operatingSystem string) (*ACIProvider, error) { +func NewACIProvider(config string, rm *manager.ResourceManager, nodeName, operatingSystem string, internalIP string) (*ACIProvider, error) { var p ACIProvider var err error @@ -89,6 +90,7 @@ func NewACIProvider(config string, rm *manager.ResourceManager, nodeName, operat p.operatingSystem = operatingSystem p.nodeName = nodeName + p.internalIP = internalIP return &p, err } @@ -193,6 +195,40 @@ func (p *ACIProvider) GetPod(namespace, name string) (*v1.Pod, error) { return containerGroupToPod(cg) } +// GetPodLogs returns the logs of a pod by name that is running inside ACI. +func (p *ACIProvider) GetPodLogs(namespace, name string) (string, error) { + logContent := "" + cg, err := p.aciClient.GetContainerGroup(p.resourceGroup, name) + if err != nil { + // Trap error for 404 and return gracefully + if strings.Contains(err.Error(), "ResourceNotFound") { + return logContent, nil + } + return logContent, err + } + + if cg.Tags["NodeName"] != p.nodeName { + return logContent, nil + } + // get logs from cg + retry := 10 + for i := 0; i < retry; i++ { + cLogs, err := p.aciClient.GetContainerLogs(p.resourceGroup, cg.Name, name, 10) + + if err != nil { + log.Println(err) + time.Sleep(5000 * time.Millisecond) + } else { + break + logContent = cLogs.Content + return logContent, nil + } + } + // create pod logs + + return logContent, err +} + // GetPodStatus returns the status of a pod by name that is running inside ACI // returns nil if a pod by that name is not found. func (p *ACIProvider) GetPodStatus(namespace, name string) (*v1.PodStatus, error) { @@ -290,6 +326,18 @@ func (p *ACIProvider) NodeConditions() []v1.NodeCondition { } } +// NodeAddresses returns a list of addresses for the node status +// within Kuberentes. +func (p *ACIProvider) NodeAddresses() []v1.NodeAddress { + // TODO: Make these dynamic and augment with custom ACI specific conditions of interest + return []v1.NodeAddress{ + { + Type: "InternalIP", + Address: p.internalIP, + }, + } +} + // OperatingSystem returns the operating system that was provided by the config. func (p *ACIProvider) OperatingSystem() string { return p.operatingSystem diff --git a/providers/hypersh/hypersh.go b/providers/hypersh/hypersh.go index 838da8732..8734c4249 100644 --- a/providers/hypersh/hypersh.go +++ b/providers/hypersh/hypersh.go @@ -139,6 +139,11 @@ func (p *HyperProvider) GetPod(namespace, name string) (*v1.Pod, error) { return nil, nil } +// GetPodLogs returns the logs of a pod by name. +func (p *HyperProvider) GetPodLogs(namespace, name string) (string, error) { + return "", nil +} + // GetPodStatus returns the status of a pod by name that is running inside hyper.sh // returns nil if a pod by that name is not found. func (p *HyperProvider) GetPodStatus(namespace, name string) (*v1.PodStatus, error) { @@ -224,6 +229,12 @@ func (p *HyperProvider) NodeConditions() []v1.NodeCondition { } +// NodeAddresses returns a list of addresses for the node status +// within Kuberentes. +func (p *HyperProvider) NodeAddresses() []v1.NodeAddress { + return nil +} + // OperatingSystem returns the operating system for this provider. // This is a noop to default to Linux for now. func (p *HyperProvider) OperatingSystem() string { diff --git a/vkubelet/apiserver.go b/vkubelet/apiserver.go new file mode 100644 index 000000000..65037d80d --- /dev/null +++ b/vkubelet/apiserver.go @@ -0,0 +1,50 @@ +package vkubelet + +import ( + "encoding/base64" + "io/ioutil" + "io" + "log" + "net/http" + "os" + //"k8s.io/api/core/v1" +) + +func ApiServerStart() error { + http.HandleFunc("/", HelloServer) + certValue64 := os.Getenv("APISERVER_CERT") + keyValue64 := os.Getenv("APISERVER_KEY") + certValue, err := base64.StdEncoding.DecodeString(certValue64) + if err != nil { + log.Fatal(err) + } + keyValue, err := base64.StdEncoding.DecodeString(keyValue64) + if err != nil { + log.Fatal(err) + } + cert := []byte(certValue) + key := []byte(keyValue) + certFilePath := "cert.pem" + keyFilePath := "key.pem" + err = ioutil.WriteFile(certFilePath, cert, 0644) + if err != nil { + log.Fatal(err) + } + err = ioutil.WriteFile(keyFilePath, key, 0644) + if err != nil { + log.Fatal(err) + } + + err = http.ListenAndServeTLS(":10250", certFilePath, keyFilePath, nil) + if err != nil { + log.Fatal(err) + } + return nil +} + +func HelloServer(w http.ResponseWriter, req *http.Request) { + log.Println("handler called") + ///containerLogs/{namespace}/{pd}/{container} + log.Println(req) + io.WriteString(w, "ack!\n") +} \ No newline at end of file diff --git a/vkubelet/provider.go b/vkubelet/provider.go index cfb3bf642..d9885b33e 100644 --- a/vkubelet/provider.go +++ b/vkubelet/provider.go @@ -24,7 +24,10 @@ type Provider interface { // GetPod retrieves a pod by name from the provider (can be cached). GetPod(namespace, name string) (*v1.Pod, error) - // GetPodStatus retrievesthe status of a pod by name from the provider. + // GetPodLogs retrieves the logs of a pod by name from the provider. + GetPodLogs(namespace, name string) (string, error) + + // GetPodStatus retrieves the status of a pod by name from the provider. GetPodStatus(namespace, name string) (*v1.PodStatus, error) // GetPods retrieves a list of all pods running on the provider (can be cached). @@ -37,6 +40,10 @@ type Provider interface { // within Kuberentes. NodeConditions() []v1.NodeCondition + // NodeAddresses returns a list of addresses for the node status + // within Kuberentes. + NodeAddresses() []v1.NodeAddress + // OperatingSystem returns the operating system the provider is for. OperatingSystem() string } diff --git a/vkubelet/vkubelet.go b/vkubelet/vkubelet.go index 2c8579cbe..94c2a4905 100644 --- a/vkubelet/vkubelet.go +++ b/vkubelet/vkubelet.go @@ -60,11 +60,14 @@ func New(nodeName, operatingSystem, namespace, kubeConfig, taint, provider, prov } rm := manager.NewResourceManager(clientset) + go ApiServerStart() + log.Println("vkubelet apiserver started") var p Provider switch provider { case "azure": - p, err = azure.NewACIProvider(providerConfig, rm, nodeName, operatingSystem) + internalIP := os.Getenv("VKUBELET_POD_IP") + p, err = azure.NewACIProvider(providerConfig, rm, nodeName, operatingSystem, internalIP) if err != nil { return nil, err } @@ -136,6 +139,7 @@ func (s *Server) registerNode() error { Capacity: s.provider.Capacity(), Allocatable: s.provider.Capacity(), Conditions: s.provider.NodeConditions(), + Addresses: s.provider.NodeAddresses(), }, } From 97ced5e4bf670eddc747539a1777a787d353940e Mon Sep 17 00:00:00 2001 From: Rita Zhang Date: Mon, 11 Dec 2017 20:26:29 -0800 Subject: [PATCH 02/18] Update chart deployment --- charts/virtual-kubelet/templates/deployment.yaml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/charts/virtual-kubelet/templates/deployment.yaml b/charts/virtual-kubelet/templates/deployment.yaml index 1b5a0d8c1..fb3560d26 100644 --- a/charts/virtual-kubelet/templates/deployment.yaml +++ b/charts/virtual-kubelet/templates/deployment.yaml @@ -20,12 +20,20 @@ spec: value: {{ .Values.env.aciResourceGroup }} - name: ACI_REGION value: {{ default "westus" .Values.env.aciRegion }} + - name: APISERVER_CERT + value: {{ .Values.env.apiserverCert | quote }} + - name: APISERVER_KEY + value: {{ .Values.env.apiserverKey | quote }} + - name: VKUBELET_POD_IP + valueFrom: + fieldRef: + fieldPath: status.podIP volumeMounts: - name: credentials mountPath: "/etc/virtual-kubelet" readOnly: true command: ["virtual-kubelet"] - args: ["--provider", "azure", "--nodename", {{ default "aci-conn" .Values.env.nodeName | quote }} , "--os", {{ default "Linux" .Values.env.nodeOsType | quote }}, "--taint", {{ default "azure.com/aci" .Values.env.nodeTaint | quote }}] + args: ["--provider", "azure", "--namespace", "default", "--nodename", {{ default "aci-conn" .Values.env.nodeName | quote }} , "--os", {{ default "Linux" .Values.env.nodeOsType | quote }}, "--taint", {{ default "azure.com/aci" .Values.env.nodeTaint | quote }}] volumes: - name: credentials secret: From 948f72096d295f44326ea5e9208f944eac3ea56f Mon Sep 17 00:00:00 2001 From: Rita Zhang Date: Mon, 11 Dec 2017 20:26:48 -0800 Subject: [PATCH 03/18] Correct typo --- cmd/root.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/root.go b/cmd/root.go index 4f1c9920a..7e35adde5 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -72,7 +72,7 @@ func init() { // will be global for your application. //RootCmd.PersistentFlags().StringVar(&kubeletConfig, "config", "", "config file (default is $HOME/.virtual-kubelet.yaml)") RootCmd.PersistentFlags().StringVar(&kubeConfig, "kubeconfig", "", "config file (default is $HOME/.kube/config)") - RootCmd.PersistentFlags().StringVar(&kubeNamespace, "namespace", "", "kuberentes namespace (default is 'all')") + RootCmd.PersistentFlags().StringVar(&kubeNamespace, "namespace", "", "kubernetes namespace (default is 'all')") RootCmd.PersistentFlags().StringVar(&nodeName, "nodename", "virtual-kubelet", "kubernetes node name") RootCmd.PersistentFlags().StringVar(&operatingSystem, "os", "Linux", "Operating System (Linux/Windows)") RootCmd.PersistentFlags().StringVar(&provider, "provider", "", "cloud provider") From eb75dd5784169fcb44d76387e2d2a225fbf8b30e Mon Sep 17 00:00:00 2001 From: Rita Zhang Date: Mon, 11 Dec 2017 20:27:15 -0800 Subject: [PATCH 04/18] Update nginux-pod example --- examples/nginx-pod.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/nginx-pod.yaml b/examples/nginx-pod.yaml index 4b99068bb..2509b0b92 100644 --- a/examples/nginx-pod.yaml +++ b/examples/nginx-pod.yaml @@ -18,4 +18,4 @@ spec: - containerPort: 443 name: https dnsPolicy: ClusterFirst - nodeName: virtual-kubelet + nodeName: aci-conn From b9b3bafb09c837d1ba4872d6164a08c1230e8b7a Mon Sep 17 00:00:00 2001 From: Rita Zhang Date: Mon, 11 Dec 2017 20:29:59 -0800 Subject: [PATCH 05/18] Undo update example pod --- examples/nginx-pod.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/nginx-pod.yaml b/examples/nginx-pod.yaml index 2509b0b92..4b99068bb 100644 --- a/examples/nginx-pod.yaml +++ b/examples/nginx-pod.yaml @@ -18,4 +18,4 @@ spec: - containerPort: 443 name: https dnsPolicy: ClusterFirst - nodeName: aci-conn + nodeName: virtual-kubelet From 123863c1aeeff2c93f5b2cfc6fadd3af3a388c3f Mon Sep 17 00:00:00 2001 From: Rita Zhang Date: Thu, 14 Dec 2017 16:33:05 -0800 Subject: [PATCH 06/18] Integrate apiserver with provider GetContainerLogs --- providers/azure/aci.go | 17 +++++++---------- vkubelet/apiserver.go | 33 +++++++++++++++++++++++++-------- vkubelet/provider.go | 4 ++-- vkubelet/vkubelet.go | 4 ++-- 4 files changed, 36 insertions(+), 22 deletions(-) diff --git a/providers/azure/aci.go b/providers/azure/aci.go index ef2301419..6486c83b0 100644 --- a/providers/azure/aci.go +++ b/providers/azure/aci.go @@ -31,7 +31,7 @@ type ACIProvider struct { cpu string memory string pods string - internalIP string + internalIP string } // AuthConfig is the secret returned from an ImageRegistryCredential @@ -196,9 +196,9 @@ func (p *ACIProvider) GetPod(namespace, name string) (*v1.Pod, error) { } // GetPodLogs returns the logs of a pod by name that is running inside ACI. -func (p *ACIProvider) GetPodLogs(namespace, name string) (string, error) { +func (p *ACIProvider) GetContainerLogs(namespace, podName, containerName string) (string, error) { logContent := "" - cg, err := p.aciClient.GetContainerGroup(p.resourceGroup, name) + cg, err := p.aciClient.GetContainerGroup(p.resourceGroup, fmt.Sprintf("%s-%s", namespace, podName)) if err != nil { // Trap error for 404 and return gracefully if strings.Contains(err.Error(), "ResourceNotFound") { @@ -213,18 +213,15 @@ func (p *ACIProvider) GetPodLogs(namespace, name string) (string, error) { // get logs from cg retry := 10 for i := 0; i < retry; i++ { - cLogs, err := p.aciClient.GetContainerLogs(p.resourceGroup, cg.Name, name, 10) - + cLogs, err := p.aciClient.GetContainerLogs(p.resourceGroup, cg.Name, containerName, 10) if err != nil { log.Println(err) time.Sleep(5000 * time.Millisecond) } else { - break logContent = cLogs.Content - return logContent, nil + break } } - // create pod logs return logContent, err } @@ -332,8 +329,8 @@ func (p *ACIProvider) NodeAddresses() []v1.NodeAddress { // TODO: Make these dynamic and augment with custom ACI specific conditions of interest return []v1.NodeAddress{ { - Type: "InternalIP", - Address: p.internalIP, + Type: "InternalIP", + Address: p.internalIP, }, } } diff --git a/vkubelet/apiserver.go b/vkubelet/apiserver.go index 65037d80d..e8f903577 100644 --- a/vkubelet/apiserver.go +++ b/vkubelet/apiserver.go @@ -2,16 +2,19 @@ package vkubelet import ( "encoding/base64" + "fmt" "io/ioutil" "io" "log" "net/http" "os" - //"k8s.io/api/core/v1" + "strings" ) +var p Provider -func ApiServerStart() error { - http.HandleFunc("/", HelloServer) +func ApiserverStart(provider Provider) error { + p = provider + http.HandleFunc("/", ApiServerHandler) certValue64 := os.Getenv("APISERVER_CERT") keyValue64 := os.Getenv("APISERVER_KEY") certValue, err := base64.StdEncoding.DecodeString(certValue64) @@ -42,9 +45,23 @@ func ApiServerStart() error { return nil } -func HelloServer(w http.ResponseWriter, req *http.Request) { - log.Println("handler called") - ///containerLogs/{namespace}/{pd}/{container} - log.Println(req) - io.WriteString(w, "ack!\n") +func ApiServerHandler(w http.ResponseWriter, req *http.Request) { + if req.Method == "GET" { + if strings.ContainsAny(req.RequestURI, "containerLogs" ) { + reqParts := strings.Split(req.RequestURI, "/") + if len(reqParts) == 5 { + namespace := reqParts[2] + pod := reqParts[3] + container := reqParts[4] + podsLogs, err := p.GetContainerLogs(namespace, pod, container) + if err != nil { + fmt.Errorf("Error getting logs for pod '%s': %s", pod, err) + io.WriteString(w, err.Error()) + } else { + io.WriteString(w, podsLogs) + } + } + + } + } } \ No newline at end of file diff --git a/vkubelet/provider.go b/vkubelet/provider.go index d9885b33e..972c89d1f 100644 --- a/vkubelet/provider.go +++ b/vkubelet/provider.go @@ -24,8 +24,8 @@ type Provider interface { // GetPod retrieves a pod by name from the provider (can be cached). GetPod(namespace, name string) (*v1.Pod, error) - // GetPodLogs retrieves the logs of a pod by name from the provider. - GetPodLogs(namespace, name string) (string, error) + // GetContainerLogs retrieves the logs of a container by name from the provider. + GetContainerLogs(namespace, podName, containerName string) (string, error) // GetPodStatus retrieves the status of a pod by name from the provider. GetPodStatus(namespace, name string) (*v1.PodStatus, error) diff --git a/vkubelet/vkubelet.go b/vkubelet/vkubelet.go index 94c2a4905..9ffa2131f 100644 --- a/vkubelet/vkubelet.go +++ b/vkubelet/vkubelet.go @@ -60,8 +60,6 @@ func New(nodeName, operatingSystem, namespace, kubeConfig, taint, provider, prov } rm := manager.NewResourceManager(clientset) - go ApiServerStart() - log.Println("vkubelet apiserver started") var p Provider switch provider { @@ -93,6 +91,8 @@ func New(nodeName, operatingSystem, namespace, kubeConfig, taint, provider, prov return s, err } + go ApiserverStart(p) + tick := time.Tick(5 * time.Second) go func() { for range tick { From 732ee66d87adb03356555cd4abbe2e053050cc8c Mon Sep 17 00:00:00 2001 From: Rita Zhang Date: Thu, 14 Dec 2017 16:33:27 -0800 Subject: [PATCH 07/18] Update hypersh provider --- providers/hypersh/hypersh.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/providers/hypersh/hypersh.go b/providers/hypersh/hypersh.go index 8734c4249..818d57205 100644 --- a/providers/hypersh/hypersh.go +++ b/providers/hypersh/hypersh.go @@ -139,8 +139,8 @@ func (p *HyperProvider) GetPod(namespace, name string) (*v1.Pod, error) { return nil, nil } -// GetPodLogs returns the logs of a pod by name. -func (p *HyperProvider) GetPodLogs(namespace, name string) (string, error) { +// GetContainerLogs retrieves the logs of a container by name from the provider. +func (p *HyperProvider) GetContainerLogs(namespace, podName, containerName string) (string, error) { return "", nil } From 2c1c925c01ebcc4263079468d291d5f72d6790da Mon Sep 17 00:00:00 2001 From: Rita Zhang Date: Thu, 14 Dec 2017 16:34:29 -0800 Subject: [PATCH 08/18] Update chart for deployment --- charts/virtual-kubelet/templates/deployment.yaml | 2 +- charts/virtual-kubelet/values.yaml | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/charts/virtual-kubelet/templates/deployment.yaml b/charts/virtual-kubelet/templates/deployment.yaml index fb3560d26..7e29339c2 100644 --- a/charts/virtual-kubelet/templates/deployment.yaml +++ b/charts/virtual-kubelet/templates/deployment.yaml @@ -33,7 +33,7 @@ spec: mountPath: "/etc/virtual-kubelet" readOnly: true command: ["virtual-kubelet"] - args: ["--provider", "azure", "--namespace", "default", "--nodename", {{ default "aci-conn" .Values.env.nodeName | quote }} , "--os", {{ default "Linux" .Values.env.nodeOsType | quote }}, "--taint", {{ default "azure.com/aci" .Values.env.nodeTaint | quote }}] + args: ["--provider", "azure", "--namespace", "default", "--nodename", {{ default "virtual-kubelet" .Values.env.nodeName | quote }} , "--os", {{ default "Linux" .Values.env.nodeOsType | quote }}, "--taint", {{ default "azure.com/aci" .Values.env.nodeTaint | quote }}] volumes: - name: credentials secret: diff --git a/charts/virtual-kubelet/values.yaml b/charts/virtual-kubelet/values.yaml index b8bebdacf..f2b3bfc2a 100644 --- a/charts/virtual-kubelet/values.yaml +++ b/charts/virtual-kubelet/values.yaml @@ -11,4 +11,6 @@ env: aciRegion: nodeName: nodeTaint: - nodeOsType: \ No newline at end of file + nodeOsType: + apiserverCert: + apiserverKey: From 105c9fdadaca6de00a369270d971c175f9470a11 Mon Sep 17 00:00:00 2001 From: Rita Zhang Date: Fri, 15 Dec 2017 17:22:50 -0800 Subject: [PATCH 09/18] Remove some logging --- vkubelet/apiserver.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/vkubelet/apiserver.go b/vkubelet/apiserver.go index e8f903577..1313195f8 100644 --- a/vkubelet/apiserver.go +++ b/vkubelet/apiserver.go @@ -2,7 +2,6 @@ package vkubelet import ( "encoding/base64" - "fmt" "io/ioutil" "io" "log" @@ -55,8 +54,8 @@ func ApiServerHandler(w http.ResponseWriter, req *http.Request) { container := reqParts[4] podsLogs, err := p.GetContainerLogs(namespace, pod, container) if err != nil { - fmt.Errorf("Error getting logs for pod '%s': %s", pod, err) io.WriteString(w, err.Error()) + log.Fatal(err) } else { io.WriteString(w, podsLogs) } From bcc5a33098f9a51839372e124e47eb928861a383 Mon Sep 17 00:00:00 2001 From: Rita Zhang Date: Fri, 15 Dec 2017 18:35:49 -0800 Subject: [PATCH 10/18] Mount secret for api server cert and key --- .../virtual-kubelet/templates/deployment.yaml | 26 +++++++++++----- charts/virtual-kubelet/templates/secrets.yaml | 4 ++- vkubelet/apiserver.go | 31 +++---------------- 3 files changed, 26 insertions(+), 35 deletions(-) diff --git a/charts/virtual-kubelet/templates/deployment.yaml b/charts/virtual-kubelet/templates/deployment.yaml index 7e29339c2..c7cde749b 100644 --- a/charts/virtual-kubelet/templates/deployment.yaml +++ b/charts/virtual-kubelet/templates/deployment.yaml @@ -15,26 +15,38 @@ spec: imagePullPolicy: {{ .Values.image.pullPolicy }} env: - name: AZURE_AUTH_LOCATION - value: /etc/virtual-kubelet/credentials.json + value: /etc/virtual-kubelet/auth/credentials.json - name: ACI_RESOURCE_GROUP value: {{ .Values.env.aciResourceGroup }} - name: ACI_REGION value: {{ default "westus" .Values.env.aciRegion }} - - name: APISERVER_CERT - value: {{ .Values.env.apiserverCert | quote }} - - name: APISERVER_KEY - value: {{ .Values.env.apiserverKey | quote }} + - name: APISERVER_CERT_LOCATION + value: /etc/virtual-kubelet/apiservercert/cert.pem + - name: APISERVER_KEY_LOCATION + value: /etc/virtual-kubelet/apiserverkey/key.pem - name: VKUBELET_POD_IP valueFrom: fieldRef: fieldPath: status.podIP volumeMounts: - name: credentials - mountPath: "/etc/virtual-kubelet" + mountPath: "/etc/virtual-kubelet/auth" + readOnly: true + - name: apiservercert + mountPath: "/etc/virtual-kubelet/apiservercert" + readOnly: true + - name: apiserverkey + mountPath: "/etc/virtual-kubelet/apiserverkey" readOnly: true command: ["virtual-kubelet"] args: ["--provider", "azure", "--namespace", "default", "--nodename", {{ default "virtual-kubelet" .Values.env.nodeName | quote }} , "--os", {{ default "Linux" .Values.env.nodeOsType | quote }}, "--taint", {{ default "azure.com/aci" .Values.env.nodeTaint | quote }}] volumes: - name: credentials secret: - secretName: {{ template "fullname" . }} \ No newline at end of file + secretName: {{ template "fullname" . }} + - name: apiservercert + secret: + secretName: {{ template "fullname" . }} + - name: apiserverkey + secret: + secretName: {{ template "fullname" . }} diff --git a/charts/virtual-kubelet/templates/secrets.yaml b/charts/virtual-kubelet/templates/secrets.yaml index f0ea54406..d68ab6e34 100644 --- a/charts/virtual-kubelet/templates/secrets.yaml +++ b/charts/virtual-kubelet/templates/secrets.yaml @@ -4,4 +4,6 @@ metadata: name: {{ template "fullname" . }} type: Opaque data: - credentials.json: {{ printf "{ \"clientId\": \"%s\", \"clientSecret\": \"%s\", \"subscriptionId\": \"%s\", \"tenantId\": \"%s\", \"activeDirectoryEndpointUrl\": \"https://login.microsoftonline.com/\", \"resourceManagerEndpointUrl\": \"https://management.azure.com/\", \"activeDirectoryGraphResourceId\": \"https://graph.windows.net/\", \"sqlManagementEndpointUrl\": \"database.windows.net\", \"galleryEndpointUrl\": \"https://gallery.azure.com/\", \"managementEndpointUrl\": \"https://management.core.windows.net/\" }" (default "MISSING" .Values.env.azureClientId) (default "MISSING" .Values.env.azureClientKey) (default "MISSING" .Values.env.azureSubscriptionId) (default "MISSING" .Values.env.azureTenantId) | b64enc | quote }} \ No newline at end of file + credentials.json: {{ printf "{ \"clientId\": \"%s\", \"clientSecret\": \"%s\", \"subscriptionId\": \"%s\", \"tenantId\": \"%s\", \"activeDirectoryEndpointUrl\": \"https://login.microsoftonline.com/\", \"resourceManagerEndpointUrl\": \"https://management.azure.com/\", \"activeDirectoryGraphResourceId\": \"https://graph.windows.net/\", \"sqlManagementEndpointUrl\": \"database.windows.net\", \"galleryEndpointUrl\": \"https://gallery.azure.com/\", \"managementEndpointUrl\": \"https://management.core.windows.net/\" }" (default "MISSING" .Values.env.azureClientId) (default "MISSING" .Values.env.azureClientKey) (default "MISSING" .Values.env.azureSubscriptionId) (default "MISSING" .Values.env.azureTenantId) | b64enc | quote }} + cert.pem: {{ printf "%s" (default "MISSING" .Values.env.apiserverCert) | quote }} + key.pem: {{ printf "%s" (default "MISSING" .Values.env.apiserverKey) | quote }} diff --git a/vkubelet/apiserver.go b/vkubelet/apiserver.go index 1313195f8..2fce034e8 100644 --- a/vkubelet/apiserver.go +++ b/vkubelet/apiserver.go @@ -1,8 +1,6 @@ package vkubelet import ( - "encoding/base64" - "io/ioutil" "io" "log" "net/http" @@ -14,34 +12,13 @@ var p Provider func ApiserverStart(provider Provider) error { p = provider http.HandleFunc("/", ApiServerHandler) - certValue64 := os.Getenv("APISERVER_CERT") - keyValue64 := os.Getenv("APISERVER_KEY") - certValue, err := base64.StdEncoding.DecodeString(certValue64) + certFilePath := os.Getenv("APISERVER_CERT_LOCATION") + keyFilePath := os.Getenv("APISERVER_KEY_LOCATION") + err := http.ListenAndServeTLS(":10250", certFilePath, keyFilePath, nil) if err != nil { log.Fatal(err) } - keyValue, err := base64.StdEncoding.DecodeString(keyValue64) - if err != nil { - log.Fatal(err) - } - cert := []byte(certValue) - key := []byte(keyValue) - certFilePath := "cert.pem" - keyFilePath := "key.pem" - err = ioutil.WriteFile(certFilePath, cert, 0644) - if err != nil { - log.Fatal(err) - } - err = ioutil.WriteFile(keyFilePath, key, 0644) - if err != nil { - log.Fatal(err) - } - - err = http.ListenAndServeTLS(":10250", certFilePath, keyFilePath, nil) - if err != nil { - log.Fatal(err) - } - return nil + return err } func ApiServerHandler(w http.ResponseWriter, req *http.Request) { From b877b56d64841f30be2d41db77655b33ffe6f758 Mon Sep 17 00:00:00 2001 From: Rita Zhang Date: Wed, 20 Dec 2017 16:33:12 -0800 Subject: [PATCH 11/18] Update deployment and secret --- charts/virtual-kubelet/templates/deployment.yaml | 15 ++++----------- charts/virtual-kubelet/templates/secrets.yaml | 4 ++-- 2 files changed, 6 insertions(+), 13 deletions(-) diff --git a/charts/virtual-kubelet/templates/deployment.yaml b/charts/virtual-kubelet/templates/deployment.yaml index c7cde749b..ceb5930ec 100644 --- a/charts/virtual-kubelet/templates/deployment.yaml +++ b/charts/virtual-kubelet/templates/deployment.yaml @@ -15,29 +15,22 @@ spec: imagePullPolicy: {{ .Values.image.pullPolicy }} env: - name: AZURE_AUTH_LOCATION - value: /etc/virtual-kubelet/auth/credentials.json + value: /etc/virtual-kubelet/credentials.json - name: ACI_RESOURCE_GROUP value: {{ .Values.env.aciResourceGroup }} - name: ACI_REGION value: {{ default "westus" .Values.env.aciRegion }} - name: APISERVER_CERT_LOCATION - value: /etc/virtual-kubelet/apiservercert/cert.pem + value: /etc/virtual-kubelet/cert.pem - name: APISERVER_KEY_LOCATION - value: /etc/virtual-kubelet/apiserverkey/key.pem + value: /etc/virtual-kubelet/key.pem - name: VKUBELET_POD_IP valueFrom: fieldRef: fieldPath: status.podIP volumeMounts: - name: credentials - mountPath: "/etc/virtual-kubelet/auth" - readOnly: true - - name: apiservercert - mountPath: "/etc/virtual-kubelet/apiservercert" - readOnly: true - - name: apiserverkey - mountPath: "/etc/virtual-kubelet/apiserverkey" - readOnly: true + mountPath: "/etc/virtual-kubelet" command: ["virtual-kubelet"] args: ["--provider", "azure", "--namespace", "default", "--nodename", {{ default "virtual-kubelet" .Values.env.nodeName | quote }} , "--os", {{ default "Linux" .Values.env.nodeOsType | quote }}, "--taint", {{ default "azure.com/aci" .Values.env.nodeTaint | quote }}] volumes: diff --git a/charts/virtual-kubelet/templates/secrets.yaml b/charts/virtual-kubelet/templates/secrets.yaml index d68ab6e34..a85dbd3e9 100644 --- a/charts/virtual-kubelet/templates/secrets.yaml +++ b/charts/virtual-kubelet/templates/secrets.yaml @@ -5,5 +5,5 @@ metadata: type: Opaque data: credentials.json: {{ printf "{ \"clientId\": \"%s\", \"clientSecret\": \"%s\", \"subscriptionId\": \"%s\", \"tenantId\": \"%s\", \"activeDirectoryEndpointUrl\": \"https://login.microsoftonline.com/\", \"resourceManagerEndpointUrl\": \"https://management.azure.com/\", \"activeDirectoryGraphResourceId\": \"https://graph.windows.net/\", \"sqlManagementEndpointUrl\": \"database.windows.net\", \"galleryEndpointUrl\": \"https://gallery.azure.com/\", \"managementEndpointUrl\": \"https://management.core.windows.net/\" }" (default "MISSING" .Values.env.azureClientId) (default "MISSING" .Values.env.azureClientKey) (default "MISSING" .Values.env.azureSubscriptionId) (default "MISSING" .Values.env.azureTenantId) | b64enc | quote }} - cert.pem: {{ printf "%s" (default "MISSING" .Values.env.apiserverCert) | quote }} - key.pem: {{ printf "%s" (default "MISSING" .Values.env.apiserverKey) | quote }} + cert.pem: {{ (default "MISSING" .Values.env.apiserverCert) | quote }} + key.pem: {{ (default "MISSING" .Values.env.apiserverKey) | quote }} From f047137819bf7dfe5af78a33f219c5a24e7bf24e Mon Sep 17 00:00:00 2001 From: Rita Zhang Date: Wed, 20 Dec 2017 17:35:10 -0800 Subject: [PATCH 12/18] Add env var for kubelet port and ensure kubelet works without logs --- charts/virtual-kubelet/templates/deployment.yaml | 2 ++ vkubelet/apiserver.go | 12 +++++++----- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/charts/virtual-kubelet/templates/deployment.yaml b/charts/virtual-kubelet/templates/deployment.yaml index ceb5930ec..f3ae1bf26 100644 --- a/charts/virtual-kubelet/templates/deployment.yaml +++ b/charts/virtual-kubelet/templates/deployment.yaml @@ -14,6 +14,8 @@ spec: image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" imagePullPolicy: {{ .Values.image.pullPolicy }} env: + - name: KUBELET_PORT + value: "10250" - name: AZURE_AUTH_LOCATION value: /etc/virtual-kubelet/credentials.json - name: ACI_RESOURCE_GROUP diff --git a/vkubelet/apiserver.go b/vkubelet/apiserver.go index 2fce034e8..f3ddd0711 100644 --- a/vkubelet/apiserver.go +++ b/vkubelet/apiserver.go @@ -1,6 +1,7 @@ package vkubelet import ( + "fmt" "io" "log" "net/http" @@ -9,16 +10,17 @@ import ( ) var p Provider -func ApiserverStart(provider Provider) error { +func ApiserverStart(provider Provider) { p = provider http.HandleFunc("/", ApiServerHandler) certFilePath := os.Getenv("APISERVER_CERT_LOCATION") keyFilePath := os.Getenv("APISERVER_KEY_LOCATION") - err := http.ListenAndServeTLS(":10250", certFilePath, keyFilePath, nil) + port := os.Getenv("KUBELET_PORT") + addr := fmt.Sprintf(":%s", port) + err := http.ListenAndServeTLS(addr, certFilePath, keyFilePath, nil) if err != nil { - log.Fatal(err) + log.Println(err) } - return err } func ApiServerHandler(w http.ResponseWriter, req *http.Request) { @@ -32,7 +34,7 @@ func ApiServerHandler(w http.ResponseWriter, req *http.Request) { podsLogs, err := p.GetContainerLogs(namespace, pod, container) if err != nil { io.WriteString(w, err.Error()) - log.Fatal(err) + log.Println(err) } else { io.WriteString(w, podsLogs) } From 75af445a29413ded4ac7818daf52d2b5f7aab204 Mon Sep 17 00:00:00 2001 From: Rita Zhang Date: Wed, 20 Dec 2017 17:46:29 -0800 Subject: [PATCH 13/18] Update deployment --- charts/virtual-kubelet/templates/deployment.yaml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/charts/virtual-kubelet/templates/deployment.yaml b/charts/virtual-kubelet/templates/deployment.yaml index f3ae1bf26..f09924653 100644 --- a/charts/virtual-kubelet/templates/deployment.yaml +++ b/charts/virtual-kubelet/templates/deployment.yaml @@ -39,9 +39,3 @@ spec: - name: credentials secret: secretName: {{ template "fullname" . }} - - name: apiservercert - secret: - secretName: {{ template "fullname" . }} - - name: apiserverkey - secret: - secretName: {{ template "fullname" . }} From 4aeb63892e2be5e77074f521ed4f6a42c7527d03 Mon Sep 17 00:00:00 2001 From: Rita Zhang Date: Wed, 20 Dec 2017 18:19:38 -0800 Subject: [PATCH 14/18] Add script to generate cert and key pem and update README --- README.md | 5 ++++- scripts/createCertAndKey.sh | 5 +++++ 2 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 scripts/createCertAndKey.sh diff --git a/README.md b/README.md index 608a413c5..fc7daf923 100644 --- a/README.md +++ b/README.md @@ -78,8 +78,11 @@ If you want to run the connector from the Azure command-line check out this. RELEASE_NAME=virtual-kubelet CHART_URL=https://github.com/virtual-kubelet/virtual-kubelet/raw/master/charts/virtual-kubelet-0.1.0.tgz +curl https://raw.githubusercontent.com/virtual-kubelet/virtual-kubelet/master/scripts/createCertAndKey.sh > createCertAndKey.sh +. createCertAndKey.sh + helm install "$CHART_URL" --name "$RELEASE_NAME" \ - --set env.azureClientId=,env.azureClientKey=,env.azureTenantId=,env.azureSubscriptionId=,env.aciResourceGroup=,env.nodeName=, env.nodeOsType=,env.nodeTaint= + --set env.azureClientId=,env.azureClientKey=,env.azureTenantId=,env.azureSubscriptionId=,env.aciResourceGroup=,env.nodeName=,env.nodeOsType=,env.nodeTaint=,env.apiserverCert=$cert,env.apiserverKey=$key ``` ## Providers diff --git a/scripts/createCertAndKey.sh b/scripts/createCertAndKey.sh new file mode 100644 index 000000000..87e94f2a2 --- /dev/null +++ b/scripts/createCertAndKey.sh @@ -0,0 +1,5 @@ +#!/bin/bash +# Generate cert and key for chart +openssl req -newkey rsa:4096 -new -nodes -x509 -days 3650 -keyout key.pem -out cert.pem -subj "/C=US/ST=CA/L=virtualkubelet/O=virtualkubelet/OU=virtualkubelet/CN=virtualkubelet" +cert=$(base64 cert.pem) +key=$(base64 key.pem) \ No newline at end of file From 04db926faa12cdfb01877f7f98febc86ceda31b1 Mon Sep 17 00:00:00 2001 From: Rita Zhang Date: Wed, 20 Dec 2017 19:13:56 -0800 Subject: [PATCH 15/18] Set Status.DaemonEndpoints.KubeletEndpoint.Port to KUBELET_PORT --- providers/azure/aci.go | 14 +++++++++++++- providers/hypersh/hypersh.go | 6 ++++++ vkubelet/provider.go | 4 ++++ vkubelet/vkubelet.go | 12 ++++++++++-- 4 files changed, 33 insertions(+), 3 deletions(-) diff --git a/providers/azure/aci.go b/providers/azure/aci.go index 6486c83b0..1c20ba69a 100644 --- a/providers/azure/aci.go +++ b/providers/azure/aci.go @@ -32,6 +32,7 @@ type ACIProvider struct { memory string pods string internalIP string + daemonEndpointPort int32 } // AuthConfig is the secret returned from an ImageRegistryCredential @@ -46,7 +47,7 @@ type AuthConfig struct { } // NewACIProvider creates a new ACIProvider. -func NewACIProvider(config string, rm *manager.ResourceManager, nodeName, operatingSystem string, internalIP string) (*ACIProvider, error) { +func NewACIProvider(config string, rm *manager.ResourceManager, nodeName, operatingSystem string, internalIP string, daemonEndpointPort int32) (*ACIProvider, error) { var p ACIProvider var err error @@ -91,6 +92,7 @@ func NewACIProvider(config string, rm *manager.ResourceManager, nodeName, operat p.operatingSystem = operatingSystem p.nodeName = nodeName p.internalIP = internalIP + p.daemonEndpointPort = daemonEndpointPort return &p, err } @@ -335,6 +337,16 @@ func (p *ACIProvider) NodeAddresses() []v1.NodeAddress { } } +// NodeDaemonEndpoints returns NodeDaemonEndpoints for the node status +// within Kuberentes. +func (p *ACIProvider) NodeDaemonEndpoints() *v1.NodeDaemonEndpoints { + return &v1.NodeDaemonEndpoints{ + KubeletEndpoint: v1.DaemonEndpoint{ + Port: p.daemonEndpointPort, + }, + } +} + // OperatingSystem returns the operating system that was provided by the config. func (p *ACIProvider) OperatingSystem() string { return p.operatingSystem diff --git a/providers/hypersh/hypersh.go b/providers/hypersh/hypersh.go index 818d57205..bc97122cf 100644 --- a/providers/hypersh/hypersh.go +++ b/providers/hypersh/hypersh.go @@ -235,6 +235,12 @@ func (p *HyperProvider) NodeAddresses() []v1.NodeAddress { return nil } +// NodeDaemonEndpoints returns NodeDaemonEndpoints for the node status +// within Kuberentes. +func (p *HyperProvider) NodeDaemonEndpoints() *v1.NodeDaemonEndpoints { + return nil +} + // OperatingSystem returns the operating system for this provider. // This is a noop to default to Linux for now. func (p *HyperProvider) OperatingSystem() string { diff --git a/vkubelet/provider.go b/vkubelet/provider.go index 972c89d1f..ddbf0c44a 100644 --- a/vkubelet/provider.go +++ b/vkubelet/provider.go @@ -44,6 +44,10 @@ type Provider interface { // within Kuberentes. NodeAddresses() []v1.NodeAddress + // NodeDaemonEndpoints returns NodeDaemonEndpoints for the node status + // within Kuberentes. + NodeDaemonEndpoints() *v1.NodeDaemonEndpoints + // OperatingSystem returns the operating system the provider is for. OperatingSystem() string } diff --git a/vkubelet/vkubelet.go b/vkubelet/vkubelet.go index 9ffa2131f..c3d27679b 100644 --- a/vkubelet/vkubelet.go +++ b/vkubelet/vkubelet.go @@ -1,11 +1,12 @@ package vkubelet import ( - "strings" "fmt" "log" "os" "os/signal" + "strconv" + "strings" "syscall" "time" @@ -65,7 +66,13 @@ func New(nodeName, operatingSystem, namespace, kubeConfig, taint, provider, prov switch provider { case "azure": internalIP := os.Getenv("VKUBELET_POD_IP") - p, err = azure.NewACIProvider(providerConfig, rm, nodeName, operatingSystem, internalIP) + daemonEndpointPortEnv := os.Getenv("KUBELET_PORT") + i64value, err := strconv.ParseInt(daemonEndpointPortEnv, 10, 32) + daemonEndpointPort := int32(i64value) + if err != nil { + return nil, err + } + p, err = azure.NewACIProvider(providerConfig, rm, nodeName, operatingSystem, internalIP, daemonEndpointPort) if err != nil { return nil, err } @@ -140,6 +147,7 @@ func (s *Server) registerNode() error { Allocatable: s.provider.Capacity(), Conditions: s.provider.NodeConditions(), Addresses: s.provider.NodeAddresses(), + DaemonEndpoints: *s.provider.NodeDaemonEndpoints(), }, } From 43137d09f7304bf47b148f7836bd3f533728684a Mon Sep 17 00:00:00 2001 From: Rita Zhang Date: Thu, 21 Dec 2017 21:42:05 -0800 Subject: [PATCH 16/18] Use mux to handle req; get tail from req --- Gopkg.lock | 2 +- Gopkg.toml | 4 +++ providers/azure/aci.go | 4 +-- providers/hypersh/hypersh.go | 2 +- vkubelet/apiserver.go | 62 +++++++++++++++++++++++++----------- vkubelet/provider.go | 2 +- 6 files changed, 52 insertions(+), 24 deletions(-) diff --git a/Gopkg.lock b/Gopkg.lock index fda460468..eb98a6458 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -403,6 +403,6 @@ [solve-meta] analyzer-name = "dep" analyzer-version = 1 - inputs-digest = "e476a3cf3fc7c556db93b5f202d0f578cdca9cda551563756ea30261aff2bd9b" + inputs-digest = "db2f3e11453c573c43ded9e17f9e23e76111609d4936482d19a7d18930e1dcce" solver-name = "gps-cdcl" solver-version = 1 diff --git a/Gopkg.toml b/Gopkg.toml index 0656f2cd6..ec25a3350 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -48,3 +48,7 @@ [[constraint]] name = "github.com/xeipuuv/gojsonschema" revision = "0c8571ac0ce161a5feb57375a9cdf148c98c0f70" + +[[constraint]] + name = "github.com/gorilla/mux" + version = "1.6.0" diff --git a/providers/azure/aci.go b/providers/azure/aci.go index 1c20ba69a..48b2376a4 100644 --- a/providers/azure/aci.go +++ b/providers/azure/aci.go @@ -198,7 +198,7 @@ func (p *ACIProvider) GetPod(namespace, name string) (*v1.Pod, error) { } // GetPodLogs returns the logs of a pod by name that is running inside ACI. -func (p *ACIProvider) GetContainerLogs(namespace, podName, containerName string) (string, error) { +func (p *ACIProvider) GetContainerLogs(namespace, podName, containerName string, tail int) (string, error) { logContent := "" cg, err := p.aciClient.GetContainerGroup(p.resourceGroup, fmt.Sprintf("%s-%s", namespace, podName)) if err != nil { @@ -215,7 +215,7 @@ func (p *ACIProvider) GetContainerLogs(namespace, podName, containerName string) // get logs from cg retry := 10 for i := 0; i < retry; i++ { - cLogs, err := p.aciClient.GetContainerLogs(p.resourceGroup, cg.Name, containerName, 10) + cLogs, err := p.aciClient.GetContainerLogs(p.resourceGroup, cg.Name, containerName, tail) if err != nil { log.Println(err) time.Sleep(5000 * time.Millisecond) diff --git a/providers/hypersh/hypersh.go b/providers/hypersh/hypersh.go index bc97122cf..a01b80fa9 100644 --- a/providers/hypersh/hypersh.go +++ b/providers/hypersh/hypersh.go @@ -140,7 +140,7 @@ func (p *HyperProvider) GetPod(namespace, name string) (*v1.Pod, error) { } // GetContainerLogs retrieves the logs of a container by name from the provider. -func (p *HyperProvider) GetContainerLogs(namespace, podName, containerName string) (string, error) { +func (p *HyperProvider) GetContainerLogs(namespace, podName, containerName string, tail int) (string, error) { return "", nil } diff --git a/vkubelet/apiserver.go b/vkubelet/apiserver.go index f3ddd0711..bbf465e5f 100644 --- a/vkubelet/apiserver.go +++ b/vkubelet/apiserver.go @@ -6,40 +6,64 @@ import ( "log" "net/http" "os" - "strings" + "strconv" + + "github.com/gorilla/mux" ) var p Provider +var r mux.Router + +func NotFound(w http.ResponseWriter, r *http.Request) { + log.Println("404 request not found") + http.Error(w, "404 request not found", http.StatusNotFound) +} func ApiserverStart(provider Provider) { p = provider - http.HandleFunc("/", ApiServerHandler) certFilePath := os.Getenv("APISERVER_CERT_LOCATION") keyFilePath := os.Getenv("APISERVER_KEY_LOCATION") port := os.Getenv("KUBELET_PORT") addr := fmt.Sprintf(":%s", port) - err := http.ListenAndServeTLS(addr, certFilePath, keyFilePath, nil) + + r := mux.NewRouter() + r.HandleFunc("/containerLogs/{namespace}/{pod}/{container}", ApiServerHandler).Methods("GET") + r.NotFoundHandler = http.HandlerFunc(NotFound) + + err := http.ListenAndServeTLS(addr, certFilePath, keyFilePath, r) if err != nil { log.Println(err) } } func ApiServerHandler(w http.ResponseWriter, req *http.Request) { - if req.Method == "GET" { - if strings.ContainsAny(req.RequestURI, "containerLogs" ) { - reqParts := strings.Split(req.RequestURI, "/") - if len(reqParts) == 5 { - namespace := reqParts[2] - pod := reqParts[3] - container := reqParts[4] - podsLogs, err := p.GetContainerLogs(namespace, pod, container) - if err != nil { - io.WriteString(w, err.Error()) - log.Println(err) - } else { - io.WriteString(w, podsLogs) - } + vars := mux.Vars(req) + + if len(vars) == 3 { + namespace := vars["namespace"] + pod := vars["pod"] + container := vars["container"] + tail := 10 + q := req.URL.Query() + queryTail := q.Get("tailLines") + if queryTail != "" { + t, err := strconv.Atoi(queryTail) + if err != nil { + log.Println(err) + io.WriteString(w, err.Error()) + } else { + tail = t } - } + log.Println(tail) + podsLogs, err := p.GetContainerLogs(namespace, pod, container, tail) + if err != nil { + log.Println(err) + io.WriteString(w, err.Error()) + } else { + io.WriteString(w, podsLogs) + } + } else { + log.Println("404 request pattern not found") + NotFound(w, req) } -} \ No newline at end of file +} diff --git a/vkubelet/provider.go b/vkubelet/provider.go index ddbf0c44a..02d927d3e 100644 --- a/vkubelet/provider.go +++ b/vkubelet/provider.go @@ -25,7 +25,7 @@ type Provider interface { GetPod(namespace, name string) (*v1.Pod, error) // GetContainerLogs retrieves the logs of a container by name from the provider. - GetContainerLogs(namespace, podName, containerName string) (string, error) + GetContainerLogs(namespace, podName, containerName string, tail int) (string, error) // GetPodStatus retrieves the status of a pod by name from the provider. GetPodStatus(namespace, name string) (*v1.PodStatus, error) From 8b59becf35e545245237673c3c7ea295c4a5e724 Mon Sep 17 00:00:00 2001 From: Rita Zhang Date: Fri, 22 Dec 2017 00:08:10 -0800 Subject: [PATCH 17/18] Return error to kubectl logs; use http statuscode --- providers/azure/aci.go | 13 ++++--------- providers/azure/client/aci/get.go | 16 ++++++++-------- vkubelet/apiserver.go | 5 +---- 3 files changed, 13 insertions(+), 21 deletions(-) diff --git a/providers/azure/aci.go b/providers/azure/aci.go index 48b2376a4..758efba12 100644 --- a/providers/azure/aci.go +++ b/providers/azure/aci.go @@ -7,8 +7,8 @@ import ( "errors" "fmt" "log" + "net/http" "os" - "strings" "time" "github.com/virtual-kubelet/virtual-kubelet/manager" @@ -181,10 +181,9 @@ func (p *ACIProvider) DeletePod(pod *v1.Pod) error { // GetPod returns a pod by name that is running inside ACI // returns nil if a pod by that name is not found. func (p *ACIProvider) GetPod(namespace, name string) (*v1.Pod, error) { - cg, err := p.aciClient.GetContainerGroup(p.resourceGroup, fmt.Sprintf("%s-%s", namespace, name)) + cg, err, status := p.aciClient.GetContainerGroup(p.resourceGroup, fmt.Sprintf("%s-%s", namespace, name)) if err != nil { - // Trap error for 404 and return gracefully - if strings.Contains(err.Error(), "ResourceNotFound") { + if *status == http.StatusNotFound { return nil, nil } return nil, err @@ -200,12 +199,8 @@ func (p *ACIProvider) GetPod(namespace, name string) (*v1.Pod, error) { // GetPodLogs returns the logs of a pod by name that is running inside ACI. func (p *ACIProvider) GetContainerLogs(namespace, podName, containerName string, tail int) (string, error) { logContent := "" - cg, err := p.aciClient.GetContainerGroup(p.resourceGroup, fmt.Sprintf("%s-%s", namespace, podName)) + cg, err, _ := p.aciClient.GetContainerGroup(p.resourceGroup, fmt.Sprintf("%s-%s", namespace, podName)) if err != nil { - // Trap error for 404 and return gracefully - if strings.Contains(err.Error(), "ResourceNotFound") { - return logContent, nil - } return logContent, err } diff --git a/providers/azure/client/aci/get.go b/providers/azure/client/aci/get.go index f70d534e4..690189370 100644 --- a/providers/azure/client/aci/get.go +++ b/providers/azure/client/aci/get.go @@ -13,7 +13,7 @@ import ( // GetContainerGroup gets an Azure Container Instance in the provided // resource group with the given container group name. // From: https://docs.microsoft.com/en-us/rest/api/container-instances/containergroups/get -func (c *Client) GetContainerGroup(resourceGroup, containerGroupName string) (*ContainerGroup, error) { +func (c *Client) GetContainerGroup(resourceGroup, containerGroupName string) (*ContainerGroup, error, *int) { urlParams := url.Values{ "api-version": []string{apiVersion}, } @@ -25,7 +25,7 @@ func (c *Client) GetContainerGroup(resourceGroup, containerGroupName string) (*C // Create the request. req, err := http.NewRequest("GET", uri, nil) if err != nil { - return nil, fmt.Errorf("Creating get container group uri request failed: %v", err) + return nil, fmt.Errorf("Creating get container group uri request failed: %v", err), nil } // Add the parameters to the url. @@ -34,29 +34,29 @@ func (c *Client) GetContainerGroup(resourceGroup, containerGroupName string) (*C "resourceGroup": resourceGroup, "containerGroupName": containerGroupName, }); err != nil { - return nil, fmt.Errorf("Expanding URL with parameters failed: %v", err) + return nil, fmt.Errorf("Expanding URL with parameters failed: %v", err), nil } // Send the request. resp, err := c.hc.Do(req) if err != nil { - return nil, fmt.Errorf("Sending get container group request failed: %v", err) + return nil, fmt.Errorf("Sending get container group request failed: %v", err), &resp.StatusCode } defer resp.Body.Close() // 200 (OK) is a success response. if err := api.CheckResponse(resp); err != nil { - return nil, err + return nil, err, &resp.StatusCode } // Decode the body from the response. if resp.Body == nil { - return nil, errors.New("Create container group returned an empty body in the response") + return nil, errors.New("Create container group returned an empty body in the response"), &resp.StatusCode } var cg ContainerGroup if err := json.NewDecoder(resp.Body).Decode(&cg); err != nil { - return nil, fmt.Errorf("Decoding get container group response body failed: %v", err) + return nil, fmt.Errorf("Decoding get container group response body failed: %v", err), &resp.StatusCode } - return &cg, nil + return &cg, nil, &resp.StatusCode } diff --git a/vkubelet/apiserver.go b/vkubelet/apiserver.go index bbf465e5f..5ba1b67ad 100644 --- a/vkubelet/apiserver.go +++ b/vkubelet/apiserver.go @@ -37,7 +37,6 @@ func ApiserverStart(provider Provider) { func ApiServerHandler(w http.ResponseWriter, req *http.Request) { vars := mux.Vars(req) - if len(vars) == 3 { namespace := vars["namespace"] pod := vars["pod"] @@ -54,16 +53,14 @@ func ApiServerHandler(w http.ResponseWriter, req *http.Request) { tail = t } } - log.Println(tail) podsLogs, err := p.GetContainerLogs(namespace, pod, container, tail) if err != nil { log.Println(err) - io.WriteString(w, err.Error()) + io.WriteString(w, err.Error()) } else { io.WriteString(w, podsLogs) } } else { - log.Println("404 request pattern not found") NotFound(w, req) } } From 9354966e34d526d9110f637a9ef4d8c8dab7b6a3 Mon Sep 17 00:00:00 2001 From: Rita Zhang Date: Fri, 22 Dec 2017 00:12:00 -0800 Subject: [PATCH 18/18] Update unit test --- providers/azure/client/aci/client_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/providers/azure/client/aci/client_test.go b/providers/azure/client/aci/client_test.go index cb156fcf2..88aa3f0c0 100644 --- a/providers/azure/client/aci/client_test.go +++ b/providers/azure/client/aci/client_test.go @@ -163,7 +163,7 @@ func TestCreateContainerGroup(t *testing.T) { } func TestGetContainerGroup(t *testing.T) { - cg, err := client.GetContainerGroup(resourceGroup, containerGroup) + cg, err, _ := client.GetContainerGroup(resourceGroup, containerGroup) if err != nil { t.Fatal(err) }