|
1 | 1 | require "sam" |
2 | 2 | require "file_utils" |
3 | | -require "colorize" |
4 | | -require "totem" |
5 | 3 | require "http/client" |
6 | | -require "halite" |
7 | 4 | require "../utils/utils.cr" |
8 | | -require "json" |
9 | | -require "yaml" |
10 | 5 |
|
11 | 6 | namespace "setup" do |
12 | 7 | desc "Install Cluster API for Kind" |
13 | | - task "cluster_api_install" do |_, args| |
14 | | - current_dir = FileUtils.pwd |
| 8 | + task "install_cluster_api" do |_, args| |
| 9 | + logger = SLOG.for("install_cluster_api") |
| 10 | + logger.info { "Installing Cluster API tool" } |
| 11 | + failed_msg = "Task 'install_cluster_api' failed" |
15 | 12 |
|
16 | | - download(Setup::CLUSTER_API_URL, Setup::CLUSTERCTL_BINARY) |
17 | | - |
18 | | - Process.run( |
19 | | - "sudo chmod +x ./clusterctl", |
20 | | - shell: true, |
21 | | - output: stdout = IO::Memory.new, |
22 | | - error: stderr = IO::Memory.new |
23 | | - ) |
24 | | - Process.run( |
25 | | - "sudo mv ./clusterctl /usr/local/bin/clusterctl", |
26 | | - shell: true, |
27 | | - output: stdout = IO::Memory.new, |
28 | | - error: stderr = IO::Memory.new |
29 | | - ) |
30 | | - |
31 | | - Log.info { "Completed downloading clusterctl" } |
32 | | - |
33 | | - clusterctl = Path["~/.cluster-api"].expand(home: true) |
34 | | - |
35 | | - FileUtils.mkdir_p("#{clusterctl}") |
| 13 | + if Dir.exists?(Setup::CLUSTER_API_DIR) |
| 14 | + logger.notice { "cluster api directory: '#{Setup::CLUSTER_API_DIR}' already exists, clusterctl should be available" } |
| 15 | + next |
| 16 | + end |
36 | 17 |
|
37 | | - File.write("#{clusterctl}/clusterctl.yaml", "CLUSTER_TOPOLOGY: \"true\"") |
| 18 | + FileUtils.mkdir_p(Setup::CLUSTER_API_DIR) |
| 19 | + begin |
| 20 | + download(Setup::CLUSTER_API_URL, Setup::CLUSTERCTL_BINARY) |
| 21 | + rescue ex : Exception |
| 22 | + logger.error { "Error while downloading clusterctl binary" } |
| 23 | + stdout_error(failed_msg) |
| 24 | + # (rafal-lal) TODO: SAM tasks error handling in setup, should we fail whole testsuite run / ignore |
| 25 | + # or something else? Applicable to all Setup tasks. |
| 26 | + next |
| 27 | + end |
| 28 | + logger.debug { "Downloaded clusterctl binary" } |
38 | 29 |
|
39 | | - cluster_init_cmd = "clusterctl init --infrastructure docker" |
40 | | - stdout = IO::Memory.new |
41 | | - Process.run(cluster_init_cmd, shell: true, output: stdout, error: stdout) |
42 | | - Log.for("clusterctl init").info { stdout } |
| 30 | + resp = ShellCmd.run("chmod +x #{Setup::CLUSTERCTL_BINARY}") |
| 31 | + unless resp[:status].success? |
| 32 | + logger.error { "Error while making cluster api binary: '#{Setup::CLUSTERCTL_BINARY}' executable" } |
| 33 | + stdout_error(failed_msg) |
| 34 | + next |
| 35 | + end |
43 | 36 |
|
44 | | - create_cluster_file = "#{current_dir}/capi.yaml" |
| 37 | + File.write("#{Setup::CLUSTER_API_DIR}/clusterctl.yaml", "CLUSTER_TOPOLOGY: \"true\"") |
| 38 | + unless ShellCmd.run("#{Setup::CLUSTERCTL_BINARY} init --infrastructure docker")[:status].success? |
| 39 | + logger.error { "Error while initializing Cluster API on the cluster" } |
| 40 | + stdout_error(failed_msg) |
| 41 | + end |
45 | 42 |
|
46 | | - create_cluster_cmd = "clusterctl generate cluster capi-quickstart --kubernetes-version v1.24.0 --control-plane-machine-count=3 --worker-machine-count=3 --flavor development > #{create_cluster_file} " |
| 43 | + cluster_name = "capi-quickstart" |
| 44 | + cluster_tpl_file = "#{Setup::CLUSTER_API_DIR}/capi.yaml" |
| 45 | + # (rafal-lal) TODO: add kubernetes version const to use widely in codebase |
| 46 | + generate_cmd = "#{Setup::CLUSTERCTL_BINARY} generate cluster #{cluster_name}" + |
| 47 | + "--kubernetes-version v1.32.0" + |
| 48 | + "--control-plane-machine-count=1" + |
| 49 | + "--worker-machine-count=1" + |
| 50 | + "--flavor development" + |
| 51 | + "--target-namespace #{DEFAULT_CNF_NAMESPACE}" + |
| 52 | + "> #{cluster_tpl_file}" |
| 53 | + unless ShellCmd.run(generate_cmd)[:status].success? |
| 54 | + logger.error { "Error while generating workload cluster YAML template" } |
| 55 | + stdout_error(failed_msg) |
| 56 | + end |
47 | 57 |
|
48 | | - Process.run( |
49 | | - create_cluster_cmd, |
50 | | - shell: true, |
51 | | - output: create_cluster_stdout = IO::Memory.new, |
52 | | - error: create_cluster_stderr = IO::Memory.new |
53 | | - ) |
| 58 | + is_ready = false |
| 59 | + begin |
| 60 | + KubectlClient::Apply.file(cluster_tpl_file) |
| 61 | + is_ready = KubectlClient::Wait.wait_for_resource_key_value("cluster", cluster_name, |
| 62 | + {"status", "phase"}, "Provisioned", 300, DEFAULT_CNF_NAMESPACE) |
| 63 | + rescue ex : KubectlClient::ShellCMD::K8sClientCMDException |
| 64 | + logger.error { "Error while waiting for cluster to be Ready: #{ex.message}" } |
| 65 | + stdout_error(failed_msg) |
| 66 | + end |
54 | 67 |
|
55 | | - # TODO (rafal-lal): Connection error is expected in first couple tries, but it's not |
56 | | - # reasonable to rescue it inside 'wait_for_install_by_apply' method, hence the while |
57 | | - # loop here. Ideally this should be implemented in different way so we don't have to |
58 | | - # rescue NetworkError at all. 'loop_count' var added so testsuite won't hang |
59 | | - # indefinitely here. |
60 | | - loop_break = false |
61 | | - loop_count = 0 |
62 | | - while !loop_break && loop_count < 10 |
63 | | - begin |
64 | | - KubectlClient::Wait.wait_for_install_by_apply(create_cluster_file) |
65 | | - loop_break = true |
66 | | - rescue KubectlClient::ShellCMD::NetworkError |
67 | | - sleep 3.seconds |
68 | | - loop_count += 1 |
69 | | - end |
| 68 | + unless is_ready |
| 69 | + logger.error { "Manifest apply not succesful or timed out while waiting for cluster to be Ready" } |
| 70 | + stdout_error(failed_msg) |
| 71 | + next |
70 | 72 | end |
71 | 73 |
|
72 | | - Log.for("clusterctl-create").info { create_cluster_stdout.to_s } |
73 | | - Log.info { "cluster api setup complete" } |
| 74 | + logger.info { "Cluster API provisioned cluster '#{cluster_name}' is ready to use" } |
74 | 75 | end |
75 | 76 |
|
76 | 77 | desc "Uninstall Cluster API" |
77 | | - task "cluster_api_uninstall" do |_, args| |
78 | | - current_dir = FileUtils.pwd |
79 | | - delete_cluster_file = "#{current_dir}/capi.yaml" |
80 | | - begin KubectlClient::Delete.file("#{delete_cluster_file}") rescue KubectlClient::ShellCMD::NotFoundError end |
| 78 | + task "uninstall_cluster_api" do |_, args| |
| 79 | + logger = SLOG.for("uninstall_cluster_api") |
| 80 | + logger.info { "Uninstalling Cluster API tool" } |
| 81 | + |
| 82 | + begin |
| 83 | + KubectlClient::Delete.file("#{Setup::CLUSTER_API_DIR}/capi.yaml") |
| 84 | + rescue KubectlClient::ShellCMD::NotFoundError |
| 85 | + logger.debug { "Cluster API 'cluster' resource does not exists" } |
| 86 | + rescue ex : KubectlClient::ShellCMD::K8sClientCMDException |
| 87 | + logger.error { "Error while deleting Cluster API 'cluster' resource: #{ex.message}" } |
| 88 | + stdout_error("Error while deleting Cluster API 'cluster' resource. Check logs for more info.") |
| 89 | + end |
| 90 | + |
| 91 | + response = ShellCmd.run("#{Setup::CLUSTERCTL_BINARY} delete --all --include-crd --include-namespace") |
| 92 | + unless response[:status].success? |
| 93 | + logger.error { "Error while deleting Cluster API from the cluster: #{response[:error]}" } |
| 94 | + stdout_error("Error while deleting Cluster API 'cluster' resource. Check logs for more info.") |
| 95 | + next |
| 96 | + end |
81 | 97 |
|
82 | | - cmd = "clusterctl delete --all --include-crd --include-namespace" |
83 | | - Process.run(cmd, shell: true, output: stdout = IO::Memory.new, error: stderr = IO::Memory.new) |
| 98 | + logger.info { "Cluster API uninstalled from the cluster" } |
84 | 99 | end |
85 | 100 | end |
0 commit comments