diff --git a/examples/Makefile b/examples/Makefile index 1238a5f4b..cdef95306 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -5,6 +5,13 @@ get-python: get-python-verify: kubeless function call get-python |egrep hello.world +get-python-update: + printf 'def foo():\n%4sreturn "hello world updated"\n' | kubeless function update get-python --runtime python2.7 --handler helloget.foo --from-file /dev/stdin + echo "curl localhost:8080/api/v1/proxy/namespaces/default/services/get-python/" + +get-python-update-verify: + kubeless function call get-python |egrep hello.world.updated + get-python-34: kubeless function deploy get-python --trigger-http --runtime python3.4 --handler helloget.foo --from-file python/helloget.py echo "curl localhost:8080/api/v1/proxy/namespaces/default/services/get-python/" diff --git a/kubeless-rbac.jsonnet b/kubeless-rbac.jsonnet index 008375cb4..f24465314 100644 --- a/kubeless-rbac.jsonnet +++ b/kubeless-rbac.jsonnet @@ -7,7 +7,7 @@ local kubeless = import "kubeless.jsonnet"; local controller_account = kubeless.controller_account; local controller_roles = [{ apiGroups: ["*"], - resources: ["services", "deployments", "functions", "configmaps"], + resources: ["services", "deployments", "functions", "configmaps", "pods", "replicasets"], verbs: ["*"] }]; diff --git a/pkg/utils/k8sutil.go b/pkg/utils/k8sutil.go index 2290a5235..1fc0cdc67 100644 --- a/pkg/utils/k8sutil.go +++ b/pkg/utils/k8sutil.go @@ -776,7 +776,8 @@ func ensureFuncConfigMap(client kubernetes.Interface, funcObj *spec.Function, or _, err = client.Core().ConfigMaps(funcObj.Metadata.Namespace).Create(configMap) if err != nil && k8sErrors.IsAlreadyExists(err) { - data, err := json.Marshal(configMap) + var data []byte + data, err = json.Marshal(configMap) if err != nil { return err } @@ -807,12 +808,12 @@ func ensureFuncService(client kubernetes.Interface, funcObj *spec.Function, or [ } _, err := client.Core().Services(funcObj.Metadata.Namespace).Create(svc) if err != nil && k8sErrors.IsAlreadyExists(err) { - data, err := json.Marshal(svc) + var data []byte + data, err = json.Marshal(svc) if err != nil { return err } _, err = client.Core().Services(funcObj.Metadata.Namespace).Patch(svc.Name, types.StrategicMergePatchType, data) - } return err } @@ -959,7 +960,8 @@ func ensureFuncDeployment(client kubernetes.Interface, funcObj *spec.Function, o _, err = client.Extensions().Deployments(funcObj.Metadata.Namespace).Create(dpm) if err != nil && k8sErrors.IsAlreadyExists(err) { - data, err := json.Marshal(dpm) + var data []byte + data, err = json.Marshal(dpm) if err != nil { return err } @@ -971,7 +973,11 @@ func ensureFuncDeployment(client kubernetes.Interface, funcObj *spec.Function, o // kick existing function pods then it will be recreated // with the new data mount from updated configmap. // TODO: This is a workaround. Do something better. - pods, err := GetPodsByLabel(client, funcObj.Metadata.Namespace, "function", funcObj.Metadata.Name) + var pods *v1.PodList + pods, err = GetPodsByLabel(client, funcObj.Metadata.Namespace, "function", funcObj.Metadata.Name) + if err != nil { + return err + } for _, pod := range pods.Items { err = client.Core().Pods(funcObj.Metadata.Namespace).Delete(pod.Name, &metav1.DeleteOptions{}) if err != nil && !k8sErrors.IsNotFound(err) { @@ -1014,14 +1020,12 @@ func ensureFuncJob(client kubernetes.Interface, funcObj *spec.Function, or []met _, err := client.BatchV2alpha1().CronJobs(funcObj.Metadata.Namespace).Create(job) if err != nil && k8sErrors.IsAlreadyExists(err) { - data, err := json.Marshal(job) + var data []byte + data, err = json.Marshal(job) if err != nil { return err } _, err = client.BatchV2alpha1().CronJobs(funcObj.Metadata.Namespace).Patch(job.Name, types.StrategicMergePatchType, data) - if err != nil { - return err - } } return err diff --git a/script/libtest.bash b/script/libtest.bash index 2aec3d4c8..6ac9ca81a 100644 --- a/script/libtest.bash +++ b/script/libtest.bash @@ -50,6 +50,16 @@ k8s_wait_for_pod_ready() { sleep 1 done } +k8s_wait_for_uniq_pod() { + echo_info "Waiting for pod '${@}' to be the only one running ... " + local -i cnt=${TEST_MAX_WAIT_SEC:?} + until [[ $(kubectl get pod "${@}" -ogo-template='{{.items|len}}') == 1 ]]; do + ((cnt=cnt-1)) || return 1 + sleep 1 + done + k8s_wait_for_pod_ready "${@}" + echo "Finished waiting" +} k8s_wait_for_pod_gone() { echo_info "Waiting for pod '${@}' to be gone ... " local -i cnt=${TEST_MAX_WAIT_SEC:?} @@ -243,4 +253,12 @@ test_kubeless_function() { esac make -sC examples ${func}-verify } + +test_kubeless_function_update() { + local func=${1:?} func_topic + echo_info "UPDATE: $func" + make -sC examples ${func}-update + k8s_wait_for_uniq_pod -l function=${func} + make -sC examples ${func}-update-verify +} # vim: sw=4 ts=4 et si diff --git a/tests/integration-tests.bats b/tests/integration-tests.bats index 8fdda69fd..4de712c71 100644 --- a/tests/integration-tests.bats +++ b/tests/integration-tests.bats @@ -37,6 +37,7 @@ load ../script/libtest # 'bats' lacks loop support, unroll-them-all -> @test "Test function: get-python" { test_kubeless_function get-python + test_kubeless_function_update get-python } @test "Test function: get-nodejs" { test_kubeless_function get-nodejs