From 4ff2e53feed84c6b5fd76dc457124785c15119e8 Mon Sep 17 00:00:00 2001 From: Matt Bruzek Date: Fri, 17 Apr 2015 17:20:07 -0500 Subject: [PATCH 01/29] Adding the initial Juju bundle to the cluster --- cluster/juju/bundles/README.md | 197 ++++++++++++++++++++++++++++++++ cluster/juju/bundles/local.yaml | 49 ++++++++ 2 files changed, 246 insertions(+) create mode 100644 cluster/juju/bundles/README.md create mode 100644 cluster/juju/bundles/local.yaml diff --git a/cluster/juju/bundles/README.md b/cluster/juju/bundles/README.md new file mode 100644 index 00000000000..2b1fdfe8f04 --- /dev/null +++ b/cluster/juju/bundles/README.md @@ -0,0 +1,197 @@ +# kubernetes-bundle + +The kubernetes-bundle allows you to deploy the many services of +Kubernetes to a cloud environment and get started using the Kubernetes +technology quickly. + +## Kubernetes + +Kubernetes is an open source system for managing containerized +applications. Kubernetes uses [Docker](http://docker.com) to run +containerized applications. + +## Juju TL;DR + +The [Juju](https://juju.ubuntu.com) system provides provisioning and +orchestration across a variety of clouds and bare metal. A juju bundle +describes collection of services and how they interelate. `juju +quickstart` allows you to bootstrap a deployment environment and +deploy a bundle. + +## Dive in! + +#### Install Juju Quickstart + +You will need to +[install the Juju client](https://juju.ubuntu.com/install/) and +`juju-quickstart` as pre-requisites. To deploy the bundle use +`juju-quickstart` which runs on Mac OS (`brew install +juju-quickstart`) or Ubuntu (`apt-get install juju-quickstart`). + +### Deploy Kubernetes Bundle + +Deploy Kubernetes onto any cloud and orchestrated directly in the Juju +Graphical User Interface using `juju quickstart`: + + juju quickstart -i https://raw.githubusercontent.com/whitmo/bundle-kubernetes/master/bundles.yaml + +The command above does few things for you: + +- Starts a curses based gui for managing your cloud or MAAS credentials +- Looks for a bootstrapped deployment environment, and bootstraps if + required. This will launch a bootstrap node in your chosen + deployment environment (machine 0). +- Deploys the Juju GUI to your environment onto the bootstrap node. +- Provisions 4 machines, and deploys the Kubernetes services on top of + them (Kubernetes-master, two Kubernetes minions using flannel, and etcd). +- Orchestrates the relations among the services, and exits. + +Now you should have a running Kubernetes. Run `juju status +--format=oneline` to see the address of your kubernetes master. + +For further reading on [Juju Quickstart](https://pypi.python.org/pypi/juju-quickstart) + +### Using the Kubernetes Client + +You'll need the Kubernetes command line client, +[kubectl](https://github.com/GoogleCloudPlatform/kubernetes/blob/master/docs/kubectl.md) +to interact with the created cluster. The kubectl command is +installed on the kubernetes-master charm. If you want to work with +the cluster from your computer you will need to install the binary +locally (see instructions below). + +You can access kubectl by a number ways using juju. + +via juju run: + + juju run --service kubernetes-master/0 "sudo kubectl get mi" + +via juju ssh: + + juju ssh kubernetes-master/0 -t "sudo kubectl get mi" + +You may also `juju ssh kubernetes-master/0` and call kubectl from that +machine. + +See the +[kubectl documentation](https://github.com/GoogleCloudPlatform/kubernetes/blob/master/docs/kubectl.md) +for more details of what can be done with the command line tool. + +### Scaling up the cluster + +You can add capacity by adding more Docker units: + + juju add-unit docker + +### Known Limitations + +Kubernetes currently has several platform specific functionality. For +example load balancers and persistence volumes only work with the +Google Compute provider at this time. + +The Juju integration uses the Kubernetes null provider. This means +external load balancers and storage can't be directly driven through +Kubernetes config files at this time. We look forward to adding these +capabilities to the charms. + + +## More about the components the bundle deploys + +### Kubernetes master + +The master controls the Kubernetes cluster. It manages for the worker +nodes and provides the primary interface for control by the user. + +### Kubernetes minion + +The minions are the servers that perform the work. Minions must +communicate with the master and run the workloads that are assigned to +them. + +### Flannel-docker + +Flannel provides individual subnets for each machine in the cluster by +creating a +[software defined networking](http://en.wikipedia.org/wiki/Software-defined_networking). + +### Docker + +An open platform for distributed applications for developers and sysadmins. + +### Etcd + +Etcd persists state for Flannel and Kubernetes. It is a distributed +key-value store with an http interface. + + +## For further information on getting started with Juju + +Juju has complete documentation with regard to setup, and cloud +configuration on it's own +[documentation site](https://juju.ubuntu.com/docs/). + +- [Getting Started](https://juju.ubuntu.com/docs/getting-started.html) +- [Using Juju](https://juju.ubuntu.com/docs/charms.html) + + +## Installing the kubectl outside of kubernetes master machine + +Download the Kuberentes release from: +https://github.com/GoogleCloudPlatform/kubernetes/releases and extract +the release, you can then just directly use the cli binary at +./kubernetes/platforms/linux/amd64/kubectl + +You'll need the address of the kubernetes-master as environment variable : + + juju status kubernetes-master/0 + +Grab the public-address there and export it as KUBERNETES_MASTER +environment variable : + + export KUBERNETES_MASTER=$(juju status --format=oneline kubernetes-master | cut -d' ' -f3):8080 + +And now you can run kubectl on the command line : + + kubectl get mi + +See the +[kubectl documentation](https://github.com/GoogleCloudPlatform/kubernetes/blob/master/docs/kubectl.md) +for more details of what can be done with the command line tool. + + +## Hacking on the kubernetes-bundle and associated charms + +The kubernetes-bundle is open source and available on github.com. If +you want to get started developing on the bundle you can clone it from +github. Often you will need the related charms which are also on +github. + + mkdir ~/bundles + git clone https://github.com/whitmo/kubernetes-bundle.git ~/bundles/kubernetes-bundle + mkdir -p ~/charms/trusty + git clone https://github.com/whitmo/kubernetes-charm.git ~/charms/trusty/kubernetes + git clone https://github.com/whitmo/kubernetes-master-charm.git ~/charms/trusty/kubernetes-master + + juju quickstart specs/develop.yaml + +## How to contribute + +Send us pull requests! We'll send you a cookie if they include tests and docs. + + +## Current and Most Complete Information + + - [kubernetes-master charm on Github](https://github.com/whitmo/charm-kubernetes-master) + - [kubernetes charm on GitHub](https://github.com/whitmo/charm-kubernetes) + - [etcd charm on GitHub](https://github.com/whitmo/etcd-charm) + - [Flannel charm on GitHub](https://github.com/chuckbutler/docker-flannel-charm) + - [Docker charm on GitHub](https://github.com/chuckbutler/docker-charm) + +More information about the +[Kubernetes project](https://github.com/GoogleCloudPlatform/kubernetes) +or check out the +[Kubernetes Documentation](https://github.com/GoogleCloudPlatform/kubernetes/tree/master/docs) +for more details about the Kubernetes concepts and terminology. + +Having a problem? Check the [Kubernetes issues database](https://github.com/GoogleCloudPlatform/kubernetes/issues) +for related issues. diff --git a/cluster/juju/bundles/local.yaml b/cluster/juju/bundles/local.yaml new file mode 100644 index 00000000000..fce84eaa7ac --- /dev/null +++ b/cluster/juju/bundles/local.yaml @@ -0,0 +1,49 @@ +kubernetes-local: + services: + kubernetes-master: + charm: local:trusty/kubernetes-master + annotations: + "gui-x": "600" + "gui-y": "0" + expose: true + options: + version: "source" + docker: + charm: cs:trusty/docker + num_units: 2 + options: + latest: true + annotations: + "gui-x": "0" + "gui-y": "0" + flannel-docker: + charm: cs:trusty/flannel-docker + annotations: + "gui-x": "0" + "gui-y": "300" + kubernetes: + charm: local:trusty/kubernetes + annotations: + "gui-x": "300" + "gui-y": "300" + etcd: + charm: cs:~kubernetes/trusty/etcd + annotations: + "gui-x": "300" + "gui-y": "0" + relations: + - - "flannel-docker:network" + - "docker:network" + - - "flannel-docker:docker-host" + - "docker:juju-info" + - - "flannel-docker:db" + - "etcd:client" + - - "kubernetes:docker-host" + - "docker:juju-info" + - - "etcd:client" + - "kubernetes:etcd" + - - "etcd:client" + - "kubernetes-master:etcd" + - - "kubernetes-master:minions-api" + - "kubernetes:api" + series: trusty From af8f31a0cdd4a7baca88a88394f92ed397bb8922 Mon Sep 17 00:00:00 2001 From: Matt Bruzek Date: Fri, 17 Apr 2015 17:21:37 -0500 Subject: [PATCH 02/29] Adding the Juju charms to the cluster directory. --- .../trusty/kubernetes-master/.bzrignore | 1 + .../trusty/kubernetes-master/.gitignore | 5 + .../trusty/kubernetes-master/.vendor-rc | 5 + .../charms/trusty/kubernetes-master/Makefile | 29 ++ .../charms/trusty/kubernetes-master/README.md | 101 +++++++ .../trusty/kubernetes-master/config.yaml | 9 + .../charms/trusty/kubernetes-master/copyright | 13 + .../docs/1-getting-started.md | 81 ++++++ .../kubernetes-master/docs/contributing.md | 52 ++++ .../files/apiserver.upstart.tmpl | 20 ++ .../files/controller-manager.upstart.tmpl | 20 ++ .../files/create_kubernetes_tar.sh | 59 ++++ .../files/distribution.conf.tmpl | 6 + .../kubernetes-master/files/nginx.conf.tmpl | 39 +++ .../files/scheduler.upstart.tmpl | 20 ++ .../kubernetes-master/hooks/__init__.py | 0 .../kubernetes-master/hooks/config-changed | 1 + .../hooks/etcd-relation-changed | 1 + .../trusty/kubernetes-master/hooks/hooks.py | 211 ++++++++++++++ .../trusty/kubernetes-master/hooks/install | 1 + .../trusty/kubernetes-master/hooks/install.py | 90 ++++++ .../hooks/kubernetes_installer.py | 91 ++++++ .../hooks/minions-api-relation-changed | 1 + .../hooks/network-relation-changed | 1 + .../trusty/kubernetes-master/hooks/setup.py | 30 ++ .../charms/trusty/kubernetes-master/icon.svg | 270 ++++++++++++++++++ .../trusty/kubernetes-master/metadata.yaml | 19 ++ .../charms/trusty/kubernetes-master/notes.txt | 75 +++++ .../trusty/kubernetes-master/requirements.txt | 5 + .../kubernetes-master/scripts/guestbook.sh | 48 ++++ .../unit_tests/kubernetes_installer_test.py | 105 +++++++ .../unit_tests/test_install.py | 92 ++++++ .../juju/charms/trusty/kubernetes/.bzrignore | 1 + .../juju/charms/trusty/kubernetes/.gitignore | 6 + .../juju/charms/trusty/kubernetes/.vendor-rc | 5 + .../juju/charms/trusty/kubernetes/Makefile | 29 ++ .../juju/charms/trusty/kubernetes/README.md | 100 +++++++ .../juju/charms/trusty/kubernetes/copyright | 13 + .../kubernetes/docs/1-getting-started.md | 81 ++++++ .../trusty/kubernetes/docs/contributing.md | 52 ++++ .../kubernetes/files/cadvisor.upstart.tmpl | 16 ++ .../kubernetes/files/create_kubernetes_tar.sh | 59 ++++ .../kubernetes/files/kubelet.upstart.tmpl | 14 + .../kubernetes/files/proxy.upstart.tmpl | 12 + .../kubernetes/hooks/api-relation-changed | 1 + .../kubernetes/hooks/etcd-relation-changed | 1 + .../charms/trusty/kubernetes/hooks/hooks.py | 225 +++++++++++++++ .../charms/trusty/kubernetes/hooks/install | 32 +++ .../kubernetes/hooks/kubernetes_installer.py | 52 ++++ .../trusty/kubernetes/hooks/lib/__init__.py | 0 .../kubernetes/hooks/lib/registrator.py | 84 ++++++ .../kubernetes/hooks/network-relation-changed | 1 + .../juju/charms/trusty/kubernetes/hooks/start | 15 + .../juju/charms/trusty/kubernetes/icon.svg | 270 ++++++++++++++++++ .../charms/trusty/kubernetes/metadata.yaml | 23 ++ .../charms/trusty/kubernetes/requirements.txt | 4 + .../unit_tests/lib/test_registrator.py | 45 +++ .../kubernetes/unit_tests/test_hooks.py | 8 + 58 files changed, 2650 insertions(+) create mode 100644 cluster/juju/charms/trusty/kubernetes-master/.bzrignore create mode 100644 cluster/juju/charms/trusty/kubernetes-master/.gitignore create mode 100644 cluster/juju/charms/trusty/kubernetes-master/.vendor-rc create mode 100644 cluster/juju/charms/trusty/kubernetes-master/Makefile create mode 100644 cluster/juju/charms/trusty/kubernetes-master/README.md create mode 100644 cluster/juju/charms/trusty/kubernetes-master/config.yaml create mode 100644 cluster/juju/charms/trusty/kubernetes-master/copyright create mode 100644 cluster/juju/charms/trusty/kubernetes-master/docs/1-getting-started.md create mode 100644 cluster/juju/charms/trusty/kubernetes-master/docs/contributing.md create mode 100644 cluster/juju/charms/trusty/kubernetes-master/files/apiserver.upstart.tmpl create mode 100644 cluster/juju/charms/trusty/kubernetes-master/files/controller-manager.upstart.tmpl create mode 100755 cluster/juju/charms/trusty/kubernetes-master/files/create_kubernetes_tar.sh create mode 100644 cluster/juju/charms/trusty/kubernetes-master/files/distribution.conf.tmpl create mode 100644 cluster/juju/charms/trusty/kubernetes-master/files/nginx.conf.tmpl create mode 100644 cluster/juju/charms/trusty/kubernetes-master/files/scheduler.upstart.tmpl create mode 100644 cluster/juju/charms/trusty/kubernetes-master/hooks/__init__.py create mode 120000 cluster/juju/charms/trusty/kubernetes-master/hooks/config-changed create mode 120000 cluster/juju/charms/trusty/kubernetes-master/hooks/etcd-relation-changed create mode 100755 cluster/juju/charms/trusty/kubernetes-master/hooks/hooks.py create mode 120000 cluster/juju/charms/trusty/kubernetes-master/hooks/install create mode 100755 cluster/juju/charms/trusty/kubernetes-master/hooks/install.py create mode 100644 cluster/juju/charms/trusty/kubernetes-master/hooks/kubernetes_installer.py create mode 120000 cluster/juju/charms/trusty/kubernetes-master/hooks/minions-api-relation-changed create mode 120000 cluster/juju/charms/trusty/kubernetes-master/hooks/network-relation-changed create mode 100644 cluster/juju/charms/trusty/kubernetes-master/hooks/setup.py create mode 100644 cluster/juju/charms/trusty/kubernetes-master/icon.svg create mode 100644 cluster/juju/charms/trusty/kubernetes-master/metadata.yaml create mode 100644 cluster/juju/charms/trusty/kubernetes-master/notes.txt create mode 100644 cluster/juju/charms/trusty/kubernetes-master/requirements.txt create mode 100755 cluster/juju/charms/trusty/kubernetes-master/scripts/guestbook.sh create mode 100644 cluster/juju/charms/trusty/kubernetes-master/unit_tests/kubernetes_installer_test.py create mode 100644 cluster/juju/charms/trusty/kubernetes-master/unit_tests/test_install.py create mode 100644 cluster/juju/charms/trusty/kubernetes/.bzrignore create mode 100644 cluster/juju/charms/trusty/kubernetes/.gitignore create mode 100644 cluster/juju/charms/trusty/kubernetes/.vendor-rc create mode 100644 cluster/juju/charms/trusty/kubernetes/Makefile create mode 100644 cluster/juju/charms/trusty/kubernetes/README.md create mode 100644 cluster/juju/charms/trusty/kubernetes/copyright create mode 100644 cluster/juju/charms/trusty/kubernetes/docs/1-getting-started.md create mode 100644 cluster/juju/charms/trusty/kubernetes/docs/contributing.md create mode 100644 cluster/juju/charms/trusty/kubernetes/files/cadvisor.upstart.tmpl create mode 100755 cluster/juju/charms/trusty/kubernetes/files/create_kubernetes_tar.sh create mode 100644 cluster/juju/charms/trusty/kubernetes/files/kubelet.upstart.tmpl create mode 100644 cluster/juju/charms/trusty/kubernetes/files/proxy.upstart.tmpl create mode 120000 cluster/juju/charms/trusty/kubernetes/hooks/api-relation-changed create mode 120000 cluster/juju/charms/trusty/kubernetes/hooks/etcd-relation-changed create mode 100755 cluster/juju/charms/trusty/kubernetes/hooks/hooks.py create mode 100755 cluster/juju/charms/trusty/kubernetes/hooks/install create mode 100644 cluster/juju/charms/trusty/kubernetes/hooks/kubernetes_installer.py create mode 100644 cluster/juju/charms/trusty/kubernetes/hooks/lib/__init__.py create mode 100644 cluster/juju/charms/trusty/kubernetes/hooks/lib/registrator.py create mode 120000 cluster/juju/charms/trusty/kubernetes/hooks/network-relation-changed create mode 100755 cluster/juju/charms/trusty/kubernetes/hooks/start create mode 100644 cluster/juju/charms/trusty/kubernetes/icon.svg create mode 100644 cluster/juju/charms/trusty/kubernetes/metadata.yaml create mode 100644 cluster/juju/charms/trusty/kubernetes/requirements.txt create mode 100644 cluster/juju/charms/trusty/kubernetes/unit_tests/lib/test_registrator.py create mode 100644 cluster/juju/charms/trusty/kubernetes/unit_tests/test_hooks.py diff --git a/cluster/juju/charms/trusty/kubernetes-master/.bzrignore b/cluster/juju/charms/trusty/kubernetes-master/.bzrignore new file mode 100644 index 00000000000..6b8710a711f --- /dev/null +++ b/cluster/juju/charms/trusty/kubernetes-master/.bzrignore @@ -0,0 +1 @@ +.git diff --git a/cluster/juju/charms/trusty/kubernetes-master/.gitignore b/cluster/juju/charms/trusty/kubernetes-master/.gitignore new file mode 100644 index 00000000000..48a383a0c99 --- /dev/null +++ b/cluster/juju/charms/trusty/kubernetes-master/.gitignore @@ -0,0 +1,5 @@ +*~ +.bzr +.venv +unit_tests/__pycache__ +*.pyc diff --git a/cluster/juju/charms/trusty/kubernetes-master/.vendor-rc b/cluster/juju/charms/trusty/kubernetes-master/.vendor-rc new file mode 100644 index 00000000000..87619d5117c --- /dev/null +++ b/cluster/juju/charms/trusty/kubernetes-master/.vendor-rc @@ -0,0 +1,5 @@ +omit: +- .git +- .gitignore +- .gitmodules +- revision diff --git a/cluster/juju/charms/trusty/kubernetes-master/Makefile b/cluster/juju/charms/trusty/kubernetes-master/Makefile new file mode 100644 index 00000000000..028938f10a5 --- /dev/null +++ b/cluster/juju/charms/trusty/kubernetes-master/Makefile @@ -0,0 +1,29 @@ + +build: virtualenv lint test + +virtualenv: + virtualenv .venv + .venv/bin/pip install -q -r requirements.txt + +lint: virtualenv + @.venv/bin/flake8 hooks unit_tests --exclude=charmhelpers + @.venv/bin/charm proof + +test: virtualenv + @CHARM_DIR=. PYTHONPATH=./hooks .venv/bin/py.test -v unit_tests/* + +functional-test: + @bundletester + +release: check-path virtualenv + @.venv/bin/pip install git-vendor + @.venv/bin/git-vendor sync -d ${KUBERNETES_MASTER_BZR} + +check-path: +ifndef KUBERNETES_MASTER_BZR + $(error KUBERNETES_MASTER_BZR is undefined) +endif + +clean: + rm -rf .venv + find -name *.pyc -delete diff --git a/cluster/juju/charms/trusty/kubernetes-master/README.md b/cluster/juju/charms/trusty/kubernetes-master/README.md new file mode 100644 index 00000000000..a676ea04bef --- /dev/null +++ b/cluster/juju/charms/trusty/kubernetes-master/README.md @@ -0,0 +1,101 @@ +# Kubernetes Master Charm + +[Kubernetes](https://github.com/googlecloudplatform/kubernetes) is an open +source system for managing containerized applications across multiple hosts. +Kubernetes uses [Docker](http://www.docker.io/) to package, instantiate and run +containerized applications. + +The Kubernetes Juju charms enable you to run Kubernetes on all the cloud +platforms that Juju supports. + +A Kubernetes deployment consists of several independent charms that can be +scaled to meet your needs + +### Etcd +Etcd is a key value store for Kubernetes. All persistent master state +is stored in `etcd`. + +### Flannel-docker +Flannel is a +[software defined networking](http://en.wikipedia.org/wiki/Software-defined_networking) +component that provides individual subnets for each machine in the cluster. + +### Docker +Docker is an open platform for distributing applications for system administrators. + +### Kubernetes master +The controlling unit in a Kubernetes cluster is called the master. It is the +main management contact point providing many management services for the worker +nodes. + +### Kubernetes minion +The servers that perform the work are known as minions. Minions must be able to +communicate with the master and run the workloads that are assigned to them. + + +## Usage + + +#### Deploying the Development Focus + +To deploy a Kubernetes environment in Juju : + + juju deploy cs:~kubernetes/trusty/etcd + juju deploy cs:trusty/flannel-docker + juju deploy cs:trusty/docker + juju deploy local:trusty/kubernetes-master + juju deploy local:trusty/kubernetes + + juju add-relation etcd flannel-docker + juju add-relation flannel-docker:network docker:network + juju add-relation flannel-docker:docker-host docker + juju add-relation etcd kubernetes + juju add-relation etcd kubernetes-master + juju add-relation kubernetes kubernetes-master + + +#### Deploying the recommended configuration + +A bundle can be used to deploy Kubernetes onto any cloud it can be +orchestrated directly in the Juju Graphical User Interface, when using +`juju quickstart`: + + juju quickstart https://raw.githubusercontent.com/whitmo/bundle-kubernetes/master/bundles.yaml + + +For more information on the recommended bundle deployment, see the +[Kubernetes bundle documentation](https://github.com/whitmo/bundle-kubernetes) + + +#### Post Deployment + +To interact with the kubernetes environment, either build or +[download](https://github.com/GoogleCloudPlatform/kubernetes/releases) the +[kubectl](https://github.com/GoogleCloudPlatform/kubernetes/blob/master/docs/kubectl.md) +binary (available in the releases binary tarball) and point it to the master with : + + + $ juju status kubernetes-master | grep public + public-address: 104.131.108.99 + $ export KUBERNETES_MASTER="104.131.108.99" + +# Configuration +For you convenience this charm supports changing the version of kubernetes binaries. +This can be done through the Juju GUI or on the command line: + + juju set kubernetes version=”v0.10.0” + +If the charm does not already contain the tar file with the desired architecture +and version it will attempt to download the kubernetes binaries using the gsutil +command. + +Congratulations you know have deployed a Kubernetes environment! Use the +[kubectl](https://github.com/GoogleCloudPlatform/kubernetes/blob/master/docs/kubectl.md) +to interact with the environment. + +# Kubernetes information + +- [Kubernetes github project](https://github.com/GoogleCloudPlatform/kubernetes) +- [Kubernetes issue tracker](https://github.com/GoogleCloudPlatform/kubernetes/issues) +- [Kubernetes Documenation](https://github.com/GoogleCloudPlatform/kubernetes/tree/master/docs) +- [Kubernetes releases](https://github.com/GoogleCloudPlatform/kubernetes/releases) diff --git a/cluster/juju/charms/trusty/kubernetes-master/config.yaml b/cluster/juju/charms/trusty/kubernetes-master/config.yaml new file mode 100644 index 00000000000..3164297dc4d --- /dev/null +++ b/cluster/juju/charms/trusty/kubernetes-master/config.yaml @@ -0,0 +1,9 @@ +options: + version: + type: string + default: "v0.8.1" + description: | + The kubernetes release to use in this charm. The binary files are + compiled from the source identified by this tag in github. Using the + value of "source" will use the master kubernetes branch when compiling + the binaries. diff --git a/cluster/juju/charms/trusty/kubernetes-master/copyright b/cluster/juju/charms/trusty/kubernetes-master/copyright new file mode 100644 index 00000000000..3306630127f --- /dev/null +++ b/cluster/juju/charms/trusty/kubernetes-master/copyright @@ -0,0 +1,13 @@ +Copyright 2015 Canonical LTD + +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 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/cluster/juju/charms/trusty/kubernetes-master/docs/1-getting-started.md b/cluster/juju/charms/trusty/kubernetes-master/docs/1-getting-started.md new file mode 100644 index 00000000000..a62ae259080 --- /dev/null +++ b/cluster/juju/charms/trusty/kubernetes-master/docs/1-getting-started.md @@ -0,0 +1,81 @@ +# Getting Started + +## Environment Considerations + +Kubernetes has specific cloud provider integration, and as of the current writing of this document that supported list includes the official Juju supported providers: + +- [Amazon AWS](https://jujucharms.com/docs/config-aws) +- [Azure](https://jujucharms.com/docs/config-azure) +- [Vagrant](https://jujucharms.com/docs/config-vagrant) + +Other providers available for use as a *juju manual environment* can be listed in the [Kubernetes Documentation](https://github.com/GoogleCloudPlatform/kubernetes/tree/master/docs/getting-started-guides) + +## Deployment + +The Kubernetes Charms are currently under heavy development. We encourage you to fork these charms and contribute back to the development effort! See our [contributing](contributing.md) doc for more information on this. + +#### Deploying the Preview Release charms + + juju deploy cs:~hazmat/trusty/etcd + juju deploy cs:~hazmat/trusty/flannel + juju deploy local:trusty/kubernetes-master + juju deploy local:trusty/kubernetes + + juju add-relation etcd flannel + juju add-relation etcd kubernetes + juju add-relation etcd kubernetes-master + juju add-relation kubernetes kubernetes-master + +#### Deploying the Development Release Charms + +> These charms are known to be unstable as they are tracking the current efforts of the community at enabling different features against Kubernetes. This includes the specifics for integration per cloud environment, and upgrading to the latest development version. + + mkdir -p ~/charms/trusty + git clone https://github.com/whitmo/kubernetes-master.git ~/charms/trusty/kubernetes-master + git clone https://github.com/whitmo/kubernetes.git ~/charms/trusty/kubernetes + +##### Skipping the manual deployment after git clone + +> **Note:** This path requires the pre-requisite of juju-deployer. You can obtain juju-deployer via `apt-get install juju-deployer` + + wget https://github.com/whitmo/bundle-kubernetes/blob/master/develop.yaml kubernetes-devel.yaml + juju-deployer kubernetes-devel.yaml + + +## Verifying Deployment with the Kubernetes Agent + +You'll need the kubernetes command line client to utlize the created cluster. And this can be fetched from the [Releases](https://github.com/GoogleCloudPlatform/kubernetes/releases) page on the Kubernetes project. Make sure you're fetching a client library that matches what the charm is deploying. + +Grab the tarball and from the extracted release you can just directly use the cli binary at ./kubernetes/platforms/linux/amd64/kubecfg + +You'll need the address of the kubernetes master as environment variable : + + juju status kubernetes-master/0 + +Grab the public-address there and export it as KUBERNETES_MASTER environment variable : + + export KUBERNETES_MASTER=$(juju status --format=oneline kubernetes-master | cut -d' ' -f3):8080 + +And now you can run through the kubernetes examples per normal. : + + kubecfg list minions + + +## Scale Up + +If the default capacity of the bundle doesn't provide enough capacity for your workload(s) you can scale horizontially by adding a unit to the flannel and kubernetes services respectively. + + juju add-unit flannel + juju add-unit kubernetes --to # (machine id of new flannel unit) + +## Known Issues / Limitations + +Kubernetes currently has platform specific functionality. For example load balancers and persistence volumes only work with the google compute provider atm. + +The Juju integration uses the kubernetes null provider. This means external load balancers and storage can't be directly driven through kubernetes config files. + +## Where to get help + +If you run into any issues, file a bug at our [issue tracker](http://github.com/whitmo/kubernetes-charm/issues), email the Juju Mailing List at <juju@lists.ubuntu.com>, or feel free to join us in #juju on irc.freenode.net. + + diff --git a/cluster/juju/charms/trusty/kubernetes-master/docs/contributing.md b/cluster/juju/charms/trusty/kubernetes-master/docs/contributing.md new file mode 100644 index 00000000000..5c18c7a0a17 --- /dev/null +++ b/cluster/juju/charms/trusty/kubernetes-master/docs/contributing.md @@ -0,0 +1,52 @@ + +#### Contributions are welcome, in any form. Whether that be Bugs, BugFixes, Documentation, or Features. + +### Submitting a bug + +1. Go to our [issue tracker](http://github.com/whitmo/kubernetes-master-charm/issues) on GitHub +2. Search for existing issues using the search field at the top of the page +3. File a new issue including the info listed below +4. Thanks a ton for helping make the Kubernetes-Master Charm higher quality! + +##### When filing a new bug, please include: + +- **Descriptive title** - use keywords so others can find your bug (avoiding duplicates) +- **Steps to trigger the problem** - that are specific, and repeatable +- **What happens** - when you follow the steps, and what you expected to happen instead. +- Include the exact text of any error messages if applicable (or upload screenshots). +- Kubernetes-Master Charm version (or if you're pulling directly from Git, your current commit SHA - use git rev-parse HEAD) and the Juju Version output from `juju --version`. +- Did this work in a previous charm version? If so, also provide the version that it worked in. +- Any errors logged in `juju debug log` Console view + +### Can I help fix a bug? + +Yes please! But first... + +- Make sure no one else is already working on it -- if the bug has a milestone assigned or is tagged 'fix in progress', then it's already under way. Otherwise, post a comment on the bug to let others know you're starting to work on it. + +We use the Fork & Pull model for distributed development. For a more in-depth overview: consult with the github documentation on [Collaborative Development Models](https://help.github.com/articles/using-pull-requests/#before-you-begin). + +> ##### Fork & pull +> +> The fork & pull model lets anyone fork an existing repository and push changes to their personal fork without requiring access be granted to the source repository. The changes must then be pulled into the source repository by the project maintainer. This model reduces the amount of friction for new contributors and is popular with open source projects because it allows people to work independently without upfront coordination. + +### Submitting a Bug Fix + +The following checklist will help developers not familiar with the fork and pull process of development. We appreciate your enthusiasm to make the Kubernetes-Master Charm a High Quality experience! To Rapidly get started - follow the 8 steps below. + +1. [Fork the repository](https://help.github.com/articles/fork-a-repo/) +2. Clone your fork `git clone git@github.com/myusername/kubernetes-master-charm.git` +3. Checkout your topic branch with `git checkout -b my-awesome-bugfix` +4. Hack away at your feature/bugfix +5. Validate your bugfix if possible in the amulet test(s) so we dont reintroduce it later. +6. Validate your code meets guidelines by passing lint tests `make lint` +6. Commit code `git commit -a -m 'i did all this work to fix #32'` +7. Push your branch to your forks remote branch `git push origin my-awesome-bugfix` +8. Create the [Pull Request](https://help.github.com/articles/using-pull-requests/#initiating-the-pull-request) +9. Await Code Review +10. Rejoice when Pull Request is accepted + +### Submitting a Feature + +The Steps are the same as [Submitting a Bug Fix](#submitting-a-bug-fix). If you want extra credit, make sure you [File an issue](http://github.com/whitmo/kubernetes-master-charm/issues) that covers the Feature you are working on - as kind of a courtesy heads up. And assign the issue to yourself so we know you are working on it. + diff --git a/cluster/juju/charms/trusty/kubernetes-master/files/apiserver.upstart.tmpl b/cluster/juju/charms/trusty/kubernetes-master/files/apiserver.upstart.tmpl new file mode 100644 index 00000000000..b45fd6dd839 --- /dev/null +++ b/cluster/juju/charms/trusty/kubernetes-master/files/apiserver.upstart.tmpl @@ -0,0 +1,20 @@ +description "Kubernetes Controller" + +start on runlevel [2345] +stop on runlevel [!2345] + +limit nofile 20000 20000 + +kill timeout 30 # wait 30s between SIGTERM and SIGKILL. + +exec /usr/local/bin/apiserver \ + --address=%(api_bind_address)s \ + --etcd_servers=%(etcd_servers)s \ + --logtostderr=true \ + --portal_net=10.244.240.0/20 + + + + + + diff --git a/cluster/juju/charms/trusty/kubernetes-master/files/controller-manager.upstart.tmpl b/cluster/juju/charms/trusty/kubernetes-master/files/controller-manager.upstart.tmpl new file mode 100644 index 00000000000..0cf183b2b49 --- /dev/null +++ b/cluster/juju/charms/trusty/kubernetes-master/files/controller-manager.upstart.tmpl @@ -0,0 +1,20 @@ +description "Kubernetes Controller" + +start on runlevel [2345] +stop on runlevel [!2345] + +limit nofile 20000 20000 + +kill timeout 30 # wait 30s between SIGTERM and SIGKILL. + +exec /usr/local/bin/controller-manager \ + --address=%(bind_address)s \ + --logtostderr=true \ + --master=%(api_server_address)s + + + + + + + diff --git a/cluster/juju/charms/trusty/kubernetes-master/files/create_kubernetes_tar.sh b/cluster/juju/charms/trusty/kubernetes-master/files/create_kubernetes_tar.sh new file mode 100755 index 00000000000..e6f48ee3af4 --- /dev/null +++ b/cluster/juju/charms/trusty/kubernetes-master/files/create_kubernetes_tar.sh @@ -0,0 +1,59 @@ +#!/bin/bash + +set -ex + +# This script downloads a Kubernetes release and creates a tar file with only +# the files that are needed for this charm. + +# Usage: create_kubernetes_tar.sh VERSION ARCHITECTURE + +usage() { + echo "Build a tar file with only the files needed for the kubernetes charm." + echo "The script accepts two arguments version and desired architecture." + echo "$0 version architecture" +} + +download_kubernetes() { + local VERSION=$1 + URL_PREFIX="https://github.com/GoogleCloudPlatform/kubernetes" + KUBERNETES_URL="${URL_PREFIX}/releases/download/${VERSION}/kubernetes.tar.gz" + # Remove the previous temporary files to remain idempotent. + if [ -f /tmp/kubernetes.tar.gz ]; then + rm /tmp/kubernetes.tar.gz + fi + # Download the kubernetes release from the Internet. + wget --no-verbose --tries 2 -O /tmp/kubernetes.tar.gz $KUBERNETES_URL +} + +extract_kubernetes() { + local ARCH=$1 + # Untar the kubernetes release file. + tar -xvzf /tmp/kubernetes.tar.gz -C /tmp + # Untar the server linux amd64 package. + tar -xvzf /tmp/kubernetes/server/kubernetes-server-linux-$ARCH.tar.gz -C /tmp +} + +create_charm_tar() { + local OUTPUT_FILE=${1:-"$PWD/kubernetes.tar.gz"} + local OUTPUT_DIR=`dirname $OUTPUT_FILE` + if [ ! -d $OUTPUT_DIR ]; then + mkdir -p $OUTPUT + fi + + # Change to the directory the binaries are. + cd /tmp/kubernetes/server/bin/ + + # Create a tar file with the binaries that are needed for kubernetes master. + tar -cvzf $OUTPUT_FILE kube-apiserver kube-controller-manager kubectl kube-scheduler +} + +if [ $# -gt 2 ]; then + usage + exit 1 +fi +VERSION=${1:-"v0.8.1"} +ARCH=${2:-"amd64"} +download_kubernetes $VERSION +extract_kubernetes $ARCH +TAR_FILE="$PWD/kubernetes-master-$VERSION-$ARCH.tar.gz" +create_charm_tar $TAR_FILE diff --git a/cluster/juju/charms/trusty/kubernetes-master/files/distribution.conf.tmpl b/cluster/juju/charms/trusty/kubernetes-master/files/distribution.conf.tmpl new file mode 100644 index 00000000000..68e26ce2ab8 --- /dev/null +++ b/cluster/juju/charms/trusty/kubernetes-master/files/distribution.conf.tmpl @@ -0,0 +1,6 @@ +server { + listen %(api_bind_address)s:80; + location %(web_uri)s { + alias /opt/kubernetes/_output/local/bin/linux/amd64/; + } +} diff --git a/cluster/juju/charms/trusty/kubernetes-master/files/nginx.conf.tmpl b/cluster/juju/charms/trusty/kubernetes-master/files/nginx.conf.tmpl new file mode 100644 index 00000000000..1101c0c62da --- /dev/null +++ b/cluster/juju/charms/trusty/kubernetes-master/files/nginx.conf.tmpl @@ -0,0 +1,39 @@ +# HTTP/HTTPS server +# +server { + listen 80; + server_name localhost; + + root html; + index index.html index.htm; + +# ssl on; +# ssl_certificate /usr/share/nginx/server.cert; +# ssl_certificate_key /usr/share/nginx/server.key; + +# ssl_session_timeout 5m; +# ssl_protocols SSLv3 TLSv1 TLSv1.1 TLSv1.2; +# ssl_ciphers ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+3DES:!aNULL:!MD5:!DSS; +# ssl_prefer_server_ciphers on; + + location / { +# auth_basic "Restricted"; +# auth_basic_user_file /usr/share/nginx/htpasswd; + + # Proxy settings + # disable buffering so that watch works + proxy_buffering off; + proxy_pass %(api_server_address)s; + proxy_connect_timeout 159s; + proxy_send_timeout 600s; + proxy_read_timeout 600s; + + # Disable retry + proxy_next_upstream off; + + # Support web sockets + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + } +} diff --git a/cluster/juju/charms/trusty/kubernetes-master/files/scheduler.upstart.tmpl b/cluster/juju/charms/trusty/kubernetes-master/files/scheduler.upstart.tmpl new file mode 100644 index 00000000000..f1bae362d5f --- /dev/null +++ b/cluster/juju/charms/trusty/kubernetes-master/files/scheduler.upstart.tmpl @@ -0,0 +1,20 @@ +description "Kubernetes Scheduler" + +start on runlevel [2345] +stop on runlevel [!2345] + +limit nofile 20000 20000 + +kill timeout 30 # wait 30s between SIGTERM and SIGKILL. + +exec /usr/local/bin/scheduler \ + --address=%(bind_address)s \ + --logtostderr=true \ + --master=%(api_server_address)s + + + + + + + diff --git a/cluster/juju/charms/trusty/kubernetes-master/hooks/__init__.py b/cluster/juju/charms/trusty/kubernetes-master/hooks/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/cluster/juju/charms/trusty/kubernetes-master/hooks/config-changed b/cluster/juju/charms/trusty/kubernetes-master/hooks/config-changed new file mode 120000 index 00000000000..9416ca6ac28 --- /dev/null +++ b/cluster/juju/charms/trusty/kubernetes-master/hooks/config-changed @@ -0,0 +1 @@ +hooks.py \ No newline at end of file diff --git a/cluster/juju/charms/trusty/kubernetes-master/hooks/etcd-relation-changed b/cluster/juju/charms/trusty/kubernetes-master/hooks/etcd-relation-changed new file mode 120000 index 00000000000..9416ca6ac28 --- /dev/null +++ b/cluster/juju/charms/trusty/kubernetes-master/hooks/etcd-relation-changed @@ -0,0 +1 @@ +hooks.py \ No newline at end of file diff --git a/cluster/juju/charms/trusty/kubernetes-master/hooks/hooks.py b/cluster/juju/charms/trusty/kubernetes-master/hooks/hooks.py new file mode 100755 index 00000000000..9550a3aa07d --- /dev/null +++ b/cluster/juju/charms/trusty/kubernetes-master/hooks/hooks.py @@ -0,0 +1,211 @@ +#!/usr/bin/python +""" +The main hook file is called by Juju. +""" +import contextlib +import os +import socket +import subprocess +import sys +from charmhelpers.core import hookenv, host +from kubernetes_installer import KubernetesInstaller +from path import path + +hooks = hookenv.Hooks() + + +@contextlib.contextmanager +def check_sentinel(filepath): + """ + A context manager method to write a file while the code block is doing + something and remove the file when done. + """ + fail = False + try: + yield filepath.exists() + except: + fail = True + filepath.touch() + raise + finally: + if fail is False and filepath.exists(): + filepath.remove() + + +@hooks.hook('config-changed') +def config_changed(): + """ + On the execution of the juju event 'config-changed' this function + determines the appropriate architecture and the configured version to + create kubernetes binary files. + """ + hookenv.log('Starting config-changed') + charm_dir = path(hookenv.charm_dir()) + config = hookenv.config() + # Get the version of kubernetes to install. + version = config['version'] + # Get the package architecture, rather than the from the kernel (uname -m). + arch = subprocess.check_output(['dpkg', '--print-architecture']).strip() + kubernetes_dir = path('/opt/kubernetes') + if not kubernetes_dir.exists(): + print('The source directory {0} does not exist'.format(kubernetes_dir)) + print('Was the kubernetes code cloned during install?') + exit(1) + + if version in ['source', 'head', 'master']: + branch = 'master' + else: + # Create a branch to a tag. + branch = 'tags/{0}'.format(version) + + # Construct the path to the binaries using the arch. + output_path = kubernetes_dir / '_output/local/bin/linux' / arch + installer = KubernetesInstaller(arch, version, output_path) + + # Change to the kubernetes directory (git repository). + with kubernetes_dir: + # Create a command to get the current branch. + git_branch = 'git branch | grep "\*" | cut -d" " -f2' + current_branch = subprocess.check_output(git_branch, shell=True).strip() + print('Current branch: ', current_branch) + # Create the path to a file to indicate if the build was broken. + broken_build = charm_dir / '.broken_build' + # write out the .broken_build file while this block is executing. + with check_sentinel(broken_build) as last_build_failed: + print('Last build failed: ', last_build_failed) + # Rebuild if the current version is different or last build failed. + if current_branch != version or last_build_failed: + installer.build(branch) + if not output_path.exists(): + broken_build.touch() + else: + print('Notifying minions of verison ' + version) + # Notify the minions of a version change. + for r in hookenv.relation_ids('minions-api'): + hookenv.relation_set(r, version=version) + print('Done notifing minions of version ' + version) + + # Create the symoblic links to the right directories. + installer.install() + + relation_changed() + + hookenv.log('The config-changed hook completed successfully.') + + +@hooks.hook('etcd-relation-changed', 'minions-api-relation-changed') +def relation_changed(): + template_data = get_template_data() + + # Check required keys + for k in ('etcd_servers',): + if not template_data.get(k): + print "Missing data for", k, template_data + return + + print "Running with\n", template_data + + # Render and restart as needed + for n in ('apiserver', 'controller-manager', 'scheduler'): + if render_file(n, template_data) or not host.service_running(n): + host.service_restart(n) + + # Render the file that makes the kubernetes binaries available to minions. + if render_file( + 'distribution', template_data, + 'conf.tmpl', '/etc/nginx/sites-enabled/distribution') or \ + not host.service_running('nginx'): + host.service_reload('nginx') + # Render the default nginx template. + if render_file( + 'nginx', template_data, + 'conf.tmpl', '/etc/nginx/sites-enabled/default') or \ + not host.service_running('nginx'): + host.service_reload('nginx') + + # Send api endpoint to minions + notify_minions() + + +def notify_minions(): + print("Notify minions.") + config = hookenv.config() + for r in hookenv.relation_ids('minions-api'): + hookenv.relation_set( + r, + hostname=hookenv.unit_private_ip(), + port=8080, + version=config['version']) + + +def get_template_data(): + rels = hookenv.relations() + config = hookenv.config() + template_data = {} + template_data['etcd_servers'] = ",".join([ + "http://%s:%s" % (s[0], s[1]) for s in sorted( + get_rel_hosts('etcd', rels, ('hostname', 'port')))]) + template_data['minions'] = ",".join(get_rel_hosts('minions-api', rels)) + + template_data['api_bind_address'] = _bind_addr(hookenv.unit_private_ip()) + template_data['bind_address'] = "127.0.0.1" + template_data['api_server_address'] = "http://%s:%s" % ( + hookenv.unit_private_ip(), 8080) + arch = subprocess.check_output(['dpkg', '--print-architecture']).strip() + template_data['web_uri'] = "/kubernetes/%s/local/bin/linux/%s/" % ( + config['version'], arch) + _encode(template_data) + return template_data + + +def _bind_addr(addr): + if addr.replace('.', '').isdigit(): + return addr + try: + return socket.gethostbyname(addr) + except socket.error: + raise ValueError("Could not resolve private address") + + +def _encode(d): + for k, v in d.items(): + if isinstance(v, unicode): + d[k] = v.encode('utf8') + + +def get_rel_hosts(rel_name, rels, keys=('private-address',)): + hosts = [] + for r, data in rels.get(rel_name, {}).items(): + for unit_id, unit_data in data.items(): + if unit_id == hookenv.local_unit(): + continue + values = [unit_data.get(k) for k in keys] + if not all(values): + continue + hosts.append(len(values) == 1 and values[0] or values) + return hosts + + +def render_file(name, data, src_suffix="upstart.tmpl", tgt_path=None): + tmpl_path = os.path.join( + os.environ.get('CHARM_DIR'), 'files', '%s.%s' % (name, src_suffix)) + + with open(tmpl_path) as fh: + tmpl = fh.read() + rendered = tmpl % data + + if tgt_path is None: + tgt_path = '/etc/init/%s.conf' % name + + if os.path.exists(tgt_path): + with open(tgt_path) as fh: + contents = fh.read() + if contents == rendered: + return False + + with open(tgt_path, 'w') as fh: + fh.write(rendered) + return True + +if __name__ == '__main__': + hooks.execute(sys.argv) diff --git a/cluster/juju/charms/trusty/kubernetes-master/hooks/install b/cluster/juju/charms/trusty/kubernetes-master/hooks/install new file mode 120000 index 00000000000..7f4fe4b083e --- /dev/null +++ b/cluster/juju/charms/trusty/kubernetes-master/hooks/install @@ -0,0 +1 @@ +install.py \ No newline at end of file diff --git a/cluster/juju/charms/trusty/kubernetes-master/hooks/install.py b/cluster/juju/charms/trusty/kubernetes-master/hooks/install.py new file mode 100755 index 00000000000..8f4384aa1c1 --- /dev/null +++ b/cluster/juju/charms/trusty/kubernetes-master/hooks/install.py @@ -0,0 +1,90 @@ +#!/usr/bin/python + +import setup +setup.pre_install() +import subprocess + +from charmhelpers.core import hookenv +from charmhelpers import fetch +from charmhelpers.fetch import archiveurl +from path import path + + +def install(): + install_packages() + hookenv.log('Installing go') + download_go() + + hookenv.log('Adding kubernetes and go to the path') + + strings = [ + 'export GOROOT=/usr/local/go\n', + 'export PATH=$PATH:$GOROOT/bin\n', + 'export KUBE_MASTER_IP=0.0.0.0\n', + 'export KUBERNETES_MASTER=http://$KUBE_MASTER_IP\n', + ] + update_rc_files(strings) + hookenv.log('Downloading kubernetes code') + clone_repository() + + hookenv.open_port(8080) + + hookenv.log('Install complete') + +def download_go(): + """ + Kubernetes charm strives to support upstream. Part of this is installing a + fairly recent edition of GO. This fetches the golang archive and installs + it in /usr/local + """ + go_url = 'https://storage.googleapis.com/golang/go1.4.2.linux-amd64.tar.gz' + go_sha1 = '5020af94b52b65cc9b6f11d50a67e4bae07b0aff' + handler = archiveurl.ArchiveUrlFetchHandler() + handler.install(go_url, '/usr/local', go_sha1, 'sha1') + + +def clone_repository(): + """ + Clone the upstream repository into /opt/kubernetes for deployment compilation + of kubernetes. Subsequently used during upgrades. + """ + + repository = 'https://github.com/GoogleCloudPlatform/kubernetes.git' + kubernetes_directory = '/opt/kubernetes' + + command = ['git', 'clone', repository, kubernetes_directory] + print(command) + output = subprocess.check_output(command) + print(output) + + + +def install_packages(): + """ + Install required packages to build the k8s source, and syndicate between + minion nodes. In addition, fetch pip to handle python dependencies + """ + hookenv.log('Installing Debian packages') + # Create the list of packages to install. + apt_packages = ['build-essential', 'git', 'make', 'nginx', 'python-pip'] + fetch.apt_install(fetch.filter_installed_packages(apt_packages)) + + + +def update_rc_files(strings): + """ + Preseed the bash environment for ubuntu and root with K8's env vars to + make interfacing with the api easier. (see: kubectrl docs) + """ + rc_files = [path('/home/ubuntu/.bashrc'), path('/root/.bashrc')] + for rc_file in rc_files: + lines = rc_file.lines() + for string in strings: + if string not in lines: + lines.append(string) + rc_file.write_lines(lines) + + + +if __name__ == "__main__": + install() diff --git a/cluster/juju/charms/trusty/kubernetes-master/hooks/kubernetes_installer.py b/cluster/juju/charms/trusty/kubernetes-master/hooks/kubernetes_installer.py new file mode 100644 index 00000000000..9a6123a72e4 --- /dev/null +++ b/cluster/juju/charms/trusty/kubernetes-master/hooks/kubernetes_installer.py @@ -0,0 +1,91 @@ +import os +import shlex +import subprocess +from path import path + + +def run(command, shell=False): + """ A convience method for executing all the commands. """ + print(command) + if shell is False: + command = shlex.split(command) + output = subprocess.check_output(command, shell=shell) + print(output) + return output + + +class KubernetesInstaller(): + """ + This class contains the logic needed to install kuberentes binary files. + """ + + def __init__(self, arch, version, output_dir): + """ Gather the required variables for the install. """ + # The kubernetes-master charm needs certain commands to be aliased. + self.aliases = {'kube-apiserver': 'apiserver', + 'kube-controller-manager': 'controller-manager', + 'kube-proxy': 'kube-proxy', + 'kube-scheduler': 'scheduler', + 'kubectl': 'kubectl', + 'kubelet': 'kubelet'} + self.arch = arch + self.version = version + self.output_dir = path(output_dir) + + def build(self, branch): + """ Build kubernetes from a github repository using the Makefile. """ + # Remove any old build artifacts. + make_clean = 'make clean' + run(make_clean) + # Always checkout the master to get the latest repository information. + git_checkout_cmd = 'git checkout master' + run(git_checkout_cmd) + # When checking out a tag, delete the old branch (not master). + if branch != 'master': + git_drop_branch = 'git branch -D {0}'.format(self.version) + print(git_drop_branch) + rc = subprocess.call(git_drop_branch.split()) + if rc != 0: + print('returned: %d' % rc) + # Make sure the git repository is up-to-date. + git_fetch = 'git fetch origin {0}'.format(branch) + run(git_fetch) + + if branch == 'master': + git_reset = 'git reset --hard origin/master' + run(git_reset) + else: + # Checkout a branch of kubernetes so the repo is correct. + checkout = 'git checkout -b {0} {1}'.format(self.version, branch) + run(checkout) + + # Create an environment with the path to the GO binaries included. + go_path = ('/usr/local/go/bin', os.environ.get('PATH', '')) + go_env = os.environ.copy() + go_env['PATH'] = ':'.join(go_path) + print(go_env['PATH']) + + # Compile the binaries with the make command using the WHAT variable. + make_what = "make all WHAT='cmd/kube-apiserver cmd/kubectl "\ + "cmd/kube-controller-manager plugin/cmd/kube-scheduler "\ + "cmd/kubelet cmd/kube-proxy'" + print(make_what) + rc = subprocess.call(shlex.split(make_what), env=go_env) + + def install(self, install_dir=path('/usr/local/bin')): + """ Install kubernetes binary files from the output directory. """ + + if not install_dir.isdir(): + install_dir.makedirs_p() + + # Create the symbolic links to the real kubernetes binaries. + for key, value in self.aliases.iteritems(): + target = self.output_dir / key + if target.exists(): + link = install_dir / value + if link.exists(): + link.remove() + target.symlink(link) + else: + print('Error target file {0} does not exist.'.format(target)) + exit(1) diff --git a/cluster/juju/charms/trusty/kubernetes-master/hooks/minions-api-relation-changed b/cluster/juju/charms/trusty/kubernetes-master/hooks/minions-api-relation-changed new file mode 120000 index 00000000000..9416ca6ac28 --- /dev/null +++ b/cluster/juju/charms/trusty/kubernetes-master/hooks/minions-api-relation-changed @@ -0,0 +1 @@ +hooks.py \ No newline at end of file diff --git a/cluster/juju/charms/trusty/kubernetes-master/hooks/network-relation-changed b/cluster/juju/charms/trusty/kubernetes-master/hooks/network-relation-changed new file mode 120000 index 00000000000..9416ca6ac28 --- /dev/null +++ b/cluster/juju/charms/trusty/kubernetes-master/hooks/network-relation-changed @@ -0,0 +1 @@ +hooks.py \ No newline at end of file diff --git a/cluster/juju/charms/trusty/kubernetes-master/hooks/setup.py b/cluster/juju/charms/trusty/kubernetes-master/hooks/setup.py new file mode 100644 index 00000000000..0c6efbffbb2 --- /dev/null +++ b/cluster/juju/charms/trusty/kubernetes-master/hooks/setup.py @@ -0,0 +1,30 @@ +def pre_install(): + """ + Do any setup required before the install hook. + """ + install_charmhelpers() + install_path() + + +def install_charmhelpers(): + """ + Install the charmhelpers library, if not present. + """ + try: + import charmhelpers # noqa + except ImportError: + import subprocess + subprocess.check_call(['apt-get', 'install', '-y', 'python-pip']) + subprocess.check_call(['pip', 'install', 'charmhelpers']) + + +def install_path(): + """ + Install the path.py library, when not present. + """ + try: + import path # noqa + except ImportError: + import subprocess + subprocess.check_call(['apt-get', 'install', '-y', 'python-pip']) + subprocess.check_call(['pip', 'install', 'path.py']) diff --git a/cluster/juju/charms/trusty/kubernetes-master/icon.svg b/cluster/juju/charms/trusty/kubernetes-master/icon.svg new file mode 100644 index 00000000000..55098d1079f --- /dev/null +++ b/cluster/juju/charms/trusty/kubernetes-master/icon.svg @@ -0,0 +1,270 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/cluster/juju/charms/trusty/kubernetes-master/metadata.yaml b/cluster/juju/charms/trusty/kubernetes-master/metadata.yaml new file mode 100644 index 00000000000..27eb421e49f --- /dev/null +++ b/cluster/juju/charms/trusty/kubernetes-master/metadata.yaml @@ -0,0 +1,19 @@ +name: kubernetes-master +summary: Container Cluster Management Master +description: | + Provides a kubernetes api endpoint, scheduler for managing containers. +maintainers: + - Matt Bruzek + - Whit Morriss + - Charles Butler +tags: + - ops + - network +provides: + client-api: + interface: kubernetes-client + minions-api: + interface: kubernetes-api +requires: + etcd: + interface: etcd diff --git a/cluster/juju/charms/trusty/kubernetes-master/notes.txt b/cluster/juju/charms/trusty/kubernetes-master/notes.txt new file mode 100644 index 00000000000..f266cabef81 --- /dev/null +++ b/cluster/juju/charms/trusty/kubernetes-master/notes.txt @@ -0,0 +1,75 @@ +kubernetes-master +----------------- + +notes on src +------------ + current provider responsibilities + - instances + - load blanacers + - zones (not useful as its only for apiserver). + + provider functionality currently hardcoded to gce across codebase + - persistent storage + + +ideas +----- + - juju provider impl + - file provider for machines/minions + - openvpn as overlay per extant salt config. + +cloud +----- + +todo +---- + - token auth file + - format csv -> token, user, uid + - config privileged + - config log-level + - config / check logs collection endpoint + - config / version and binary location via url + +Q/A +---- + +https://botbot.me/freenode/google-containers/2014-10-17/?msg=23696683&page=6 + +Q. The new volumes/storage provider api appears to be hardcoded to +gce.. Is there a plan to abstract that anytime soon? +A. effectively it is abstract enough for the moment, no plans to +change, but willing subject to suitable abstraction. + +Q.The zone provider api appears to return the address only of the api +server afaics. How is that useful? afaics the better semantic would be +an attribute on the minions to instantiate multiple templates across +zones? +A. apparently not considered, current solution for ha is multiple k8s +per zone with external lb. pointed out this was inane. + + +Q. Several previous platforms supported have been moved to the icebox, +just curious what was subject to bitrot. the salt/shell script for +those platforms or something more api intrinsic? +A. apparently the change to ship binaries instead of build from src +broke them.. somehow. + +Q. i'm mostly interested in flannel due to its portability. Does the +inter pod networking setup need to include the other components of the +system, ie does api talk directly to containers, or only via kubelet. +A. api server only talks to kubelet + + +Q. Status of HA? +A. not done yet, election package merged, nothing using it. + +Afaics design discussion doesn't take place on the list. + +Q. Is minion registration supported, ie. bypassing cloud provider +filter all instances via regex match? +A. not done yet, pull request in review for minions in etcd (not +found, perhaps merged) + +------------- +cadvisor usage helper +https://github.com/GoogleCloudPlatform/heapster diff --git a/cluster/juju/charms/trusty/kubernetes-master/requirements.txt b/cluster/juju/charms/trusty/kubernetes-master/requirements.txt new file mode 100644 index 00000000000..0cd4a6a2d65 --- /dev/null +++ b/cluster/juju/charms/trusty/kubernetes-master/requirements.txt @@ -0,0 +1,5 @@ +flake8 +pytest +bundletester +path.py +charmhelpers diff --git a/cluster/juju/charms/trusty/kubernetes-master/scripts/guestbook.sh b/cluster/juju/charms/trusty/kubernetes-master/scripts/guestbook.sh new file mode 100755 index 00000000000..b59ae5e55b2 --- /dev/null +++ b/cluster/juju/charms/trusty/kubernetes-master/scripts/guestbook.sh @@ -0,0 +1,48 @@ +#!/bin/bash + +# This script sets up the guestbook example application in Kubernetes. +# The KUBERENTES_MASTER variable must be set to the URL for kubectl to work. +# The first argument is optional and can be used for debugging. + +set -o errexit # (set -e) + +DEBUG=false +if [[ "$1" == "-d" ]] || [[ "$1" == "--debug" ]]; then + DEBUG=true + set -o xtrace # (set -x) +fi +cd /opt/kubernetes/ +# Step One Turn up the redis master +kubectl create -f examples/guestbook/redis-master.json +if [[ "${DEBUG}" == true ]]; then + kubectl get pods +fi +# Step Two: Turn up the master service +kubectl create -f examples/guestbook/redis-master-service.json +if [[ "${DEBUG}" == true ]]; then + kubectl get services +fi +# Step Three: Turn up the replicated slave pods +kubectl create -f examples/guestbook/redis-slave-controller.json +if [[ "${DEBUG}" == true ]]; then + kubectl get replicationcontrollers + kubectl get pods +fi +# Step Four: Create the redis slave service +kubectl create -f examples/guestbook/redis-slave-service.json +if [[ "${DEBUG}" == true ]]; then + kubectl get services +fi +# Step Five: Create the frontend pod +kubectl create -f examples/guestbook/frontend-controller.json +if [[ "${DEBUG}" == true ]]; then + kubectl get replicationcontrollers + kubectl get pods +fi + +set +x + +echo "# Now run the following commands on your juju client" +echo "juju run --service kubernetes 'open-port 8000'" +echo "juju expose kubernetes" +echo "# Go to the kubernetes public address on port 8000 to see the guestbook application" diff --git a/cluster/juju/charms/trusty/kubernetes-master/unit_tests/kubernetes_installer_test.py b/cluster/juju/charms/trusty/kubernetes-master/unit_tests/kubernetes_installer_test.py new file mode 100644 index 00000000000..ba0367863fd --- /dev/null +++ b/cluster/juju/charms/trusty/kubernetes-master/unit_tests/kubernetes_installer_test.py @@ -0,0 +1,105 @@ +from mock import patch +from path import path +from path import Path +import pytest +import subprocess +import sys + +# Add the hooks directory to the python path. +hooks_dir = Path('__file__').parent.abspath() / 'hooks' +sys.path.insert(0, hooks_dir.abspath()) +# Import the module to be tested. +import kubernetes_installer + + +def test_run(): + """ Test the run method both with valid commands and invalid commands. """ + ls = 'ls -l {0}/kubernetes_installer.py'.format(hooks_dir) + output = kubernetes_installer.run(ls, False) + assert output + assert 'kubernetes_installer.py' in output + output = kubernetes_installer.run(ls, True) + assert output + assert 'kubernetes_installer.py' in output + + invalid_directory = path('/not/a/real/directory') + assert not invalid_directory.exists() + invalid_command = 'ls {0}'.format(invalid_directory) + with pytest.raises(subprocess.CalledProcessError) as error: + kubernetes_installer.run(invalid_command) + print(error) + with pytest.raises(subprocess.CalledProcessError) as error: + kubernetes_installer.run(invalid_command, shell=True) + print(error) + + +class TestKubernetesInstaller(): + + def makeone(self, *args, **kw): + """ Create the KubernetesInstaller object and return it. """ + from kubernetes_installer import KubernetesInstaller + return KubernetesInstaller(*args, **kw) + + def test_init(self): + """ Test that the init method correctly assigns the variables. """ + ki = self.makeone('i386', '3.0.1', '/tmp/does_not_exist') + assert ki.aliases + assert 'kube-apiserver' in ki.aliases + assert 'kube-controller-manager' in ki.aliases + assert 'kube-scheduler' in ki.aliases + assert 'kubectl' in ki.aliases + assert 'kubelet' in ki.aliases + assert ki.arch == 'i386' + assert ki.version == '3.0.1' + assert ki.output_dir == path('/tmp/does_not_exist') + + @patch('kubernetes_installer.run') + @patch('kubernetes_installer.subprocess.call') + def test_build(self, cmock, rmock): + """ Test the build method with master and non-master branches. """ + directory = path('/tmp/kubernetes_installer_test/build') + ki = self.makeone('amd64', 'v99.00.11', directory) + assert not directory.exists(), 'The %s directory exists!' % directory + # Call the build method with "master" branch. + ki.build("master") + # TODO: run is called many times but mock only remembers last one. + rmock.assert_called_with('git reset --hard origin/master') + # TODO: call is complex and hard to verify with mock, fix that. + cmock.assert_called_once() + + # Call the build method with something other than "master" branch. + ki.build("branch") + # TODO: run is called many times, but mock only remembers last one. + rmock.assert_called_with('git checkout -b v99.00.11 branch') + # TODO: call is complex and hard to verify with mock, fix that. + cmock.assert_called_once() + + directory.rmtree_p() + + def test_install(self): + """ Test the install method that it creates the correct links. """ + directory = path('/tmp/kubernetes_installer_test/install') + ki = self.makeone('ppc64le', '1.2.3', directory) + assert not directory.exists(), 'The %s directory exits!' % directory + directory.makedirs_p() + # Create the files for the install method to link to. + (directory / 'kube-apiserver').touch() + (directory / 'kube-controller-manager').touch() + (directory / 'kube-proxy').touch() + (directory / 'kube-scheduler').touch() + (directory / 'kubectl').touch() + (directory / 'kubelet').touch() + + results = directory / 'install/results/go/here' + assert not results.exists() + ki.install(results) + assert results.isdir() + # Check that all the files were correctly aliased and are links. + assert (results / 'apiserver').islink() + assert (results / 'controller-manager').islink() + assert (results / 'kube-proxy').islink() + assert (results / 'scheduler').islink() + assert (results / 'kubectl').islink() + assert (results / 'kubelet').islink() + + directory.rmtree_p() diff --git a/cluster/juju/charms/trusty/kubernetes-master/unit_tests/test_install.py b/cluster/juju/charms/trusty/kubernetes-master/unit_tests/test_install.py new file mode 100644 index 00000000000..e6fe3d08e89 --- /dev/null +++ b/cluster/juju/charms/trusty/kubernetes-master/unit_tests/test_install.py @@ -0,0 +1,92 @@ +from mock import patch, Mock, MagicMock +from path import Path +import pytest +import sys + +# Munge the python path so we can find our hook code +d = Path('__file__').parent.abspath() / 'hooks' +sys.path.insert(0, d.abspath()) + +# Import the modules from the hook +import install + +class TestInstallHook(): + + @patch('install.path') + def test_update_rc_files(self, pmock): + """ + Test happy path on updating env files. Assuming everything + exists and is in place. + """ + pmock.return_value.lines.return_value = ['line1', 'line2'] + install.update_rc_files(['test1', 'test2']) + pmock.return_value.write_lines.assert_called_with(['line1', 'line2', + 'test1', 'test2']) + + def test_update_rc_files_with_nonexistant_path(self): + """ + Test an unhappy path if the bashrc/users do not exist. + """ + with pytest.raises(OSError) as exinfo: + install.update_rc_files(['test1','test2']) + + @patch('install.fetch') + @patch('install.hookenv') + def test_package_installation(self, hemock, ftmock): + """ + Verify we are calling the known essentials to build and syndicate + kubes. + """ + pkgs = ['build-essential', 'git', + 'make', 'nginx', 'python-pip'] + install.install_packages() + hemock.log.assert_called_with('Installing Debian packages') + ftmock.filter_installed_packages.assert_called_with(pkgs) + + @patch('install.archiveurl.ArchiveUrlFetchHandler') + def test_go_download(self, aumock): + """ + Test that we are actually handing off to charm-helpers to + download a specific archive of Go. This is non-configurable so + its reasonably safe to assume we're going to always do this, + and when it changes we shall curse the brittleness of this test. + """ + ins_mock = aumock.return_value.install + install.download_go() + url = 'https://storage.googleapis.com/golang/go1.4.2.linux-amd64.tar.gz' + sha1='5020af94b52b65cc9b6f11d50a67e4bae07b0aff' + ins_mock.assert_called_with(url, '/usr/local', sha1, 'sha1') + + @patch('install.subprocess') + def test_clone_repository(self, spmock): + """ + We're not using a unit-tested git library - so ensure our subprocess + call is consistent. If we change this, we want to know we've broken it. + """ + install.clone_repository() + repo = 'https://github.com/GoogleCloudPlatform/kubernetes.git' + direct = '/opt/kubernetes' + spmock.check_output.assert_called_with(['git', 'clone', repo, direct]) + + @patch('install.install_packages') + @patch('install.download_go') + @patch('install.clone_repository') + @patch('install.update_rc_files') + @patch('install.hookenv') + def test_install_main(self, hemock, urmock, crmock, dgmock, ipmock): + """ + Ensure the driver/main method is calling all the supporting methods. + """ + strings = [ + 'export GOROOT=/usr/local/go\n', + 'export PATH=$PATH:$GOROOT/bin\n', + 'export KUBE_MASTER_IP=0.0.0.0\n', + 'export KUBERNETES_MASTER=http://$KUBE_MASTER_IP\n', + ] + + install.install() + crmock.assert_called_once() + dgmock.assert_called_once() + crmock.assert_called_once() + urmock.assert_called_with(strings) + hemock.open_port.assert_called_with(8080) diff --git a/cluster/juju/charms/trusty/kubernetes/.bzrignore b/cluster/juju/charms/trusty/kubernetes/.bzrignore new file mode 100644 index 00000000000..6b8710a711f --- /dev/null +++ b/cluster/juju/charms/trusty/kubernetes/.bzrignore @@ -0,0 +1 @@ +.git diff --git a/cluster/juju/charms/trusty/kubernetes/.gitignore b/cluster/juju/charms/trusty/kubernetes/.gitignore new file mode 100644 index 00000000000..f42003421e2 --- /dev/null +++ b/cluster/juju/charms/trusty/kubernetes/.gitignore @@ -0,0 +1,6 @@ +.bzr +*.pyc +*~ +*\#* +/files/.kubernetes-* +.venv diff --git a/cluster/juju/charms/trusty/kubernetes/.vendor-rc b/cluster/juju/charms/trusty/kubernetes/.vendor-rc new file mode 100644 index 00000000000..87619d5117c --- /dev/null +++ b/cluster/juju/charms/trusty/kubernetes/.vendor-rc @@ -0,0 +1,5 @@ +omit: +- .git +- .gitignore +- .gitmodules +- revision diff --git a/cluster/juju/charms/trusty/kubernetes/Makefile b/cluster/juju/charms/trusty/kubernetes/Makefile new file mode 100644 index 00000000000..afbe61a1a06 --- /dev/null +++ b/cluster/juju/charms/trusty/kubernetes/Makefile @@ -0,0 +1,29 @@ + +build: virtualenv lint test + +virtualenv: + virtualenv .venv + .venv/bin/pip install -q -r requirements.txt + +lint: virtualenv + @.venv/bin/flake8 hooks unit_tests --exclude=charmhelpers + @.venv/bin/charm proof + +test: virtualenv + @CHARM_DIR=. PYTHONPATH=./hooks .venv/bin/py.test unit_tests/* + +functional-test: + @bundletester + +release: check-path virtualenv + @.venv/bin/pip install git-vendor + @.venv/bin/git-vendor sync -d ${KUBERNETES_BZR} + +check-path: +ifndef KUBERNETES_BZR + $(error KUBERNETES_BZR is undefined) +endif + +clean: + rm -rf .venv + find -name *.pyc -delete diff --git a/cluster/juju/charms/trusty/kubernetes/README.md b/cluster/juju/charms/trusty/kubernetes/README.md new file mode 100644 index 00000000000..c40479e901c --- /dev/null +++ b/cluster/juju/charms/trusty/kubernetes/README.md @@ -0,0 +1,100 @@ +# Kubernetes Minion Charm + +[Kubernetes](https://github.com/googlecloudplatform/kubernetes) is an open +source system for managing containerized applications across multiple hosts. +Kubernetes uses [Docker](http://www.docker.io/) to package, instantiate and run +containerized applications. + +The Kubernetes Juju charms enable you to run Kubernetes on all the cloud +platforms that Juju supports. + +A Kubernetes deployment consists of several independent charms that can be +scaled to meet your needs + +### Etcd +Etcd is a key value store for Kubernetes. All persistent master state +is stored in `etcd`. + +### Flannel-docker +Flannel is a +[software defined networking](http://en.wikipedia.org/wiki/Software-defined_networking) +component that provides individual subnets for each machine in the cluster. + +### Docker +Docker is an open platform for distributing applications for system administrators. + +### Kubernetes master +The controlling unit in a Kubernetes cluster is called the master. It is the +main management contact point providing many management services for the worker +nodes. + +### Kubernetes minion +The servers that perform the work are known as minions. Minions must be able to +communicate with the master and run the workloads that are assigned to them. + + +## Usage + +#### Deploying the Development Focus + +To deploy a Kubernetes environment in Juju : + + juju deploy cs:~kubernetes/trusty/etcd + juju deploy cs:trusty/flannel-docker + juju deploy cs:trusty/docker + juju deploy local:trusty/kubernetes-master + juju deploy local:trusty/kubernetes + + juju add-relation etcd flannel-docker + juju add-relation flannel-docker:network docker:network + juju add-relation flannel-docker:docker-host docker + juju add-relation etcd kubernetes + juju add-relation etcd kubernetes-master + juju add-relation kubernetes kubernetes-master + + +#### Deploying the recommended configuration + +A bundle can be used to deploy Kubernetes onto any cloud it can be +orchestrated directly in the Juju Graphical User Interface, when using +`juju quickstart`: + + juju quickstart https://raw.githubusercontent.com/whitmo/bundle-kubernetes/master/bundles.yaml + + +For more information on the recommended bundle deployment, see the +[Kubernetes bundle documentation](https://github.com/whitmo/bundle-kubernetes) + + +#### Post Deployment + +To interact with the kubernetes environment, either build or +[download](https://github.com/GoogleCloudPlatform/kubernetes/releases) the +[kubectl](https://github.com/GoogleCloudPlatform/kubernetes/blob/master/docs/kubectl.md) +binary (available in the releases binary tarball) and point it to the master with : + + + $ juju status kubernetes-master | grep public + public-address: 104.131.108.99 + $ export KUBERNETES_MASTER="104.131.108.99" + +# Configuration +For you convenience this charm supports changing the version of kubernetes binaries. +This can be done through the Juju GUI or on the command line: + + juju set kubernetes version=”v0.10.0” + +If the charm does not already contain the tar file with the desired architecture +and version it will attempt to download the kubernetes binaries using the gsutil +command. + +Congratulations you know have deployed a Kubernetes environment! Use the +[kubectl](https://github.com/GoogleCloudPlatform/kubernetes/blob/master/docs/kubectl.md) +to interact with the environment. + +# Kubernetes information + +- [Kubernetes github project](https://github.com/GoogleCloudPlatform/kubernetes) +- [Kubernetes issue tracker](https://github.com/GoogleCloudPlatform/kubernetes/issues) +- [Kubernetes Documenation](https://github.com/GoogleCloudPlatform/kubernetes/tree/master/docs) +- [Kubernetes releases](https://github.com/GoogleCloudPlatform/kubernetes/releases) diff --git a/cluster/juju/charms/trusty/kubernetes/copyright b/cluster/juju/charms/trusty/kubernetes/copyright new file mode 100644 index 00000000000..3306630127f --- /dev/null +++ b/cluster/juju/charms/trusty/kubernetes/copyright @@ -0,0 +1,13 @@ +Copyright 2015 Canonical LTD + +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 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/cluster/juju/charms/trusty/kubernetes/docs/1-getting-started.md b/cluster/juju/charms/trusty/kubernetes/docs/1-getting-started.md new file mode 100644 index 00000000000..a62ae259080 --- /dev/null +++ b/cluster/juju/charms/trusty/kubernetes/docs/1-getting-started.md @@ -0,0 +1,81 @@ +# Getting Started + +## Environment Considerations + +Kubernetes has specific cloud provider integration, and as of the current writing of this document that supported list includes the official Juju supported providers: + +- [Amazon AWS](https://jujucharms.com/docs/config-aws) +- [Azure](https://jujucharms.com/docs/config-azure) +- [Vagrant](https://jujucharms.com/docs/config-vagrant) + +Other providers available for use as a *juju manual environment* can be listed in the [Kubernetes Documentation](https://github.com/GoogleCloudPlatform/kubernetes/tree/master/docs/getting-started-guides) + +## Deployment + +The Kubernetes Charms are currently under heavy development. We encourage you to fork these charms and contribute back to the development effort! See our [contributing](contributing.md) doc for more information on this. + +#### Deploying the Preview Release charms + + juju deploy cs:~hazmat/trusty/etcd + juju deploy cs:~hazmat/trusty/flannel + juju deploy local:trusty/kubernetes-master + juju deploy local:trusty/kubernetes + + juju add-relation etcd flannel + juju add-relation etcd kubernetes + juju add-relation etcd kubernetes-master + juju add-relation kubernetes kubernetes-master + +#### Deploying the Development Release Charms + +> These charms are known to be unstable as they are tracking the current efforts of the community at enabling different features against Kubernetes. This includes the specifics for integration per cloud environment, and upgrading to the latest development version. + + mkdir -p ~/charms/trusty + git clone https://github.com/whitmo/kubernetes-master.git ~/charms/trusty/kubernetes-master + git clone https://github.com/whitmo/kubernetes.git ~/charms/trusty/kubernetes + +##### Skipping the manual deployment after git clone + +> **Note:** This path requires the pre-requisite of juju-deployer. You can obtain juju-deployer via `apt-get install juju-deployer` + + wget https://github.com/whitmo/bundle-kubernetes/blob/master/develop.yaml kubernetes-devel.yaml + juju-deployer kubernetes-devel.yaml + + +## Verifying Deployment with the Kubernetes Agent + +You'll need the kubernetes command line client to utlize the created cluster. And this can be fetched from the [Releases](https://github.com/GoogleCloudPlatform/kubernetes/releases) page on the Kubernetes project. Make sure you're fetching a client library that matches what the charm is deploying. + +Grab the tarball and from the extracted release you can just directly use the cli binary at ./kubernetes/platforms/linux/amd64/kubecfg + +You'll need the address of the kubernetes master as environment variable : + + juju status kubernetes-master/0 + +Grab the public-address there and export it as KUBERNETES_MASTER environment variable : + + export KUBERNETES_MASTER=$(juju status --format=oneline kubernetes-master | cut -d' ' -f3):8080 + +And now you can run through the kubernetes examples per normal. : + + kubecfg list minions + + +## Scale Up + +If the default capacity of the bundle doesn't provide enough capacity for your workload(s) you can scale horizontially by adding a unit to the flannel and kubernetes services respectively. + + juju add-unit flannel + juju add-unit kubernetes --to # (machine id of new flannel unit) + +## Known Issues / Limitations + +Kubernetes currently has platform specific functionality. For example load balancers and persistence volumes only work with the google compute provider atm. + +The Juju integration uses the kubernetes null provider. This means external load balancers and storage can't be directly driven through kubernetes config files. + +## Where to get help + +If you run into any issues, file a bug at our [issue tracker](http://github.com/whitmo/kubernetes-charm/issues), email the Juju Mailing List at <juju@lists.ubuntu.com>, or feel free to join us in #juju on irc.freenode.net. + + diff --git a/cluster/juju/charms/trusty/kubernetes/docs/contributing.md b/cluster/juju/charms/trusty/kubernetes/docs/contributing.md new file mode 100644 index 00000000000..b418ee8bb45 --- /dev/null +++ b/cluster/juju/charms/trusty/kubernetes/docs/contributing.md @@ -0,0 +1,52 @@ + +#### Contributions are welcome, in any form. Whether that be Bugs, BugFixes, Documentation, or Features. + +### Submitting a bug + +1. Go to our [issue tracker](http://github.com/whitmo/kubernetes-charm/issues) on GitHub +2. Search for existing issues using the search field at the top of the page +3. File a new issue including the info listed below +4. Thanks a ton for helping make the Kubernetes Charm higher quality! + +##### When filing a new bug, please include: + +- **Descriptive title** - use keywords so others can find your bug (avoiding duplicates) +- **Steps to trigger the problem** - that are specific, and repeatable +- **What happens** - when you follow the steps, and what you expected to happen instead. +- Include the exact text of any error messages if applicable (or upload screenshots). +- Kubernetes Charm version (or if you're pulling directly from Git, your current commit SHA - use git rev-parse HEAD) and the Juju Version output from `juju --version`. +- Did this work in a previous charm version? If so, also provide the version that it worked in. +- Any errors logged in `juju debug log` Console view + +### Can I help fix a bug? + +Yes please! But first... + +- Make sure no one else is already working on it -- if the bug has a milestone assigned or is tagged 'fix in progress', then it's already under way. Otherwise, post a comment on the bug to let others know you're starting to work on it. + +We use the Fork & Pull model for distributed development. For a more in-depth overview: consult with the github documentation on [Collaborative Development Models](https://help.github.com/articles/using-pull-requests/#before-you-begin). + +> ##### Fork & pull +> +> The fork & pull model lets anyone fork an existing repository and push changes to their personal fork without requiring access be granted to the source repository. The changes must then be pulled into the source repository by the project maintainer. This model reduces the amount of friction for new contributors and is popular with open source projects because it allows people to work independently without upfront coordination. + +### Submitting a Bug Fix + +The following checklist will help developers not familiar with the fork and pull process of development. We appreciate your enthusiasm to make the Kubernetes Charm a High Quality experience! To Rapidly get started - follow the 8 steps below. + +1. [Fork the repository](https://help.github.com/articles/fork-a-repo/) +2. Clone your fork `git clone git@github.com/myusername/kubernetes-charm.git` +3. Checkout your topic branch with `git checkout -b my-awesome-bugfix` +4. Hack away at your feature/bugfix +5. Validate your bugfix if possible in the amulet test(s) so we dont reintroduce it later. +6. Validate your code meets guidelines by passing lint tests `make lint` +6. Commit code `git commit -a -m 'i did all this work to fix #32'` +7. Push your branch to your forks remote branch `git push origin my-awesome-bugfix` +8. Create the [Pull Request](https://help.github.com/articles/using-pull-requests/#initiating-the-pull-request) +9. Await Code Review +10. Rejoice when Pull Request is accepted + +### Submitting a Feature + +The Steps are the same as [Submitting a Bug Fix](#submitting-a-bug-fix). If you want extra credit, make sure you [File an issue](http://github.com/whitmo/kubernetes-charm/issues) that covers the Feature you are working on - as kind of a courtesy heads up. And assign the issue to yourself so we know you are working on it. + diff --git a/cluster/juju/charms/trusty/kubernetes/files/cadvisor.upstart.tmpl b/cluster/juju/charms/trusty/kubernetes/files/cadvisor.upstart.tmpl new file mode 100644 index 00000000000..78b7ae0b933 --- /dev/null +++ b/cluster/juju/charms/trusty/kubernetes/files/cadvisor.upstart.tmpl @@ -0,0 +1,16 @@ +description "cadvisor container metrics" + +start on started docker +stop on stopping docker + +limit nofile 20000 20000 + +kill timeout 60 # wait 60s between SIGTERM and SIGKILL. + +exec docker run \ + --volume=/var/run:/var/run:rw \ + --volume=/sys/fs/cgroup:/sys/fs/cgroup:ro \ + --volume=/var/lib/docker/:/var/lib/docker:ro \ + --publish=127.0.0.1:4194:8080 \ + --name=cadvisor \ + google/cadvisor:latest diff --git a/cluster/juju/charms/trusty/kubernetes/files/create_kubernetes_tar.sh b/cluster/juju/charms/trusty/kubernetes/files/create_kubernetes_tar.sh new file mode 100755 index 00000000000..bf0dd73ea0c --- /dev/null +++ b/cluster/juju/charms/trusty/kubernetes/files/create_kubernetes_tar.sh @@ -0,0 +1,59 @@ +#!/bin/bash + +set -ex + +# This script downloads a Kubernetes release and creates a tar file with only +# the files that are needed for this charm. + +# Usage: create_kubernetes_tar.sh VERSION ARCHITECTURE + +usage() { + echo "Build a tar file with only the files needed for the kubernetes charm." + echo "The script accepts two arguments version and desired architecture." + echo "$0 version architecture" +} + +download_kubernetes() { + local VERSION=$1 + URL_PREFIX="https://github.com/GoogleCloudPlatform/kubernetes" + KUBERNETES_URL="${URL_PREFIX}/releases/download/${VERSION}/kubernetes.tar.gz" + # Remove the previous temporary files to remain idempotent. + if [ -f /tmp/kubernetes.tar.gz ]; then + rm /tmp/kubernetes.tar.gz + fi + # Download the kubernetes release from the Internet. + wget --no-verbose --tries 2 -O /tmp/kubernetes.tar.gz $KUBERNETES_URL +} + +extract_kubernetes() { + local ARCH=$1 + # Untar the kubernetes release file. + tar -xvzf /tmp/kubernetes.tar.gz -C /tmp + # Untar the server linux amd64 package. + tar -xvzf /tmp/kubernetes/server/kubernetes-server-linux-$ARCH.tar.gz -C /tmp +} + +create_charm_tar() { + local OUTPUT_FILE=${1:-"$PWD/kubernetes.tar.gz"} + local OUTPUT_DIR=`dirname $OUTPUT_FILE` + if [ ! -d $OUTPUT_DIR ]; then + mkdir -p $OUTPUT + fi + + # Change to the directory the binaries are. + cd /tmp/kubernetes/server/bin/ + + # Create a tar file with the binaries that are needed for kubernetes minion. + tar -cvzf $OUTPUT_FILE kubelet kube-proxy +} + +if [ $# -gt 2 ]; then + usage + exit 1 +fi +VERSION=${1:-"v0.8.1"} +ARCH=${2:-"amd64"} +download_kubernetes $VERSION +extract_kubernetes $ARCH +TAR_FILE="$PWD/kubernetes-$VERSION-$ARCH.tar.gz" +create_charm_tar $TAR_FILE diff --git a/cluster/juju/charms/trusty/kubernetes/files/kubelet.upstart.tmpl b/cluster/juju/charms/trusty/kubernetes/files/kubelet.upstart.tmpl new file mode 100644 index 00000000000..183756ce814 --- /dev/null +++ b/cluster/juju/charms/trusty/kubernetes/files/kubelet.upstart.tmpl @@ -0,0 +1,14 @@ +description "kubernetes kubelet" + +start on runlevel [2345] +stop on runlevel [!2345] + +limit nofile 20000 20000 + +kill timeout 60 # wait 60s between SIGTERM and SIGKILL. + +exec /usr/local/bin/kubelet \ + --address=%(kubelet_bind_addr)s \ + --api_servers=%(kubeapi_server)s \ + --hostname_override=%(kubelet_bind_addr)s \ + --logtostderr=true diff --git a/cluster/juju/charms/trusty/kubernetes/files/proxy.upstart.tmpl b/cluster/juju/charms/trusty/kubernetes/files/proxy.upstart.tmpl new file mode 100644 index 00000000000..ef150ae2581 --- /dev/null +++ b/cluster/juju/charms/trusty/kubernetes/files/proxy.upstart.tmpl @@ -0,0 +1,12 @@ +description "kubernetes proxy" + +start on runlevel [2345] +stop on runlevel [!2345] + +limit nofile 20000 20000 + +kill timeout 60 # wait 60s between SIGTERM and SIGKILL. + +exec /usr/local/bin/proxy \ + --master=%(kubeapi_server)s \ + --logtostderr=true diff --git a/cluster/juju/charms/trusty/kubernetes/hooks/api-relation-changed b/cluster/juju/charms/trusty/kubernetes/hooks/api-relation-changed new file mode 120000 index 00000000000..9416ca6ac28 --- /dev/null +++ b/cluster/juju/charms/trusty/kubernetes/hooks/api-relation-changed @@ -0,0 +1 @@ +hooks.py \ No newline at end of file diff --git a/cluster/juju/charms/trusty/kubernetes/hooks/etcd-relation-changed b/cluster/juju/charms/trusty/kubernetes/hooks/etcd-relation-changed new file mode 120000 index 00000000000..9416ca6ac28 --- /dev/null +++ b/cluster/juju/charms/trusty/kubernetes/hooks/etcd-relation-changed @@ -0,0 +1 @@ +hooks.py \ No newline at end of file diff --git a/cluster/juju/charms/trusty/kubernetes/hooks/hooks.py b/cluster/juju/charms/trusty/kubernetes/hooks/hooks.py new file mode 100755 index 00000000000..000b58cff55 --- /dev/null +++ b/cluster/juju/charms/trusty/kubernetes/hooks/hooks.py @@ -0,0 +1,225 @@ +#!/usr/bin/python +""" +The main hook file that is called by Juju. +""" +import json +import httplib +import os +import time +import socket +import subprocess +import sys +import urlparse + +from charmhelpers.core import hookenv, host +from kubernetes_installer import KubernetesInstaller +from path import path + +from lib.registrator import Registrator + +hooks = hookenv.Hooks() + + +@hooks.hook('api-relation-changed') +def api_relation_changed(): + """ + On the relation to the api server, this function determines the appropriate + architecture and the configured version to copy the kubernetes binary files + from the kubernetes-master charm and installs it locally on this machine. + """ + hookenv.log('Starting api-relation-changed') + charm_dir = path(hookenv.charm_dir()) + # Get the package architecture, rather than the from the kernel (uname -m). + arch = subprocess.check_output(['dpkg', '--print-architecture']).strip() + kubernetes_bin_dir = path('/opt/kubernetes/bin') + # Get the version of kubernetes to install. + version = subprocess.check_output(['relation-get', 'version']).strip() + print('Relation version: ', version) + if not version: + print('No version present in the relation.') + exit(0) + version_file = charm_dir / '.version' + if version_file.exists(): + previous_version = version_file.text() + print('Previous version: ', previous_version) + if version == previous_version: + exit(0) + # Can not download binaries while the service is running, so stop it. + # TODO: Figure out a better way to handle upgraded kubernetes binaries. + for service in ('kubelet', 'proxy'): + if host.service_running(service): + host.service_stop(service) + command = ['relation-get', 'private-address'] + # Get the kubernetes-master address. + server = subprocess.check_output(command).strip() + print('Kubernetes master private address: ', server) + installer = KubernetesInstaller(arch, version, server, kubernetes_bin_dir) + installer.download() + installer.install() + # Write the most recently installed version number to the file. + version_file.write_text(version) + relation_changed() + + +@hooks.hook('etcd-relation-changed', + 'network-relation-changed') +def relation_changed(): + """Connect the parts and go :-) + """ + template_data = get_template_data() + + # Check required keys + for k in ('etcd_servers', 'kubeapi_server'): + if not template_data.get(k): + print("Missing data for %s %s" % (k, template_data)) + return + print("Running with\n%s" % template_data) + + # Setup kubernetes supplemental group + setup_kubernetes_group() + + # Register services + for n in ("cadvisor", "kubelet", "proxy"): + if render_upstart(n, template_data) or not host.service_running(n): + print("Starting %s" % n) + host.service_restart(n) + + # Register machine via api + print("Registering machine") + register_machine(template_data['kubeapi_server']) + + # Save the marker (for restarts to detect prev install) + template_data.save() + + +def get_template_data(): + rels = hookenv.relations() + template_data = hookenv.Config() + template_data.CONFIG_FILE_NAME = ".unit-state" + + overlay_type = get_scoped_rel_attr('network', rels, 'overlay_type') + etcd_servers = get_rel_hosts('etcd', rels, ('hostname', 'port')) + api_servers = get_rel_hosts('api', rels, ('hostname', 'port')) + + # kubernetes master isn't ha yet. + if api_servers: + api_info = api_servers.pop() + api_servers = "http://%s:%s" % (api_info[0], api_info[1]) + + template_data['overlay_type'] = overlay_type + template_data['kubelet_bind_addr'] = _bind_addr( + hookenv.unit_private_ip()) + template_data['proxy_bind_addr'] = _bind_addr( + hookenv.unit_get('public-address')) + template_data['kubeapi_server'] = api_servers + template_data['etcd_servers'] = ",".join([ + 'http://%s:%s' % (s[0], s[1]) for s in sorted(etcd_servers)]) + template_data['identifier'] = os.environ['JUJU_UNIT_NAME'].replace( + '/', '-') + return _encode(template_data) + + +def _bind_addr(addr): + if addr.replace('.', '').isdigit(): + return addr + try: + return socket.gethostbyname(addr) + except socket.error: + raise ValueError("Could not resolve private address") + + +def _encode(d): + for k, v in d.items(): + if isinstance(v, unicode): + d[k] = v.encode('utf8') + return d + + +def get_scoped_rel_attr(rel_name, rels, attr): + private_ip = hookenv.unit_private_ip() + for r, data in rels.get(rel_name, {}).items(): + for unit_id, unit_data in data.items(): + if unit_data.get('private-address') != private_ip: + continue + if unit_data.get(attr): + return unit_data.get(attr) + + +def get_rel_hosts(rel_name, rels, keys=('private-address',)): + hosts = [] + for r, data in rels.get(rel_name, {}).items(): + for unit_id, unit_data in data.items(): + if unit_id == hookenv.local_unit(): + continue + values = [unit_data.get(k) for k in keys] + if not all(values): + continue + hosts.append(len(values) == 1 and values[0] or values) + return hosts + + +def render_upstart(name, data): + tmpl_path = os.path.join( + os.environ.get('CHARM_DIR'), 'files', '%s.upstart.tmpl' % name) + + with open(tmpl_path) as fh: + tmpl = fh.read() + rendered = tmpl % data + + tgt_path = '/etc/init/%s.conf' % name + + if os.path.exists(tgt_path): + with open(tgt_path) as fh: + contents = fh.read() + if contents == rendered: + return False + + with open(tgt_path, 'w') as fh: + fh.write(rendered) + return True + + +def register_machine(apiserver, retry=False): + parsed = urlparse.urlparse(apiserver) + # identity = hookenv.local_unit().replace('/', '-') + private_address = hookenv.unit_private_ip() + + with open('/proc/meminfo') as fh: + info = fh.readline() + mem = info.strip().split(":")[1].strip().split()[0] + cpus = os.sysconf("SC_NPROCESSORS_ONLN") + + registration_request = Registrator() + registration_request.data['Kind'] = 'Minion' + registration_request.data['id'] = private_address + registration_request.data['name'] = private_address + registration_request.data['metadata']['name'] = private_address + registration_request.data['spec']['capacity']['mem'] = mem + ' K' + registration_request.data['spec']['capacity']['cpu'] = cpus + registration_request.data['spec']['externalID'] = private_address + registration_request.data['status']['hostIP'] = private_address + + response, result = registration_request.register(parsed.hostname, + parsed.port, + "/api/v1beta3/nodes") + + print(response) + + try: + registration_request.command_succeeded(response, result) + except ValueError: + # This happens when we have already registered + # for now this is OK + pass + +def setup_kubernetes_group(): + output = subprocess.check_output(['groups', 'kubernetes']) + + # TODO: check group exists + if 'docker' not in output: + subprocess.check_output( + ['usermod', '-a', '-G', 'docker', 'kubernetes']) + + +if __name__ == '__main__': + hooks.execute(sys.argv) diff --git a/cluster/juju/charms/trusty/kubernetes/hooks/install b/cluster/juju/charms/trusty/kubernetes/hooks/install new file mode 100755 index 00000000000..32c3251eb4a --- /dev/null +++ b/cluster/juju/charms/trusty/kubernetes/hooks/install @@ -0,0 +1,32 @@ +#!/bin/bash + +set -ex + +# Install is guaranteed to run once per rootfs + +echo "Installing kubernetes-node on $JUJU_UNIT_NAME" + +apt-get update -qq +apt-get install -q -y \ + bridge-utils \ + python-dev \ + python-pip \ + wget + +pip install path.py + +# Create the necessary kubernetes group. +groupadd kubernetes +useradd -d /var/lib/kubernetes \ + -g kubernetes \ + -s /sbin/nologin \ + --system \ + kubernetes + +install -d -m 0744 -o kubernetes -g kubernetes /var/lib/kubernetes +install -d -m 0744 -o kubernetes -g kubernetes /etc/kubernetes/manifests + +# wait for the world, depends on where we installed it from distro +#sudo service docker.io stop +# or upstream archive +#sudo service docker stop diff --git a/cluster/juju/charms/trusty/kubernetes/hooks/kubernetes_installer.py b/cluster/juju/charms/trusty/kubernetes/hooks/kubernetes_installer.py new file mode 100644 index 00000000000..d85beb47443 --- /dev/null +++ b/cluster/juju/charms/trusty/kubernetes/hooks/kubernetes_installer.py @@ -0,0 +1,52 @@ +import subprocess +from path import path + + +class KubernetesInstaller(): + """ + This class contains the logic needed to install kuberentes binary files. + """ + + def __init__(self, arch, version, master, output_dir): + """ Gather the required variables for the install. """ + # The kubernetes charm needs certain commands to be aliased. + self.aliases = {'kube-proxy': 'proxy', + 'kubelet': 'kubelet'} + self.arch = arch + self.version = version + self.master = master + self.output_dir = output_dir + + def download(self): + """ Download the kuberentes binaries from the kubernetes master. """ + url = 'http://{0}/kubernetes/{1}/local/bin/linux/{2}'.format( + self.master, self.version, self.arch) + if not self.output_dir.isdir(): + self.output_dir.makedirs_p() + + for key in self.aliases: + uri = '{0}/{1}'.format(url, key) + destination = self.output_dir / key + wget = 'wget -nv {0} -O {1}'.format(uri, destination) + print(wget) + output = subprocess.check_output(wget.split()) + print(output) + destination.chmod(0o755) + + def install(self, install_dir=path('/usr/local/bin')): + """ Create links to the binary files to the install directory. """ + + if not install_dir.isdir(): + install_dir.makedirs_p() + + # Create the symbolic links to the real kubernetes binaries. + for key, value in self.aliases.iteritems(): + target = self.output_dir / key + if target.exists(): + link = install_dir / value + if link.exists(): + link.remove() + target.symlink(link) + else: + print('Error target file {0} does not exist.'.format(target)) + exit(1) diff --git a/cluster/juju/charms/trusty/kubernetes/hooks/lib/__init__.py b/cluster/juju/charms/trusty/kubernetes/hooks/lib/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/cluster/juju/charms/trusty/kubernetes/hooks/lib/registrator.py b/cluster/juju/charms/trusty/kubernetes/hooks/lib/registrator.py new file mode 100644 index 00000000000..e096110730d --- /dev/null +++ b/cluster/juju/charms/trusty/kubernetes/hooks/lib/registrator.py @@ -0,0 +1,84 @@ +import httplib +import json +import time + +class Registrator: + + def __init__(self): + self.ds ={ + "creationTimestamp": "", + "kind": "Minion", + "name": "", # private_address + "metadata": { + "name": "", #private_address, + }, + "spec": { + "externalID": "", #private_address + "capacity": { + "mem": "", # mem + ' K', + "cpu": "", # cpus + } + }, + "status": { + "conditions": [], + "hostIP": "", #private_address + } + } + + @property + def data(self): + ''' Returns a data-structure for population to make a request. ''' + return self.ds + + def register(self, hostname, port, api_path): + ''' Contact the API Server for a new registration ''' + headers = {"Content-type": "application/json", + "Accept": "application/json"} + connection = httplib.HTTPConnection(hostname, port) + print 'CONN {}'.format(connection) + connection.request("POST", api_path, json.dumps(self.data), headers) + response = connection.getresponse() + body = response.read() + print(body) + result = json.loads(body) + print("Response status:%s reason:%s body:%s" % ( + response.status, response.reason, result)) + return response, result + + + def update(self): + ''' Contact the API Server to update a registration ''' + # do a get on the API for the node + # repost to the API with any modified data + pass + + def save(self): + ''' Marshall the registration data ''' + # TODO + pass + + def command_succeeded(self, response, result): + ''' Evaluate response data to determine if the command was successful ''' + if response.status in [200, 201]: + print("Registered") + return True + elif response.status in [409,]: + print("Status Conflict") + # Suggested return a PUT instead of a POST with this response + # code, this predicates use of the UPDATE method + # TODO + elif response.status in (500,) and result.get( + 'message', '').startswith('The requested resource does not exist'): + # There's something fishy in the kube api here (0.4 dev), first time we + # go to register a new minion, we always seem to get this error. + # https://github.com/GoogleCloudPlatform/kubernetes/issues/1995 + time.sleep(1) + print("Retrying registration...") + raise ValueError("Registration returned 500, retry") + # return register_machine(apiserver, retry=True) + else: + print("Registration error") + # TODO - get request data + raise RuntimeError("Unable to register machine with") + + diff --git a/cluster/juju/charms/trusty/kubernetes/hooks/network-relation-changed b/cluster/juju/charms/trusty/kubernetes/hooks/network-relation-changed new file mode 120000 index 00000000000..9416ca6ac28 --- /dev/null +++ b/cluster/juju/charms/trusty/kubernetes/hooks/network-relation-changed @@ -0,0 +1 @@ +hooks.py \ No newline at end of file diff --git a/cluster/juju/charms/trusty/kubernetes/hooks/start b/cluster/juju/charms/trusty/kubernetes/hooks/start new file mode 100755 index 00000000000..d8e63394372 --- /dev/null +++ b/cluster/juju/charms/trusty/kubernetes/hooks/start @@ -0,0 +1,15 @@ +#!/bin/bash + +set -ex + +# Start is guaranteed to be called once when after the unit is installed +# *AND* once everytime a machine is rebooted. + +if [ ! -f $CHARM_DIR/.unit-state ] +then + exit 0; +fi + +service docker restart +service proxy restart +service kubelet restart diff --git a/cluster/juju/charms/trusty/kubernetes/icon.svg b/cluster/juju/charms/trusty/kubernetes/icon.svg new file mode 100644 index 00000000000..55098d1079f --- /dev/null +++ b/cluster/juju/charms/trusty/kubernetes/icon.svg @@ -0,0 +1,270 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/cluster/juju/charms/trusty/kubernetes/metadata.yaml b/cluster/juju/charms/trusty/kubernetes/metadata.yaml new file mode 100644 index 00000000000..0de51dda336 --- /dev/null +++ b/cluster/juju/charms/trusty/kubernetes/metadata.yaml @@ -0,0 +1,23 @@ +name: kubernetes +summary: Container Cluster Management Node +maintainers: + - Matt Bruzek + - Whit Morriss + - Charles Butler +description: | + Provides a kubernetes node for running containers + See http://goo.gl/CSggxE +tags: + - ops + - network +subordinate: true +requires: + etcd: + interface: etcd + api: + interface: kubernetes-api + network: + interface: overlay-network + docker-host: + interface: juju-info + scope: container diff --git a/cluster/juju/charms/trusty/kubernetes/requirements.txt b/cluster/juju/charms/trusty/kubernetes/requirements.txt new file mode 100644 index 00000000000..aaf7acb8996 --- /dev/null +++ b/cluster/juju/charms/trusty/kubernetes/requirements.txt @@ -0,0 +1,4 @@ +flake8 +pytest +bundletester +path.py diff --git a/cluster/juju/charms/trusty/kubernetes/unit_tests/lib/test_registrator.py b/cluster/juju/charms/trusty/kubernetes/unit_tests/lib/test_registrator.py new file mode 100644 index 00000000000..95f7c1dacaa --- /dev/null +++ b/cluster/juju/charms/trusty/kubernetes/unit_tests/lib/test_registrator.py @@ -0,0 +1,45 @@ +import json +from mock import MagicMock, patch, call +from path import Path +import pytest +import sys + +d = Path('__file__').parent.abspath() / 'hooks' +sys.path.insert(0, d.abspath()) + +from lib.registrator import Registrator + +class TestRegistrator(): + + def setup_method(self, method): + self.r = Registrator() + + def test_data_type(self): + if type(self.r.data) is not dict: + pytest.fail("Invalid type") + + @patch('json.loads') + @patch('httplib.HTTPConnection') + def test_register(self, httplibmock, jsonmock): + result = self.r.register('foo', 80, '/v1beta1/test') + + httplibmock.assert_called_with('foo', 80) + requestmock = httplibmock().request + requestmock.assert_called_with( + "POST", "/v1beta1/test", + json.dumps(self.r.data), + {"Content-type": "application/json", + "Accept": "application/json"}) + + + def test_command_succeeded(self): + response = MagicMock() + result = json.loads('{"status": "Failure", "kind": "Status", "code": 409, "apiVersion": "v1beta2", "reason": "AlreadyExists", "details": {"kind": "minion", "id": "10.200.147.200"}, "message": "minion \\"10.200.147.200\\" already exists", "creationTimestamp": null}') + response.status = 200 + self.r.command_succeeded(response, result) + response.status = 500 + with pytest.raises(RuntimeError): + self.r.command_succeeded(response, result) + response.status = 409 + with pytest.raises(ValueError): + self.r.command_succeeded(response, result) diff --git a/cluster/juju/charms/trusty/kubernetes/unit_tests/test_hooks.py b/cluster/juju/charms/trusty/kubernetes/unit_tests/test_hooks.py new file mode 100644 index 00000000000..49e59f44fc2 --- /dev/null +++ b/cluster/juju/charms/trusty/kubernetes/unit_tests/test_hooks.py @@ -0,0 +1,8 @@ +# import pytest + + +class TestHooks(): + + # TODO: Actually write tests. + def test_fake(self): + pass From 8f038a82a422bd70a8c815a1d55b942be2244dbc Mon Sep 17 00:00:00 2001 From: Matt Bruzek Date: Fri, 17 Apr 2015 17:22:48 -0500 Subject: [PATCH 03/29] Adding a python file to parse the IP addresses. --- cluster/juju/return-node-ips.py | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100755 cluster/juju/return-node-ips.py diff --git a/cluster/juju/return-node-ips.py b/cluster/juju/return-node-ips.py new file mode 100755 index 00000000000..a1fc703fb6a --- /dev/null +++ b/cluster/juju/return-node-ips.py @@ -0,0 +1,7 @@ +#!/usr/bin/env python +import json +import sys +nodes = json.loads(sys.argv[1]) +for num in nodes: + print num['Stdout'].rstrip() + From 89043414f6f686773afa37135e60aeabd6a0b414 Mon Sep 17 00:00:00 2001 From: Matt Bruzek Date: Fri, 17 Apr 2015 17:23:53 -0500 Subject: [PATCH 04/29] Changed the kube-up logic to use local bundles and charms. Implemented a feature of kube-down Corrected a bug on bootstrap of Juju environment. --- cluster/juju/util.sh | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/cluster/juju/util.sh b/cluster/juju/util.sh index 12587edc357..fb0a396c465 100755 --- a/cluster/juju/util.sh +++ b/cluster/juju/util.sh @@ -20,7 +20,9 @@ set -o nounset set -o pipefail source $KUBE_ROOT/cluster/juju/prereqs/ubuntu-juju.sh -KUBE_BUNDLE_URL='https://raw.githubusercontent.com/whitmo/bundle-kubernetes/master/bundles.yaml' +export JUJU_REPOSITORY=${KUBE_ROOT}/cluster/juju/charms +#KUBE_BUNDLE_URL='https://raw.githubusercontent.com/whitmo/bundle-kubernetes/master/bundles.yaml' +KUBE_BUNDLE_PATH=${KUBE_ROOT}/cluster/juju/bundles/local.yaml function verify-prereqs() { gather_installation_reqs } @@ -30,6 +32,11 @@ function get-password() { } function kube-up() { + if [[ -d "~/.juju/current-env" ]]; then + juju quickstart -i --no-browser + else + juju quickstart --no-browser + fi # If something were to happen that I'm not accounting for, do not # punish the user by making them tear things down. In a perfect world # quickstart should handle this situation, so be nice in the meantime @@ -37,17 +44,17 @@ function kube-up() { envstatus=$(juju status kubernetes-master --format=oneline) if [[ "" == "${envstatus}" ]]; then - if [[ -d "~/.juju/current-env" ]]; then - juju quickstart -i --no-browser -i $KUBE_BUNDLE_URL - else - juju quickstart --no-browser ${KUBE_BUNDLE_URL} - fi - sleep 60 + juju deployer -c ${KUBE_BUNDLE_PATH} fi # Sleep due to juju bug http://pad.lv/1432759 sleep-status } +function kube-down() { + local jujuenv + jujuenv=$(cat ~/.juju/current-environment) + juju destroy-environment $jujuenv +} function detect-master() { local kubestatus @@ -56,8 +63,7 @@ function detect-master() { export KUBE_MASTER_IP=${kubestatus} export KUBE_MASTER=$KUBE_MASTER_IP:8080 export KUBERNETES_MASTER=$KUBE_MASTER - - } +} function detect-minions(){ # Strip out the components except for STDOUT return @@ -72,10 +78,10 @@ function detect-minions(){ # Stdout: '10.202.146.124 # ' # UnitId: kubernetes/1 - - KUBE_MINION_IP_ADDRESSES=($(juju run --service kubernetes \ - "unit-get private-address" --format=yaml \ - | awk '/Stdout/ {gsub(/'\''/,""); print $2}')) + KUBERNETES_JSON=$(juju run --service kubernetes \ + "unit-get private-address" --format=json) + KUBE_MINION_IP_ADDRESSES=($(${KUBE_ROOT}/cluster/juju/return-node-ips.py $KUBERNETES_JSON)) + echo $KUBE_MINION_IP_ADDRESSES NUM_MINIONS=${#KUBE_MINION_IP_ADDRESSES[@]} MINION_NAMES=$KUBE_MINION_IP_ADDRESSES } @@ -88,7 +94,6 @@ function teardown-logging-firewall(){ echo "TODO: teardown logging and firewall rules" } - function sleep-status(){ local i local maxtime @@ -109,4 +114,3 @@ function sleep-status(){ echo "Sleeping an additional minute to allow the cluster to settle" sleep 60 } - From 57683ce0ecccc55ad1f3b5de78d2001217a8757b Mon Sep 17 00:00:00 2001 From: Matt Bruzek Date: Fri, 17 Apr 2015 17:25:23 -0500 Subject: [PATCH 05/29] Adding deployer to the dependency list. --- cluster/juju/prereqs/ubuntu-juju.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cluster/juju/prereqs/ubuntu-juju.sh b/cluster/juju/prereqs/ubuntu-juju.sh index d5ffd7c8f91..9d3f7672c8b 100644 --- a/cluster/juju/prereqs/ubuntu-juju.sh +++ b/cluster/juju/prereqs/ubuntu-juju.sh @@ -45,5 +45,5 @@ function gather_installation_reqs(){ fi package_status 'juju-quickstart' + package_status 'juju-deployer' } - From 3dd62a5c652bc762e4dd73cf9bd7876de897f8c2 Mon Sep 17 00:00:00 2001 From: Matt Bruzek Date: Mon, 20 Apr 2015 16:55:08 -0500 Subject: [PATCH 06/29] Log the JSON output from BASH --- cluster/juju/util.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cluster/juju/util.sh b/cluster/juju/util.sh index fb0a396c465..1e2065fd81a 100755 --- a/cluster/juju/util.sh +++ b/cluster/juju/util.sh @@ -80,7 +80,8 @@ function detect-minions(){ # UnitId: kubernetes/1 KUBERNETES_JSON=$(juju run --service kubernetes \ "unit-get private-address" --format=json) - KUBE_MINION_IP_ADDRESSES=($(${KUBE_ROOT}/cluster/juju/return-node-ips.py $KUBERNETES_JSON)) + echo $KUBERNETES_JSON + KUBE_MINION_IP_ADDRESSES=($(${KUBE_ROOT}/cluster/juju/return-node-ips.py "$KUBERNETES_JSON")) echo $KUBE_MINION_IP_ADDRESSES NUM_MINIONS=${#KUBE_MINION_IP_ADDRESSES[@]} MINION_NAMES=$KUBE_MINION_IP_ADDRESSES From 7802db4862ebbf483ad3300d4635363a569a7583 Mon Sep 17 00:00:00 2001 From: Matt Bruzek Date: Mon, 20 Apr 2015 16:57:42 -0500 Subject: [PATCH 07/29] Added protetecion if the arguments are not there. --- cluster/juju/return-node-ips.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/cluster/juju/return-node-ips.py b/cluster/juju/return-node-ips.py index a1fc703fb6a..c652ccd079d 100755 --- a/cluster/juju/return-node-ips.py +++ b/cluster/juju/return-node-ips.py @@ -1,7 +1,13 @@ #!/usr/bin/env python import json import sys -nodes = json.loads(sys.argv[1]) -for num in nodes: - print num['Stdout'].rstrip() +# This script helps parse out the private IP addreses from the +# `juju run` command's JSON object, see cluster/juju/util.sh +if len(sys.argv) > 1: + print(sys.argv[1]) + # It takes the JSON output as the first argument. + nodes = json.loads(sys.argv[1]) + # There can be multiple nodes to print the Stdout. + for num in nodes: + print num['Stdout'].rstrip() From a5da3708d22c1f7314bf362ef129b73e417ce30a Mon Sep 17 00:00:00 2001 From: Matt Bruzek Date: Mon, 20 Apr 2015 17:00:41 -0500 Subject: [PATCH 08/29] Removing old docs, setting latest false on docker --- cluster/juju/bundles/local.yaml | 2 +- .../docs/1-getting-started.md | 81 ------------------- .../kubernetes-master/docs/contributing.md | 52 ------------ .../kubernetes/docs/1-getting-started.md | 81 ------------------- .../trusty/kubernetes/docs/contributing.md | 52 ------------ 5 files changed, 1 insertion(+), 267 deletions(-) delete mode 100644 cluster/juju/charms/trusty/kubernetes-master/docs/1-getting-started.md delete mode 100644 cluster/juju/charms/trusty/kubernetes-master/docs/contributing.md delete mode 100644 cluster/juju/charms/trusty/kubernetes/docs/1-getting-started.md delete mode 100644 cluster/juju/charms/trusty/kubernetes/docs/contributing.md diff --git a/cluster/juju/bundles/local.yaml b/cluster/juju/bundles/local.yaml index fce84eaa7ac..9dcd4153d12 100644 --- a/cluster/juju/bundles/local.yaml +++ b/cluster/juju/bundles/local.yaml @@ -12,7 +12,7 @@ kubernetes-local: charm: cs:trusty/docker num_units: 2 options: - latest: true + latest: false annotations: "gui-x": "0" "gui-y": "0" diff --git a/cluster/juju/charms/trusty/kubernetes-master/docs/1-getting-started.md b/cluster/juju/charms/trusty/kubernetes-master/docs/1-getting-started.md deleted file mode 100644 index a62ae259080..00000000000 --- a/cluster/juju/charms/trusty/kubernetes-master/docs/1-getting-started.md +++ /dev/null @@ -1,81 +0,0 @@ -# Getting Started - -## Environment Considerations - -Kubernetes has specific cloud provider integration, and as of the current writing of this document that supported list includes the official Juju supported providers: - -- [Amazon AWS](https://jujucharms.com/docs/config-aws) -- [Azure](https://jujucharms.com/docs/config-azure) -- [Vagrant](https://jujucharms.com/docs/config-vagrant) - -Other providers available for use as a *juju manual environment* can be listed in the [Kubernetes Documentation](https://github.com/GoogleCloudPlatform/kubernetes/tree/master/docs/getting-started-guides) - -## Deployment - -The Kubernetes Charms are currently under heavy development. We encourage you to fork these charms and contribute back to the development effort! See our [contributing](contributing.md) doc for more information on this. - -#### Deploying the Preview Release charms - - juju deploy cs:~hazmat/trusty/etcd - juju deploy cs:~hazmat/trusty/flannel - juju deploy local:trusty/kubernetes-master - juju deploy local:trusty/kubernetes - - juju add-relation etcd flannel - juju add-relation etcd kubernetes - juju add-relation etcd kubernetes-master - juju add-relation kubernetes kubernetes-master - -#### Deploying the Development Release Charms - -> These charms are known to be unstable as they are tracking the current efforts of the community at enabling different features against Kubernetes. This includes the specifics for integration per cloud environment, and upgrading to the latest development version. - - mkdir -p ~/charms/trusty - git clone https://github.com/whitmo/kubernetes-master.git ~/charms/trusty/kubernetes-master - git clone https://github.com/whitmo/kubernetes.git ~/charms/trusty/kubernetes - -##### Skipping the manual deployment after git clone - -> **Note:** This path requires the pre-requisite of juju-deployer. You can obtain juju-deployer via `apt-get install juju-deployer` - - wget https://github.com/whitmo/bundle-kubernetes/blob/master/develop.yaml kubernetes-devel.yaml - juju-deployer kubernetes-devel.yaml - - -## Verifying Deployment with the Kubernetes Agent - -You'll need the kubernetes command line client to utlize the created cluster. And this can be fetched from the [Releases](https://github.com/GoogleCloudPlatform/kubernetes/releases) page on the Kubernetes project. Make sure you're fetching a client library that matches what the charm is deploying. - -Grab the tarball and from the extracted release you can just directly use the cli binary at ./kubernetes/platforms/linux/amd64/kubecfg - -You'll need the address of the kubernetes master as environment variable : - - juju status kubernetes-master/0 - -Grab the public-address there and export it as KUBERNETES_MASTER environment variable : - - export KUBERNETES_MASTER=$(juju status --format=oneline kubernetes-master | cut -d' ' -f3):8080 - -And now you can run through the kubernetes examples per normal. : - - kubecfg list minions - - -## Scale Up - -If the default capacity of the bundle doesn't provide enough capacity for your workload(s) you can scale horizontially by adding a unit to the flannel and kubernetes services respectively. - - juju add-unit flannel - juju add-unit kubernetes --to # (machine id of new flannel unit) - -## Known Issues / Limitations - -Kubernetes currently has platform specific functionality. For example load balancers and persistence volumes only work with the google compute provider atm. - -The Juju integration uses the kubernetes null provider. This means external load balancers and storage can't be directly driven through kubernetes config files. - -## Where to get help - -If you run into any issues, file a bug at our [issue tracker](http://github.com/whitmo/kubernetes-charm/issues), email the Juju Mailing List at <juju@lists.ubuntu.com>, or feel free to join us in #juju on irc.freenode.net. - - diff --git a/cluster/juju/charms/trusty/kubernetes-master/docs/contributing.md b/cluster/juju/charms/trusty/kubernetes-master/docs/contributing.md deleted file mode 100644 index 5c18c7a0a17..00000000000 --- a/cluster/juju/charms/trusty/kubernetes-master/docs/contributing.md +++ /dev/null @@ -1,52 +0,0 @@ - -#### Contributions are welcome, in any form. Whether that be Bugs, BugFixes, Documentation, or Features. - -### Submitting a bug - -1. Go to our [issue tracker](http://github.com/whitmo/kubernetes-master-charm/issues) on GitHub -2. Search for existing issues using the search field at the top of the page -3. File a new issue including the info listed below -4. Thanks a ton for helping make the Kubernetes-Master Charm higher quality! - -##### When filing a new bug, please include: - -- **Descriptive title** - use keywords so others can find your bug (avoiding duplicates) -- **Steps to trigger the problem** - that are specific, and repeatable -- **What happens** - when you follow the steps, and what you expected to happen instead. -- Include the exact text of any error messages if applicable (or upload screenshots). -- Kubernetes-Master Charm version (or if you're pulling directly from Git, your current commit SHA - use git rev-parse HEAD) and the Juju Version output from `juju --version`. -- Did this work in a previous charm version? If so, also provide the version that it worked in. -- Any errors logged in `juju debug log` Console view - -### Can I help fix a bug? - -Yes please! But first... - -- Make sure no one else is already working on it -- if the bug has a milestone assigned or is tagged 'fix in progress', then it's already under way. Otherwise, post a comment on the bug to let others know you're starting to work on it. - -We use the Fork & Pull model for distributed development. For a more in-depth overview: consult with the github documentation on [Collaborative Development Models](https://help.github.com/articles/using-pull-requests/#before-you-begin). - -> ##### Fork & pull -> -> The fork & pull model lets anyone fork an existing repository and push changes to their personal fork without requiring access be granted to the source repository. The changes must then be pulled into the source repository by the project maintainer. This model reduces the amount of friction for new contributors and is popular with open source projects because it allows people to work independently without upfront coordination. - -### Submitting a Bug Fix - -The following checklist will help developers not familiar with the fork and pull process of development. We appreciate your enthusiasm to make the Kubernetes-Master Charm a High Quality experience! To Rapidly get started - follow the 8 steps below. - -1. [Fork the repository](https://help.github.com/articles/fork-a-repo/) -2. Clone your fork `git clone git@github.com/myusername/kubernetes-master-charm.git` -3. Checkout your topic branch with `git checkout -b my-awesome-bugfix` -4. Hack away at your feature/bugfix -5. Validate your bugfix if possible in the amulet test(s) so we dont reintroduce it later. -6. Validate your code meets guidelines by passing lint tests `make lint` -6. Commit code `git commit -a -m 'i did all this work to fix #32'` -7. Push your branch to your forks remote branch `git push origin my-awesome-bugfix` -8. Create the [Pull Request](https://help.github.com/articles/using-pull-requests/#initiating-the-pull-request) -9. Await Code Review -10. Rejoice when Pull Request is accepted - -### Submitting a Feature - -The Steps are the same as [Submitting a Bug Fix](#submitting-a-bug-fix). If you want extra credit, make sure you [File an issue](http://github.com/whitmo/kubernetes-master-charm/issues) that covers the Feature you are working on - as kind of a courtesy heads up. And assign the issue to yourself so we know you are working on it. - diff --git a/cluster/juju/charms/trusty/kubernetes/docs/1-getting-started.md b/cluster/juju/charms/trusty/kubernetes/docs/1-getting-started.md deleted file mode 100644 index a62ae259080..00000000000 --- a/cluster/juju/charms/trusty/kubernetes/docs/1-getting-started.md +++ /dev/null @@ -1,81 +0,0 @@ -# Getting Started - -## Environment Considerations - -Kubernetes has specific cloud provider integration, and as of the current writing of this document that supported list includes the official Juju supported providers: - -- [Amazon AWS](https://jujucharms.com/docs/config-aws) -- [Azure](https://jujucharms.com/docs/config-azure) -- [Vagrant](https://jujucharms.com/docs/config-vagrant) - -Other providers available for use as a *juju manual environment* can be listed in the [Kubernetes Documentation](https://github.com/GoogleCloudPlatform/kubernetes/tree/master/docs/getting-started-guides) - -## Deployment - -The Kubernetes Charms are currently under heavy development. We encourage you to fork these charms and contribute back to the development effort! See our [contributing](contributing.md) doc for more information on this. - -#### Deploying the Preview Release charms - - juju deploy cs:~hazmat/trusty/etcd - juju deploy cs:~hazmat/trusty/flannel - juju deploy local:trusty/kubernetes-master - juju deploy local:trusty/kubernetes - - juju add-relation etcd flannel - juju add-relation etcd kubernetes - juju add-relation etcd kubernetes-master - juju add-relation kubernetes kubernetes-master - -#### Deploying the Development Release Charms - -> These charms are known to be unstable as they are tracking the current efforts of the community at enabling different features against Kubernetes. This includes the specifics for integration per cloud environment, and upgrading to the latest development version. - - mkdir -p ~/charms/trusty - git clone https://github.com/whitmo/kubernetes-master.git ~/charms/trusty/kubernetes-master - git clone https://github.com/whitmo/kubernetes.git ~/charms/trusty/kubernetes - -##### Skipping the manual deployment after git clone - -> **Note:** This path requires the pre-requisite of juju-deployer. You can obtain juju-deployer via `apt-get install juju-deployer` - - wget https://github.com/whitmo/bundle-kubernetes/blob/master/develop.yaml kubernetes-devel.yaml - juju-deployer kubernetes-devel.yaml - - -## Verifying Deployment with the Kubernetes Agent - -You'll need the kubernetes command line client to utlize the created cluster. And this can be fetched from the [Releases](https://github.com/GoogleCloudPlatform/kubernetes/releases) page on the Kubernetes project. Make sure you're fetching a client library that matches what the charm is deploying. - -Grab the tarball and from the extracted release you can just directly use the cli binary at ./kubernetes/platforms/linux/amd64/kubecfg - -You'll need the address of the kubernetes master as environment variable : - - juju status kubernetes-master/0 - -Grab the public-address there and export it as KUBERNETES_MASTER environment variable : - - export KUBERNETES_MASTER=$(juju status --format=oneline kubernetes-master | cut -d' ' -f3):8080 - -And now you can run through the kubernetes examples per normal. : - - kubecfg list minions - - -## Scale Up - -If the default capacity of the bundle doesn't provide enough capacity for your workload(s) you can scale horizontially by adding a unit to the flannel and kubernetes services respectively. - - juju add-unit flannel - juju add-unit kubernetes --to # (machine id of new flannel unit) - -## Known Issues / Limitations - -Kubernetes currently has platform specific functionality. For example load balancers and persistence volumes only work with the google compute provider atm. - -The Juju integration uses the kubernetes null provider. This means external load balancers and storage can't be directly driven through kubernetes config files. - -## Where to get help - -If you run into any issues, file a bug at our [issue tracker](http://github.com/whitmo/kubernetes-charm/issues), email the Juju Mailing List at <juju@lists.ubuntu.com>, or feel free to join us in #juju on irc.freenode.net. - - diff --git a/cluster/juju/charms/trusty/kubernetes/docs/contributing.md b/cluster/juju/charms/trusty/kubernetes/docs/contributing.md deleted file mode 100644 index b418ee8bb45..00000000000 --- a/cluster/juju/charms/trusty/kubernetes/docs/contributing.md +++ /dev/null @@ -1,52 +0,0 @@ - -#### Contributions are welcome, in any form. Whether that be Bugs, BugFixes, Documentation, or Features. - -### Submitting a bug - -1. Go to our [issue tracker](http://github.com/whitmo/kubernetes-charm/issues) on GitHub -2. Search for existing issues using the search field at the top of the page -3. File a new issue including the info listed below -4. Thanks a ton for helping make the Kubernetes Charm higher quality! - -##### When filing a new bug, please include: - -- **Descriptive title** - use keywords so others can find your bug (avoiding duplicates) -- **Steps to trigger the problem** - that are specific, and repeatable -- **What happens** - when you follow the steps, and what you expected to happen instead. -- Include the exact text of any error messages if applicable (or upload screenshots). -- Kubernetes Charm version (or if you're pulling directly from Git, your current commit SHA - use git rev-parse HEAD) and the Juju Version output from `juju --version`. -- Did this work in a previous charm version? If so, also provide the version that it worked in. -- Any errors logged in `juju debug log` Console view - -### Can I help fix a bug? - -Yes please! But first... - -- Make sure no one else is already working on it -- if the bug has a milestone assigned or is tagged 'fix in progress', then it's already under way. Otherwise, post a comment on the bug to let others know you're starting to work on it. - -We use the Fork & Pull model for distributed development. For a more in-depth overview: consult with the github documentation on [Collaborative Development Models](https://help.github.com/articles/using-pull-requests/#before-you-begin). - -> ##### Fork & pull -> -> The fork & pull model lets anyone fork an existing repository and push changes to their personal fork without requiring access be granted to the source repository. The changes must then be pulled into the source repository by the project maintainer. This model reduces the amount of friction for new contributors and is popular with open source projects because it allows people to work independently without upfront coordination. - -### Submitting a Bug Fix - -The following checklist will help developers not familiar with the fork and pull process of development. We appreciate your enthusiasm to make the Kubernetes Charm a High Quality experience! To Rapidly get started - follow the 8 steps below. - -1. [Fork the repository](https://help.github.com/articles/fork-a-repo/) -2. Clone your fork `git clone git@github.com/myusername/kubernetes-charm.git` -3. Checkout your topic branch with `git checkout -b my-awesome-bugfix` -4. Hack away at your feature/bugfix -5. Validate your bugfix if possible in the amulet test(s) so we dont reintroduce it later. -6. Validate your code meets guidelines by passing lint tests `make lint` -6. Commit code `git commit -a -m 'i did all this work to fix #32'` -7. Push your branch to your forks remote branch `git push origin my-awesome-bugfix` -8. Create the [Pull Request](https://help.github.com/articles/using-pull-requests/#initiating-the-pull-request) -9. Await Code Review -10. Rejoice when Pull Request is accepted - -### Submitting a Feature - -The Steps are the same as [Submitting a Bug Fix](#submitting-a-bug-fix). If you want extra credit, make sure you [File an issue](http://github.com/whitmo/kubernetes-charm/issues) that covers the Feature you are working on - as kind of a courtesy heads up. And assign the issue to yourself so we know you are working on it. - From 7b3534e012086c97af231b450b81473f22f5fdf1 Mon Sep 17 00:00:00 2001 From: Whit Morriss Date: Mon, 20 Apr 2015 17:07:19 -0500 Subject: [PATCH 09/29] move cadvisor port to 4193 to avoid collision with kubelet --- .../juju/charms/trusty/kubernetes/files/cadvisor.upstart.tmpl | 2 +- .../juju/charms/trusty/kubernetes/files/kubelet.upstart.tmpl | 1 + cluster/juju/charms/trusty/kubernetes/hooks/hooks.py | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/cluster/juju/charms/trusty/kubernetes/files/cadvisor.upstart.tmpl b/cluster/juju/charms/trusty/kubernetes/files/cadvisor.upstart.tmpl index 78b7ae0b933..f142ca868f3 100644 --- a/cluster/juju/charms/trusty/kubernetes/files/cadvisor.upstart.tmpl +++ b/cluster/juju/charms/trusty/kubernetes/files/cadvisor.upstart.tmpl @@ -11,6 +11,6 @@ exec docker run \ --volume=/var/run:/var/run:rw \ --volume=/sys/fs/cgroup:/sys/fs/cgroup:ro \ --volume=/var/lib/docker/:/var/lib/docker:ro \ - --publish=127.0.0.1:4194:8080 \ + --publish=127.0.0.1:4193:8080 \ --name=cadvisor \ google/cadvisor:latest diff --git a/cluster/juju/charms/trusty/kubernetes/files/kubelet.upstart.tmpl b/cluster/juju/charms/trusty/kubernetes/files/kubelet.upstart.tmpl index 183756ce814..de421eeb9da 100644 --- a/cluster/juju/charms/trusty/kubernetes/files/kubelet.upstart.tmpl +++ b/cluster/juju/charms/trusty/kubernetes/files/kubelet.upstart.tmpl @@ -11,4 +11,5 @@ exec /usr/local/bin/kubelet \ --address=%(kubelet_bind_addr)s \ --api_servers=%(kubeapi_server)s \ --hostname_override=%(kubelet_bind_addr)s \ + --cadvisor_port=4193 --logtostderr=true diff --git a/cluster/juju/charms/trusty/kubernetes/hooks/hooks.py b/cluster/juju/charms/trusty/kubernetes/hooks/hooks.py index 000b58cff55..f11f7b6f70d 100755 --- a/cluster/juju/charms/trusty/kubernetes/hooks/hooks.py +++ b/cluster/juju/charms/trusty/kubernetes/hooks/hooks.py @@ -78,7 +78,7 @@ def relation_changed(): # Setup kubernetes supplemental group setup_kubernetes_group() - # Register services + # Register upstart managed services for n in ("cadvisor", "kubelet", "proxy"): if render_upstart(n, template_data) or not host.service_running(n): print("Starting %s" % n) From c0412776bcad982b5189e7c1db761f9f84d1be6c Mon Sep 17 00:00:00 2001 From: Matt Bruzek Date: Mon, 20 Apr 2015 17:19:45 -0500 Subject: [PATCH 10/29] @chuckbutler changed the documentation to current --- docs/getting-started-guides/juju.md | 56 +++++++++++++++++++---------- 1 file changed, 38 insertions(+), 18 deletions(-) diff --git a/docs/getting-started-guides/juju.md b/docs/getting-started-guides/juju.md index f2f04502670..71c2a1ced25 100644 --- a/docs/getting-started-guides/juju.md +++ b/docs/getting-started-guides/juju.md @@ -1,12 +1,17 @@ -## Getting start with Juju +## Getting started with Juju Juju handles provisioning machines and deploying complex systems to a -wide number of clouds. +wide number of clouds, supporting service orchestration once the bundle of +services has been deployed. ### Prerequisites +> Note: If you're running kube-up, on ubuntu - all of the dependencies +> will be handled for you. You may safely skip to the section: +> [Launch Kubernetes Cluster](#launch-kubernetes-cluster) + #### On Ubuntu [Install the Juju client](https://juju.ubuntu.com/install) on your @@ -39,13 +44,19 @@ interface. ## Launch Kubernetes cluster - juju quickstart https://raw.githubusercontent.com/whitmo/bundle-kubernetes/master/bundles.yaml +You will need to have the Kubernetes tools compiled before launching the cluster -First this command will start a curses based gui allowing you to set -up credentials and other environmental settings for several different -providers including Azure and AWS. + make all WHAT=cmd/kubectl + export KUBERNETES_PROVIDER=juju + cluster/kube-up.sh -Next it will deploy the kubernetes master, etcd, 2 minions with flannel networking. +If this is your first time running the `kube-up.sh` script, it will install +the required predependencies to get started with Juju, additionally it will +launch a curses based configuration utility allowing you to select your cloud +provider and enter the proper access credentials. + +Next it will deploy the kubernetes master, etcd, 2 minions with flannel based +Software Defined Networking. ## Exploring the cluster @@ -53,14 +64,15 @@ Next it will deploy the kubernetes master, etcd, 2 minions with flannel networki Juju status provides information about each unit in the cluster: juju status --format=oneline - - - etcd/0: 52.0.74.109 (started) - - flannel/0: 52.0.149.150 (started) - - flannel/1: 52.0.185.81 (started) - - juju-gui/0: 52.1.150.81 (started) - - kubernetes/0: 52.0.149.150 (started) - - kubernetes/1: 52.0.185.81 (started) - - kubernetes-master/0: 52.1.120.142 (started) + - docker/0: 52.4.92.78 (started) + - flannel-docker/0: 52.4.92.78 (started) + - kubernetes/0: 52.4.92.78 (started) + - docker/1: 52.6.104.142 (started) + - flannel-docker/1: 52.6.104.142 (started) + - kubernetes/1: 52.6.104.142 (started) + - etcd/0: 52.5.216.210 (started) 4001/tcp + - juju-gui/0: 52.5.205.174 (started) 80/tcp, 443/tcp + - kubernetes-master/0: 52.6.19.238 (started) 8080/tcp You can use `juju ssh` to access any of the units: @@ -150,8 +162,7 @@ Finally delete the pod: We can add minion units like so: - juju add-unit flannel # creates unit flannel/2 - juju add-unit kubernetes --to flannel/2 + juju add-unit docker # creates unit docker/2, kubernetes/2, docker-flannel/2 ## Tear down cluster @@ -175,6 +186,16 @@ Kubernetes Bundle on Github Juju runs natively against a variety of cloud providers and can be made to work against many more using a generic manual provider. +Provider | v0.15.0 +-------------- | ------- +AWS | TBD +HPCloud | TBD +OpenStack | TBD +Joyent | TBD +Azure | TBD +Digital Ocean | TBD +MAAS (bare metal) | TBD +GCE | TBD Provider | v0.8.1 @@ -187,4 +208,3 @@ Azure | TBD Digital Ocean | TBD MAAS (bare metal) | TBD GCE | TBD - From 85e0e9d6c73df1f3540a6d8cb2b2e814acef69bb Mon Sep 17 00:00:00 2001 From: Matt Bruzek Date: Tue, 21 Apr 2015 11:02:02 -0500 Subject: [PATCH 11/29] Adding a slash to continue the line. --- .../juju/charms/trusty/kubernetes/files/kubelet.upstart.tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cluster/juju/charms/trusty/kubernetes/files/kubelet.upstart.tmpl b/cluster/juju/charms/trusty/kubernetes/files/kubelet.upstart.tmpl index de421eeb9da..0aa6cb72349 100644 --- a/cluster/juju/charms/trusty/kubernetes/files/kubelet.upstart.tmpl +++ b/cluster/juju/charms/trusty/kubernetes/files/kubelet.upstart.tmpl @@ -11,5 +11,5 @@ exec /usr/local/bin/kubelet \ --address=%(kubelet_bind_addr)s \ --api_servers=%(kubeapi_server)s \ --hostname_override=%(kubelet_bind_addr)s \ - --cadvisor_port=4193 + --cadvisor_port=4193 \ --logtostderr=true From c1a56187b8076f4439054e5f4f52b59d9cb69a95 Mon Sep 17 00:00:00 2001 From: Matt Bruzek Date: Tue, 21 Apr 2015 11:02:47 -0500 Subject: [PATCH 12/29] Removing debug statements from the python code. --- cluster/juju/return-node-ips.py | 1 - 1 file changed, 1 deletion(-) diff --git a/cluster/juju/return-node-ips.py b/cluster/juju/return-node-ips.py index c652ccd079d..4a32a8c245f 100755 --- a/cluster/juju/return-node-ips.py +++ b/cluster/juju/return-node-ips.py @@ -5,7 +5,6 @@ import sys # `juju run` command's JSON object, see cluster/juju/util.sh if len(sys.argv) > 1: - print(sys.argv[1]) # It takes the JSON output as the first argument. nodes = json.loads(sys.argv[1]) # There can be multiple nodes to print the Stdout. From 60e0a77a0cc0c847919c53f3faad5ce34eed55fa Mon Sep 17 00:00:00 2001 From: Matt Bruzek Date: Tue, 21 Apr 2015 16:46:21 -0500 Subject: [PATCH 13/29] Removing cadvisor and normalizing python quotes. --- .../charms/trusty/kubernetes/hooks/hooks.py | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/cluster/juju/charms/trusty/kubernetes/hooks/hooks.py b/cluster/juju/charms/trusty/kubernetes/hooks/hooks.py index f11f7b6f70d..aeff669e91b 100755 --- a/cluster/juju/charms/trusty/kubernetes/hooks/hooks.py +++ b/cluster/juju/charms/trusty/kubernetes/hooks/hooks.py @@ -71,21 +71,21 @@ def relation_changed(): # Check required keys for k in ('etcd_servers', 'kubeapi_server'): if not template_data.get(k): - print("Missing data for %s %s" % (k, template_data)) + print('Missing data for %s %s' % (k, template_data)) return - print("Running with\n%s" % template_data) + print('Running with\n%s' % template_data) # Setup kubernetes supplemental group setup_kubernetes_group() # Register upstart managed services - for n in ("cadvisor", "kubelet", "proxy"): + for n in ('kubelet', 'proxy'): if render_upstart(n, template_data) or not host.service_running(n): - print("Starting %s" % n) + print('Starting %s' % n) host.service_restart(n) # Register machine via api - print("Registering machine") + print('Registering machine') register_machine(template_data['kubeapi_server']) # Save the marker (for restarts to detect prev install) @@ -95,7 +95,7 @@ def relation_changed(): def get_template_data(): rels = hookenv.relations() template_data = hookenv.Config() - template_data.CONFIG_FILE_NAME = ".unit-state" + template_data.CONFIG_FILE_NAME = '.unit-state' overlay_type = get_scoped_rel_attr('network', rels, 'overlay_type') etcd_servers = get_rel_hosts('etcd', rels, ('hostname', 'port')) @@ -104,7 +104,7 @@ def get_template_data(): # kubernetes master isn't ha yet. if api_servers: api_info = api_servers.pop() - api_servers = "http://%s:%s" % (api_info[0], api_info[1]) + api_servers = 'http://%s:%s' % (api_info[0], api_info[1]) template_data['overlay_type'] = overlay_type template_data['kubelet_bind_addr'] = _bind_addr( @@ -112,7 +112,7 @@ def get_template_data(): template_data['proxy_bind_addr'] = _bind_addr( hookenv.unit_get('public-address')) template_data['kubeapi_server'] = api_servers - template_data['etcd_servers'] = ",".join([ + template_data['etcd_servers'] = ','.join([ 'http://%s:%s' % (s[0], s[1]) for s in sorted(etcd_servers)]) template_data['identifier'] = os.environ['JUJU_UNIT_NAME'].replace( '/', '-') @@ -125,7 +125,7 @@ def _bind_addr(addr): try: return socket.gethostbyname(addr) except socket.error: - raise ValueError("Could not resolve private address") + raise ValueError('Could not resolve private address') def _encode(d): @@ -186,8 +186,8 @@ def register_machine(apiserver, retry=False): with open('/proc/meminfo') as fh: info = fh.readline() - mem = info.strip().split(":")[1].strip().split()[0] - cpus = os.sysconf("SC_NPROCESSORS_ONLN") + mem = info.strip().split(':')[1].strip().split()[0] + cpus = os.sysconf('SC_NPROCESSORS_ONLN') registration_request = Registrator() registration_request.data['Kind'] = 'Minion' @@ -201,7 +201,7 @@ def register_machine(apiserver, retry=False): response, result = registration_request.register(parsed.hostname, parsed.port, - "/api/v1beta3/nodes") + '/api/v1beta3/nodes') print(response) From 9d2129264662edfe83b2904087eac169dea1b30a Mon Sep 17 00:00:00 2001 From: Matt Bruzek Date: Tue, 21 Apr 2015 16:50:47 -0500 Subject: [PATCH 14/29] Changing bundle to v0.15.0 and docker git head. --- cluster/juju/bundles/local.yaml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cluster/juju/bundles/local.yaml b/cluster/juju/bundles/local.yaml index 9dcd4153d12..e17b7e1e816 100644 --- a/cluster/juju/bundles/local.yaml +++ b/cluster/juju/bundles/local.yaml @@ -7,9 +7,10 @@ kubernetes-local: "gui-y": "0" expose: true options: - version: "source" + version: "v0.15.0" docker: - charm: cs:trusty/docker + charm: docker-0 + branch: https://github.com/chuckbutler/docker-charm.git num_units: 2 options: latest: false From cc8104423029d46c3841e8042052a2e7705bc74b Mon Sep 17 00:00:00 2001 From: Whit Morriss Date: Wed, 22 Apr 2015 09:31:19 -0500 Subject: [PATCH 15/29] use git copy of docker charms for debugging --- cluster/juju/bundles/local.yaml | 4 ++-- cluster/juju/charms/trusty/.gitignore | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) create mode 100644 cluster/juju/charms/trusty/.gitignore diff --git a/cluster/juju/bundles/local.yaml b/cluster/juju/bundles/local.yaml index e17b7e1e816..1ba1b38f23f 100644 --- a/cluster/juju/bundles/local.yaml +++ b/cluster/juju/bundles/local.yaml @@ -9,11 +9,11 @@ kubernetes-local: options: version: "v0.15.0" docker: - charm: docker-0 + charm: docker branch: https://github.com/chuckbutler/docker-charm.git num_units: 2 options: - latest: false + latest: true annotations: "gui-x": "0" "gui-y": "0" diff --git a/cluster/juju/charms/trusty/.gitignore b/cluster/juju/charms/trusty/.gitignore new file mode 100644 index 00000000000..b3d791e0788 --- /dev/null +++ b/cluster/juju/charms/trusty/.gitignore @@ -0,0 +1 @@ +/docker \ No newline at end of file From a57a64781a6fb5d27c73d3fe10d864c68a0465d5 Mon Sep 17 00:00:00 2001 From: Whit Morriss Date: Wed, 22 Apr 2015 09:31:45 -0500 Subject: [PATCH 16/29] scripting tweaks - use absolute path for kube_root (fixes JUJU_REPOSITORY directory creation issue) - shortcircuit status polling (for rerunning kubeup) - more granular polling iterations --- cluster/juju/util.sh | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/cluster/juju/util.sh b/cluster/juju/util.sh index 1e2065fd81a..1ba5fa2de4b 100755 --- a/cluster/juju/util.sh +++ b/cluster/juju/util.sh @@ -19,9 +19,11 @@ set -o errexit set -o nounset set -o pipefail +KUBE_ROOT=$(readlink -f $KUBE_ROOT) source $KUBE_ROOT/cluster/juju/prereqs/ubuntu-juju.sh export JUJU_REPOSITORY=${KUBE_ROOT}/cluster/juju/charms #KUBE_BUNDLE_URL='https://raw.githubusercontent.com/whitmo/bundle-kubernetes/master/bundles.yaml' + KUBE_BUNDLE_PATH=${KUBE_ROOT}/cluster/juju/bundles/local.yaml function verify-prereqs() { gather_installation_reqs @@ -103,10 +105,17 @@ function sleep-status(){ maxtime=900 jujustatus='' echo "Waiting up to 15 minutes to allow the cluster to come online... wait for it..." + + jujustatus=$(juju status kubernetes-master --format=oneline) + if [[ $jujustatus == *"started"* ]]; + then + return + fi + while [[ $i < $maxtime && $jujustatus != *"started"* ]]; do + sleep 15 + i+=15 jujustatus=$(juju status kubernetes-master --format=oneline) - sleep 30 - i+=30 done # sleep because we cannot get the status back of where the minions are in the deploy phase From 0ab77ae8be88bc030770ae5ef5dfb88199607fc5 Mon Sep 17 00:00:00 2001 From: Whit Morriss Date: Wed, 22 Apr 2015 09:36:05 -0500 Subject: [PATCH 17/29] line formatting --- .../charms/trusty/kubernetes/hooks/lib/registrator.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/cluster/juju/charms/trusty/kubernetes/hooks/lib/registrator.py b/cluster/juju/charms/trusty/kubernetes/hooks/lib/registrator.py index e096110730d..d8a57f0a7aa 100644 --- a/cluster/juju/charms/trusty/kubernetes/hooks/lib/registrator.py +++ b/cluster/juju/charms/trusty/kubernetes/hooks/lib/registrator.py @@ -2,6 +2,7 @@ import httplib import json import time + class Registrator: def __init__(self): @@ -41,11 +42,10 @@ class Registrator: body = response.read() print(body) result = json.loads(body) - print("Response status:%s reason:%s body:%s" % ( - response.status, response.reason, result)) + print("Response status:%s reason:%s body:%s" % \ + (response.status, response.reason, result)) return response, result - def update(self): ''' Contact the API Server to update a registration ''' # do a get on the API for the node @@ -80,5 +80,3 @@ class Registrator: print("Registration error") # TODO - get request data raise RuntimeError("Unable to register machine with") - - From 5f59e167fdd6de33e2deea2e479f6c09fdc4d551 Mon Sep 17 00:00:00 2001 From: Matt Bruzek Date: Wed, 22 Apr 2015 10:29:07 -0500 Subject: [PATCH 18/29] Editing the local bundle to use github. --- cluster/juju/bundles/local.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cluster/juju/bundles/local.yaml b/cluster/juju/bundles/local.yaml index e17b7e1e816..01ab4ebf99c 100644 --- a/cluster/juju/bundles/local.yaml +++ b/cluster/juju/bundles/local.yaml @@ -13,7 +13,7 @@ kubernetes-local: branch: https://github.com/chuckbutler/docker-charm.git num_units: 2 options: - latest: false + latest: true annotations: "gui-x": "0" "gui-y": "0" From 3342bb42e0db661cf2b955abbba355fa272ad759 Mon Sep 17 00:00:00 2001 From: Matt Bruzek Date: Wed, 22 Apr 2015 10:29:55 -0500 Subject: [PATCH 19/29] Removed extra c in path to distro files. --- cluster/juju/prereqs/ubuntu-juju.sh | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/cluster/juju/prereqs/ubuntu-juju.sh b/cluster/juju/prereqs/ubuntu-juju.sh index 9d3f7672c8b..bd9a42808f0 100644 --- a/cluster/juju/prereqs/ubuntu-juju.sh +++ b/cluster/juju/prereqs/ubuntu-juju.sh @@ -20,12 +20,12 @@ set -o nounset set -o pipefail -function check_for_ppa(){ +function check_for_ppa() { local repo="$1" - grep -qsw $repo /etcc/apt/sources.list /etc/apt/sources.list.d/* + grep -qsw $repo /etc/apt/sources.list /etc/apt/sources.list.d/* } -function package_status(){ +function package_status() { local pkgname=$1 local pkgstatus pkgstatus=$(dpkg-query -W --showformat='${Status}\n' "${pkgname}") @@ -33,10 +33,9 @@ function package_status(){ echo "Missing package ${pkgname}" sudo apt-get --force-yes --yes install ${pkgname} fi - } -function gather_installation_reqs(){ +function gather_installation_reqs() { if ! check_for_ppa "juju"; then echo "... Detected missing dependencies.. running" echo "... add-apt-repository ppa:juju/stable" From af15d6d6143ed54b0eadb0a0e31669f1d9c5e5fb Mon Sep 17 00:00:00 2001 From: Matt Bruzek Date: Wed, 22 Apr 2015 10:31:26 -0500 Subject: [PATCH 20/29] Removed the need for an extra python file. i - Formatted for consistency - Used different variables for juju directory --- cluster/juju/return-node-ips.py | 12 ---------- cluster/juju/util.sh | 39 ++++++++++++++++++--------------- 2 files changed, 21 insertions(+), 30 deletions(-) delete mode 100755 cluster/juju/return-node-ips.py diff --git a/cluster/juju/return-node-ips.py b/cluster/juju/return-node-ips.py deleted file mode 100755 index 4a32a8c245f..00000000000 --- a/cluster/juju/return-node-ips.py +++ /dev/null @@ -1,12 +0,0 @@ -#!/usr/bin/env python -import json -import sys -# This script helps parse out the private IP addreses from the -# `juju run` command's JSON object, see cluster/juju/util.sh - -if len(sys.argv) > 1: - # It takes the JSON output as the first argument. - nodes = json.loads(sys.argv[1]) - # There can be multiple nodes to print the Stdout. - for num in nodes: - print num['Stdout'].rstrip() diff --git a/cluster/juju/util.sh b/cluster/juju/util.sh index 1e2065fd81a..a8c5499d47e 100755 --- a/cluster/juju/util.sh +++ b/cluster/juju/util.sh @@ -19,10 +19,13 @@ set -o errexit set -o nounset set -o pipefail -source $KUBE_ROOT/cluster/juju/prereqs/ubuntu-juju.sh -export JUJU_REPOSITORY=${KUBE_ROOT}/cluster/juju/charms +UTIL_SCRIPT=$(realpath "${BASH_SOURCE}") +JUJU_PATH=$(dirname ${UTIL_SCRIPT}) +source ${JUJU_PATH}/prereqs/ubuntu-juju.sh +export JUJU_REPOSITORY=${JUJU_PATH}/charms #KUBE_BUNDLE_URL='https://raw.githubusercontent.com/whitmo/bundle-kubernetes/master/bundles.yaml' -KUBE_BUNDLE_PATH=${KUBE_ROOT}/cluster/juju/bundles/local.yaml +KUBE_BUNDLE_PATH=${JUJU_PATH}/bundles/local.yaml + function verify-prereqs() { gather_installation_reqs } @@ -65,37 +68,37 @@ function detect-master() { export KUBERNETES_MASTER=$KUBE_MASTER } -function detect-minions(){ - # Strip out the components except for STDOUT return - # and trim out the single quotes to build an array of minions +function detect-minions() { + # Run the Juju command that gets the minion private IP addresses. + local ipoutput + ipoutput=$(juju run --service kubernetes "unit-get private-address" --format=yaml) + echo $ipoutput + # Strip out the IP addresses # # Example Output: #- MachineId: "10" - # Stdout: '10.197.55.232 - #' + # Stdout: | + # 10.197.55.232 # UnitId: kubernetes/0 # - MachineId: "11" - # Stdout: '10.202.146.124 - # ' + # Stdout: | + # 10.202.146.124 # UnitId: kubernetes/1 - KUBERNETES_JSON=$(juju run --service kubernetes \ - "unit-get private-address" --format=json) - echo $KUBERNETES_JSON - KUBE_MINION_IP_ADDRESSES=($(${KUBE_ROOT}/cluster/juju/return-node-ips.py "$KUBERNETES_JSON")) - echo $KUBE_MINION_IP_ADDRESSES + KUBE_MINION_IP_ADDRESSES=($(echo $ipoutput | grep -Eo '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}')) + echo ${KUBE_MINION_IP_ADDRESSES[@]} NUM_MINIONS=${#KUBE_MINION_IP_ADDRESSES[@]} MINION_NAMES=$KUBE_MINION_IP_ADDRESSES } -function setup-logging-firewall(){ +function setup-logging-firewall() { echo "TODO: setup logging and firewall rules" } -function teardown-logging-firewall(){ +function teardown-logging-firewall() { echo "TODO: teardown logging and firewall rules" } -function sleep-status(){ +function sleep-status() { local i local maxtime local jujustatus From 5deef091783f0f38f8b3abe61a528d60f32f9263 Mon Sep 17 00:00:00 2001 From: Matt Bruzek Date: Wed, 22 Apr 2015 11:35:49 -0500 Subject: [PATCH 21/29] Exporting master and minion variables and calling detect methods in kube-up. --- cluster/juju/util.sh | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/cluster/juju/util.sh b/cluster/juju/util.sh index be97d4b14d4..ea73ae758f0 100755 --- a/cluster/juju/util.sh +++ b/cluster/juju/util.sh @@ -51,6 +51,8 @@ function kube-up() { fi # Sleep due to juju bug http://pad.lv/1432759 sleep-status + detect-master + detect-minions } function kube-down() { @@ -64,14 +66,15 @@ function detect-master() { # Capturing a newline, and my awk-fu was weak - pipe through tr -d kubestatus=$(juju status --format=oneline kubernetes-master | awk '{print $3}' | tr -d "\n") export KUBE_MASTER_IP=${kubestatus} - export KUBE_MASTER=$KUBE_MASTER_IP:8080 - export KUBERNETES_MASTER=$KUBE_MASTER + export KUBE_MASTER=${KUBE_MASTER_IP} + export KUBERNETES_MASTER=http://${KUBE_MASTER}:8080 + echo "Kubernetes master: " ${KUBERNETES_MASTER} } function detect-minions() { # Run the Juju command that gets the minion private IP addresses. local ipoutput - ipoutput=$(juju run --service kubernetes "unit-get private-address" --format=yaml) + ipoutput=$(juju run --service kubernetes "unit-get private-address" --format=json) echo $ipoutput # Strip out the IP addresses # @@ -84,10 +87,10 @@ function detect-minions() { # Stdout: | # 10.202.146.124 # UnitId: kubernetes/1 - KUBE_MINION_IP_ADDRESSES=($(echo $ipoutput | grep -Eo '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}')) - echo ${KUBE_MINION_IP_ADDRESSES[@]} - NUM_MINIONS=${#KUBE_MINION_IP_ADDRESSES[@]} - MINION_NAMES=$KUBE_MINION_IP_ADDRESSES + export KUBE_MINION_IP_ADDRESSES=($(${JUJU_PATH}/return-node-ips.py "${ipoutput}")) + echo "Kubernetes minions: " ${KUBE_MINION_IP_ADDRESSES[@]} + export NUM_MINIONS=${#KUBE_MINION_IP_ADDRESSES[@]} + export MINION_NAMES=$KUBE_MINION_IP_ADDRESSES } function setup-logging-firewall() { From dbca4bf5dd95256cfc16b3dffc2cbd25fc428ab2 Mon Sep 17 00:00:00 2001 From: Matt Bruzek Date: Wed, 22 Apr 2015 11:36:37 -0500 Subject: [PATCH 22/29] Using python to parse the json output from Juju. --- cluster/juju/return-node-ips.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100755 cluster/juju/return-node-ips.py diff --git a/cluster/juju/return-node-ips.py b/cluster/juju/return-node-ips.py new file mode 100755 index 00000000000..a8848f019a6 --- /dev/null +++ b/cluster/juju/return-node-ips.py @@ -0,0 +1,14 @@ +#!/usr/bin/env python +import json +import sys +# This script helps parse out the private IP addreses from the +# `juju run` command's JSON object, see cluster/juju/util.sh + +if len(sys.argv) > 1: + # It takes the JSON output as the first argument. + nodes = json.loads(sys.argv[1]) + # There can be multiple nodes to print the Stdout. + for num in nodes: + print num['Stdout'].rstrip() +else: + exit(1) From 450f1f021538777bcc99389a0f6ff622a9115dfe Mon Sep 17 00:00:00 2001 From: Matt Bruzek Date: Wed, 22 Apr 2015 12:53:30 -0500 Subject: [PATCH 23/29] Using readlink instead of realpath. --- cluster/juju/util.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cluster/juju/util.sh b/cluster/juju/util.sh index ea73ae758f0..2b6c4fd8527 100755 --- a/cluster/juju/util.sh +++ b/cluster/juju/util.sh @@ -19,7 +19,7 @@ set -o errexit set -o nounset set -o pipefail -UTIL_SCRIPT=$(realpath "${BASH_SOURCE}") +UTIL_SCRIPT=$(readlink -m "${BASH_SOURCE}") JUJU_PATH=$(dirname ${UTIL_SCRIPT}) source ${JUJU_PATH}/prereqs/ubuntu-juju.sh export JUJU_REPOSITORY=${JUJU_PATH}/charms From b4766bb3808bafdbcd3b7289219e37d3fe1929ba Mon Sep 17 00:00:00 2001 From: Matt Bruzek Date: Wed, 22 Apr 2015 14:45:50 -0500 Subject: [PATCH 24/29] Removing unneeded status check before juju deployer --- cluster/juju/util.sh | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/cluster/juju/util.sh b/cluster/juju/util.sh index 2b6c4fd8527..317ce17847e 100755 --- a/cluster/juju/util.sh +++ b/cluster/juju/util.sh @@ -40,15 +40,9 @@ function kube-up() { else juju quickstart --no-browser fi - # If something were to happen that I'm not accounting for, do not - # punish the user by making them tear things down. In a perfect world - # quickstart should handle this situation, so be nice in the meantime - local envstatus - envstatus=$(juju status kubernetes-master --format=oneline) - - if [[ "" == "${envstatus}" ]]; then - juju deployer -c ${KUBE_BUNDLE_PATH} - fi + # The juju-deployer command will deploy the bundle and can be run + # multiple times to continue deploying the parts that fail. + juju deployer -c ${KUBE_BUNDLE_PATH} # Sleep due to juju bug http://pad.lv/1432759 sleep-status detect-master From b69792535d478f0c5c95e560192991ea2f91b73f Mon Sep 17 00:00:00 2001 From: Matt Bruzek Date: Wed, 22 Apr 2015 15:05:46 -0500 Subject: [PATCH 25/29] Updating guestbook with the v1beta3 json files. --- .../kubernetes-master/scripts/guestbook.sh | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/cluster/juju/charms/trusty/kubernetes-master/scripts/guestbook.sh b/cluster/juju/charms/trusty/kubernetes-master/scripts/guestbook.sh index b59ae5e55b2..caac0678a00 100755 --- a/cluster/juju/charms/trusty/kubernetes-master/scripts/guestbook.sh +++ b/cluster/juju/charms/trusty/kubernetes-master/scripts/guestbook.sh @@ -13,33 +13,37 @@ if [[ "$1" == "-d" ]] || [[ "$1" == "--debug" ]]; then fi cd /opt/kubernetes/ # Step One Turn up the redis master -kubectl create -f examples/guestbook/redis-master.json +kubectl create -f examples/guestbook/v1beta3/redis-master.json if [[ "${DEBUG}" == true ]]; then kubectl get pods fi # Step Two: Turn up the master service -kubectl create -f examples/guestbook/redis-master-service.json +kubectl create -f examples/guestbook/v1beta3/redis-master-service.json if [[ "${DEBUG}" == true ]]; then kubectl get services fi # Step Three: Turn up the replicated slave pods -kubectl create -f examples/guestbook/redis-slave-controller.json +kubectl create -f examples/guestbook/v1beta3/redis-slave-controller.json if [[ "${DEBUG}" == true ]]; then kubectl get replicationcontrollers kubectl get pods fi # Step Four: Create the redis slave service -kubectl create -f examples/guestbook/redis-slave-service.json +kubectl create -f examples/guestbook/v1beta3/redis-slave-service.json if [[ "${DEBUG}" == true ]]; then kubectl get services fi # Step Five: Create the frontend pod -kubectl create -f examples/guestbook/frontend-controller.json +kubectl create -f examples/guestbook/v1beta3/frontend-controller.json if [[ "${DEBUG}" == true ]]; then kubectl get replicationcontrollers kubectl get pods fi - +# Step Six: Create the guestbook service +kubectl create -f examples/guestbook/v1beta3/frontend-service.json +if [[ "${DEBUG}" == true ]]; then + kubectl get services +fi set +x echo "# Now run the following commands on your juju client" From cdc671a86f7e2f18aee85b2654703e03865e130d Mon Sep 17 00:00:00 2001 From: Matt Bruzek Date: Wed, 22 Apr 2015 16:39:36 -0500 Subject: [PATCH 26/29] Setting the default release number to v0.15.0 --- cluster/juju/charms/trusty/kubernetes-master/config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cluster/juju/charms/trusty/kubernetes-master/config.yaml b/cluster/juju/charms/trusty/kubernetes-master/config.yaml index 3164297dc4d..3041f7f07b2 100644 --- a/cluster/juju/charms/trusty/kubernetes-master/config.yaml +++ b/cluster/juju/charms/trusty/kubernetes-master/config.yaml @@ -1,7 +1,7 @@ options: version: type: string - default: "v0.8.1" + default: "v0.15.0" description: | The kubernetes release to use in this charm. The binary files are compiled from the source identified by this tag in github. Using the From dce5f28a636108592712da91c172839d9ae5380c Mon Sep 17 00:00:00 2001 From: Matt Bruzek Date: Wed, 22 Apr 2015 16:40:16 -0500 Subject: [PATCH 27/29] Changing the copyright to the Google. --- .../juju/charms/trusty/kubernetes-master/copyright | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/cluster/juju/charms/trusty/kubernetes-master/copyright b/cluster/juju/charms/trusty/kubernetes-master/copyright index 3306630127f..a0b409a8e84 100644 --- a/cluster/juju/charms/trusty/kubernetes-master/copyright +++ b/cluster/juju/charms/trusty/kubernetes-master/copyright @@ -1,13 +1,13 @@ -Copyright 2015 Canonical LTD +Copyright 2015 Google Inc. All rights reserved. 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 + http://www.apache.org/licenses/LICENSE-2.0 - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. From ee2d43ac35f84103ed9e06ae2b70543403d40640 Mon Sep 17 00:00:00 2001 From: Matt Bruzek Date: Wed, 22 Apr 2015 16:41:03 -0500 Subject: [PATCH 28/29] Changing the copyright to the Google. --- cluster/juju/charms/trusty/kubernetes/copyright | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/cluster/juju/charms/trusty/kubernetes/copyright b/cluster/juju/charms/trusty/kubernetes/copyright index 3306630127f..a0b409a8e84 100644 --- a/cluster/juju/charms/trusty/kubernetes/copyright +++ b/cluster/juju/charms/trusty/kubernetes/copyright @@ -1,13 +1,13 @@ -Copyright 2015 Canonical LTD +Copyright 2015 Google Inc. All rights reserved. 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 + http://www.apache.org/licenses/LICENSE-2.0 - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. From 74c00d431ef4a309d6a93e722983d3d3029551c8 Mon Sep 17 00:00:00 2001 From: Matt Bruzek Date: Thu, 30 Apr 2015 09:27:51 +0200 Subject: [PATCH 29/29] Removing unused scripts from km and kubernetes. --- .../files/create_kubernetes_tar.sh | 59 ------------------- .../kubernetes-master/scripts/guestbook.sh | 52 ---------------- .../kubernetes/files/create_kubernetes_tar.sh | 59 ------------------- 3 files changed, 170 deletions(-) delete mode 100755 cluster/juju/charms/trusty/kubernetes-master/files/create_kubernetes_tar.sh delete mode 100755 cluster/juju/charms/trusty/kubernetes-master/scripts/guestbook.sh delete mode 100755 cluster/juju/charms/trusty/kubernetes/files/create_kubernetes_tar.sh diff --git a/cluster/juju/charms/trusty/kubernetes-master/files/create_kubernetes_tar.sh b/cluster/juju/charms/trusty/kubernetes-master/files/create_kubernetes_tar.sh deleted file mode 100755 index e6f48ee3af4..00000000000 --- a/cluster/juju/charms/trusty/kubernetes-master/files/create_kubernetes_tar.sh +++ /dev/null @@ -1,59 +0,0 @@ -#!/bin/bash - -set -ex - -# This script downloads a Kubernetes release and creates a tar file with only -# the files that are needed for this charm. - -# Usage: create_kubernetes_tar.sh VERSION ARCHITECTURE - -usage() { - echo "Build a tar file with only the files needed for the kubernetes charm." - echo "The script accepts two arguments version and desired architecture." - echo "$0 version architecture" -} - -download_kubernetes() { - local VERSION=$1 - URL_PREFIX="https://github.com/GoogleCloudPlatform/kubernetes" - KUBERNETES_URL="${URL_PREFIX}/releases/download/${VERSION}/kubernetes.tar.gz" - # Remove the previous temporary files to remain idempotent. - if [ -f /tmp/kubernetes.tar.gz ]; then - rm /tmp/kubernetes.tar.gz - fi - # Download the kubernetes release from the Internet. - wget --no-verbose --tries 2 -O /tmp/kubernetes.tar.gz $KUBERNETES_URL -} - -extract_kubernetes() { - local ARCH=$1 - # Untar the kubernetes release file. - tar -xvzf /tmp/kubernetes.tar.gz -C /tmp - # Untar the server linux amd64 package. - tar -xvzf /tmp/kubernetes/server/kubernetes-server-linux-$ARCH.tar.gz -C /tmp -} - -create_charm_tar() { - local OUTPUT_FILE=${1:-"$PWD/kubernetes.tar.gz"} - local OUTPUT_DIR=`dirname $OUTPUT_FILE` - if [ ! -d $OUTPUT_DIR ]; then - mkdir -p $OUTPUT - fi - - # Change to the directory the binaries are. - cd /tmp/kubernetes/server/bin/ - - # Create a tar file with the binaries that are needed for kubernetes master. - tar -cvzf $OUTPUT_FILE kube-apiserver kube-controller-manager kubectl kube-scheduler -} - -if [ $# -gt 2 ]; then - usage - exit 1 -fi -VERSION=${1:-"v0.8.1"} -ARCH=${2:-"amd64"} -download_kubernetes $VERSION -extract_kubernetes $ARCH -TAR_FILE="$PWD/kubernetes-master-$VERSION-$ARCH.tar.gz" -create_charm_tar $TAR_FILE diff --git a/cluster/juju/charms/trusty/kubernetes-master/scripts/guestbook.sh b/cluster/juju/charms/trusty/kubernetes-master/scripts/guestbook.sh deleted file mode 100755 index caac0678a00..00000000000 --- a/cluster/juju/charms/trusty/kubernetes-master/scripts/guestbook.sh +++ /dev/null @@ -1,52 +0,0 @@ -#!/bin/bash - -# This script sets up the guestbook example application in Kubernetes. -# The KUBERENTES_MASTER variable must be set to the URL for kubectl to work. -# The first argument is optional and can be used for debugging. - -set -o errexit # (set -e) - -DEBUG=false -if [[ "$1" == "-d" ]] || [[ "$1" == "--debug" ]]; then - DEBUG=true - set -o xtrace # (set -x) -fi -cd /opt/kubernetes/ -# Step One Turn up the redis master -kubectl create -f examples/guestbook/v1beta3/redis-master.json -if [[ "${DEBUG}" == true ]]; then - kubectl get pods -fi -# Step Two: Turn up the master service -kubectl create -f examples/guestbook/v1beta3/redis-master-service.json -if [[ "${DEBUG}" == true ]]; then - kubectl get services -fi -# Step Three: Turn up the replicated slave pods -kubectl create -f examples/guestbook/v1beta3/redis-slave-controller.json -if [[ "${DEBUG}" == true ]]; then - kubectl get replicationcontrollers - kubectl get pods -fi -# Step Four: Create the redis slave service -kubectl create -f examples/guestbook/v1beta3/redis-slave-service.json -if [[ "${DEBUG}" == true ]]; then - kubectl get services -fi -# Step Five: Create the frontend pod -kubectl create -f examples/guestbook/v1beta3/frontend-controller.json -if [[ "${DEBUG}" == true ]]; then - kubectl get replicationcontrollers - kubectl get pods -fi -# Step Six: Create the guestbook service -kubectl create -f examples/guestbook/v1beta3/frontend-service.json -if [[ "${DEBUG}" == true ]]; then - kubectl get services -fi -set +x - -echo "# Now run the following commands on your juju client" -echo "juju run --service kubernetes 'open-port 8000'" -echo "juju expose kubernetes" -echo "# Go to the kubernetes public address on port 8000 to see the guestbook application" diff --git a/cluster/juju/charms/trusty/kubernetes/files/create_kubernetes_tar.sh b/cluster/juju/charms/trusty/kubernetes/files/create_kubernetes_tar.sh deleted file mode 100755 index bf0dd73ea0c..00000000000 --- a/cluster/juju/charms/trusty/kubernetes/files/create_kubernetes_tar.sh +++ /dev/null @@ -1,59 +0,0 @@ -#!/bin/bash - -set -ex - -# This script downloads a Kubernetes release and creates a tar file with only -# the files that are needed for this charm. - -# Usage: create_kubernetes_tar.sh VERSION ARCHITECTURE - -usage() { - echo "Build a tar file with only the files needed for the kubernetes charm." - echo "The script accepts two arguments version and desired architecture." - echo "$0 version architecture" -} - -download_kubernetes() { - local VERSION=$1 - URL_PREFIX="https://github.com/GoogleCloudPlatform/kubernetes" - KUBERNETES_URL="${URL_PREFIX}/releases/download/${VERSION}/kubernetes.tar.gz" - # Remove the previous temporary files to remain idempotent. - if [ -f /tmp/kubernetes.tar.gz ]; then - rm /tmp/kubernetes.tar.gz - fi - # Download the kubernetes release from the Internet. - wget --no-verbose --tries 2 -O /tmp/kubernetes.tar.gz $KUBERNETES_URL -} - -extract_kubernetes() { - local ARCH=$1 - # Untar the kubernetes release file. - tar -xvzf /tmp/kubernetes.tar.gz -C /tmp - # Untar the server linux amd64 package. - tar -xvzf /tmp/kubernetes/server/kubernetes-server-linux-$ARCH.tar.gz -C /tmp -} - -create_charm_tar() { - local OUTPUT_FILE=${1:-"$PWD/kubernetes.tar.gz"} - local OUTPUT_DIR=`dirname $OUTPUT_FILE` - if [ ! -d $OUTPUT_DIR ]; then - mkdir -p $OUTPUT - fi - - # Change to the directory the binaries are. - cd /tmp/kubernetes/server/bin/ - - # Create a tar file with the binaries that are needed for kubernetes minion. - tar -cvzf $OUTPUT_FILE kubelet kube-proxy -} - -if [ $# -gt 2 ]; then - usage - exit 1 -fi -VERSION=${1:-"v0.8.1"} -ARCH=${2:-"amd64"} -download_kubernetes $VERSION -extract_kubernetes $ARCH -TAR_FILE="$PWD/kubernetes-$VERSION-$ARCH.tar.gz" -create_charm_tar $TAR_FILE