From 468bf1da756894ba10648c0a6bbe796a5f5d92de Mon Sep 17 00:00:00 2001 From: derekwaynecarr Date: Fri, 6 Mar 2015 15:41:13 -0500 Subject: [PATCH 1/4] Enable common set of admission controllers across salt providers --- .../templates/create-dynamic-salt-files.sh | 1 + cluster/gce/config-default.sh | 3 + cluster/gce/configure-vm.sh | 1 + cluster/gce/util.sh | 1 + cluster/saltbase/salt/kube-apiserver/default | 4 +- cluster/vagrant/config-default.sh | 2 +- cluster/vagrant/provision-master.sh | 2 +- .../namespace/autoprovision/admission.go | 4 + .../namespace/autoprovision/admission_test.go | 88 +++++++++++++++++++ 9 files changed, 102 insertions(+), 4 deletions(-) diff --git a/cluster/aws/templates/create-dynamic-salt-files.sh b/cluster/aws/templates/create-dynamic-salt-files.sh index 85c3153968a..682d9fbbc3b 100644 --- a/cluster/aws/templates/create-dynamic-salt-files.sh +++ b/cluster/aws/templates/create-dynamic-salt-files.sh @@ -33,6 +33,7 @@ enable_cluster_dns: '$(echo "$ENABLE_CLUSTER_DNS" | sed -e "s/'/''/g")' dns_replicas: '$(echo "$DNS_REPLICAS" | sed -e "s/'/''/g")' dns_server: '$(echo "$DNS_SERVER_IP" | sed -e "s/'/''/g")' dns_domain: '$(echo "$DNS_DOMAIN" | sed -e "s/'/''/g")' +admission_control: '$(echo "$ADMISSION_CONTROL" | sed -e "s/'/''/g")' EOF mkdir -p /srv/salt-overlay/salt/nginx diff --git a/cluster/gce/config-default.sh b/cluster/gce/config-default.sh index 11c08bf50a4..326e53508ef 100755 --- a/cluster/gce/config-default.sh +++ b/cluster/gce/config-default.sh @@ -105,3 +105,6 @@ ENABLE_CLUSTER_DNS=true DNS_SERVER_IP="10.0.0.10" DNS_DOMAIN="kubernetes.local" DNS_REPLICAS=1 + +# Admission Controllers to invoke prior to persisting objects in cluster +ADMISSION_CONTROL=NamespaceAutoProvision,LimitRanger,ResourceQuota diff --git a/cluster/gce/configure-vm.sh b/cluster/gce/configure-vm.sh index 18e51c53ed2..1929a5ba762 100644 --- a/cluster/gce/configure-vm.sh +++ b/cluster/gce/configure-vm.sh @@ -200,6 +200,7 @@ enable_cluster_dns: '$(echo "$ENABLE_CLUSTER_DNS" | sed -e "s/'/''/g")' dns_replicas: '$(echo "$DNS_REPLICAS" | sed -e "s/'/''/g")' dns_server: '$(echo "$DNS_SERVER_IP" | sed -e "s/'/''/g")' dns_domain: '$(echo "$DNS_DOMAIN" | sed -e "s/'/''/g")' +admission_control: '$(echo "$ADMISSION_CONTROL" | sed -e "s/'/''/g")' EOF if [[ "${KUBERNETES_MASTER}" == "true" ]]; then diff --git a/cluster/gce/util.sh b/cluster/gce/util.sh index 706aca6f87f..2525cb3058e 100755 --- a/cluster/gce/util.sh +++ b/cluster/gce/util.sh @@ -452,6 +452,7 @@ DNS_REPLICAS: $(yaml-quote ${DNS_REPLICAS:-}) DNS_SERVER_IP: $(yaml-quote ${DNS_SERVER_IP:-}) DNS_DOMAIN: $(yaml-quote ${DNS_DOMAIN:-}) MASTER_HTPASSWD: $(yaml-quote ${MASTER_HTPASSWD}) +ADMISSION_CONTROL: $(yaml-quota ${ADMISSION_CONTROL:-}) EOF if [[ "${master}" != "true" ]]; then diff --git a/cluster/saltbase/salt/kube-apiserver/default b/cluster/saltbase/salt/kube-apiserver/default index bedbb68c42d..64dbb9018fc 100644 --- a/cluster/saltbase/salt/kube-apiserver/default +++ b/cluster/saltbase/salt/kube-apiserver/default @@ -59,8 +59,8 @@ {% endif -%} {% set admission_control = "" -%} -{% if grains.admission_control is defined -%} - {% set admission_control = "--admission_control=" + grains.admission_control -%} +{% if pillar['admission_control'] is defined -%} + {% set admission_control = "--admission_control=" + pillar['admission_control'] -%} {% endif -%} {% set runtime_config = "" -%} diff --git a/cluster/vagrant/config-default.sh b/cluster/vagrant/config-default.sh index f6e91ca1ddf..cf2c5f84a3b 100755 --- a/cluster/vagrant/config-default.sh +++ b/cluster/vagrant/config-default.sh @@ -49,7 +49,7 @@ MASTER_USER=vagrant MASTER_PASSWD=vagrant # Admission Controllers to invoke prior to persisting objects in cluster -ADMISSION_CONTROL=NamespaceExists,LimitRanger,ResourceQuota,AlwaysAdmit +ADMISSION_CONTROL=NamespaceAutoProvision,LimitRanger,ResourceQuota # Optional: Install node monitoring. ENABLE_NODE_MONITORING=true diff --git a/cluster/vagrant/provision-master.sh b/cluster/vagrant/provision-master.sh index 01987e3856b..e938927cf3f 100755 --- a/cluster/vagrant/provision-master.sh +++ b/cluster/vagrant/provision-master.sh @@ -83,7 +83,6 @@ grains: cloud_provider: vagrant roles: - kubernetes-master - admission_control: '$(echo "$ADMISSION_CONTROL" | sed -e "s/'/''/g")' runtime_config: '$(echo "$RUNTIME_CONFIG" | sed -e "s/'/''/g")' EOF @@ -102,6 +101,7 @@ cat </srv/salt-overlay/pillar/cluster-params.sls dns_server: '$(echo "$DNS_SERVER_IP" | sed -e "s/'/''/g")' dns_domain: '$(echo "$DNS_DOMAIN" | sed -e "s/'/''/g")' instance_prefix: '$(echo "$INSTANCE_PREFIX" | sed -e "s/'/''/g")' + admission_control: '$(echo "$ADMISSION_CONTROL" | sed -e "s/'/''/g")' EOF # Configure the salt-master diff --git a/plugin/pkg/admission/namespace/autoprovision/admission.go b/plugin/pkg/admission/namespace/autoprovision/admission.go index 3e18f08c6d9..8f2ed0140ec 100644 --- a/plugin/pkg/admission/namespace/autoprovision/admission.go +++ b/plugin/pkg/admission/namespace/autoprovision/admission.go @@ -45,6 +45,10 @@ type provision struct { } func (p *provision) Admit(a admission.Attributes) (err error) { + // only handle create requests + if a.GetOperation() != "CREATE" { + return nil + } defaultVersion, kind, err := latest.RESTMapper.VersionAndKindForResource(a.GetResource()) if err != nil { return err diff --git a/plugin/pkg/admission/namespace/autoprovision/admission_test.go b/plugin/pkg/admission/namespace/autoprovision/admission_test.go index 8c95eac68e5..b6f6bb26974 100644 --- a/plugin/pkg/admission/namespace/autoprovision/admission_test.go +++ b/plugin/pkg/admission/namespace/autoprovision/admission_test.go @@ -15,3 +15,91 @@ limitations under the License. */ package autoprovision + +import ( + "testing" + + "github.com/GoogleCloudPlatform/kubernetes/pkg/admission" + "github.com/GoogleCloudPlatform/kubernetes/pkg/api" + "github.com/GoogleCloudPlatform/kubernetes/pkg/client" + "github.com/GoogleCloudPlatform/kubernetes/pkg/client/cache" +) + +// TestAdmission verifies a namespace is created on create requests for namespace managed resources +func TestAdmission(t *testing.T) { + namespace := "test" + mockClient := &client.Fake{} + handler := &provision{ + client: mockClient, + store: cache.NewStore(cache.MetaNamespaceKeyFunc), + } + pod := api.Pod{ + ObjectMeta: api.ObjectMeta{Name: "123", Namespace: namespace}, + Spec: api.PodSpec{ + Volumes: []api.Volume{{Name: "vol"}}, + Containers: []api.Container{{Name: "ctr", Image: "image"}}, + }, + } + err := handler.Admit(admission.NewAttributesRecord(&pod, namespace, "pods", "CREATE")) + if err != nil { + t.Errorf("Unexpected error returned from admission handler") + } + if len(mockClient.Actions) != 1 { + t.Errorf("Expected a create-namespace request") + } + if mockClient.Actions[0].Action != "create-namespace" { + t.Errorf("Expected a create-namespace request to be made via the client") + } +} + +// TestAdmissionNamespaceExists verifies that no client call is made when a namespace already exists +func TestAdmissionNamespaceExists(t *testing.T) { + namespace := "test" + mockClient := &client.Fake{} + store := cache.NewStore(cache.MetaNamespaceKeyFunc) + store.Add(&api.Namespace{ + ObjectMeta: api.ObjectMeta{Name: namespace}, + }) + handler := &provision{ + client: mockClient, + store: store, + } + pod := api.Pod{ + ObjectMeta: api.ObjectMeta{Name: "123", Namespace: namespace}, + Spec: api.PodSpec{ + Volumes: []api.Volume{{Name: "vol"}}, + Containers: []api.Container{{Name: "ctr", Image: "image"}}, + }, + } + err := handler.Admit(admission.NewAttributesRecord(&pod, namespace, "pods", "CREATE")) + if err != nil { + t.Errorf("Unexpected error returned from admission handler") + } + if len(mockClient.Actions) != 0 { + t.Errorf("No client request should have been made") + } +} + +// TestIgnoreAdmission validates that a request is ignored if its not a create +func TestIgnoreAdmission(t *testing.T) { + namespace := "test" + mockClient := &client.Fake{} + handler := &provision{ + client: mockClient, + store: cache.NewStore(cache.MetaNamespaceKeyFunc), + } + pod := api.Pod{ + ObjectMeta: api.ObjectMeta{Name: "123", Namespace: namespace}, + Spec: api.PodSpec{ + Volumes: []api.Volume{{Name: "vol"}}, + Containers: []api.Container{{Name: "ctr", Image: "image"}}, + }, + } + err := handler.Admit(admission.NewAttributesRecord(&pod, namespace, "pods", "UPDATE")) + if err != nil { + t.Errorf("Unexpected error returned from admission handler") + } + if len(mockClient.Actions) != 0 { + t.Errorf("No client request should have been made") + } +} From 20853410bd696b4668d78c83f5be0f85994e3ed8 Mon Sep 17 00:00:00 2001 From: derekwaynecarr Date: Tue, 10 Mar 2015 15:47:47 -0400 Subject: [PATCH 2/4] Unify azure and aws admission control --- cluster/aws/config-default.sh | 3 +++ cluster/aws/util.sh | 1 + cluster/azure/config-default.sh | 3 +++ cluster/azure/templates/create-dynamic-salt-files.sh | 1 + cluster/azure/util.sh | 1 + 5 files changed, 9 insertions(+) diff --git a/cluster/aws/config-default.sh b/cluster/aws/config-default.sh index bac2839a304..1e8ac6884c6 100644 --- a/cluster/aws/config-default.sh +++ b/cluster/aws/config-default.sh @@ -65,3 +65,6 @@ ENABLE_CLUSTER_DNS=true DNS_SERVER_IP="10.0.0.10" DNS_DOMAIN="kubernetes.local" DNS_REPLICAS=1 + +# Admission Controllers to invoke prior to persisting objects in cluster +ADMISSION_CONTROL=NamespaceAutoProvision,LimitRanger,ResourceQuota diff --git a/cluster/aws/util.sh b/cluster/aws/util.sh index dbce068df5b..13897f39195 100644 --- a/cluster/aws/util.sh +++ b/cluster/aws/util.sh @@ -314,6 +314,7 @@ function kube-up { echo "readonly DNS_REPLICAS='${DNS_REPLICAS:-}'" echo "readonly DNS_SERVER_IP='${DNS_SERVER_IP:-}'" echo "readonly DNS_DOMAIN='${DNS_DOMAIN:-}'" + echo "readonly ADMISSION_CONTROL='${ADMISSION_CONTROL:-}'" grep -v "^#" "${KUBE_ROOT}/cluster/aws/templates/common.sh" grep -v "^#" "${KUBE_ROOT}/cluster/aws/templates/create-dynamic-salt-files.sh" grep -v "^#" "${KUBE_ROOT}/cluster/aws/templates/download-release.sh" diff --git a/cluster/azure/config-default.sh b/cluster/azure/config-default.sh index f7822c4ce4b..38b1f3e7d8b 100644 --- a/cluster/azure/config-default.sh +++ b/cluster/azure/config-default.sh @@ -44,3 +44,6 @@ LOGGING_DESTINATION=elasticsearch # options: elasticsearch, gcp # Optional: When set to true, Elasticsearch and Kibana will be setup as part of the cluster bring up. ENABLE_CLUSTER_LOGGING=false ELASTICSEARCH_LOGGING_REPLICAS=1 + +# Admission Controllers to invoke prior to persisting objects in cluster +ADMISSION_CONTROL=NamespaceAutoProvision,LimitRanger,ResourceQuota diff --git a/cluster/azure/templates/create-dynamic-salt-files.sh b/cluster/azure/templates/create-dynamic-salt-files.sh index 977738b007c..548c6ff2620 100644 --- a/cluster/azure/templates/create-dynamic-salt-files.sh +++ b/cluster/azure/templates/create-dynamic-salt-files.sh @@ -23,6 +23,7 @@ cat </srv/salt-overlay/pillar/cluster-params.sls instance_prefix: '$(echo "$INSTANCE_PREFIX" | sed -e "s/'/''/g")' node_instance_prefix: $NODE_INSTANCE_PREFIX portal_net: $PORTAL_NET +admission_control: '$(echo "$ADMISSION_CONTROL" | sed -e "s/'/''/g")' EOF mkdir -p /srv/salt-overlay/salt/nginx diff --git a/cluster/azure/util.sh b/cluster/azure/util.sh index 40710bd5ab2..c5da546970b 100644 --- a/cluster/azure/util.sh +++ b/cluster/azure/util.sh @@ -349,6 +349,7 @@ function kube-up { echo "readonly SALT_TAR_URL='${SALT_TAR_URL}'" echo "readonly MASTER_HTPASSWD='${htpasswd}'" echo "readonly PORTAL_NET='${PORTAL_NET}'" + echo "readonly ADMISSION_CONTROL='${ADMISSION_CONTROL:-}'" grep -v "^#" "${KUBE_ROOT}/cluster/azure/templates/common.sh" grep -v "^#" "${KUBE_ROOT}/cluster/azure/templates/create-dynamic-salt-files.sh" grep -v "^#" "${KUBE_ROOT}/cluster/azure/templates/download-release.sh" From f71a91a1311290cf847c491a8fcecdfd2a014abd Mon Sep 17 00:00:00 2001 From: derekwaynecarr Date: Tue, 10 Mar 2015 16:47:26 -0400 Subject: [PATCH 3/4] Fix regression introduced when moving to standalone salt --- cluster/saltbase/pillar/mine.sls | 5 ++--- cluster/vagrant/provision-minion.sh | 1 + 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cluster/saltbase/pillar/mine.sls b/cluster/saltbase/pillar/mine.sls index 874dafc3e35..45035e47957 100644 --- a/cluster/saltbase/pillar/mine.sls +++ b/cluster/saltbase/pillar/mine.sls @@ -1,6 +1,6 @@ +{% if grains.cloud is defined and grains.cloud == 'gce' -%} # On GCE, there is no Salt mine. We run standalone. -{% if grains.cloud != 'gce' -%} - +{% else %} # Allow everyone to see cached values of who sits at what IP {% set networkInterfaceName = "eth0" %} {% if grains.networkInterfaceName is defined %} @@ -9,5 +9,4 @@ mine_functions: network.ip_addrs: [{{networkInterfaceName}}] grains.items: [] - {% endif -%} diff --git a/cluster/vagrant/provision-minion.sh b/cluster/vagrant/provision-minion.sh index a9401c80fb4..8749021b3fb 100755 --- a/cluster/vagrant/provision-minion.sh +++ b/cluster/vagrant/provision-minion.sh @@ -64,6 +64,7 @@ EOF # Our minions will have a pool role to distinguish them from the master. cat </etc/salt/minion.d/grains.conf grains: + cloud: vagrant network_mode: openvswitch node_ip: '$(echo "$MINION_IP" | sed -e "s/'/''/g")' etcd_servers: '$(echo "$MASTER_IP" | sed -e "s/'/''/g")' From 64eca7393aa76d8a30e362baeb2512a543e35617 Mon Sep 17 00:00:00 2001 From: derekwaynecarr Date: Wed, 11 Mar 2015 11:07:36 -0400 Subject: [PATCH 4/4] Update to use yaml quote --- cluster/gce/util.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cluster/gce/util.sh b/cluster/gce/util.sh index 2525cb3058e..7e81c4af4d3 100755 --- a/cluster/gce/util.sh +++ b/cluster/gce/util.sh @@ -452,7 +452,7 @@ DNS_REPLICAS: $(yaml-quote ${DNS_REPLICAS:-}) DNS_SERVER_IP: $(yaml-quote ${DNS_SERVER_IP:-}) DNS_DOMAIN: $(yaml-quote ${DNS_DOMAIN:-}) MASTER_HTPASSWD: $(yaml-quote ${MASTER_HTPASSWD}) -ADMISSION_CONTROL: $(yaml-quota ${ADMISSION_CONTROL:-}) +ADMISSION_CONTROL: $(yaml-quote ${ADMISSION_CONTROL:-}) EOF if [[ "${master}" != "true" ]]; then