Merge "Add state for kubernetes federation"
diff --git a/README.rst b/README.rst
index 2fdaf2a..4d375e8 100644
--- a/README.rst
+++ b/README.rst
@@ -91,6 +91,25 @@
             netchecker:
               enabled: true
 
+Enable Kubenetes Federation control plane
+
+.. code-block:: yaml
+
+    parameters:
+      kubernetes:
+        master:
+          federation:
+            enabled: True
+            name: federation
+            namespace: federation-system
+            source: https://dl.k8s.io/v1.6.6/kubernetes-client-linux-amd64.tar.gz
+            hash: 94b2c9cd29981a8e150c187193bab0d8c0b6e906260f837367feff99860a6376
+            service_type: NodePort
+            dns_provider: coredns
+            childclusters:
+              - secondcluster.mydomain
+              - thirdcluster.mydomain
+
 Configure service verbosity
 
 .. code-block:: yaml
@@ -102,7 +121,7 @@
         pool:
           verbosity: 2
 
-Set cluster domain
+Set cluster name and domain
 
 .. code-block:: yaml
 
@@ -110,6 +129,7 @@
       kubernetes:
         common:
           kubernetes_cluster_domain: mycluster.domain
+          cluster_name : mycluster
 
 Enable autoscaler for dns addon. Poll period can be skipped.
 
@@ -182,6 +202,7 @@
 
     kubernetes:
         common:
+          cluster_name: cluster
           addons:
             dns:
               domain: cluster.local
diff --git a/kubernetes/files/federation/coredns.conf b/kubernetes/files/federation/coredns.conf
new file mode 100644
index 0000000..1999965
--- /dev/null
+++ b/kubernetes/files/federation/coredns.conf
@@ -0,0 +1,6 @@
+{%- from "kubernetes/map.jinja" import master with context %}
+{%- from "kubernetes/map.jinja" import common with context %}
+[Global]
+etcd-endpoints = http://coredns-etcd.{{ common.addons.coredns.namespace }}:2379
+zones = {{ master.federation.name }}
+
diff --git a/kubernetes/files/kube-addons/coredns/coredns-cm.yml b/kubernetes/files/kube-addons/coredns/coredns-cm.yml
new file mode 100644
index 0000000..43d9ad4
--- /dev/null
+++ b/kubernetes/files/kube-addons/coredns/coredns-cm.yml
@@ -0,0 +1,23 @@
+{%- from "kubernetes/map.jinja" import common with context %}
+{%- from "kubernetes/map.jinja" import master with context %}
+---
+apiVersion: v1
+kind: ConfigMap
+metadata:
+  name: coredns
+  namespace: {{ common.addons.coredns.namespace }}
+  addonmanager.kubernetes.io/mode: Reconcile
+data:
+  Corefile: |
+    .:53 {
+        etcd {{ master.federation.name }} {
+          stubzones
+          path /skydns
+          endpoint http://coredns-etcd:2379
+        }
+        errors
+        log stdout
+        health
+        proxy . /etc/resolv.conf
+        cache 30
+    }
diff --git a/kubernetes/files/kube-addons/coredns/coredns-deploy.yml b/kubernetes/files/kube-addons/coredns/coredns-deploy.yml
new file mode 100644
index 0000000..f225af5
--- /dev/null
+++ b/kubernetes/files/kube-addons/coredns/coredns-deploy.yml
@@ -0,0 +1,60 @@
+{%- from "kubernetes/map.jinja" import common with context %}
+---
+apiVersion: extensions/v1beta1
+kind: Deployment
+metadata:
+  name: coredns
+  namespace: {{ common.addons.coredns.namespace }}
+  labels:
+    k8s-app: coredns
+    kubernetes.io/cluster-service: "true"
+    kubernetes.io/name: "CoreDNS"
+    addonmanager.kubernetes.io/mode: Reconcile
+spec:
+  replicas: 1
+  selector:
+    matchLabels:
+      k8s-app: coredns
+  template:
+    metadata:
+      labels:
+        k8s-app: coredns
+      annotations:
+        scheduler.alpha.kubernetes.io/critical-pod: ''
+        scheduler.alpha.kubernetes.io/tolerations: '[{"key":"CriticalAddonsOnly", "operator":"Exists"}]'
+    spec:
+      tolerations:
+        - key: node-role.kubernetes.io/master
+          effect: NoSchedule
+      containers:
+      - name: coredns
+        image: {{ common.addons.coredns.image }}
+        imagePullPolicy: Always
+        args: [ "-conf", "/etc/coredns/Corefile" ]
+        volumeMounts:
+        - name: config-volume
+          mountPath: /etc/coredns
+        ports:
+        - containerPort: 53
+          name: dns
+          protocol: UDP
+        - containerPort: 53
+          name: dns-tcp
+          protocol: TCP
+        livenessProbe:
+          httpGet:
+            path: /health
+            port: 8080
+            scheme: HTTP
+          initialDelaySeconds: 60
+          timeoutSeconds: 5
+          successThreshold: 1
+          failureThreshold: 5
+      dnsPolicy: ClusterFirst
+      volumes:
+        - name: config-volume
+          configMap:
+            name: coredns
+            items:
+            - key: Corefile
+              path: Corefile
diff --git a/kubernetes/files/kube-addons/coredns/coredns-svc.yml b/kubernetes/files/kube-addons/coredns/coredns-svc.yml
new file mode 100644
index 0000000..be49e94
--- /dev/null
+++ b/kubernetes/files/kube-addons/coredns/coredns-svc.yml
@@ -0,0 +1,22 @@
+{%- from "kubernetes/map.jinja" import common with context %}
+---
+apiVersion: v1
+kind: Service
+metadata:
+  name: coredns
+  namespace: {{ common.addons.coredns.namespace }}
+  labels:
+    k8s-app: coredns
+    kubernetes.io/cluster-service: "true"
+    kubernetes.io/name: "coredns"
+    addonmanager.kubernetes.io/mode: Reconcile
+spec:
+  selector:
+    k8s-app: coredns
+  ports:
+  - name: dns
+    port: 53
+    protocol: UDP
+  - name: dns-tcp
+    port: 53
+    protocol: TCP
diff --git a/kubernetes/files/kube-addons/coredns/etcd-deploy.yml b/kubernetes/files/kube-addons/coredns/etcd-deploy.yml
new file mode 100644
index 0000000..937ae69
--- /dev/null
+++ b/kubernetes/files/kube-addons/coredns/etcd-deploy.yml
@@ -0,0 +1,48 @@
+{%- from "kubernetes/map.jinja" import common with context %}
+---
+apiVersion: extensions/v1beta1
+kind: Deployment
+metadata:
+  namespace: {{ common.addons.coredns.namespace }}
+  labels:
+    app: coredns-etcd
+    addonmanager.kubernetes.io/mode: Reconcile
+  name: coredns-etcd
+spec:
+  strategy:
+    type: Recreate
+  replicas: 1
+  selector:
+    matchLabels:
+      name: coredns-etcd
+  template:
+    metadata:
+      labels:
+        name: coredns-etcd
+    spec:
+      tolerations:
+        - key: node-role.kubernetes.io/master
+          effect: NoSchedule
+      containers:
+      - command:
+        - /usr/local/bin/etcd
+        - --name
+        - coredns-etcd
+        - --listen-peer-urls
+        - http://0.0.0.0:2380
+        - --listen-client-urls
+        - http://0.0.0.0:2379
+        - --advertise-client-urls
+        - http://coredns-etcd:2379
+        - --initial-cluster-state
+        - new
+        image: {{ common.addons.coredns.etcd_image }}
+        name: coredns-etcd
+        ports:
+        - containerPort: 2379
+          name: client
+          protocol: TCP
+        - containerPort: 2380
+          name: server
+          protocol: TCP
+      restartPolicy: Always
diff --git a/kubernetes/files/kube-addons/coredns/etcd-svc.yml b/kubernetes/files/kube-addons/coredns/etcd-svc.yml
new file mode 100644
index 0000000..4272275
--- /dev/null
+++ b/kubernetes/files/kube-addons/coredns/etcd-svc.yml
@@ -0,0 +1,24 @@
+{%- from "kubernetes/map.jinja" import common with context %}
+---
+apiVersion: v1
+kind: Service
+metadata:
+  name: coredns-etcd
+  namespace: {{ common.addons.coredns.namespace }}
+  labels:
+    k8s-app: coredns-etcd
+    kubernetes.io/cluster-service: "true"
+    kubernetes.io/name: "coredns-etcd"
+    addonmanager.kubernetes.io/mode: Reconcile
+spec:
+  selector:
+    k8s-app: coredns-etcd
+  ports:
+  - name: client
+    port: 2379
+    protocol: TCP
+    targetPort: 2379
+  - name: server
+    port: 2380
+    protocol: TCP
+    targetPort: 2380
diff --git a/kubernetes/files/kube-controller-manager/controller-manager.kubeconfig b/kubernetes/files/kube-controller-manager/controller-manager.kubeconfig
index 7505864..d65c770 100644
--- a/kubernetes/files/kube-controller-manager/controller-manager.kubeconfig
+++ b/kubernetes/files/kube-controller-manager/controller-manager.kubeconfig
@@ -1,21 +1,22 @@
 {%- from "kubernetes/map.jinja" import pool with context %}
+{%- from "kubernetes/map.jinja" import common with context %}
 
 apiVersion: v1
 kind: Config
-current-context: {{ pool.cluster_domain }}
+current-context: {{ common.cluster_name }}
 preferences: {}
 clusters:
 - cluster:
     certificate-authority: /etc/kubernetes/ssl/ca-kubernetes.crt
     server: https://{{ pool.apiserver.host }}:{{ pool.apiserver.get('port', '443') }}
-  name: {{ pool.cluster_domain }}
+  name: {{ common.cluster_name }}
 contexts:
 - context:
-    cluster: {{ pool.cluster_domain }}
-    user: controller_manager-{{ pool.cluster_domain }}
-  name: {{ pool.cluster_domain }}
+    cluster: {{ common.cluster_name }}
+    user: controller_manager-{{ common.cluster_name }}
+  name: {{ common.cluster_name }}
 users:
-- name: controller_manager-{{ pool.cluster_domain }}
+- name: controller_manager-{{ common.cluster_name }}
   user:
     client-certificate: /etc/kubernetes/ssl/kubelet-client.crt
     client-key: /etc/kubernetes/ssl/kubelet-client.key
diff --git a/kubernetes/files/kube-proxy/proxy.kubeconfig b/kubernetes/files/kube-proxy/proxy.kubeconfig
index a089f0b..773c177 100644
--- a/kubernetes/files/kube-proxy/proxy.kubeconfig
+++ b/kubernetes/files/kube-proxy/proxy.kubeconfig
@@ -1,21 +1,22 @@
 {%- from "kubernetes/map.jinja" import pool with context %}
+{%- from "kubernetes/map.jinja" import common with context %}
 
 apiVersion: v1
 kind: Config
-current-context: {{ pool.cluster_domain }}
+current-context: {{ common.cluster_name }}
 preferences: {}
 clusters:
 - cluster:
     certificate-authority: /etc/kubernetes/ssl/ca-kubernetes.crt
     server: https://{{ pool.apiserver.host }}:{{ pool.apiserver.get('port', '443') }}
-  name: {{ pool.cluster_domain }}
+  name: {{ common.cluster_name }}
 contexts:
 - context:
-    cluster: {{ pool.cluster_domain }}
-    user: kube_proxy-{{ pool.cluster_domain }}
-  name: {{ pool.cluster_domain }}
+    cluster: {{ common.cluster_name }}
+    user: kube_proxy-{{ common.cluster_name }}
+  name: {{ common.cluster_name }}
 users:
-- name: kube_proxy-{{ pool.cluster_domain }}
+- name: kube_proxy-{{ common.cluster_name }}
   user:
     client-certificate: /etc/kubernetes/ssl/kubelet-client.crt
     client-key: /etc/kubernetes/ssl/kubelet-client.key
diff --git a/kubernetes/files/kube-scheduler/scheduler.kubeconfig b/kubernetes/files/kube-scheduler/scheduler.kubeconfig
index cb09b95..26ba1de 100644
--- a/kubernetes/files/kube-scheduler/scheduler.kubeconfig
+++ b/kubernetes/files/kube-scheduler/scheduler.kubeconfig
@@ -1,20 +1,21 @@
 {%- from "kubernetes/map.jinja" import pool with context %}
+{%- from "kubernetes/map.jinja" import common with context %}
 apiVersion: v1
 kind: Config
-current-context: {{ pool.cluster_domain }}
+current-context: {{ common.cluster_name }}
 preferences: {}
 clusters:
 - cluster:
     certificate-authority: /etc/kubernetes/ssl/ca-kubernetes.crt
     server: https://{{ pool.apiserver.host }}:{{ pool.apiserver.port|default('443') }}
-  name: {{ pool.cluster_domain }}
+  name: {{ common.cluster_name }}
 contexts:
 - context:
-    cluster: {{ pool.cluster_domain }}
-    user: scheduler-{{ pool.cluster_domain }}
-  name: {{ pool.cluster_domain }}
+    cluster: {{ common.cluster_name }}
+    user: scheduler-{{ common.cluster_name }}
+  name: {{ common.cluster_name }}
 users:
-- name: scheduler-{{ pool.cluster_domain }}
+- name: scheduler-{{ common.cluster_name }}
   user:
     client-certificate: /etc/kubernetes/ssl/kubelet-client.crt
     client-key: /etc/kubernetes/ssl/kubelet-client.key
diff --git a/kubernetes/files/kubeconfig.sh b/kubernetes/files/kubeconfig.sh
index 74ab159..b05e907 100644
--- a/kubernetes/files/kubeconfig.sh
+++ b/kubernetes/files/kubeconfig.sh
@@ -8,7 +8,7 @@
 cert="$(base64 /etc/kubernetes/ssl/kubelet-client.crt | sed 's/^/      /g')"
 key="$(base64 /etc/kubernetes/ssl/kubelet-client.key | sed 's/^/      /g')"
 ca="$(base64 /etc/kubernetes/ssl/ca-kubernetes.crt | sed 's/^/      /g')"
-cluster="{{ common.addons.dns.domain }}"
+cluster="{{ common.cluster_name }}"
 
 echo "apiVersion: v1
 clusters:
diff --git a/kubernetes/files/kubelet/kubelet.kubeconfig.master b/kubernetes/files/kubelet/kubelet.kubeconfig.master
index 178270b..7cd76dc 100644
--- a/kubernetes/files/kubelet/kubelet.kubeconfig.master
+++ b/kubernetes/files/kubelet/kubelet.kubeconfig.master
@@ -2,20 +2,20 @@
 {%- from "kubernetes/map.jinja" import master with context -%}
 apiVersion: v1
 kind: Config
-current-context: {{ common.addons.dns.domain }}
+current-context: {{ common.cluster_name }}
 preferences: {}
 clusters:
 - cluster:
     certificate-authority: /etc/kubernetes/ssl/ca-kubernetes.crt
     server: https://{{ master.apiserver.address }}:{{ master.apiserver.get('secure_port', '443') }}
-  name: {{ common.addons.dns.domain }}
+  name: {{ common.cluster_name }}
 contexts:
 - context:
-    cluster: {{ common.addons.dns.domain }}
-    user: kubelet-{{ common.addons.dns.domain }}
-  name: {{ common.addons.dns.domain }}
+    cluster: {{ common.cluster_name }}
+    user: kubelet-{{ common.cluster_name }}
+  name: {{ common.cluster_name }}
 users:
-- name: kubelet-{{ common.addons.dns.domain }}
+- name: kubelet-{{ common.cluster_name }}
   user:
     client-certificate: /etc/kubernetes/ssl/kubelet-client.crt
     client-key: /etc/kubernetes/ssl/kubelet-client.key
diff --git a/kubernetes/files/kubelet/kubelet.kubeconfig.pool b/kubernetes/files/kubelet/kubelet.kubeconfig.pool
index eabe033..37ce67e 100644
--- a/kubernetes/files/kubelet/kubelet.kubeconfig.pool
+++ b/kubernetes/files/kubelet/kubelet.kubeconfig.pool
@@ -2,20 +2,20 @@
 {%- from "kubernetes/map.jinja" import common with context -%}
 apiVersion: v1
 kind: Config
-current-context: {{ common.cluster_domain }}
+current-context: {{ common.cluster_name }}
 preferences: {}
 clusters:
 - cluster:
     certificate-authority: /etc/kubernetes/ssl/ca-kubernetes.crt
     server: https://{{ pool.apiserver.host }}:{{ pool.apiserver.get('port', '443') }}
-  name: {{ common.cluster_domain }}
+  name: {{ common.cluster_name }}
 contexts:
 - context:
-    cluster: {{ common.cluster_domain }}
-    user: kubelet-{{ common.cluster_domain }}
-  name: {{ common.cluster_domain }}
+    cluster: {{ common.cluster_name }}
+    user: kubelet-{{ common.cluster_name }}
+  name: {{ common.cluster_name }}
 users:
-- name: kubelet-{{ common.cluster_domain }}
+- name: kubelet-{{ common.cluster_name }}
   user:
     client-certificate: /etc/kubernetes/ssl/kubelet-client.crt
     client-key: /etc/kubernetes/ssl/kubelet-client.key
diff --git a/kubernetes/master/federation.sls b/kubernetes/master/federation.sls
new file mode 100644
index 0000000..2becd61
--- /dev/null
+++ b/kubernetes/master/federation.sls
@@ -0,0 +1,122 @@
+{%- from "kubernetes/map.jinja" import master with context %}
+{%- from "kubernetes/map.jinja" import common with context %}
+{%- if master.enabled %}
+
+extract_kubernetes_client:
+  archive.extracted:
+    - name: /tmp/kubernetes-client
+    - source: {{ master.federation.source }}
+    {%- if {{ master.federation.get('hash') }} %}
+    - source_hash: sha256={{ master.federation.hash }}
+    {%- endif %}
+    - tar_options: xzf
+    - archive_format: tar
+    - keep: true
+    {%- if grains.get('noservices') %}
+    - onlyif: /bin/false
+    {%- endif %}
+
+/usr/bin/kubefed:
+  file.managed:
+  - source: /tmp/kubernetes-client/kubernetes/client/bin/kubefed
+  - mode: 755
+  - owner: root
+  - group: root
+  - require:
+    - archive: extract_kubernetes_client
+
+/etc/kubernetes/federation/federation.kubeconfig:
+  file.copy:
+  - source: /etc/kubernetes/admin-kube-config
+  - force: false
+  - mode: 0700
+  - owner: root
+  - group: root
+  - dir_mode: 755
+  - makedirs: True
+
+#Set server to apiserver VIP instead of localhost to be reached from pod net
+federation_kubeconfig_replace_server:
+  file.replace:
+  - name: /etc/kubernetes/federation/federation.kubeconfig
+  - repl: "server: https://{{ master.apiserver.vip_address }}:{{ master.apiserver.secure_port }}"
+  - pattern: "server: http://127.0.0.1:{{ master.apiserver.insecure_port }}"
+  - count: 1
+  - show_changes: True
+
+/etc/kubernetes/federation/dns.conf:
+  file.managed:
+  - source: salt://kubernetes/files/federation/{{ master.federation.dns_provider }}.conf
+  - template: jinja
+  - user: root
+  - group: root
+  - mode: 644
+  - makedirs: true
+  - dir_mode: 755
+
+kubefed_init:
+  cmd.run:
+  - name: kubefed init {{ master.federation.name }} --host-cluster-context=local --kubeconfig=/etc/kubernetes/federation/federation.kubeconfig --federation-system-namespace={{ master.federation.namespace }} --api-server-service-type={{ master.federation.service_type }} --etcd-persistent-storage=false  --dns-provider={{ master.federation.dns_provider }} --dns-provider-config=/etc/kubernetes/federation/dns.conf --dns-zone-name={{ master.federation.name }} --image={{ common.hyperkube.image }}
+  - require:
+    - file: /usr/bin/kubefed
+    - file: /etc/kubernetes/federation/federation.kubeconfig
+  - unless: kubectl get namespace {{ master.federation.namespace }}
+  {%- if grains.get('noservices') %}
+  - onlyif: /bin/false
+  {%- endif %}
+
+federation_kubeconfig_set_context:
+  cmd.run:
+  - name: kubectl config use-context {{ master.federation.name }}
+  - env:
+    - KUBECONFIG: /etc/kubernetes/federation/federation.kubeconfig
+  - require:
+    - cmd: kubefed_init
+  - unless: kubectl config current-context | grep {{ master.federation.name }}
+  {%- if grains.get('noservices') %}
+  - onlyif: /bin/false
+  {%- endif %}
+
+kubefed_join_host_cluster:
+  cmd.run:
+  - name: kubefed join {{ common.cluster_name }} --host-cluster-context=local --context={{ master.federation.name }}
+  - env:
+    - KUBECONFIG: /etc/kubernetes/federation/federation.kubeconfig
+  - require:
+    - cmd: kubefed_init
+  - unless: kubectl --context={{ master.federation.name }} get clusters | grep {{ common.cluster_name }}
+  {%- if grains.get('noservices') %}
+  - onlyif: /bin/false
+  {%- endif %}
+
+# Assumes the following:
+# * Pillar data master.federation.childclusters is populated
+# * kubeconfig data for each cluster exists in /etc/kubernetes/federation/federation.kubeconfig
+{%- if master.federation.get('childclusters') }
+{%- for childcluster in master.federation.childclusters %}
+
+federation_verify_kubeconfig_{{ childcluster }}:
+  cmd.run:
+  - name: kubectl config get-contexts -o name | grep {{ childcluster }}
+  - env:
+    - KUBECONFIG: /etc/kubernetes/federation/childclusters.kubeconfig
+  - require:
+    - cmd: kubefed_init
+  {%- if grains.get('noservices') %}
+  - onlyif: /bin/false
+  {%- endif %}
+
+federation_join_cluster_{{ childcluster }}:
+  cmd.run:
+  - name: kubefed join {{ childcluster }} --host-cluster-context=local --context={{ master.federation.name }}
+  - env:
+    - KUBECONFIG: /etc/kubernetes/federation.kubeconfig
+  - require:
+    - cmd: verify_kubeconfig_{{ childcluster }}
+  - unless: kubectl get clusters | grep {{ childcluster }}
+
+{%- endfor %}
+{%- endif %}
+
+{%- endif %}
+
diff --git a/kubernetes/master/kube-addons.sls b/kubernetes/master/kube-addons.sls
index 80dd2ff..75f7c26 100644
--- a/kubernetes/master/kube-addons.sls
+++ b/kubernetes/master/kube-addons.sls
@@ -108,6 +108,49 @@
 
 {% endif %}
 
+{%- if common.addons.coredns.enabled or master.federation.enabled %}
+
+/etc/kubernetes/addons/coredns/coredns-cm.yml:
+  file.managed:
+    - source: salt://kubernetes/files/kube-addons/coredns/coredns-cm.yml
+    - template: jinja
+    - group: root
+    - dir_mode: 755
+    - makedirs: True
+
+/etc/kubernetes/addons/coredns/coredns-deploy.yml:
+  file.managed:
+    - source: salt://kubernetes/files/kube-addons/coredns/coredns-deploy.yml
+    - template: jinja
+    - group: root
+    - dir_mode: 755
+    - makedirs: True
+
+/etc/kubernetes/addons/coredns/coredns-svc.yml:
+  file.managed:
+    - source: salt://kubernetes/files/kube-addons/coredns/coredns-svc.yml
+    - template: jinja
+    - group: root
+    - dir_mode: 755
+    - makedirs: True
+
+/etc/kubernetes/addons/coredns/etcd-svc.yml:
+  file.managed:
+    - source: salt://kubernetes/files/kube-addons/coredns/etcd-svc.yml
+    - template: jinja
+    - group: root
+    - dir_mode: 755
+    - makedirs: True
+
+/etc/kubernetes/addons/coredns/etcd-deploy.yml:
+  file.managed:
+    - source: salt://kubernetes/files/kube-addons/coredns/etcd-deploy.yml
+    - template: jinja
+    - group: root
+    - dir_mode: 755
+    - makedirs: True
+{% endif %}
+
 {% endif %}
 
 {%- if common.addons.dashboard.enabled %}
diff --git a/metadata/service/common.yml b/metadata/service/common.yml
index a62fb9f..02c41fe 100644
--- a/metadata/service/common.yml
+++ b/metadata/service/common.yml
@@ -41,11 +41,17 @@
           enabled: False
           namespace: kube-system
           image: yashulyak/contrail-controller:latest
+        coredns:
+          enabled: False
+          namespace: kube-system
+          image: coredns/coredns:latest
+          etcd_image: quay.io/coreos/etcd:v3.1.0
         virtlet:
           enabled: False
           namespace: kube-system
           image: mirantis/virtlet:v0.7.0
       cluster_domain: ${_param:kubernetes_cluster_domain}
+      cluster_name: ${_param:cluster_name}
       network:
         engine: none
         mtu: 1500
diff --git a/metadata/service/master/cluster.yml b/metadata/service/master/cluster.yml
index 7262174..f267e5e 100644
--- a/metadata/service/master/cluster.yml
+++ b/metadata/service/master/cluster.yml
@@ -20,6 +20,7 @@
         allow_privileged: True
       apiserver:
         address: ${_param:cluster_local_address}
+        vip_address: ${_param:cluster_vip_address}
         secure_port: 6443
         internal_address: ${_param:kubernetes_internal_api_address}
         insecure_address: 127.0.0.1
@@ -57,3 +58,11 @@
             port: 4001
           - host: ${_param:cluster_node03_address}
             port: 4001
+      federation:
+        enabled: False
+        name: federation
+        namespace: federation-system
+        source: https://dl.k8s.io/v1.6.6/kubernetes-client-linux-amd64.tar.gz
+        hash: 94b2c9cd29981a8e150c187193bab0d8c0b6e906260f837367feff99860a6376
+        service_type: NodePort
+        dns_provider: coredns
diff --git a/metadata/service/master/single.yml b/metadata/service/master/single.yml
index ac9e2aa..5133b5d 100644
--- a/metadata/service/master/single.yml
+++ b/metadata/service/master/single.yml
@@ -80,3 +80,11 @@
           members:
             - host: ${_param:single_address}
               port: 4001
+      federation:
+        enabled: False
+        name: federation
+        namespace: federation-system
+        source: https://dl.k8s.io/v1.6.6/kubernetes-client-linux-amd64.tar.gz
+        hash: 94b2c9cd29981a8e150c187193bab0d8c0b6e906260f837367feff99860a6376
+        service_type: NodePort
+        dns_provider: coredns
diff --git a/tests/pillar/master_cluster.sls b/tests/pillar/master_cluster.sls
index af99ceb..513d6b1 100644
--- a/tests/pillar/master_cluster.sls
+++ b/tests/pillar/master_cluster.sls
@@ -1,6 +1,7 @@
 kubernetes:
   common:
     cluster_domain: cluster.local
+    cluster_name: cluster
     network:
       engine: none
     hyperkube:
diff --git a/tests/pillar/master_contrail.sls b/tests/pillar/master_contrail.sls
index ff03327..862bb9a 100644
--- a/tests/pillar/master_contrail.sls
+++ b/tests/pillar/master_contrail.sls
@@ -1,6 +1,7 @@
 kubernetes:
   common:
     cluster_domain: cluster.local
+    cluster_name: cluster
     network:
       engine: opencontrail
     hyperkube:
diff --git a/tests/pillar/master_contrail4_0.sls b/tests/pillar/master_contrail4_0.sls
index 202b25d..d948e7c 100644
--- a/tests/pillar/master_contrail4_0.sls
+++ b/tests/pillar/master_contrail4_0.sls
@@ -1,6 +1,7 @@
 kubernetes:
   common:
     cluster_domain: cluster.local
+    cluster_name: cluster
     network:
       engine: opencontrail
     hyperkube:
diff --git a/tests/pillar/pool_cluster.sls b/tests/pillar/pool_cluster.sls
index ce9769c..34e62d5 100644
--- a/tests/pillar/pool_cluster.sls
+++ b/tests/pillar/pool_cluster.sls
@@ -1,6 +1,7 @@
 kubernetes:
   common:
     cluster_domain: cluster.local
+    cluster_name: cluster
     network:
       engine: none
     hyperkube:
diff --git a/tests/pillar/pool_contrail4_0.sls b/tests/pillar/pool_contrail4_0.sls
index a4680fc..0426faf 100644
--- a/tests/pillar/pool_contrail4_0.sls
+++ b/tests/pillar/pool_contrail4_0.sls
@@ -1,6 +1,7 @@
 kubernetes:
   common:
     cluster_domain: cluster.local
+    cluster_name: cluster
     network:
       engine: none
     hyperkube: