From 7875c0996645b1b0f3d5a4d55960068b238e8779 Mon Sep 17 00:00:00 2001 From: dhendel Date: Fri, 23 Mar 2018 16:50:08 -0500 Subject: [PATCH] Adding support for urls and file paths --- README.md | 9 ++++ cluster.yml | 5 ++ cluster/addons.go | 117 +++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 125 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index bf5bb32b..ed6cb212 100644 --- a/README.md +++ b/README.md @@ -135,6 +135,15 @@ addons: |- Note that we are using `|-` because the addons option is a multi line string option, where you can specify multiple yaml files and separate them with `---` +For `addons_include:` you may pass either http/https urls or file paths, for example: +```yaml +addons_include: + - https://raw.githubusercontent.com/rook/rook/master/cluster/examples/kubernetes/rook-operator.yaml + - https://raw.githubusercontent.com/rook/rook/master/cluster/examples/kubernetes/rook-cluster.yaml + - /opt/manifests/example.yaml + - ./nginx.yaml +``` + ## High Availability RKE is HA ready, you can specify more than one controlplane host in the `cluster.yml` file, and rke will deploy master components on all of them, the kubelets are configured to connect to `127.0.0.1:6443` by default which is the address of `nginx-proxy` service that proxy requests to all master nodes. diff --git a/cluster.yml b/cluster.yml index c40f9137..57f74d38 100644 --- a/cluster.yml +++ b/cluster.yml @@ -104,6 +104,11 @@ addons: |- ports: - containerPort: 80 +addons_include: + - https://raw.githubusercontent.com/rook/rook/master/cluster/examples/kubernetes/rook-operator.yaml + - https://raw.githubusercontent.com/rook/rook/master/cluster/examples/kubernetes/rook-cluster.yaml + - /path/to/manifest + system_images: etcd: rancher/etcd:v3.0.17 kubernetes: rancher/k8s:v1.8.9-rancher1-1 diff --git a/cluster/addons.go b/cluster/addons.go index b9fb1183..bb7df598 100644 --- a/cluster/addons.go +++ b/cluster/addons.go @@ -11,12 +11,18 @@ import ( "github.com/rancher/rke/addons" "github.com/rancher/rke/k8s" "github.com/rancher/rke/log" + "github.com/sirupsen/logrus" + "gopkg.in/yaml.v2" + "io/ioutil" + "net/http" + "strings" ) const ( - KubeDNSAddonResourceName = "rke-kubedns-addon" - UserAddonResourceName = "rke-user-addon" - IngressAddonResourceName = "rke-ingress-controller" + KubeDNSAddonResourceName = "rke-kubedns-addon" + UserAddonResourceName = "rke-user-addon" + IngressAddonResourceName = "rke-ingress-controller" + UserAddonsIncludeResourceName = "rke-user-includes-addons" ) type ingressOptions struct { @@ -38,15 +44,114 @@ func (c *Cluster) deployK8sAddOns(ctx context.Context) error { func (c *Cluster) deployUserAddOns(ctx context.Context) error { log.Infof(ctx, "[addons] Setting up user addons..") if c.Addons == "" { - log.Infof(ctx, "[addons] No user addons configured..") - return nil + if err := c.deployAddonsInclude(ctx); err != nil { + return err + } } if err := c.doAddonDeploy(ctx, c.Addons, UserAddonResourceName); err != nil { return err } - log.Infof(ctx, "[addons] User addon deployed successfully..") + + if err := c.deployAddonsInclude(ctx); err != nil { + return err + } + log.Infof(ctx, "[addons] User addons deployed successfully..") return nil +} + +func (c *Cluster) deployAddonsInclude(ctx context.Context) error { + var manifests []byte + log.Infof(ctx, "[addons] Checking for included user addons") + + if len(c.AddonsInclude) == 0 { + log.Infof(ctx, "[addons] No included addon paths or urls..") + return nil + } + + for _, addon := range c.AddonsInclude { + if strings.HasPrefix(addon, "http") { + addonYAML, err := getAddonFromURL(addon) + + if err != nil { + return err + } + + log.Infof(ctx, "[addons] Adding addon from url %s", addon) + logrus.Debugf("URL Yaml: %s", addonYAML) + + if err := validateUserAddonYAML(addonYAML); err != nil { + return err + } + + manifests = append(manifests, addonYAML...) + + } else if isFilePath(addon) { + addonYAML, err := ioutil.ReadFile(addon) + + if err != nil { + return err + } + + log.Infof(ctx, "[addons] Adding addon from %s", addon) + logrus.Debugf("FilePath Yaml: %s", string(addonYAML)) + + if err := validateUserAddonYAML(addonYAML); err != nil { + return err + } + + manifests = append(manifests, addonYAML...) + + } else { + log.Warnf(ctx, "[addons] Unable to determine if %s is a file path or url, skipping", addon) + } + + } + + log.Infof(ctx, "[addons] Deploying %s", UserAddonsIncludeResourceName) + + logrus.Debugf("[addons] Compiled addons yaml: %s", string(manifests)) + + if err := c.doAddonDeploy(ctx, string(manifests), UserAddonsIncludeResourceName); err != nil { + return err + } + + return nil +} + +func validateUserAddonYAML(addon []byte) error { + yamlContents := make(map[string]interface{}) + if err := yaml.Unmarshal(addon, &yamlContents); err != nil { + return err + } + + return nil +} + +func isFilePath(addonPath string) bool { + if _, err := os.Stat(addonPath); os.IsNotExist(err) { + return false + } + + return true +} + +func getAddonFromURL(yamlURL string) ([]byte, error) { + resp, err := http.Get(yamlURL) + + if err != nil { + return nil, err + } + + defer resp.Body.Close() + + addonYaml, err := ioutil.ReadAll(resp.Body) + + if err != nil { + return nil, err + } + + return addonYaml, nil }