File 0001-Add-SUSE-Kubernetes-support-for-Magnum.patch of Package openstack-magnum

Index: magnum-2.0.1.dev11/magnum.egg-info/SOURCES.txt
===================================================================
--- magnum-2.0.1.dev11.orig/magnum.egg-info/SOURCES.txt
+++ magnum-2.0.1.dev11/magnum.egg-info/SOURCES.txt
@@ -346,13 +346,17 @@ magnum/templates/kubernetes/COPYING
 magnum/templates/kubernetes/README.md
 magnum/templates/kubernetes/kubecluster-coreos.yaml
 magnum/templates/kubernetes/kubecluster-fedora-ironic.yaml
+magnum/templates/kubernetes/kubecluster-opensuse.yaml
 magnum/templates/kubernetes/kubecluster.yaml
 magnum/templates/kubernetes/kubemaster-coreos.yaml
 magnum/templates/kubernetes/kubemaster-fedora-ironic.yaml
+magnum/templates/kubernetes/kubemaster-opensuse.yaml
 magnum/templates/kubernetes/kubemaster.yaml
 magnum/templates/kubernetes/kubeminion-coreos.yaml
 magnum/templates/kubernetes/kubeminion-fedora-ironic.yaml
+magnum/templates/kubernetes/kubeminion-opensuse.yaml
 magnum/templates/kubernetes/kubeminion.yaml
+magnum/templates/kubernetes/kubenetwork-opensuse.yaml
 magnum/templates/kubernetes/elements/README.md
 magnum/templates/kubernetes/elements/kubernetes/elements-deps
 magnum/templates/kubernetes/elements/kubernetes/package-installs.yaml
@@ -360,11 +364,18 @@ magnum/templates/kubernetes/fragments/ad
 magnum/templates/kubernetes/fragments/configure-docker-registry.sh
 magnum/templates/kubernetes/fragments/configure-docker-storage.sh
 magnum/templates/kubernetes/fragments/configure-etcd-coreos.yaml
+magnum/templates/kubernetes/fragments/configure-docker-opensuse.sh
+magnum/templates/kubernetes/fragments/configure-etcd-opensuse.sh
 magnum/templates/kubernetes/fragments/configure-etcd.sh
+magnum/templates/kubernetes/fragments/configure-flanneld-master-opensuse.sh
+magnum/templates/kubernetes/fragments/configure-flanneld-minion-opensuse.sh
 magnum/templates/kubernetes/fragments/configure-flannel.sh
+magnum/templates/kubernetes/fragments/configure-kubernetes-master-opensuse.sh
 magnum/templates/kubernetes/fragments/configure-kubernetes-master.sh
+magnum/templates/kubernetes/fragments/configure-kubernetes-minion-opensuse.sh
 magnum/templates/kubernetes/fragments/configure-kubernetes-minion.sh
 magnum/templates/kubernetes/fragments/create-kube-namespace-coreos.yaml
+magnum/templates/kubernetes/fragments/create-kubernetes-user-opensuse.yaml
 magnum/templates/kubernetes/fragments/disable-selinux.sh
 magnum/templates/kubernetes/fragments/enable-docker-registry.sh
 magnum/templates/kubernetes/fragments/enable-etcd.sh
@@ -397,6 +408,8 @@ magnum/templates/kubernetes/fragments/wr
 magnum/templates/kubernetes/fragments/write-kubeconfig.yaml
 magnum/templates/kubernetes/fragments/write-network-config-coreos.yaml
 magnum/templates/kubernetes/fragments/write-network-config.sh
+magnum/templates/kubernetes/fragments/write-params-minion-opensuse.yaml
+magnum/templates/kubernetes/fragments/write-params-master-opensuse.yaml
 magnum/templates/mesos/COPYING
 magnum/templates/mesos/Dockerfile
 magnum/templates/mesos/README.md
@@ -604,4 +617,4 @@ specs/magnum-horizon-plugin.rst
 specs/resource-quotas.rst
 specs/tls-support-magnum.rst
 tools/flake8wrap.sh
-tools/pretty_tox.sh
\ No newline at end of file
+tools/pretty_tox.sh
Index: magnum-2.0.1.dev11/magnum/conductor/template_definition.py
===================================================================
--- magnum-2.0.1.dev11.orig/magnum/conductor/template_definition.py
+++ magnum-2.0.1.dev11/magnum/conductor/template_definition.py
@@ -45,6 +45,14 @@ template_def_opts = [
                                          'kubecluster-coreos.yaml'),
                help=_(
                    'Location of template to build a k8s cluster on CoreOS.')),
+    cfg.StrOpt('k8s_opensuse_template_path',
+               default=paths.basedir_def('templates/kubernetes/'
+                                         'kubecluster-opensuse.yaml'),
+               help=_(
+                   'Location of template to build a k8s cluster on openSUSE.')),
+    cfg.BoolOpt('enable_discovery_etcd_io',
+               default=False,
+               help=_('Enable public etcd discovery service.')),
     cfg.StrOpt('etcd_discovery_service_endpoint_format',
                default='https://discovery.etcd.io/new?size=%(size)d',
                help=_('Url for etcd public discovery endpoint.')),
@@ -60,7 +68,8 @@ template_def_opts = [
                       'on Ubuntu.')),
     cfg.ListOpt('enabled_definitions',
                 default=['magnum_vm_atomic_k8s', 'magnum_vm_coreos_k8s',
-                         'magnum_vm_atomic_swarm', 'magnum_vm_ubuntu_mesos'],
+                         'magnum_vm_opensuse_k8s', 'magnum_vm_atomic_swarm',
+                         'magnum_vm_ubuntu_mesos'],
                 help=_('Enabled bay definition entry points.')),
 ]
 
@@ -480,10 +489,13 @@ class K8sTemplateDefinition(BaseTemplate
             extra_params['minions_to_remove'] = (
                 scale_mgr.get_removal_nodes(hosts))
 
-        extra_params['discovery_url'] = self.get_discovery_url(bay)
+        if cfg.CONF.bay.enable_discovery_etcd_io:
+            extra_params['discovery_url'] = self.get_discovery_url(bay)
+        else:
+            extra_params['discovery_url'] = 'None'
 
         label_list = ['flannel_network_cidr', 'flannel_use_vxlan',
-                      'flannel_network_subnetlen']
+                      'flannel_network_subnetlen', 'registry_url']
         for label in label_list:
             extra_params[label] = baymodel.labels.get(label)
 
@@ -533,6 +545,52 @@ class AtomicK8sTemplateDefinition(K8sTem
         return cfg.CONF.bay.k8s_atomic_template_path
 
 
+class JeOSK8sTemplateDefinition(K8sTemplateDefinition):
+    """Kubernetes template for openSUSE/SLES JeOS VM."""
+
+    provides = [
+        {'server_type': 'vm',
+         'os': 'opensuse',
+         'coe': 'kubernetes'},
+    ]
+
+    def __init__(self):
+        super(JeOSK8sTemplateDefinition, self).__init__()
+        self.add_parameter('bay_uuid',
+                           bay_attr='uuid',
+                           param_type=str)
+        self.add_parameter('docker_volume_size',
+                           baymodel_attr='docker_volume_size')
+        self.add_parameter('registry_enabled',
+                           baymodel_attr='registry_enabled')
+
+    def get_params(self, context, baymodel, bay, **kwargs):
+        extra_params = kwargs.pop('extra_params', {})
+
+        extra_params['username'] = context.user_name
+        extra_params['tenant_name'] = context.tenant
+        osc = clients.OpenStackClients(context)
+        extra_params['user_token'] = self._get_user_token(context, osc, bay)
+        extra_params['magnum_url'] = osc.magnum_url()
+
+        if baymodel.tls_disabled:
+            extra_params['loadbalancing_protocol'] = 'HTTP'
+            extra_params['kubernetes_port'] = 8080
+
+        if not cfg.CONF.bay.enable_discovery_etcd_io:
+            extra_params['discovery_etcd'] = 'false'
+            extra_params['discovery_url'] = 'None'
+
+        return super(JeOSK8sTemplateDefinition,
+                     self).get_params(context, baymodel, bay,
+                                      extra_params=extra_params,
+                                      **kwargs)
+
+    @property
+    def template_path(self):
+        return cfg.CONF.bay.k8s_opensuse_template_path
+
+
 class CoreOSK8sTemplateDefinition(K8sTemplateDefinition):
     """Kubernetes template for CoreOS VM."""
 
Index: magnum-2.0.1.dev11/magnum/templates/kubernetes/fragments/configure-docker-opensuse.sh
===================================================================
--- /dev/null
+++ magnum-2.0.1.dev11/magnum/templates/kubernetes/fragments/configure-docker-opensuse.sh
@@ -0,0 +1,73 @@
+#!/bin/sh
+
+. /etc/sysconfig/heat-params
+
+echo "stopping docker"
+systemctl stop docker
+ip link del docker0
+
+if [ "$NETWORK_DRIVER" == "flannel" ]; then
+
+    FLANNEL_ENV=/run/flannel/subnet.env
+
+    attempts=60
+    while [[ ! -f $FLANNEL_ENV && $attempts != 0 ]]; do
+        echo "waiting for file $FLANNEL_ENV"
+        sleep 1
+        let attempts--
+    done
+
+    source $FLANNEL_ENV
+
+    if ! [ "\$FLANNEL_SUBNET" ] && [ "\$FLANNEL_MTU" ] ; then
+        echo "ERROR: missing required environment variables." >&2
+        exit 1
+    fi
+
+    if `grep -q DOCKER_NETWORK_OPTIONS /etc/sysconfig/docker`; then
+        sed -i '
+            /^DOCKER_NETWORK_OPTIONS=/ s|=.*|="--bip='"$FLANNEL_SUBNET"' --mtu='"$FLANNEL_MTU"'"|
+        ' /etc/sysconfig/docker
+    else
+        echo "DOCKER_NETWORK_OPTIONS=\"--bip=$FLANNEL_SUBNET --mtu=$FLANNEL_MTU\"" >> /etc/sysconfig/docker
+    fi
+fi
+
+if [ "$REGISTRY_ENABLED" == "True" ]; then
+    REGISTRY_DOMAIN=${REGISTRY_URL##*/}
+    sed -i '
+        /^DOCKER_OPTS=/ s|=.*|="--storage-driver=btrfs --insecure-registry='"$REGISTRY_DOMAIN"' --registry-mirror='"$REGISTRY_URL"'"|
+    ' /etc/sysconfig/docker
+else
+    sed -i '
+        /^DOCKER_OPTS=/ s/=.*/="--storage-driver=btrfs"/
+    ' /etc/sysconfig/docker
+fi
+
+DOCKER_DEV=/dev/disk/by-id/virtio-${DOCKER_VOLUME:0:20}
+
+attempts=60
+while [[ ! -b $DOCKER_DEV && $attempts != 0 ]]; do
+    echo "waiting for disk $DOCKER_DEV"
+    sleep 0.5
+    udevadm trigger
+    let attempts--
+done
+
+if ! [ -b $DOCKER_DEV ]; then
+    echo "ERROR: device $DOCKER_DEV does not exist" >&2
+    exit 1
+fi
+
+mkfs.btrfs $DOCKER_DEV
+
+mount $DOCKER_DEV /var/lib/docker
+
+# make sure we pick up any modified unit files
+systemctl daemon-reload
+
+echo "activating docker service"
+systemctl enable docker
+
+echo "starting docker service"
+systemctl --no-block start docker
Index: magnum-2.0.1.dev11/magnum/templates/kubernetes/fragments/configure-etcd-opensuse.sh
===================================================================
--- /dev/null
+++ magnum-2.0.1.dev11/magnum/templates/kubernetes/fragments/configure-etcd-opensuse.sh
@@ -0,0 +1,57 @@
+#!/bin/sh
+
+. /etc/sysconfig/heat-params
+
+myip="$KUBE_NODE_IP"
+
+sed -i '
+    /ETCD_NAME=/c ETCD_NAME="'$KUBE_NODE_NAME'"
+    /ETCD_DATA_DIR=/c ETCD_DATA_DIR="/var/lib/etcd/default.etcd"
+    /ETCD_LISTEN_CLIENT_URLS=/c ETCD_LISTEN_CLIENT_URLS="http://0.0.0.0:2379"
+    /ETCD_LISTEN_PEER_URLS=/c ETCD_LISTEN_PEER_URLS="http://'$myip':2380"
+    /ETCD_ADVERTISE_CLIENT_URLS=/c ETCD_ADVERTISE_CLIENT_URLS="http://'$myip':2379"
+    /ETCD_INITIAL_ADVERTISE_PEER_URLS=/c ETCD_INITIAL_ADVERTISE_PEER_URLS="http://'$myip':2380"
+' /etc/sysconfig/etcd
+
+if [ "$ETCD_DISCOVERY" == "false" ]; then
+
+    echo "# IP address used by kube-apiserver to provide kubernetes" >> /etc/hosts
+    echo "$KUBE_API_PRIVATE_ADDRESS        kube-master" >> /etc/hosts
+    echo "# IP addresses of kubernetes master nodes" >> /etc/hosts
+
+    IFS='|'
+    ETCD_IPS=($KUBE_MASTER_IPS)
+
+    LOOP_NUM=`expr ${#ETCD_IPS[@]} - 1`
+    ETCD_INIT=""
+    for i in "${!ETCD_IPS[@]}"; do
+        echo "${ETCD_IPS[$i]}        kube-master${i}" >> /etc/hosts
+        ETCD_INIT="${ETCD_INIT}kube-master${i}=http://${ETCD_IPS[$i]}:2380"
+        if [ "$i" -lt "$LOOP_NUM" ]; then
+            ETCD_INIT="${ETCD_INIT},"
+        fi
+    done
+
+    MINION_IPS=($KUBE_MINION_IPS)
+    for i in "${!MINION_IPS[@]}"; do
+        echo "${MINION_IPS[$i]}        kube-minion${i}" >> /etc/hosts
+    done
+
+    sed -i '
+        /ETCD_INITIAL_CLUSTER=/c ETCD_INITIAL_CLUSTER="'$ETCD_INIT'"
+        /ETCD_INITIAL_CLUSTER_STATE=/c ETCD_INITIAL_CLUSTER_STATE=new
+' /etc/sysconfig/etcd
+
+else
+
+    sed -i '
+        /ETCD_DISCOVERY=/c ETCD_DISCOVERY="'$ETCD_DISCOVERY_URL'"
+' /etc/sysconfig/etcd
+
+fi
+
+echo "activating etcd service"
+systemctl enable etcd
+
+echo "starting etcd service"
+systemctl --no-block start etcd
Index: magnum-2.0.1.dev11/magnum/templates/kubernetes/fragments/configure-flanneld-master-opensuse.sh
===================================================================
--- /dev/null
+++ magnum-2.0.1.dev11/magnum/templates/kubernetes/fragments/configure-flanneld-master-opensuse.sh
@@ -0,0 +1,80 @@
+#!/bin/sh
+
+. /etc/sysconfig/heat-params
+
+if [ "$NETWORK_DRIVER" != "flannel" ]; then
+    exit 0
+fi
+
+FLANNEL_ETCD="http://127.0.0.1:2379"
+FLANNEL_JSON=/etc/sysconfig/flannel-network.json
+FLANNELD_CONFIG=/etc/sysconfig/flanneld
+FLANNEL_NETWORK_CIDR="$FLANNEL_NETWORK_CIDR"
+FLANNEL_NETWORK_SUBNETLEN="$FLANNEL_NETWORK_SUBNETLEN"
+FLANNEL_NETWORK_SUBNET_MIN="$FLANNEL_NETWORK_SUBNET_MIN"
+FLANNEL_NETWORK_SUBNET_MAX="$FLANNEL_NETWORK_SUBNET_MAX"
+FLANNEL_USE_VXLAN="$FLANNEL_USE_VXLAN"
+
+sed -i '
+    /^FLANNEL_ETCD=/ s/=.*/="http:\/\/127.0.0.1:2379"/
+    /^#FLANNEL_OPTIONS=/ s//FLANNEL_OPTIONS="-iface eth0 --ip-masq"/
+' /etc/sysconfig/flanneld
+
+cat >> /etc/sysconfig/flanneld <<EOF
+
+# etcd config key.  This is the configuration key that flannel queries
+# For address range assignment
+FLANNEL_ETCD_KEY="/flannel/network"
+EOF
+
+. /etc/sysconfig/flanneld
+
+if [ "$FLANNEL_USE_VXLAN" == "true" ]; then
+    use_vxlan=1
+fi
+
+# Generate a flannel configuration that we will
+# store into etcd using curl.
+cat > $FLANNEL_JSON <<EOF
+{
+  "Network": "$FLANNEL_NETWORK_CIDR",
+  "Subnetlen": $FLANNEL_NETWORK_SUBNETLEN,
+  "SubnetMin": "$FLANNEL_NETWORK_SUBNET_MIN",
+  "SubnetMax": "$FLANNEL_NETWORK_SUBNET_MAX",
+EOF
+
+if [ "$use_vxlan" = 1 ]; then
+cat >> $FLANNEL_JSON <<EOF
+  "Backend": {
+    "Type": "vxlan"
+  }
+EOF
+else
+cat >> $FLANNEL_JSON <<EOF
+  "Backend": {
+    "Type": "udp"
+  }
+EOF
+fi
+
+cat >> $FLANNEL_JSON <<EOF
+}
+EOF
+
+# wait for etcd to become active (we will need it to push the flanneld config)
+while ! curl -sf -o /dev/null $FLANNEL_ETCD/v2/keys/; do
+  echo "waiting for etcd"
+  sleep 1
+done
+
+# put the flannel config in etcd
+echo "creating flanneld config in etcd"
+curl -sf -L $FLANNEL_ETCD/v2/keys$FLANNEL_ETCD_KEY/config \
+  -X PUT \
+  --data-urlencode value@$FLANNEL_JSON
+
+echo "activating flanneld service"
+systemctl enable flanneld
+
+echo "starting flanneld service"
+systemctl --no-block start flanneld
Index: magnum-2.0.1.dev11/magnum/templates/kubernetes/fragments/configure-flanneld-minion-opensuse.sh
===================================================================
--- /dev/null
+++ magnum-2.0.1.dev11/magnum/templates/kubernetes/fragments/configure-flanneld-minion-opensuse.sh
@@ -0,0 +1,36 @@
+#!/bin/sh
+
+. /etc/sysconfig/heat-params
+
+IFS='|'
+MASTER_IPS=($KUBE_MASTER_IPS)
+for i in "${!MASTER_IPS[@]}"; do
+    echo "${MASTER_IPS[$i]}        kube-master${i}" >> /etc/hosts
+done
+
+MINION_IPS=($KUBE_MINION_IPS)
+for i in "${!MINION_IPS[@]}"; do
+    echo "${MINION_IPS[$i]}        kube-minion${i}" >> /etc/hosts
+done
+
+if [ "$NETWORK_DRIVER" == "flannel" ]; then
+
+sed -i '
+    /^FLANNEL_ETCD_ENDPOINTS=/ s|=.*|="http://'"$ETCD_SERVER_IP"':2379"|
+    /^#FLANNEL_OPTIONS=/ s//FLANNEL_OPTIONS="-iface eth0 --ip-masq"/
+' /etc/sysconfig/flanneld
+
+cat >> /etc/sysconfig/flanneld <<EOF
+
+# etcd config key.  This is the configuration key that flannel queries
+# For address range assignment
+FLANNEL_ETCD_KEY="/flannel/network"
+EOF
+
+echo "activating flanneld service"
+systemctl enable flanneld
+
+echo "starting flanneld service"
+systemctl --no-block start flanneld
+
+fi
Index: magnum-2.0.1.dev11/magnum/templates/kubernetes/fragments/configure-kubernetes-master-opensuse.sh
===================================================================
--- /dev/null
+++ magnum-2.0.1.dev11/magnum/templates/kubernetes/fragments/configure-kubernetes-master-opensuse.sh
@@ -0,0 +1,54 @@
+#!/bin/sh
+
+. /etc/sysconfig/heat-params
+
+echo "configuring kubernetes (master)"
+
+KUBE_API_ADDRESS="--insecure-port=$KUBE_API_PORT"
+
+sed -i '
+    /^KUBE_ALLOW_PRIV=/ s/=.*/="--allow-privileged='"$KUBE_ALLOW_PRIV"'"/
+' /etc/kubernetes/config
+
+sed -i '
+    /^KUBE_API_ADDRESS=/ s/=.*/="--advertise-address='"$KUBE_NODE_IP"' --insecure-bind-address=0.0.0.0 --insecure-port='"$KUBE_API_PORT"'"/
+    /^KUBE_API_PORT=/ s/=.*/="--insecure-port='"$KUBE_API_PORT"'"/
+    /^KUBE_SERVICE_ADDRESSES=/ s|=.*|="--service-cluster-ip-range='"$PORTAL_NETWORK_CIDR"'"|
+    /^KUBE_API_ARGS=/ s/=.*/="--runtime-config=api\/all=true"/
+    /^KUBE_ETCD_SERVERS=/ s/=.*/="--etcd-servers=http:\/\/127.0.0.1:2379"/
+    /^KUBE_ADMISSION_CONTROL=/ s/=.*/=""/
+' /etc/kubernetes/apiserver
+
+cat >> /etc/kubernetes/apiserver <<EOF
+# Uncomment the following line to enable Load Balancer feature
+# KUBE_API_ARGS="--runtime-config=api/all=true --cloud-config=/etc/sysconfig/kubernetes_openstack_config --cloud-provider=openstack"
+EOF
+
+# TODO: we should not depend on flannel for getting the FLANNEL_SUBNET
+
+sed -i '
+    /^KUBE_CONTROLLER_MANAGER_ARGS=/ s|=.*|="--leader-elect=true --cluster-name=kubernetes --cluster-cidr='"$FLANNEL_NETWORK_CIDR"'"|
+' /etc/kubernetes/controller-manager
+
+# Generate a the configuration for Kubernetes services to talk to OpenStack Neutron
+cat > /etc/sysconfig/kubernetes_openstack_config <<EOF
+[Global]
+auth-url=$AUTH_URL
+Username=$USERNAME
+Password=$PASSWORD
+tenant-name=$TENANT_NAME
+[LoadBalancer]
+subnet-id=$CLUSTER_SUBNET
+create-monitor=yes
+monitor-delay=1m
+monitor-timeout=30s
+monitor-max-retries=3
+EOF
+
+for service in kube-apiserver kube-scheduler kube-controller-manager; do
+    echo "activating $service service"
+    systemctl enable $service
+
+    echo "starting $service services"
+    systemctl --no-block start $service
+done
Index: magnum-2.0.1.dev11/magnum/templates/kubernetes/fragments/configure-kubernetes-minion-opensuse.sh
===================================================================
--- /dev/null
+++ magnum-2.0.1.dev11/magnum/templates/kubernetes/fragments/configure-kubernetes-minion-opensuse.sh
@@ -0,0 +1,50 @@
+#!/bin/sh
+
+. /etc/sysconfig/heat-params
+
+echo "configuring kubernetes (minion)"
+
+myip=$(ip addr show eth0 |
+       awk '$1 == "inet" {print $2}' |
+       cut -f1 -d/)
+
+ETCD_SERVER_IP=${ETCD_SERVER_IP:-$KUBE_MASTER_IP}
+
+if [ "$TLS_DISABLED" == "True" ]; then
+    KUBE_PROTOCOL="http"
+    KUBE_CONFIG=""
+else
+    KUBE_PROTOCOL="https"
+    KUBE_CONFIG="--kubeconfig=/srv/kubernetes/kubeconfig.yaml"
+fi
+
+KUBE_MASTER_URI="$KUBE_PROTOCOL://$KUBE_MASTER_IP:$KUBE_API_PORT"
+
+sed -i '
+    /^KUBE_ALLOW_PRIV=/ s/=.*/="--allow-privileged='"$KUBE_ALLOW_PRIV"'"/
+    /^KUBE_ETCD_SERVERS=/ s|=.*|="--etcd-servers=http://'"$ETCD_SERVER_IP"':2379"|
+    /^KUBE_MASTER=/ s|=.*|="--master='"$KUBE_MASTER_URI"'"|
+' /etc/kubernetes/config
+
+sed -i '
+    /^KUBELET_ADDRESS=/ s/=.*/="--address=0.0.0.0"/
+    /^KUBELET_HOSTNAME=/ s/=.*/=""/
+    /^KUBELET_API_SERVER=/ s|=.*|="--api-servers='"$KUBE_MASTER_URI"'"|
+    /^KUBELET_ARGS=/ s|=.*|="--node-ip='"$myip"' --config=/etc/kubernetes/manifests '"$KUBE_CONFIG"'"|
+' /etc/kubernetes/kubelet
+
+sed -i '
+    /^KUBE_PROXY_ARGS=/ s/=.*/="--proxy-mode=iptables"/
+' /etc/kubernetes/proxy
+
+cat >> /etc/environment <<EOF
+KUBERNETES_MASTER=$KUBE_MASTER_URI
+EOF
+
+for service in kubelet kube-proxy; do
+    echo "activating $service service"
+    systemctl enable $service
+
+    echo "starting $service service"
+    systemctl --no-block start $service
+done
Index: magnum-2.0.1.dev11/magnum/templates/kubernetes/fragments/create-kubernetes-user-opensuse.yaml
===================================================================
--- /dev/null
+++ magnum-2.0.1.dev11/magnum/templates/kubernetes/fragments/create-kubernetes-user-opensuse.yaml
@@ -0,0 +1,9 @@
+#cloud-config
+system_info:
+  default_user:
+    name: kubernetes
+    lock_passwd: true
+    gecos: Kubernetes Interactive User
+    groups: [wheel, systemd-journal]
+    sudo: ["ALL=(ALL) NOPASSWD:ALL"]
+    shell: /bin/bash
Index: magnum-2.0.1.dev11/magnum/templates/kubernetes/kubecluster-opensuse.yaml
===================================================================
--- /dev/null
+++ magnum-2.0.1.dev11/magnum/templates/kubernetes/kubecluster-opensuse.yaml
@@ -0,0 +1,533 @@
+heat_template_version: 2013-05-23
+
+description: >
+  This template will boot a Kubernetes cluster with one or more
+  minions (as specified by the number_of_minions parameter, which
+  defaults to 1).
+
+parameters:
+
+  ssh_key_name:
+    type: string
+    description: name of ssh key to be provisioned on our server
+
+  external_network:
+    type: string
+    description: uuid/name of a network to use for floating ip addresses
+    default: public
+
+  server_image:
+    type: string
+    description: glance image used to boot the server
+
+  master_flavor:
+    type: string
+    default: m1.small
+    description: flavor to use when booting the server
+
+  minion_flavor:
+    type: string
+    default: m1.small
+    description: flavor to use when booting the server
+
+  dns_nameserver:
+    type: string
+    description: address of a dns nameserver reachable in your environment
+    default: 8.8.8.8
+
+  number_of_masters:
+    type: number
+    description: how many kubernetes masters to spawn
+    default: 1
+
+  number_of_minions:
+    type: number
+    description: how many kubernetes minions to spawn
+    default: 1
+
+  fixed_network_cidr:
+    type: string
+    description: network range for fixed ip network
+    default: 10.0.0.0/24
+
+  portal_network_cidr:
+    type: string
+    description: >
+      address range used by kubernetes for service portals
+    default: 172.21.0.0/16
+
+  network_driver:
+    type: string
+    description: network driver to use for instantiating container networks
+    default: flannel
+
+  flannel_network_cidr:
+    type: string
+    description: network range for flannel overlay network
+    default: 172.20.0.0/16
+
+  flannel_network_subnetlen:
+    type: string
+    description: size of subnet assigned to each minion
+    default: 24
+
+  flannel_network_subnet_min:
+    type: string
+    description: minimum subnet
+    default: 172.20.50.0
+
+  flannel_network_subnet_max:
+    type: string
+    description: maximum subnet
+    default: 172.20.199.0
+
+  flannel_use_vxlan:
+    type: string
+    description: >
+      if true use the vxlan backend, otherwise use the default
+      udp backend
+    default: "false"
+    constraints:
+      - allowed_values: ["true", "false"]
+
+  kube_allow_priv:
+    type: string
+    description: >
+      whether or not kubernetes should permit privileged containers.
+    default: "true"
+    constraints:
+      - allowed_values: ["true", "false"]
+
+  docker_volume_size:
+    type: number
+    description: >
+      size of a cinder volume to allocate to docker for container/image
+      storage
+    default: 25
+
+  wait_condition_timeout:
+    type: number
+    description: >
+      timeout for the Wait Conditions
+    default: 600
+
+  minions_to_remove:
+    type: comma_delimited_list
+    description: >
+      List of minions to be removed when doing an update. Individual minion may
+      be referenced several ways: (1) The resource name (e.g. ['1', '3']),
+      (2) The private IP address ['10.0.0.4', '10.0.0.6']. Note: the list should
+      be empty when doing an create.
+    default: []
+
+  discovery_etcd:
+    type: string
+    description: >
+      Use discovery service for bootstrapping the etcd cluster.
+    default: "true"
+    constraints:
+      - allowed_values: ["true", "false"]
+
+  discovery_url:
+    type: string
+    description: >
+      Discovery URL used for bootstrapping the etcd cluster.
+
+  registry_enabled:
+    type: boolean
+    description: >
+      Indicates whether the docker registry is enabled.
+    default: false
+
+  registry_url:
+    type: string
+    description: Docker Registry URL service
+    default: ""
+
+  auth_url:
+    type: string
+    description: >
+      url for kubernetes to authenticate before sending request to neutron
+      must be v2 since kubernetes backend only suppor v2 at this point
+
+  username:
+    type: string
+    description: >
+      user account
+
+  password:
+    type: string
+    description: >
+      user password, not set in current implementation, only used to
+      fill in for Kubernetes config file
+    default:
+      ChangeMe
+
+  tenant_name:
+    type: string
+    description: >
+      tenant name
+
+  loadbalancing_protocol:
+    type: string
+    description: >
+      The protocol which is used for load balancing. If you want to change
+      tls_disabled option to 'True', please change this to "HTTP".
+    default: TCP
+    constraints:
+      - allowed_values: ["TCP", "HTTP"]
+
+  tls_disabled:
+    type: boolean
+    description: whether or not to disable TLS
+    default: False
+
+  kubernetes_port:
+    type: number
+    description: >
+      The port which are used by kube-apiserver to provide Kubernetes
+      service.
+    default: 6443
+
+  user_token:
+    type: string
+    description: token used for communicating back to Magnum for TLS certs
+
+  bay_uuid:
+    type: string
+    description: identifier for the bay this template is generating
+
+  magnum_url:
+    type: string
+    description: endpoint to retrieve TLS certs from
+
+  trustee_domain_id:
+    type: string
+    description: domain id of the trustee
+    default: ""
+
+  trustee_user_id:
+    type: string
+    description: user id of the trustee
+    default: ""
+
+  trustee_username:
+    type: string
+    description: username of the trustee
+    default: ""
+
+  trustee_password:
+    type: string
+    description: password of the trustee
+    default: ""
+    hidden: true
+
+  trust_id:
+    type: string
+    description: id of the trust which is used by the trustee
+    default: ""
+    hidden: true
+
+resources:
+
+  ######################################################################
+  #
+  # network resources.  allocate a network and router for our server.
+  # Important: the Load Balancer feature in Kubernetes requires that
+  # the name for the fixed_network must be "private" for the
+  # address lookup in Kubernetes to work properly
+  #
+
+  fixed_network:
+    type: OS::Neutron::Net
+    properties:
+      name: private
+
+  fixed_subnet:
+    type: OS::Neutron::Subnet
+    properties:
+      cidr: {get_param: fixed_network_cidr}
+      network: {get_resource: fixed_network}
+      dns_nameservers:
+        - {get_param: dns_nameserver}
+
+  extrouter:
+    type: OS::Neutron::Router
+    properties:
+      external_gateway_info:
+        network: {get_param: external_network}
+
+  extrouter_inside:
+    type: OS::Neutron::RouterInterface
+    properties:
+      router_id: {get_resource: extrouter}
+      subnet: {get_resource: fixed_subnet}
+
+  ######################################################################
+  #
+  # security groups.  we need to permit network traffic of various
+  # sorts.
+  #
+
+  secgroup_base:
+    type: OS::Neutron::SecurityGroup
+    properties:
+      rules:
+        - protocol: icmp
+        - protocol: tcp
+          port_range_min: 22
+          port_range_max: 22
+
+  secgroup_kube_master:
+    type: OS::Neutron::SecurityGroup
+    properties:
+      rules:
+        - protocol: tcp
+          port_range_min: 7080
+          port_range_max: 7080
+        - protocol: tcp
+          port_range_min: 8080
+          port_range_max: 8080
+        - protocol: tcp
+          port_range_min: 2379
+          port_range_max: 2379
+        - protocol: tcp
+          port_range_min: 2380
+          port_range_max: 2380
+        - protocol: tcp
+          port_range_min: 6443
+          port_range_max: 6443
+        - protocol: tcp
+          port_range_min: 10250
+          port_range_max: 10250
+        - protocol: tcp
+          port_range_min: 30000
+          port_range_max: 40000
+
+  secgroup_kube_minion:
+    type: OS::Neutron::SecurityGroup
+    properties:
+      rules:
+        - protocol: icmp
+        - protocol: tcp
+        - protocol: udp
+
+  ######################################################################
+  #
+  # load balancers.
+  #
+
+  api_monitor:
+    type: OS::Neutron::HealthMonitor
+    properties:
+      type: TCP
+      delay: 5
+      max_retries: 5
+      timeout: 5
+
+  api_pool:
+    type: OS::Neutron::Pool
+    properties:
+      protocol: {get_param: loadbalancing_protocol}
+      monitors: [{get_resource: api_monitor}]
+      subnet: {get_resource: fixed_subnet}
+      lb_method: ROUND_ROBIN
+      vip:
+        protocol_port: {get_param: kubernetes_port}
+
+  api_pool_floating:
+    type: OS::Neutron::FloatingIP
+    depends_on:
+      - extrouter_inside
+    properties:
+      floating_network: {get_param: external_network}
+      port_id: {get_attr: [api_pool, vip, port_id]}
+
+  etcd_monitor:
+    type: OS::Neutron::HealthMonitor
+    properties:
+      type: TCP
+      delay: 5
+      max_retries: 5
+      timeout: 5
+
+  etcd_pool:
+    type: OS::Neutron::Pool
+    properties:
+      protocol: HTTP
+      monitors: [{get_resource: etcd_monitor}]
+      subnet: {get_resource: fixed_subnet}
+      lb_method: ROUND_ROBIN
+      vip:
+        protocol_port: 2379
+
+  ######################################################################
+  #
+  # kubernetes network. These are a resource groups that will create
+  # network ports for masters and minions nodes.
+  #
+
+  kube_master_ports:
+    type: OS::Heat::ResourceGroup
+    depends_on:
+      - extrouter_inside
+    properties:
+      count: { get_param: number_of_masters }
+      resource_def:
+        type: kubenetwork-opensuse.yaml
+        properties:
+          fixed_network: { get_resource: fixed_network }
+          security_groups:
+            - { get_resource: secgroup_base }
+            - { get_resource: secgroup_kube_master }
+          fixed_subnet: { get_resource: fixed_subnet }
+
+  kube_minion_ports:
+    type: OS::Heat::ResourceGroup
+    depends_on:
+      - extrouter_inside
+    properties:
+      count: { get_param: number_of_minions }
+      resource_def:
+        type: kubenetwork-opensuse.yaml
+        properties:
+          fixed_network: { get_resource: fixed_network }
+          security_groups:
+            - { get_resource: secgroup_base }
+            - { get_resource: secgroup_kube_master }
+          fixed_subnet: { get_resource: fixed_subnet }
+
+  ######################################################################
+  #
+  # kubernetes masters. This is a resource group that will create
+  # <number_of_masters> masters.
+  #
+
+
+  kube_masters:
+    type: OS::Heat::ResourceGroup
+    depends_on:
+      - extrouter_inside
+      - kube_master_ports
+      - kube_minion_ports
+    properties:
+      count: {get_param: number_of_masters}
+      resource_def:
+        type: kubemaster-opensuse.yaml
+        properties:
+          api_public_address: {get_attr: [api_pool_floating, floating_ip_address]}
+          api_private_address: {get_attr: [api_pool, vip, address]}
+          ssh_key_name: {get_param: ssh_key_name}
+          server_image: {get_param: server_image}
+          master_flavor: {get_param: master_flavor}
+          external_network: {get_param: external_network}
+          kube_allow_priv: {get_param: kube_allow_priv}
+          wait_condition_timeout: {get_param: wait_condition_timeout}
+          network_driver: {get_param: network_driver}
+          flannel_network_cidr: {get_param: flannel_network_cidr}
+          flannel_network_subnetlen: {get_param: flannel_network_subnetlen}
+          flannel_network_subnet_min: {get_param: flannel_network_subnet_min}
+          flannel_network_subnet_max: {get_param: flannel_network_subnet_max}
+          flannel_use_vxlan: {get_param: flannel_use_vxlan}
+          portal_network_cidr: {get_param: portal_network_cidr}
+          discovery_etcd: {get_param: discovery_etcd}
+          discovery_url: {get_param: discovery_url}
+          user_token: {get_param: user_token}
+          bay_uuid: {get_param: bay_uuid}
+          magnum_url: {get_param: magnum_url}
+          kube_master_ports: { get_attr: [kube_master_ports, refs] }
+          kube_master_index: '%index%'
+          kube_master_ips: {get_attr: [kube_master_ports, fixed_ip]}
+          kube_master_ips_list: { list_join: ["|", {get_attr: [kube_master_ports, fixed_ip]} ] }
+          kube_minion_ips_list: { list_join: ["|", {get_attr: [kube_minion_ports, fixed_ip]} ] }
+          fixed_network: {get_resource: fixed_network}
+          fixed_subnet: {get_resource: fixed_subnet}
+          api_pool_id: {get_resource: api_pool}
+          etcd_pool_id: {get_resource: etcd_pool}
+          auth_url: {get_param: auth_url}
+          username: {get_param: username}
+          password: {get_param: password}
+          tenant_name: {get_param: tenant_name}
+          kubernetes_port: {get_param: kubernetes_port}
+          tls_disabled: {get_param: tls_disabled}
+          secgroup_base_id: {get_resource: secgroup_base}
+          secgroup_kube_master_id: {get_resource: secgroup_kube_master}
+          kube_master_id: 'kube-master%index%'
+
+  ######################################################################
+  #
+  # kubernetes minions. This is an resource group that will initially
+  # create <number_of_minions> minions, and needs to be manually scaled.
+  #
+
+  kube_minions:
+    type: OS::Heat::ResourceGroup
+    depends_on:
+      - extrouter_inside
+      - kube_masters
+    properties:
+      count: {get_param: number_of_minions}
+      removal_policies: [{resource_list: {get_param: minions_to_remove}}]
+      resource_def:
+        type: kubeminion-opensuse.yaml
+        properties:
+          ssh_key_name: {get_param: ssh_key_name}
+          server_image: {get_param: server_image}
+          minion_flavor: {get_param: minion_flavor}
+          fixed_network: {get_resource: fixed_network}
+          fixed_subnet: {get_resource: fixed_subnet}
+          network_driver: {get_param: network_driver}
+          kube_minion_ports: { get_attr: [kube_minion_ports, refs] }
+          kube_minion_index: '%index%'
+          kube_minion_ips: {get_attr: [kube_minion_ports, fixed_ip]}
+          kube_master_ips_list: { list_join: ["|", {get_attr: [kube_master_ports, fixed_ip]} ] }
+          kube_minion_ips_list: { list_join: ["|", {get_attr: [kube_minion_ports, fixed_ip]} ] }
+          kube_master_ip: {get_attr: [api_pool, vip, address]}
+          etcd_server_ip: {get_attr: [etcd_pool, vip, address]}
+          external_network: {get_param: external_network}
+          kube_allow_priv: {get_param: kube_allow_priv}
+          docker_volume_size: {get_param: docker_volume_size}
+          wait_condition_timeout: {get_param: wait_condition_timeout}
+          registry_enabled: {get_param: registry_enabled}
+          registry_url: {get_param: registry_url}
+          user_token: {get_param: user_token}
+          bay_uuid: {get_param: bay_uuid}
+          magnum_url: {get_param: magnum_url}
+          kubernetes_port: {get_param: kubernetes_port}
+          tls_disabled: {get_param: tls_disabled}
+          secgroup_kube_minion_id: {get_resource: secgroup_kube_minion}
+          kube_minion_id: 'kube-minion%index%'
+
+outputs:
+
+  api_address:
+    value:
+      str_replace:
+        template: api_ip_address
+        params:
+          api_ip_address: {get_attr: [api_pool_floating, floating_ip_address]}
+    description: >
+      This is the API endpoint of the Kubernetes server. Use this to access
+      the Kubernetes API from outside the cluster.
+
+  kube_masters:
+    value: {get_attr: [kube_master_ports, fixed_ip]}
+    description: >
+      This is a list of "private" ip addresses of all Kubernetes master servers.
+
+  kube_masters_external:
+    value: {get_attr: [kube_masters, kube_master_external_ip]}
+    description: >
+      This is a list of "public" ip addresses of all Kubernetes master servers.
+      Use these addresses to log in to the Kubernetes masters via ssh.
+
+  kube_minions:
+    value: {get_attr: [kube_minions, kube_minion_ip]}
+    description: >
+      This is a list of the "private" addresses of all the Kubernetes minions.
+
+  kube_minions_external:
+    value: {get_attr: [kube_minions, kube_minion_external_ip]}
+    description: >
+      This is a list of the "public" addresses of all the Kubernetes minions. Use
+      these addresses to, e.g., log into the minions.
Index: magnum-2.0.1.dev11/magnum/templates/kubernetes/kubemaster-opensuse.yaml
===================================================================
--- /dev/null
+++ magnum-2.0.1.dev11/magnum/templates/kubernetes/kubemaster-opensuse.yaml
@@ -0,0 +1,322 @@
+heat_template_version: 2013-05-23
+
+description: >
+  This is a nested stack that defines a single Kubernetes master, This stack is
+  included by an ResourceGroup resource in the parent template
+  (kubecluster-opensuse.yaml).
+
+parameters:
+
+  server_image:
+    type: string
+    description: glance image used to boot the server
+
+  master_flavor:
+    type: string
+    default: m1.small
+    description: flavor to use when booting the server
+
+  ssh_key_name:
+    type: string
+    description: name of ssh key to be provisioned on our server
+    default: lars
+
+  external_network:
+    type: string
+    description: uuid/name of a network to use for floating ip addresses
+
+  portal_network_cidr:
+    type: string
+    description: >
+      address range used by kubernetes for service portals
+    default: 172.21.0.0/16
+
+  kube_allow_priv:
+    type: string
+    description: >
+      whether or not kubernetes should permit privileged containers.
+    default: "false"
+    constraints:
+      - allowed_values: ["true", "false"]
+
+  flannel_network_cidr:
+    type: string
+    description: network range for flannel overlay network
+    default: 172.20.0.0/16
+
+  flannel_network_subnetlen:
+    type: string
+    description: size of subnet assigned to each master
+    default: 24
+
+  flannel_network_subnet_min:
+    type: string
+    description: minimum subnet
+    default: 172.20.50.0
+
+  flannel_network_subnet_max:
+    type: string
+    description: maximum subnet
+    default: 172.20.199.0
+
+  flannel_use_vxlan:
+    type: string
+    description: >
+      If true use the vxlan backend, otherwise use the default
+      udp backend
+    default: "false"
+    constraints:
+      - allowed_values: ["true", "false"]
+
+  discovery_etcd:
+    type: string
+    description: >
+      Use discovery service for bootstrapping the etcd cluster.
+    default: "false"
+    constraints:
+      - allowed_values: ["true", "false"]
+
+  discovery_url:
+    type: string
+    description: >
+      Discovery URL used for bootstrapping the etcd cluster.
+
+  tls_disabled:
+    type: boolean
+    description: whether or not to enable TLS
+    default: False
+
+  kubernetes_port:
+    type: number
+    description: >
+      The port which are used by kube-apiserver to provide Kubernetes
+      service.
+    default: 6443
+
+  user_token:
+    type: string
+    description: token used for communicating back to Magnum for TLS certs
+
+  bay_uuid:
+    type: string
+    description: identifier for the bay this template is generating
+
+  magnum_url:
+    type: string
+    description: endpoint to retrieve TLS certs from
+
+  # The following are all generated in the parent template.
+  api_public_address:
+    type: string
+    description: Public IP address of the Kubernetes master server.
+  api_private_address:
+    type: string
+    description: Private IP address of the Kubernetes master server.
+  kube_master_ips:
+    type: comma_delimited_list
+    description: Table of IP address of the Kubernetes mastes server.
+  kube_master_ips_list:
+    type: string
+    description: List of IP addresses of the Kubernetes mastes servers.
+  kube_master_ports:
+    type: comma_delimited_list
+    description: List of port UUIDs
+  kube_master_index:
+    type: number
+    description: index into ports list
+  kube_minion_ips_list:
+    type: string
+    description: List of IP addresses of the Kubernetes minion servers.
+  fixed_network:
+    type: string
+    description: Network from which to allocate fixed addresses.
+  fixed_subnet:
+    type: string
+    description: Subnet from which to allocate fixed addresses.
+  network_driver:
+    type: string
+    description: network driver to use for instantiating container networks
+  wait_condition_timeout:
+    type: number
+    description : >
+      timeout for the Wait Conditions
+  secgroup_base_id:
+    type: string
+    description: ID of the security group for base.
+  secgroup_kube_master_id:
+    type: string
+    description: ID of the security group for kubernetes master.
+  kube_master_id:
+    type: string
+    description: ID of for kubernetes master.
+  api_pool_id:
+    type: string
+    description: ID of the load balancer pool of k8s API server.
+  etcd_pool_id:
+    type: string
+    description: ID of the load balancer pool of etcd server.
+  auth_url:
+    type: string
+    description: >
+      url for kubernetes to authenticate before sending request to neutron
+  username:
+    type: string
+    description: >
+      user account
+  password:
+    type: string
+    description: >
+      user password
+  tenant_name:
+    type: string
+    description: >
+      tenant name
+
+resources:
+
+  master_wait_handle:
+    type: OS::Heat::WaitConditionHandle
+
+  master_wait_condition:
+    type: OS::Heat::WaitCondition
+    depends_on: kube_master
+    properties:
+      handle: {get_resource: master_wait_handle}
+      timeout: {get_param: wait_condition_timeout}
+
+  ######################################################################
+  #
+  # software configs.  these are components that are combined into
+  # a multipart MIME user-data archive.
+  #
+
+  write_heat_params:
+    type: OS::Heat::SoftwareConfig
+    properties:
+      group: ungrouped
+      config:
+        str_replace:
+          template: {get_file: fragments/write-params-master-opensuse.yaml}
+          params:
+            "$KUBE_API_PUBLIC_ADDRESS": {get_param: api_public_address}
+            "$KUBE_API_PRIVATE_ADDRESS": {get_param: api_private_address}
+            "$KUBE_API_PORT": {get_param: kubernetes_port}
+            "$KUBE_ALLOW_PRIV": {get_param: kube_allow_priv}
+            "$KUBE_MASTER_IPS": {get_param: kube_master_ips_list}
+            "$KUBE_MINION_IPS": {get_param: kube_minion_ips_list}
+            "$KUBE_NODE_IP": { "Fn::Select": [ { get_param: kube_master_index }, { get_param: kube_master_ips} ] }
+            "$KUBE_NODE_NAME": {get_param: kube_master_id}
+            "$NETWORK_DRIVER": {get_param: network_driver}
+            "$FLANNEL_NETWORK_CIDR": {get_param: flannel_network_cidr}
+            "$FLANNEL_NETWORK_SUBNETLEN": {get_param: flannel_network_subnetlen}
+            "$FLANNEL_NETWORK_SUBNET_MIN": {get_param: flannel_network_subnet_min}
+            "$FLANNEL_NETWORK_SUBNET_MAX": {get_param: flannel_network_subnet_max}
+            "$FLANNEL_USE_VXLAN": {get_param: flannel_use_vxlan}
+            "$PORTAL_NETWORK_CIDR": {get_param: portal_network_cidr}
+            "$ETCD_DISCOVERY": {get_param: discovery_etcd}
+            "$ETCD_DISCOVERY_URL": {get_param: discovery_url}
+            "$AUTH_URL": {get_param: auth_url}
+            "$USERNAME": {get_param: username}
+            "$PASSWORD": {get_param: password}
+            "$TENANT_NAME": {get_param: tenant_name}
+            "$CLUSTER_SUBNET": {get_param: fixed_subnet}
+            "$TLS_DISABLED": {get_param: tls_disabled}
+            "$BAY_UUID": {get_param: bay_uuid}
+            "$USER_TOKEN": {get_param: user_token}
+            "$MAGNUM_URL": {get_param: magnum_url}
+
+  configure_etcd:
+    type: OS::Heat::SoftwareConfig
+    properties:
+      group: ungrouped
+      config: {get_file: fragments/configure-etcd-opensuse.sh}
+
+  configure_flanneld:
+    type: OS::Heat::SoftwareConfig
+    properties:
+      group: ungrouped
+      config: {get_file: fragments/configure-flanneld-master-opensuse.sh}
+
+  create_kubernetes_user:
+    type: OS::Heat::SoftwareConfig
+    properties:
+      group: ungrouped
+      config: {get_file: fragments/create-kubernetes-user-opensuse.yaml}
+
+  configure_kubernetes:
+    type: OS::Heat::SoftwareConfig
+    properties:
+      group: ungrouped
+      config: {get_file: fragments/configure-kubernetes-master-opensuse.sh}
+
+  master_wc_notify:
+    type: OS::Heat::SoftwareConfig
+    properties:
+      group: ungrouped
+      config:
+        str_replace:
+          template: |
+            #!/bin/bash -v
+            wc_notify --data-binary '{"status": "SUCCESS"}'
+          params:
+            wc_notify: {get_attr: [master_wait_handle, curl_cli]}
+
+  kube_master_init:
+    type: OS::Heat::MultipartMime
+    properties:
+      parts:
+        - config: {get_resource: write_heat_params}
+        - config: {get_resource: configure_etcd}
+        - config: {get_resource: configure_flanneld}
+        - config: {get_resource: create_kubernetes_user}
+        - config: {get_resource: configure_kubernetes}
+        - config: {get_resource: master_wc_notify}
+
+  ######################################################################
+  #
+  # a single kubernetes master.
+  #
+
+  kube_master:
+    type: OS::Nova::Server
+    properties:
+      name: {get_param: kube_master_id}
+      image: {get_param: server_image}
+      flavor: {get_param: master_flavor}
+      key_name: {get_param: ssh_key_name}
+      user_data_format: RAW
+      user_data: {get_resource: kube_master_init}
+      config_drive: true
+      networks:
+        - port: { "Fn::Select": [ { get_param: kube_master_index }, { get_param: kube_master_ports} ] }
+
+  kube_master_floating:
+    type: OS::Neutron::FloatingIP
+    properties:
+      floating_network: {get_param: external_network}
+      port_id: { "Fn::Select": [ { get_param: kube_master_index }, { get_param: kube_master_ports} ] }
+
+  api_pool_member:
+    type: OS::Neutron::PoolMember
+    properties:
+      pool_id: {get_param: api_pool_id}
+      address: { "Fn::Select": [ { get_param: kube_master_index }, { get_param: kube_master_ips} ] }
+      protocol_port: {get_param: kubernetes_port}
+
+  etcd_pool_member:
+    type: OS::Neutron::PoolMember
+    properties:
+      pool_id: {get_param: etcd_pool_id}
+      address: { "Fn::Select": [ { get_param: kube_master_index }, { get_param: kube_master_ips} ] }
+      protocol_port: 2379
+
+outputs:
+
+  kube_master_port:
+    value: { get_param: kube_master_port }
+
+  kube_master_ip:
+    value:  { "Fn::Select": [ { get_param: kube_master_index }, { get_param: kube_master_ips} ] }
+
+  kube_master_external_ip:
+    value: {get_attr: [kube_master_floating, floating_ip_address]}
Index: magnum-2.0.1.dev11/magnum/templates/kubernetes/kubeminion-opensuse.yaml
===================================================================
--- /dev/null
+++ magnum-2.0.1.dev11/magnum/templates/kubernetes/kubeminion-opensuse.yaml
@@ -0,0 +1,267 @@
+heat_template_version: 2013-05-23
+
+description: >
+  This is a nested stack that defines a single Kubernetes minion, This stack is
+  included by an AutoScalingGroup resource in the parent template
+  (kubecluster-opensuse.yaml).
+
+parameters:
+
+  server_image:
+    type: string
+    description: glance image used to boot the server
+
+  minion_flavor:
+    type: string
+    default: m1.small
+    description: flavor to use when booting the server
+
+  ssh_key_name:
+    type: string
+    description: name of ssh key to be provisioned on our server
+    default: lars
+
+  external_network:
+    type: string
+    description: uuid/name of a network to use for floating ip addresses
+
+  kube_allow_priv:
+    type: string
+    description: >
+      whether or not kubernetes should permit privileged containers.
+    default: "false"
+    constraints:
+      - allowed_values: ["true", "false"]
+
+  docker_volume_size:
+    type: number
+    description: >
+      size of a cinder volume to allocate to docker for container/image
+      storage
+    default: 25
+
+  tls_disabled:
+    type: boolean
+    description: whether or not to enable TLS
+    default: False
+
+  kubernetes_port:
+    type: number
+    description: >
+      The port which are used by kube-apiserver to provide Kubernetes
+      service.
+    default: 6443
+
+  user_token:
+    type: string
+    description: token used for communicating back to Magnum for TLS certs
+
+  bay_uuid:
+    type: string
+    description: identifier for the bay this template is generating
+
+  magnum_url:
+    type: string
+    description: endpoint to retrieve TLS certs from
+
+
+  # The following are all generated in the parent template.
+  kube_master_ip:
+    type: string
+    description: IP address of the Kubernetes master server.
+  kube_minion_ips:
+    type: comma_delimited_list
+    description: Table of IP address of the Kubernetes minion server.
+  kube_minion_ports:
+    type: comma_delimited_list
+    description: List of port UUIDs
+  kube_minion_index:
+    type: number
+    description: index into ports list
+  kube_master_ips_list:
+    type: string
+    description: List of IP addresses of the Kubernetes mastes servers.
+  kube_minion_ips_list:
+    type: string
+    description: List of IP addresses of the Kubernetes minion servers.
+  etcd_server_ip:
+    type: string
+    description: IP address of the Etcd server.
+  fixed_network:
+    type: string
+    description: Network from which to allocate fixed addresses.
+  fixed_subnet:
+    type: string
+    description: Subnet from which to allocate fixed addresses.
+  network_driver:
+    type: string
+    description: network driver to use for instantiating container networks
+  wait_condition_timeout:
+    type: number
+    description : >
+      timeout for the Wait Conditions
+
+  registry_enabled:
+    type: boolean
+    description: >
+      Indicates whether the docker registry is enabled.
+    default: false
+
+  registry_url:
+    type: string
+    description: Docker Registry URL service
+
+  secgroup_kube_minion_id:
+    type: string
+    description: ID of the security group for kubernetes minion.
+
+  kube_minion_id:
+    type: string
+    description: ID of for kubernetes minion.
+
+resources:
+
+  minion_wait_handle:
+    type: OS::Heat::WaitConditionHandle
+
+  minion_wait_condition:
+    type: OS::Heat::WaitCondition
+    depends_on: kube-minion
+    properties:
+      handle: {get_resource: minion_wait_handle}
+      timeout: {get_param: wait_condition_timeout}
+
+  ######################################################################
+  #
+  # software configs.  these are components that are combined into
+  # a multipart MIME user-data archive.
+  #
+
+  write_heat_params:
+    type: OS::Heat::SoftwareConfig
+    properties:
+      group: ungrouped
+      config:
+        str_replace:
+          template: {get_file: fragments/write-params-minion-opensuse.yaml}
+          params:
+            $KUBE_ALLOW_PRIV: {get_param: kube_allow_priv}
+            $KUBE_MASTER_IP: {get_param: kube_master_ip}
+            $KUBE_API_PORT: {get_param: kubernetes_port}
+            $KUBE_MASTER_IPS: {get_param: kube_master_ips_list}
+            $KUBE_MINION_IPS: {get_param: kube_minion_ips_list}
+            $ETCD_SERVER_IP: {get_param: etcd_server_ip}
+            $DOCKER_VOLUME: {get_resource: docker_volume}
+            $NETWORK_DRIVER: {get_param: network_driver}
+            $REGISTRY_ENABLED: {get_param: registry_enabled}
+            $REGISTRY_URL: {get_param: registry_url}
+            $TLS_DISABLED: {get_param: tls_disabled}
+            $BAY_UUID: {get_param: bay_uuid}
+            $USER_TOKEN: {get_param: user_token}
+            $MAGNUM_URL: {get_param: magnum_url}
+            $NODE_FIXED_IP: { "Fn::Select": [ { get_param: kube_minion_index }, { get_param: kube_minion_ips} ] }
+
+  configure_flanneld:
+    type: OS::Heat::SoftwareConfig
+    properties:
+      group: ungrouped
+      config: {get_file: fragments/configure-flanneld-minion-opensuse.sh}
+
+  configure_docker:
+    type: OS::Heat::SoftwareConfig
+    properties:
+      group: ungrouped
+      config: {get_file: fragments/configure-docker-opensuse.sh}
+
+  create_kubernetes_user:
+    type: OS::Heat::SoftwareConfig
+    properties:
+      group: ungrouped
+      config: {get_file: fragments/create-kubernetes-user-opensuse.yaml}
+
+  configure_kubernetes:
+    type: OS::Heat::SoftwareConfig
+    properties:
+      group: ungrouped
+      config: {get_file: fragments/configure-kubernetes-minion-opensuse.sh}
+
+  minion_wc_notify:
+    type: OS::Heat::SoftwareConfig
+    properties:
+      group: ungrouped
+      config:
+        str_replace:
+          template: |
+            #!/bin/bash -v
+            wc_notify --data-binary '{"status": "SUCCESS"}'
+          params:
+            wc_notify: {get_attr: [minion_wait_handle, curl_cli]}
+
+  kube_minion_init:
+    type: OS::Heat::MultipartMime
+    properties:
+      parts:
+        - config: {get_resource: write_heat_params}
+        - config: {get_resource: configure_flanneld}
+        - config: {get_resource: configure_docker}
+        - config: {get_resource: create_kubernetes_user}
+        - config: {get_resource: configure_kubernetes}
+        - config: {get_resource: minion_wc_notify}
+
+  ######################################################################
+  #
+  # a single kubernetes minion.
+  # Important:  the name for the heat resource kube-minion below must
+  # not contain "_" (underscore) because it will be used in the
+  # hostname.  Because DNS domain name does not allow "_", the "_"
+  # will be converted to a "-" and this will make the hostname different
+  # from the Nova instance name.  This in turn will break the load
+  # balancer feature in Kubernetes.
+  #
+
+  kube-minion:
+    type: OS::Nova::Server
+    properties:
+      name: {get_param: kube_minion_id}
+      image: {get_param: server_image}
+      flavor: {get_param: minion_flavor}
+      key_name: {get_param: ssh_key_name}
+      user_data_format: RAW
+      user_data: {get_resource: kube_minion_init}
+      networks:
+        - port: { "Fn::Select": [ { get_param: kube_minion_index }, { get_param: kube_minion_ports} ] }
+
+  kube_minion_floating:
+    type: OS::Neutron::FloatingIP
+    properties:
+      floating_network: {get_param: external_network}
+      port_id: { "Fn::Select": [ { get_param: kube_minion_index }, { get_param: kube_minion_ports} ] }
+
+  ######################################################################
+  #
+  # docker storage.  This allocates a cinder volume and attaches it
+  # to the minion.
+  #
+
+  docker_volume:
+    type: OS::Cinder::Volume
+    properties:
+      size: {get_param: docker_volume_size}
+
+  docker_volume_attach:
+    type: OS::Cinder::VolumeAttachment
+    properties:
+      instance_uuid: {get_resource: kube-minion}
+      volume_id: {get_resource: docker_volume}
+      mountpoint: /dev/vdb
+
+outputs:
+
+  kube_minion_ip:
+    value: { "Fn::Select": [ { get_param: kube_minion_index }, { get_param: kube_minion_ips} ] }
+
+  kube_minion_external_ip:
+    value: {get_attr: [kube_minion_floating, floating_ip_address]}
+
+  OS::stack_id:
+    value: { "Fn::Select": [ { get_param: kube_minion_index }, { get_param: kube_minion_ips} ] }
Index: magnum-2.0.1.dev11/setup.cfg
===================================================================
--- magnum-2.0.1.dev11.orig/setup.cfg
+++ magnum-2.0.1.dev11/setup.cfg
@@ -55,6 +55,7 @@ oslo.config.opts.defaults =
 magnum.template_definitions = 
 	magnum_vm_atomic_k8s = magnum.conductor.template_definition:AtomicK8sTemplateDefinition
 	magnum_vm_coreos_k8s = magnum.conductor.template_definition:CoreOSK8sTemplateDefinition
+	magnum_vm_opensuse_k8s = magnum.conductor.template_definition:JeOSK8sTemplateDefinition
 	magnum_vm_atomic_swarm = magnum.conductor.template_definition:AtomicSwarmTemplateDefinition
 	magnum_vm_ubuntu_mesos = magnum.conductor.template_definition:UbuntuMesosTemplateDefinition
 magnum.database.migration_backend = 
Index: magnum-2.0.1.dev11/magnum/templates/kubernetes/fragments/write-params-minion-opensuse.yaml
===================================================================
--- /dev/null
+++ magnum-2.0.1.dev11/magnum/templates/kubernetes/fragments/write-params-minion-opensuse.yaml
@@ -0,0 +1,26 @@
+#cloud-config
+merge_how: dict(recurse_array)+list(append)
+write_files:
+  - path: /etc/sysconfig/heat-params
+    owner: "root:root"
+    permissions: "0644"
+    content: |
+      KUBE_ALLOW_PRIV="$KUBE_ALLOW_PRIV"
+      KUBE_MASTER_IP="$KUBE_MASTER_IP"
+      KUBE_API_PORT="$KUBE_API_PORT"
+      KUBE_NODE_IP="$KUBE_NODE_IP"
+      KUBE_MASTER_IPS="$KUBE_MASTER_IPS"
+      KUBE_MINION_IPS="$KUBE_MINION_IPS"
+      ETCD_SERVER_IP="$ETCD_SERVER_IP"
+      DOCKER_VOLUME="$DOCKER_VOLUME"
+      NETWORK_DRIVER="$NETWORK_DRIVER"
+      REGISTRY_ENABLED="$REGISTRY_ENABLED"
+      REGISTRY_URL="$REGISTRY_URL"
+      TLS_DISABLED="$TLS_DISABLED"
+      BAY_UUID="$BAY_UUID"
+      USER_TOKEN="$USER_TOKEN"
+      MAGNUM_URL="$MAGNUM_URL"
+      HTTP_PROXY="$HTTP_PROXY"
+      HTTPS_PROXY="$HTTPS_PROXY"
+      NO_PROXY="$NO_PROXY"
+      WAIT_CURL="$WAIT_CURL"
Index: magnum-2.0.1.dev11/magnum/templates/kubernetes/fragments/write-params-master-opensuse.yaml
===================================================================
--- /dev/null
+++ magnum-2.0.1.dev11/magnum/templates/kubernetes/fragments/write-params-master-opensuse.yaml
@@ -0,0 +1,38 @@
+#cloud-config
+merge_how: dict(recurse_array)+list(append)
+write_files:
+  - path: /etc/sysconfig/heat-params
+    owner: "root:root"
+    permissions: "0644"
+    content: |
+      KUBE_API_PUBLIC_ADDRESS="$KUBE_API_PUBLIC_ADDRESS"
+      KUBE_API_PRIVATE_ADDRESS="$KUBE_API_PRIVATE_ADDRESS"
+      KUBE_API_PORT="$KUBE_API_PORT"
+      KUBE_MASTER_IPS="$KUBE_MASTER_IPS"
+      KUBE_MINION_IPS="$KUBE_MINION_IPS"
+      KUBE_NODE_IP="$KUBE_NODE_IP"
+      KUBE_NODE_NAME="$KUBE_NODE_NAME"
+      KUBE_ALLOW_PRIV="$KUBE_ALLOW_PRIV"
+      DOCKER_VOLUME="$DOCKER_VOLUME"
+      NETWORK_DRIVER="$NETWORK_DRIVER"
+      FLANNEL_NETWORK_CIDR="$FLANNEL_NETWORK_CIDR"
+      FLANNEL_NETWORK_SUBNETLEN="$FLANNEL_NETWORK_SUBNETLEN"
+      FLANNEL_NETWORK_SUBNET_MIN="$FLANNEL_NETWORK_SUBNET_MIN"
+      FLANNEL_NETWORK_SUBNET_MAX="$FLANNEL_NETWORK_SUBNET_MAX"
+      FLANNEL_USE_VXLAN="$FLANNEL_USE_VXLAN"
+      PORTAL_NETWORK_CIDR="$PORTAL_NETWORK_CIDR"
+      ETCD_DISCOVERY="$ETCD_DISCOVERY"
+      ETCD_DISCOVERY_URL="$ETCD_DISCOVERY_URL"
+      AUTH_URL="$AUTH_URL"
+      USERNAME="$USERNAME"
+      PASSWORD="$PASSWORD"
+      TENANT_NAME="$TENANT_NAME"
+      CLUSTER_SUBNET="$CLUSTER_SUBNET"
+      TLS_DISABLED="$TLS_DISABLED"
+      BAY_UUID="$BAY_UUID"
+      USER_TOKEN="$USER_TOKEN"
+      MAGNUM_URL="$MAGNUM_URL"
+      HTTP_PROXY="$HTTP_PROXY"
+      HTTPS_PROXY="$HTTPS_PROXY"
+      NO_PROXY="$NO_PROXY"
+      WAIT_CURL="$WAIT_CURL"
Index: magnum-2.0.1.dev11/magnum/templates/kubernetes/kubenetwork-opensuse.yaml
===================================================================
--- /dev/null
+++ magnum-2.0.1.dev11/magnum/templates/kubernetes/kubenetwork-opensuse.yaml
@@ -0,0 +1,39 @@
+heat_template_version: 2013-05-23
+
+description: >
+  This is a nested stack that defines a single Neutron port for kubernetes nodes.
+  This stack is included by an AutoScalingGroup resource in the parent template
+  (kubecluster-opensuse.yaml).
+
+parameters:
+  security_groups:
+    type: comma_delimited_list
+    default: []
+    description: List of the IDs security groups for kubernetes master.
+
+  fixed_network:
+    type: string
+    description: Network from which to allocate fixed addresses.
+
+  fixed_subnet:
+    type: string
+    description: Subnet from which to allocate fixed addresses.
+
+resources:
+
+  port:
+    type: OS::Neutron::Port
+    properties:
+      network: { get_param: fixed_network }
+      security_groups: { get_param: security_groups }
+      fixed_ips:
+        - subnet: { get_param: fixed_subnet }
+      replacement_policy: AUTO
+
+outputs:
+
+  OS::stack_id:
+    value: { get_resource: port }
+
+  fixed_ip:
+    value: { get_attr: [ port, fixed_ips, 0, ip_address ] }
Index: magnum-2.0.1.dev11/magnum/templates/kubernetes/fragments/write-heat-params.yaml
===================================================================
--- magnum-2.0.1.dev11.orig/magnum/templates/kubernetes/fragments/write-heat-params.yaml
+++ magnum-2.0.1.dev11/magnum/templates/kubernetes/fragments/write-heat-params.yaml
@@ -13,16 +13,7 @@ write_files:
       DOCKER_VOLUME="$DOCKER_VOLUME"
       NETWORK_DRIVER="$NETWORK_DRIVER"
       REGISTRY_ENABLED="$REGISTRY_ENABLED"
-      REGISTRY_PORT="$REGISTRY_PORT"
-      REGISTRY_AUTH_URL="$REGISTRY_AUTH_URL"
-      REGISTRY_REGION="$REGISTRY_REGION"
-      REGISTRY_USERNAME="$REGISTRY_USERNAME"
-      REGISTRY_PASSWORD="$REGISTRY_PASSWORD"
-      REGISTRY_DOMAIN="$REGISTRY_DOMAIN"
-      REGISTRY_TRUST_ID="$REGISTRY_TRUST_ID"
-      REGISTRY_CONTAINER="$REGISTRY_CONTAINER"
-      REGISTRY_INSECURE="$REGISTRY_INSECURE"
-      REGISTRY_CHUNKSIZE="$REGISTRY_CHUNKSIZE"
+      REGISTRY_URL="$REGISTRY_URL"
       TLS_DISABLED="$TLS_DISABLED"
       BAY_UUID="$BAY_UUID"
       USER_TOKEN="$USER_TOKEN"
openSUSE Build Service is sponsored by