Skip to content

Commit

Permalink
Merge branch 'main' into 267_Add_configuration_object
Browse files Browse the repository at this point in the history
  • Loading branch information
christoph-hamm committed Oct 1, 2024
2 parents 8440e58 + 81cffe6 commit 592efe2
Show file tree
Hide file tree
Showing 11 changed files with 67 additions and 188 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,13 @@ jobs:
- name: Run clippy code checks
run: cargo clippy --all-targets --no-deps --all-features -- -D warnings
- name: Prevent docker.io images in test
run: make check-test-images
run: just check-test-images
# If the next step fails, then a license used by a new dependency is currently
# not part of the whitelist in deny.toml. If the new license fits to the project
# then it should be added to the whitelist otherwise the dependency needs to be
# removed.
- name: Check licenses
run: make check-licenses
run: just check-licenses
- name: Create license report
run: |
mkdir -p build
Expand Down
3 changes: 0 additions & 3 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,6 @@
"editor.defaultFormatter": "rust-lang.rust-analyzer",
"editor.formatOnSave": true
},
"[makefile]": {
"editor.detectIndentation": false,
},
"rust-analyzer.cargo.loadOutDirsFromCheck": true,
"rust-analyzer.cargo.unsetTest": [
"api",
Expand Down
3 changes: 3 additions & 0 deletions agent/doc/swdesign/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,9 @@ Status: approved

The Ankaios CLI shall enforce agent names which respect the naming convention defined in the common library.

Comment:
We need to check the agent names in order to ensure the proper function of the filtering.

Tags:
- AgentManager

Expand Down
185 changes: 18 additions & 167 deletions ank/src/cli_commands/set_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,7 @@
//
// SPDX-License-Identifier: Apache-2.0

use common::{
objects::{CompleteState, StoredWorkloadSpec},
state_manipulation::{Object, Path},
};
use common::state_manipulation::Object;
use std::io::{self, Read};

#[cfg(not(test))]
Expand All @@ -28,30 +25,6 @@ use tests::read_to_string_mock as read_file_to_string;

use super::CliCommands;

fn create_state_with_default_workload_specs(update_mask: &[String]) -> CompleteState {
let mut complete_state = CompleteState::default();
const WORKLOAD_ATTRIBUTE_LEVEL: usize = 4;
let workload_level_mask_parts = ["desiredState".to_string(), "workloads".to_string()];
const WORKLOAD_NAME_POSITION: usize = 2;

for field_mask in update_mask {
let path: Path = field_mask.into();

// if we want to set an attribute of a workload create a default object for the workload
let mask_parts = path.parts();
if mask_parts.len() >= WORKLOAD_ATTRIBUTE_LEVEL
&& mask_parts.starts_with(&workload_level_mask_parts)
{
complete_state.desired_state.workloads.insert(
mask_parts[WORKLOAD_NAME_POSITION].to_string(),
StoredWorkloadSpec::default(),
);
}
}

complete_state
}

// [impl->swdd~cli-supports-yaml-to-set-desired-state~1]
async fn process_inputs<R: Read>(reader: R, state_object_file: &str) -> Result<Object, CliError> {
match state_object_file {
Expand Down Expand Up @@ -90,30 +63,6 @@ async fn process_inputs<R: Read>(reader: R, state_object_file: &str) -> Result<O
}
}

fn overwrite_using_field_mask(
mut complete_state_object: Object,
object_field_mask: &Vec<String>,
temp_obj: &Object,
) -> Result<Object, CliError> {
for field_mask in object_field_mask {
let path: Path = field_mask.into();

complete_state_object
.set(
&path,
temp_obj
.get(&path)
.ok_or(CliError::ExecutionError(format!(
"Specified update mask '{field_mask}' not found in the input config.",
)))?
.clone(),
)
.map_err(|err| CliError::ExecutionError(err.to_string()))?;
}

Ok(complete_state_object)
}

impl CliCommands {
// [impl->swdd~cli-provides-set-desired-state~1]
pub async fn set_state(
Expand All @@ -127,22 +76,17 @@ impl CliCommands {
state_object_file
);

let temp_obj = process_inputs(io::stdin(), &state_object_file).await?;
let default_complete_state = create_state_with_default_workload_specs(&object_field_mask);

// now overwrite with the values from the field mask
let mut complete_state_object: Object = default_complete_state.try_into()?;
complete_state_object =
overwrite_using_field_mask(complete_state_object, &object_field_mask, &temp_obj)?;
let new_complete_state = complete_state_object.try_into()?;
let complete_state = process_inputs(io::stdin(), &state_object_file)
.await?
.try_into()?;

output_debug!(
"Send UpdateState request with the CompleteState {:?}",
new_complete_state
complete_state
);

// [impl->swdd~cli-blocks-until-ankaios-server-responds-set-desired-state~2]
self.update_state_and_wait_for_complete(new_complete_state, object_field_mask)
self.update_state_and_wait_for_complete(complete_state, object_field_mask)
.await
}
}
Expand All @@ -156,14 +100,11 @@ impl CliCommands {
//////////////////////////////////////////////////////////////////////////////
#[cfg(test)]
mod tests {
use super::{
create_state_with_default_workload_specs, io, overwrite_using_field_mask, process_inputs,
CliCommands, StoredWorkloadSpec,
};
use super::{io, process_inputs, CliCommands};
use crate::cli_commands::server_connection::MockServerConnection;
use api::ank_base::UpdateStateSuccess;
use common::{
objects::{CompleteState, RestartPolicy, State},
objects::{CompleteState, RestartPolicy, State, StoredWorkloadSpec, Tag},
state_manipulation::Object,
};
use mockall::predicate::eq;
Expand All @@ -177,6 +118,7 @@ mod tests {
const RESPONSE_TIMEOUT_MS: u64 = 3000;

const SAMPLE_CONFIG: &str = r#"desiredState:
apiVersion: api_version
workloads:
nginx:
agent: agent_A
Expand All @@ -190,85 +132,6 @@ mod tests {
image: docker.io/nginx:latest
commandOptions: ["-p", "8081:80"]"#;

// [utest->swdd~cli-provides-set-desired-state~1]
#[test]
fn utest_create_state_with_default_workload_specs_empty_update_mask() {
let update_mask = vec![];

let complete_state = create_state_with_default_workload_specs(&update_mask);

assert!(complete_state.desired_state.workloads.is_empty());
}

// [utest->swdd~cli-provides-set-desired-state~1]
#[test]
fn utest_create_state_with_default_workload_specs_with_update_mask() {
let update_mask = vec![
"desiredState.workloads.nginx.restartPolicy".to_string(),
"desiredState.workloads.nginx2.restartPolicy".to_string(),
"desiredState.workloads.nginx3".to_string(),
];

let complete_state = create_state_with_default_workload_specs(&update_mask);

assert_eq!(
complete_state.desired_state.workloads.get("nginx"),
Some(&StoredWorkloadSpec::default())
);

assert_eq!(
complete_state.desired_state.workloads.get("nginx2"),
Some(&StoredWorkloadSpec::default())
);
assert!(!complete_state
.desired_state
.workloads
.contains_key("nginx3"));
}

// [utest->swdd~cli-provides-set-desired-state~1]
#[test]
fn utest_create_state_with_default_workload_specs_invalid_path() {
let update_mask = vec!["invalid.path".to_string()];

let complete_state = create_state_with_default_workload_specs(&update_mask);

assert!(complete_state.desired_state.workloads.is_empty());
}

// [utest->swdd~cli-provides-set-desired-state~1]
#[test]
fn utest_overwrite_using_field_mask() {
let workload_spec = StoredWorkloadSpec::default();
let mut complete_state = CompleteState {
desired_state: State {
workloads: HashMap::from([("nginx".to_string(), workload_spec)]),
..Default::default()
},
..Default::default()
};
let mut complete_state_object: Object = complete_state.try_into().unwrap();
let value: serde_yaml::Value = serde_yaml::from_str(SAMPLE_CONFIG).unwrap();
let temp_object = Object::try_from(&value).unwrap();
let update_mask = vec!["desiredState.workloads.nginx".to_string()];

complete_state_object =
overwrite_using_field_mask(complete_state_object, &update_mask, &temp_object).unwrap();

complete_state = complete_state_object.try_into().unwrap();

assert!(complete_state.desired_state.workloads.contains_key("nginx"));
assert_eq!(
complete_state
.desired_state
.workloads
.get("nginx")
.unwrap()
.restart_policy,
RestartPolicy::Always
)
}

// [utest->swdd~cli-supports-yaml-to-set-desired-state~1]
#[tokio::test]
async fn utest_process_inputs_stdin() {
Expand Down Expand Up @@ -318,13 +181,21 @@ mod tests {
let state_object_file = SAMPLE_CONFIG.to_owned();

let workload_spec = StoredWorkloadSpec {
agent: "agent_A".into(),
tags: vec![Tag {
key: "owner".into(),
value: "Ankaios team".into(),
}],
restart_policy: RestartPolicy::Always,
runtime: "podman".into(),
runtime_config: "image: docker.io/nginx:latest\ncommandOptions: [\"-p\", \"8081:80\"]"
.into(),
..Default::default()
};
let updated_state = CompleteState {
desired_state: State {
workloads: HashMap::from([("nginx".to_string(), workload_spec)]),
..Default::default()
api_version: "api_version".into(),
},
..Default::default()
};
Expand All @@ -343,24 +214,4 @@ mod tests {
let set_state_result = cmd.set_state(update_mask, state_object_file).await;
assert!(set_state_result.is_ok());
}

// [utest->swdd~cli-provides-set-desired-state~1]
#[tokio::test]
async fn utest_set_state_failed() {
let wrong_update_mask = vec!["desiredState.workloads.notExistingWorkload".to_string()];
let state_object_file = SAMPLE_CONFIG.to_owned();
let mut mock_server_connection = MockServerConnection::default();
mock_server_connection
.expect_update_state()
.return_once(|_, _| Ok(UpdateStateSuccess::default()));

let mut cmd = CliCommands {
_response_timeout_ms: RESPONSE_TIMEOUT_MS,
no_wait: true,
server_connection: mock_server_connection,
};

let set_state_result = cmd.set_state(wrong_update_mask, state_object_file).await;
assert!(set_state_result.is_err());
}
}
4 changes: 2 additions & 2 deletions common/doc/swdesign/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -343,7 +343,7 @@ The Common library shall provide functionality for enforcing a workload name to:
* have a maximal length of 63 characters

Rationale:
A consistent naming manner assures stability in usage, compatibility with Ankaios internal structure and compliance to internet standards (RFC-1123).
A consistent naming manner assures stability in usage, compatibility with Ankaios internal structure by ensuring proper function of the filtering.

Tags:
- Objects
Expand All @@ -361,7 +361,7 @@ Status: approved
The Common library shall provide functionality for enforcing an agent name to contain only regular upper and lowercase characters (a-z and A-Z), numbers and the symbols "-" and "_".

Rationale:
A consistent naming manner allows a flawless usage of the Ankaios CLI and does not tamper with the internal structure of Ankaios.
A consistent naming manner assures stability in usage, compatibility with Ankaios internal structure by ensuring proper function of the filtering.

Tags:
- Objects
Expand Down
29 changes: 22 additions & 7 deletions Makefile → justfile
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,32 @@
#
# SPDX-License-Identifier: Apache-2.0

# Note:
#
# This Makefile is work in progress. Currently it contains only a small subset
# of all steps.
all: check-test-images check-licenses test stest build-release

build:
cargo build

build-release:
cargo build --release

all: check-test-images check-licenses
clean:
cargo clean
./tools/dev_scripts/ankaios-clean
rm -rf build

check-licenses:
cargo deny check licenses
cargo deny check licenses

# Prevent non ghcr.io images to be used in test due to rate limit problem
check-test-images:
test -z "$(shell find tests/resources/configs -type f -exec grep -H -P 'image: (?!ghcr\.io/|image_typo:latest)' {} \;)"
test -z "$(find tests/resources/configs -type f -exec grep -H -P 'image: (?!ghcr\.io/|image_typo:latest)' {} \;)"

test:
cargo nextest run

# Build debug and run all system tests
stest: build stest-only

# only execute the stests without building
stest-only:
./tools/run_robot_tests.sh tests
2 changes: 1 addition & 1 deletion server/src/ankaios_server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ impl AnkaiosServer {
let added_workloads = self.server_state.get_workloads_for_agent(&agent_name);

log::debug!(
"Sending initial UpdateWorkload to agent '{}' with added workloads: '{:?}'",
"Sending initial ServerHello to agent '{}' with added workloads: '{:?}'",
agent_name,
added_workloads,
);
Expand Down
3 changes: 3 additions & 0 deletions tests/resources/configs/minimal_set_state.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
desiredState:
apiVersion: "v0.1"
workloads:
simple:
agent: ""
runtime: ""
runtimeConfig: ""
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
desiredState:
apiVersion: v0.1
workloads:
nginx:
runtime: podman
Expand Down
1 change: 0 additions & 1 deletion tests/resources/configs/update_state_pending_create.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,3 @@ desiredState:
runtimeConfig: |
image: ghcr.io/eclipse-ankaios/tests/alpine:latest
commandArgs: ["echo", "backend succeeded"]
workloadStates: []
Loading

0 comments on commit 592efe2

Please sign in to comment.