From ab07355fdc9d8e1098428dd09f38d9079d75b57a Mon Sep 17 00:00:00 2001 From: Robbin Baauw Date: Wed, 24 Jun 2020 16:34:35 +0200 Subject: [PATCH 1/2] Updating resources upon relative to pod update --- docs/configuration.md | 6 +++--- services/apatelet/store/get_flag.go | 31 +++++++++++++++++++-------- services/apatelet/store/set_flag.go | 2 +- services/apatelet/store/store_test.go | 8 ++++--- 4 files changed, 31 insertions(+), 16 deletions(-) diff --git a/docs/configuration.md b/docs/configuration.md index 0d2af1f3..e217fae2 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -20,7 +20,7 @@ for automation. Even though most use-cases are covered by either planned or direct emulation, some edge-cases might require both. However, this is not supported in the initial version of Apate, and might lead to unexpected results in some cases, due to CRD resync. -We invite others to contribute to Apate and add this feature, as it should be a good first issue. +We invite others to contribute to Apate and add this feature, as it should be a [good first issue](https://github.com/atlarge-research/apate/issues/5). ::: ## Nodes @@ -90,7 +90,7 @@ State is the desired state of the node. ::: warning In the initial version of Apate, it is not possible to revert `node_failed` or `heartbeat_failed` directly. However, this can still be achieved using a custom state, and reverting the timout responses manually. -We invite others to contribute to Apate and add this feature, as it should be a good first issue. +We invite others to contribute to Apate and add this feature, as it should be a [good first issue](https://github.com/atlarge-research/apate/issues/6). ::: #### Custom state @@ -152,7 +152,7 @@ Task is a combination of a timestamp and a state | Field | Type | Description | Required | | --- | --- | --- | --- | | timestamp | [Time](#time) | Time at which this task will be executed | Yes | -| relative_to_pod | bool | If true, the timestamp will be relative to the start time of the pod, instead of the start time of the scenario | No | +| relative_to_pod | bool | If true, the timestamp will be relative to the start time of the pod, instead of the start time of the scenario. Note that currently, if this setting is used once for a certain flag, further updates of this flag relative to the scenario will not be used. This is a limitation we aim to solve [in the future](https://github.com/atlarge-research/apate/issues/7). | No | | state | [State](#pod-state) | Desired state after this task | Yes | ### Pod state diff --git a/services/apatelet/store/get_flag.go b/services/apatelet/store/get_flag.go index 292988f1..1a0ac9cf 100644 --- a/services/apatelet/store/get_flag.go +++ b/services/apatelet/store/get_flag.go @@ -39,11 +39,11 @@ func (s *store) GetPodFlag(pod *corev1.Pod, flag events.PodEventFlag) (interface label, ok := getPodLabelByPod(pod) if ok { - if val, ok := s.podFlags[label][flag]; ok { + if val, ok := s.getPodTimeFlag(pod, flag, label); ok { return val, nil } - if val, ok := s.getPodTimeFlag(pod, flag, label); ok { + if val, ok := s.podFlags[label][flag]; ok { return val, nil } } @@ -92,20 +92,33 @@ func (s *store) getPodTimeFlag(pod *corev1.Pod, flag events.PodEventFlag, label // Look at the previous index currentPodFlags := timeFlags[previousIndex] - // If this index has time flags before now (it might not have if this is the first iteration) - if podStartTime.Add(currentPodFlags.TimeSincePodStart).Before(time.Now()) { - if pf, ok := currentPodFlags.Flags[flag]; ok { - // Set cache and return it - s.podTimeIndexCache[pod][flag] = previousIndex + if pf, ok := currentPodFlags.Flags[flag]; ok { + if podStartTime.Add(currentPodFlags.TimeSincePodStart).Before(time.Now()) { + // If this index has time flags before now (it might not have if this is the first iteration) + s.updateCache(pf, pod, flag, previousIndex) return pf, true } } - // Else set the current index, as the next iteration can skip every index thus far - s.podTimeIndexCache[pod][flag] = i break } } return nil, false } + +func (s *store) updateCache(flagValue interface{}, pod *corev1.Pod, flag events.EventFlag, newIndex int) { + prevIndex, ok := s.podTimeIndexCache[pod][flag] + s.podTimeIndexCache[pod][flag] = newIndex + + // Trigger an update in pod resources + if (!ok || prevIndex != newIndex) && flag == events.PodResources { + s.podListenersLock.RLock() + if listeners, ok := s.podListeners[events.PodResources]; ok { + for _, listener := range listeners { + go listener(flagValue) + } + } + s.podListenersLock.RUnlock() + } +} diff --git a/services/apatelet/store/set_flag.go b/services/apatelet/store/set_flag.go index 53847ed0..fd548b9b 100644 --- a/services/apatelet/store/set_flag.go +++ b/services/apatelet/store/set_flag.go @@ -42,7 +42,7 @@ func (s *store) SetPodFlags(label string, flags Flags) { for flag, val := range flags { if listeners, ok := s.podListeners[flag]; ok { for _, listener := range listeners { - listener(val) + go listener(val) } } } diff --git a/services/apatelet/store/store_test.go b/services/apatelet/store/store_test.go index 0ef47cbd..dc7bc4ac 100644 --- a/services/apatelet/store/store_test.go +++ b/services/apatelet/store/store_test.go @@ -515,6 +515,8 @@ func TestAddPodListener(t *testing.T) { st.SetPodFlags("a/b", Flags{events.PodCreatePodResponse: scenario.ResponseTimeout}) st.SetPodFlags("b/c", Flags{events.PodUpdatePodResponse: scenario.ResponseError}) + time.Sleep(100 * time.Millisecond) // Sleep a bit as the listeners are executed in goroutines + // Retrieve unset flag and verify default value and err val, err := st.GetPodFlag(createPodWithLabel("a", "b"), events.PodCreatePodResponse) assert.NoError(t, err) @@ -585,7 +587,7 @@ func TestGetPodTimeFlag(t *testing.T) { flag, ok = st.getPodTimeFlag(pod, 11, "a/b") assert.False(t, ok) assert.Nil(t, flag) - assert.Equal(t, 1, st.podTimeIndexCache[pod][11]) + assert.Equal(t, 0, st.podTimeIndexCache[pod][11]) // After 1 more second we expect tf2 to become active time.Sleep(1 * time.Second) @@ -615,7 +617,7 @@ func TestGetPodTimeFlag(t *testing.T) { assert.Equal(t, 1, st.podTimeIndexCache[pod][11]) } -func TestScenarioMoreImportantThanPodTime(t *testing.T) { +func TestPodTimeMoreImportantThanScenario(t *testing.T) { t.Parallel() newStore := NewStore() @@ -635,7 +637,7 @@ func TestScenarioMoreImportantThanPodTime(t *testing.T) { flag, err := st.GetPodFlag(createPodWithLabel("a", "b"), 42) assert.NoError(t, err) - assert.Equal(t, "k9s", flag) + assert.Equal(t, "k8s", flag) } func TestPodTimeMoreImportantThanDefault(t *testing.T) { From eead59b45998ace43c210b8364e0701e51edb4ce Mon Sep 17 00:00:00 2001 From: Robbin Baauw Date: Wed, 24 Jun 2020 21:04:15 +0200 Subject: [PATCH 2/2] Updated registry settings --- .gitlab-ci.yml | 10 ++++------ ci/build.gitlab-ci.yml | 4 ++-- ci/test.gitlab-ci.yml | 2 +- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 2dc037dd..65119176 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -7,11 +7,9 @@ stages: - deploy variables: - REGISTRY_URL: "registry.planning.nl" - REGISTRY_IMAGE: "registry.planning.nl/emulating-k8s/emulating-k8s" - CI_IMAGE: "$REGISTRY_IMAGE/build-image-$CI_COMMIT_REF_SLUG" - VK_IMAGE: "$REGISTRY_IMAGE/apatelet-$CI_COMMIT_REF_SLUG" - CP_IMAGE: "$REGISTRY_IMAGE/controlplane-$CI_COMMIT_REF_SLUG" + CI_IMAGE: "$CI_REGISTRY_IMAGE/build-image-$CI_COMMIT_REF_SLUG" + VK_IMAGE: "$CI_REGISTRY_IMAGE/apatelet-$CI_COMMIT_REF_SLUG" + CP_IMAGE: "$CI_REGISTRY_IMAGE/controlplane-$CI_COMMIT_REF_SLUG" GOPATH: "$CI_PROJECT_DIR/.go" DS_EXCLUDED_PATHS: ".go" # Exclude the caching dir from scans (doesn't work for now, https://gitlab.com/gitlab-org/gitlab/-/issues/10030) SAST_EXCLUDED_PATHS: ".go" # Exclude the caching dir from scans (doesn't work for now, https://gitlab.com/gitlab-org/gitlab/-/issues/10030) @@ -30,7 +28,7 @@ prepare-ci-image: services: - docker:dind before_script: - - docker login -u "$REGISTRY_USER" -p "$REGISTRY_PASSWORD" $REGISTRY_URL + - docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY - cd ./ci/build-image script: - docker pull "$CI_IMAGE" || true diff --git a/ci/build.gitlab-ci.yml b/ci/build.gitlab-ci.yml index 9232bbfd..83d3f81b 100644 --- a/ci/build.gitlab-ci.yml +++ b/ci/build.gitlab-ci.yml @@ -22,7 +22,7 @@ build apatelet container: services: - docker:dind before_script: - - docker login -u "$REGISTRY_USER" -p "$REGISTRY_PASSWORD" $REGISTRY_URL + - docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY script: - docker pull $VK_IMAGE || true - docker build --cache-from $VK_IMAGE -f services/apatelet/Dockerfile -t $VK_IMAGE . @@ -36,7 +36,7 @@ build cp container: services: - docker:dind before_script: - - docker login -u "$REGISTRY_USER" -p "$REGISTRY_PASSWORD" $REGISTRY_URL + - docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY script: - docker pull $CP_IMAGE || true - docker build --cache-from $CP_IMAGE -f services/controlplane/Dockerfile -t $CP_IMAGE . diff --git a/ci/test.gitlab-ci.yml b/ci/test.gitlab-ci.yml index 651ddfe5..e199b7e3 100644 --- a/ci/test.gitlab-ci.yml +++ b/ci/test.gitlab-ci.yml @@ -22,7 +22,7 @@ test suite: - name: registry.gitlab.com/gitlab-org/cluster-integration/test-utils/k3s-gitlab-ci/releases/v1.16.7-k3s1 alias: k3s-service before_script: - - docker login -u "$REGISTRY_USER" -p "$REGISTRY_PASSWORD" $REGISTRY_URL + - docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY script: - curl k3s-service:8081?service=k3s-service > k3s.yml - export K3S_KUBE_CONFIG=$(pwd)/k3s.yml