diff --git a/Makefile b/Makefile index 7617754..ce7d8cc 100644 --- a/Makefile +++ b/Makefile @@ -132,6 +132,6 @@ endif ifndef HAS_GIT $(error You must install git) endif - glide install + glide install --strip-vendor include versioning.mk diff --git a/NOTICE b/NOTICE index f80fbe7..be4c933 100644 --- a/NOTICE +++ b/NOTICE @@ -76,3 +76,12 @@ The MIT License (MIT) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +**** + +Kubernetes client-go +Apache 2.0 License +Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 +THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT. +See the Apache Version 2.0 License for specific language governing permissions and limitations under the License. + diff --git a/api/server.go b/api/server.go index ca741e7..9449ada 100644 --- a/api/server.go +++ b/api/server.go @@ -24,6 +24,8 @@ import ( "github.com/ghodss/yaml" "github.com/gorilla/websocket" "github.com/julienschmidt/httprouter" + "k8s.io/client-go/kubernetes" + "k8s.io/client-go/pkg/api/v1" "k8s.io/helm/pkg/chartutil" "k8s.io/helm/pkg/helm" "k8s.io/helm/pkg/proto/hapi/release" @@ -33,6 +35,13 @@ import ( "github.com/Azure/draft/pkg/version" ) +const ( + // name of the docker pull secret draftd will create in the desired destination namespace + pullSecretName = "draftd-pullsecret" + // name of the default service account draftd will modify with the imagepullsecret + defaultServiceAccountName = "default" +) + // WebsocketUpgrader represents the default websocket.Upgrader that Draft employs var WebsocketUpgrader = websocket.Upgrader{ EnableCompression: true, @@ -48,6 +57,7 @@ type Server struct { Listener net.Listener DockerClient *docker.Client HelmClient *helm.Client + KubeClient *kubernetes.Clientset // RegistryAuth is the authorization token used to push images up to the registry. // // This field follows the format of the X-Registry-Auth header. @@ -61,6 +71,17 @@ type Server struct { Basedomain string } +// DockerAuth is a container for the registry authentication credentials wrapped by the registry server name +type DockerAuth map[string]RegistryAuth + +// RegistryAuth is the registry authentication credentials +type RegistryAuth struct { + Username string `json:"username"` + Password string `json:"password"` + Email string `json:"email"` + RegistryToken string `json:"registrytoken"` +} + // Serve starts the HTTP server, accepting all new connections. func (s *Server) Serve() error { return s.HTTPServer.Serve(s.Listener) @@ -358,6 +379,78 @@ func buildApp(w http.ResponseWriter, r *http.Request, p httprouter.Params) { handleClosingError(conn, "Could not load chart archive", err) } + // Determine if the destination namespace exists, create it if not. + _, err = server.KubeClient.CoreV1().Namespaces().Get(namespace) + if err != nil { + _, err = server.KubeClient.CoreV1().Namespaces().Create(&v1.Namespace{ + ObjectMeta: v1.ObjectMeta{ + Name: namespace, + }, + }) + if err != nil { + handleClosingError(conn, "Could not create namespace", err) + } + } + + // Determine if the registry pull secret exists in the desired namespace, create it if not. + _, err = server.KubeClient.CoreV1().Secrets(namespace).Get(pullSecretName) + if err != nil { + // Base64 decode the registryauth string. + data, err := base64.StdEncoding.DecodeString(server.RegistryAuth) + if err != nil { + handleClosingError(conn, "Could not base64 decode registry authentication string", err) + } + + // Break up registry auth json string into a RegistryAuth object. + var regAuth RegistryAuth + err = json.Unmarshal(data, ®Auth) + if err != nil { + handleClosingError(conn, "Could not json decode registry authentication string", err) + } + + // Create a new json string with the full dockerauth, including the registry URL. + jsonString, err := json.Marshal(DockerAuth{server.RegistryURL: regAuth}) + if err != nil { + handleClosingError(conn, "Could not json encode docker authentication string", err) + } + + _, err = server.KubeClient.CoreV1().Secrets(namespace).Create(&v1.Secret{ + ObjectMeta: v1.ObjectMeta{ + Name: pullSecretName, + Namespace: namespace, + }, + Type: v1.SecretTypeDockercfg, + StringData: map[string]string{ + ".dockercfg": string(jsonString), + }, + }) + if err != nil { + handleClosingError(conn, "Could not create registry pull secret", err) + } + } + + // Determine if the default service account in the desired namespace has the correct imagePullSecret, add it if not. + serviceAccount, err := server.KubeClient.CoreV1().ServiceAccounts(namespace).Get(defaultServiceAccountName) + if err != nil { + handleClosingError(conn, "Could not load default service account", err) + } + foundPullSecret := false + for _, ps := range serviceAccount.ImagePullSecrets { + if ps.Name == pullSecretName { + foundPullSecret = true + break + } + } + if !foundPullSecret { + serviceAccount.ImagePullSecrets = append(serviceAccount.ImagePullSecrets, v1.LocalObjectReference{ + Name: pullSecretName, + }) + _, err = server.KubeClient.CoreV1().ServiceAccounts(namespace).Update(serviceAccount) + if err != nil { + handleClosingError(conn, "Could not modify default service account with registry pull secret", err) + } + } + // combinedVars takes the basedomain configured in draftd and appends that to the rawVals combinedVars := append([]byte(fmt.Sprintf("basedomain: %s\n", server.Basedomain))[:], []byte(rawVals)[:]...) diff --git a/cmd/draftd/start.go b/cmd/draftd/start.go index ac4aed7..3551cf5 100644 --- a/cmd/draftd/start.go +++ b/cmd/draftd/start.go @@ -8,6 +8,8 @@ import ( log "github.com/Sirupsen/logrus" docker "github.com/docker/docker/client" "github.com/spf13/cobra" + "k8s.io/client-go/kubernetes" + "k8s.io/client-go/rest" "k8s.io/helm/pkg/helm" "github.com/Azure/draft/api" @@ -86,6 +88,15 @@ func (c *startCmd) run() error { return err } + kubeConfig, err := rest.InClusterConfig() + if err != nil { + return err + } + kubeClientset, err := kubernetes.NewForConfig(kubeConfig) + if err != nil { + return err + } + server, err := api.NewServer(protoAndAddr[0], protoAndAddr[1]) if err != nil { return fmt.Errorf("failed to create server at %s: %v", c.listenAddr, err) @@ -96,6 +107,7 @@ func (c *startCmd) run() error { server.RegistryURL = c.registryURL server.Basedomain = c.basedomain server.HelmClient = helm.NewClient(helm.Host(c.tillerURI)) + server.KubeClient = kubeClientset log.Printf("server is now listening at %s", c.listenAddr) return server.Serve() } diff --git a/glide.lock b/glide.lock index 6772ac1..2eb8ffd 100644 --- a/glide.lock +++ b/glide.lock @@ -1,5 +1,5 @@ -hash: d26f2b79aa1989919720da9a9b7dbd7d6bd6fab51c1aa7e8b99a47e7ad5d6bf1 -updated: 2017-05-08T10:21:44.503026775-07:00 +hash: f40bc7017f0f46cf9ffaaaa82f7fc973cdca0884d24287171c3bb484303f3eac +updated: 2017-05-09T14:23:38.824759012-06:00 imports: - name: cloud.google.com/go version: 3b1ae45394a234c385be014e9a488f2bb6eef821 @@ -27,8 +27,6 @@ imports: - name: github.com/coreos/pkg version: fa29b1d70f0beaddd4c7021607cc3c3be8ce94b8 subpackages: - - capnslog - - dlopen - health - httputil - timeutil @@ -163,31 +161,8 @@ imports: - name: github.com/gogo/protobuf version: e18d7aa8f8c624c915db340349aad4c49b10d173 subpackages: - - gogoproto - - plugin/compare - - plugin/defaultcheck - - plugin/description - - plugin/embedcheck - - plugin/enumstringer - - plugin/equal - - plugin/face - - plugin/gostring - - plugin/marshalto - - plugin/oneofcheck - - plugin/populate - - plugin/size - - plugin/stringer - - plugin/testgen - - plugin/union - - plugin/unmarshal - proto - - protoc-gen-gogo/descriptor - - protoc-gen-gogo/generator - - protoc-gen-gogo/grpc - - protoc-gen-gogo/plugin - sortkeys - - vanity - - vanity/command - name: github.com/golang/glog version: 44145f04b68cf362d9c4df2182967c2275eaefed - name: github.com/golang/groupcache @@ -195,7 +170,7 @@ imports: subpackages: - lru - name: github.com/golang/protobuf - version: df1d3ca07d2d07bba352d5b73c4313b4e2a6203e + version: 8616e8ee5e20a1704615e6c8d7afcdac06087a67 subpackages: - proto - ptypes/any @@ -258,7 +233,7 @@ imports: - name: github.com/pborman/uuid version: ca53cad383cad2479bbba7f7a1a05797ec1386e4 - name: github.com/pkg/errors - version: a22138067af1c4942683050411a841ade67fe1eb + version: 645ef00459ed84a119197bfb8d8205042c6df63d - name: github.com/PuerkitoBio/purell version: 8a290539e2e8629dbc4e6bad948158f790ec31f4 - name: github.com/PuerkitoBio/urlesc @@ -279,7 +254,6 @@ imports: version: f1f1a805ed361a0e078bb537e4ea78cd37dcf065 subpackages: - codec - - codec/codecgen - name: github.com/vbatts/tar-split version: b9127a139315e57ebc26030e7decf72d0a20acb4 subpackages: @@ -289,14 +263,8 @@ imports: - name: golang.org/x/crypto version: 1f22c0103821b9390939b6776727195525381532 subpackages: - - bcrypt - - blowfish - - curve25519 - pbkdf2 - - pkcs12 - - pkcs12/internal/rc2 - scrypt - - ssh - ssh/terminal - name: golang.org/x/net version: e90d6d0afc4c315a0d87a568ae68577cc15149a0 @@ -367,6 +335,114 @@ imports: version: 3887ee99ecf07df5b447e9b00d9c0b2adaa9f3e4 - name: gopkg.in/yaml.v2 version: a3f3340b5840cee44f372bddb5880fcbc419b46a +- name: k8s.io/client-go + version: e121606b0d09b2e1c467183ee46217fa85a6b672 + subpackages: + - discovery + - kubernetes + - kubernetes/typed/apps/v1beta1 + - kubernetes/typed/authentication/v1beta1 + - kubernetes/typed/authorization/v1beta1 + - kubernetes/typed/autoscaling/v1 + - kubernetes/typed/batch/v1 + - kubernetes/typed/batch/v2alpha1 + - kubernetes/typed/certificates/v1alpha1 + - kubernetes/typed/core/v1 + - kubernetes/typed/extensions/v1beta1 + - kubernetes/typed/policy/v1beta1 + - kubernetes/typed/rbac/v1alpha1 + - kubernetes/typed/storage/v1beta1 + - pkg/api + - pkg/api/errors + - pkg/api/install + - pkg/api/meta + - pkg/api/meta/metatypes + - pkg/api/resource + - pkg/api/unversioned + - pkg/api/v1 + - pkg/api/validation/path + - pkg/apimachinery + - pkg/apimachinery/announced + - pkg/apimachinery/registered + - pkg/apis/apps + - pkg/apis/apps/install + - pkg/apis/apps/v1beta1 + - pkg/apis/authentication + - pkg/apis/authentication/install + - pkg/apis/authentication/v1beta1 + - pkg/apis/authorization + - pkg/apis/authorization/install + - pkg/apis/authorization/v1beta1 + - pkg/apis/autoscaling + - pkg/apis/autoscaling/install + - pkg/apis/autoscaling/v1 + - pkg/apis/batch + - pkg/apis/batch/install + - pkg/apis/batch/v1 + - pkg/apis/batch/v2alpha1 + - pkg/apis/certificates + - pkg/apis/certificates/install + - pkg/apis/certificates/v1alpha1 + - pkg/apis/extensions + - pkg/apis/extensions/install + - pkg/apis/extensions/v1beta1 + - pkg/apis/policy + - pkg/apis/policy/install + - pkg/apis/policy/v1beta1 + - pkg/apis/rbac + - pkg/apis/rbac/install + - pkg/apis/rbac/v1alpha1 + - pkg/apis/storage + - pkg/apis/storage/install + - pkg/apis/storage/v1beta1 + - pkg/auth/user + - pkg/conversion + - pkg/conversion/queryparams + - pkg/fields + - pkg/genericapiserver/openapi/common + - pkg/labels + - pkg/runtime + - pkg/runtime/serializer + - pkg/runtime/serializer/json + - pkg/runtime/serializer/protobuf + - pkg/runtime/serializer/recognizer + - pkg/runtime/serializer/streaming + - pkg/runtime/serializer/versioning + - pkg/selection + - pkg/third_party/forked/golang/reflect + - pkg/third_party/forked/golang/template + - pkg/types + - pkg/util + - pkg/util/cert + - pkg/util/clock + - pkg/util/errors + - pkg/util/flowcontrol + - pkg/util/framer + - pkg/util/integer + - pkg/util/intstr + - pkg/util/json + - pkg/util/jsonpath + - pkg/util/labels + - pkg/util/net + - pkg/util/parsers + - pkg/util/rand + - pkg/util/runtime + - pkg/util/sets + - pkg/util/uuid + - pkg/util/validation + - pkg/util/validation/field + - pkg/util/wait + - pkg/util/yaml + - pkg/version + - pkg/watch + - pkg/watch/versioned + - plugin/pkg/client/auth + - plugin/pkg/client/auth/gcp + - plugin/pkg/client/auth/oidc + - rest + - tools/clientcmd/api + - tools/metrics + - transport - name: k8s.io/helm version: 32562a3040bb5ca690339b9840b6f60f8ce25da4 subpackages: @@ -388,7 +464,7 @@ imports: - pkg/tiller/environment - pkg/version - name: k8s.io/kubernetes - version: f07eea23494be1e7c11a8e2cf51bd96d1ec9fdf1 + version: 8eb75a5810cba92ccad845ca360cf924f2385881 subpackages: - federation/apis/federation - federation/apis/federation/install diff --git a/glide.yaml b/glide.yaml index 8e926d3..43eada1 100644 --- a/glide.yaml +++ b/glide.yaml @@ -1,8 +1,8 @@ package: github.com/Azure/draft import: - package: github.com/gorilla/websocket - repo: https://github.com/bacongobbler/websocket version: 7fe3183ee95b29153898356cc2c6026a8cb7afe5 + repo: https://github.com/bacongobbler/websocket vcs: git - package: github.com/docker/docker version: v17.03.0-ce @@ -21,3 +21,5 @@ import: - package: github.com/ghodss/yaml version: 04f313413ffd65ce25f2541bfd2b2ceec5c0908c - package: github.com/BurntSushi/toml +- package: k8s.io/client-go + version: ~v2.0.0