Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Updating resources upon relative to pod update #8

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 4 additions & 6 deletions .gitlab-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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
Expand Down
4 changes: 2 additions & 2 deletions ci/build.gitlab-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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 .
Expand All @@ -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 .
Expand Down
2 changes: 1 addition & 1 deletion ci/test.gitlab-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 3 additions & 3 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
31 changes: 22 additions & 9 deletions services/apatelet/store/get_flag.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
}
Expand Down Expand Up @@ -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()
}
}
2 changes: 1 addition & 1 deletion services/apatelet/store/set_flag.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}
}
Expand Down
8 changes: 5 additions & 3 deletions services/apatelet/store/store_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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()
Expand All @@ -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) {
Expand Down