From 538131b685c883fe9a2d50ffacd60e73ff87c371 Mon Sep 17 00:00:00 2001 From: Derek Nola Date: Thu, 6 Feb 2025 11:33:37 -0800 Subject: [PATCH] Migrate E2E Token test into a Docker Token test Remove E2E token test Signed-off-by: Derek Nola --- .github/workflows/e2e.yaml | 2 +- tests/docker/test-helpers.go | 129 +++++++++++++++++----- tests/{e2e => docker}/token/token_test.go | 114 +++++++------------ tests/e2e/token/Vagrantfile | 92 --------------- 4 files changed, 140 insertions(+), 197 deletions(-) rename tests/{e2e => docker}/token/token_test.go (58%) delete mode 100644 tests/e2e/token/Vagrantfile diff --git a/.github/workflows/e2e.yaml b/.github/workflows/e2e.yaml index 8960e2b7a25..8731e4bf919 100644 --- a/.github/workflows/e2e.yaml +++ b/.github/workflows/e2e.yaml @@ -160,7 +160,7 @@ jobs: strategy: fail-fast: false matrix: - dtest: [basics, bootstraptoken, cacerts, etcd, lazypull, skew, snapshotrestore, upgrade] + dtest: [basics, bootstraptoken, cacerts, etcd, lazypull, skew, snapshotrestore, token, upgrade] arch: [amd64, arm64] runs-on: ${{ matrix.arch == 'arm64' && 'ubuntu-24.04-arm' || 'ubuntu-latest' }} env: diff --git a/tests/docker/test-helpers.go b/tests/docker/test-helpers.go index bc5baacf146..41b5b93e70d 100644 --- a/tests/docker/test-helpers.go +++ b/tests/docker/test-helpers.go @@ -22,6 +22,7 @@ type TestConfig struct { Token string K3sImage string DBType string + SkipStart bool Servers []Server Agents []DockerNode ServerYaml string @@ -101,21 +102,11 @@ func (config *TestConfig) ProvisionServers(numOfServers int) error { testID := filepath.Base(config.TestDir) name := fmt.Sprintf("server-%d-%s", i, strings.ToLower(testID)) - port := getPort() if port == -1 { return fmt.Errorf("failed to find an available port") } - // Write the server yaml to a tmp file and mount it into the container - var yamlMount string - if config.ServerYaml != "" { - if err := os.WriteFile(filepath.Join(config.TestDir, fmt.Sprintf("server-%d.yaml", i)), []byte(config.ServerYaml), 0644); err != nil { - return fmt.Errorf("failed to write server yaml: %v", err) - } - yamlMount = fmt.Sprintf("--mount type=bind,src=%s,dst=/etc/rancher/k3s/config.yaml", filepath.Join(config.TestDir, fmt.Sprintf("server-%d.yaml", i))) - } - var joinServer string var dbConnect string var err error @@ -146,6 +137,11 @@ func (config *TestConfig) ProvisionServers(numOfServers int) error { Port: port, } + var skipStart string + if config.SkipStart { + skipStart = "INSTALL_K3S_SKIP_START=true" + } + // If we need restarts, we use the systemd-node container, volume mount the k3s binary // and start the server using the install script if config.K3sImage == "rancher/systemd-node" { @@ -162,7 +158,6 @@ func (config *TestConfig) ProvisionServers(numOfServers int) error { "-v", "/lib/modules:/lib/modules", "-v", "/var/run/docker.sock:/var/run/docker.sock", "-v", "/var/lib/docker:/var/lib/docker", - yamlMount, "--mount", "type=bind,source=$(pwd)/../../../dist/artifacts/k3s,target=/usr/local/bin/k3s", fmt.Sprintf("%s:v0.0.5", config.K3sImage), "/usr/lib/systemd/systemd --unit=noop.target --show-status=true"}, " ") @@ -174,13 +169,38 @@ func (config *TestConfig) ProvisionServers(numOfServers int) error { if out, err := newServer.RunCmdOnNode(cmd); err != nil { return fmt.Errorf("failed to create coverage directory: %s: %v", out, err) } - // The pipe requires that we use sh -c with "" to run the command - cmd = fmt.Sprintf("/bin/sh -c \"curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC='%s' INSTALL_K3S_SKIP_DOWNLOAD=true sh -\"", - dbConnect+" "+joinServer+" "+os.Getenv(fmt.Sprintf("SERVER_%d_ARGS", i))) + + // Create empty config.yaml for later use + cmd = "mkdir -p /etc/rancher/k3s; touch /etc/rancher/k3s/config.yaml" if out, err := newServer.RunCmdOnNode(cmd); err != nil { - return fmt.Errorf("failed to start server: %s: %v", out, err) + return fmt.Errorf("failed to create empty config.yaml: %s: %v", out, err) + } + // Write the raw YAML directly to the config.yaml on the systemd-node container + if config.ServerYaml != "" { + cmd = fmt.Sprintf("echo \"%s\" > /etc/rancher/k3s/config.yaml", config.ServerYaml) + if out, err := newServer.RunCmdOnNode(cmd); err != nil { + return fmt.Errorf("failed to write server yaml: %s: %v", out, err) + } + } + + // The pipe requires that we use sh -c with "" to run the command + cmd = fmt.Sprintf("/bin/sh -c \"curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC='%s' %s INSTALL_K3S_SKIP_DOWNLOAD=true sh -\"", + dbConnect+" "+joinServer+" "+os.Getenv(fmt.Sprintf("SERVER_%d_ARGS", i)), skipStart) + if _, err := newServer.RunCmdOnNode(cmd); err != nil { + // Attempt to dump the last few lines of the journalctl logs + logs, _ := newServer.DumpServiceLogs(10) + return fmt.Errorf("failed to start server: %s: %v", logs, err) } } else { + // Write the server yaml to the testing directory and mount it into the container + var yamlMount string + if config.ServerYaml != "" { + if err := os.WriteFile(filepath.Join(config.TestDir, fmt.Sprintf("server-%d.yaml", i)), []byte(config.ServerYaml), 0644); err != nil { + return fmt.Errorf("failed to write server yaml: %v", err) + } + yamlMount = fmt.Sprintf("--mount type=bind,src=%s,dst=/etc/rancher/k3s/config.yaml", filepath.Join(config.TestDir, fmt.Sprintf("server-%d.yaml", i))) + } + // Assemble all the Docker args dRun := strings.Join([]string{"docker run -d", "--name", name, @@ -222,9 +242,12 @@ func (config *TestConfig) ProvisionServers(numOfServers int) error { } } + if config.SkipStart { + return nil + } // Wait for kubeconfig to be available time.Sleep(5 * time.Second) - return copyAndModifyKubeconfig(config) + return CopyAndModifyKubeconfig(config) } // setupDatabase will start the configured database if startDB is true, @@ -279,6 +302,10 @@ func (config *TestConfig) ProvisionAgents(numOfAgents int) error { Name: name, } + var skipStart string + if config.SkipStart { + skipStart = "INSTALL_K3S_SKIP_START=true" + } if config.K3sImage == "rancher/systemd-node" { dRun := strings.Join([]string{"docker run -d", "--name", name, @@ -298,12 +325,27 @@ func (config *TestConfig) ProvisionAgents(numOfAgents int) error { return fmt.Errorf("failed to start systemd container: %s: %v", out, err) } time.Sleep(5 * time.Second) - // The pipe requires that we use sh -c with "" to run the command - sCmd := fmt.Sprintf("/bin/sh -c \"curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC='agent %s' INSTALL_K3S_SKIP_DOWNLOAD=true sh -\"", - os.Getenv(agentInstanceArgs)) - if out, err := newAgent.RunCmdOnNode(sCmd); err != nil { - return fmt.Errorf("failed to start server: %s: %v", out, err) + // Create empty config.yaml for later use + cmd := "mkdir -p /etc/rancher/k3s; touch /etc/rancher/k3s/config.yaml" + if out, err := newAgent.RunCmdOnNode(cmd); err != nil { + return fmt.Errorf("failed to create empty config.yaml: %s: %v", out, err) + } + // Write the raw YAML directly to the config.yaml on the systemd-node container + if config.AgentYaml != "" { + cmd = fmt.Sprintf("echo \"%s\" > /etc/rancher/k3s/config.yaml", config.ServerYaml) + if out, err := newAgent.RunCmdOnNode(cmd); err != nil { + return fmt.Errorf("failed to write server yaml: %s: %v", out, err) + } + } + + // The pipe requires that we use sh -c with "" to run the command + sCmd := fmt.Sprintf("/bin/sh -c \"curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC='agent %s' %s INSTALL_K3S_SKIP_DOWNLOAD=true sh -\"", + os.Getenv(agentInstanceArgs), skipStart) + if _, err := newAgent.RunCmdOnNode(sCmd); err != nil { + // Attempt to dump the last few lines of the journalctl logs + logs, _ := newAgent.DumpServiceLogs(10) + return fmt.Errorf("failed to start server: %s: %v", logs, err) } } else { // Assemble all the Docker args @@ -358,15 +400,29 @@ func (config *TestConfig) RemoveNode(nodeName string) error { return nil } +// Returns a list of all server names +func (config *TestConfig) GetServerNames() []string { + var serverNames []string + for _, server := range config.Servers { + serverNames = append(serverNames, server.Name) + } + return serverNames +} + +// Returns a list of all agent names +func (config *TestConfig) GetAgentNames() []string { + var agentNames []string + for _, agent := range config.Agents { + agentNames = append(agentNames, agent.Name) + } + return agentNames +} + // Returns a list of all node names func (config *TestConfig) GetNodeNames() []string { var nodeNames []string - for _, server := range config.Servers { - nodeNames = append(nodeNames, server.Name) - } - for _, agent := range config.Agents { - nodeNames = append(nodeNames, agent.Name) - } + nodeNames = append(nodeNames, config.GetServerNames()...) + nodeNames = append(nodeNames, config.GetAgentNames()...) return nodeNames } @@ -412,9 +468,9 @@ func (config *TestConfig) Cleanup() error { return nil } -// copyAndModifyKubeconfig copies out kubeconfig from first control-plane server +// CopyAndModifyKubeconfig copies out kubeconfig from first control-plane server // and updates the port to match the external port -func copyAndModifyKubeconfig(config *TestConfig) error { +func CopyAndModifyKubeconfig(config *TestConfig) error { if len(config.Servers) == 0 { return fmt.Errorf("no servers available to copy kubeconfig") } @@ -499,6 +555,21 @@ func VerifyValidVersion(node Server, binary string) error { return nil } +// Dump the journalctl logs for the k3s service +func (node DockerNode) DumpServiceLogs(lines int) (string, error) { + var cmd string + if strings.Contains(node.Name, "agent") { + cmd = fmt.Sprintf("journalctl -u k3s-agent -n %d", lines) + } else { + cmd = fmt.Sprintf("journalctl -u k3s -n %d", lines) + } + res, err := node.RunCmdOnNode(cmd) + if strings.Contains(res, "No entries") { + return "", fmt.Errorf("no logs found") + } + return res, err +} + // Returns the latest version from the update channel func GetVersionFromChannel(upgradeChannel string) (string, error) { url := fmt.Sprintf("https://update.k3s.io/v1-release/channels/%s", upgradeChannel) diff --git a/tests/e2e/token/token_test.go b/tests/docker/token/token_test.go similarity index 58% rename from tests/e2e/token/token_test.go rename to tests/docker/token/token_test.go index 180ea202db3..553dddb469d 100644 --- a/tests/e2e/token/token_test.go +++ b/tests/docker/token/token_test.go @@ -3,72 +3,49 @@ package snapshotrestore import ( "flag" "fmt" - "os" "testing" "time" "github.com/k3s-io/k3s/tests" - "github.com/k3s-io/k3s/tests/e2e" + "github.com/k3s-io/k3s/tests/docker" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) -// Valid nodeOS: -// bento/ubuntu-24.04, opensuse/Leap-15.6.x86_64 -// eurolinux-vagrant/rocky-8, eurolinux-vagrant/rocky-9, - -var nodeOS = flag.String("nodeOS", "bento/ubuntu-24.04", "VM operating system") -var serverCount = flag.Int("serverCount", 3, "number of server nodes") -var agentCount = flag.Int("agentCount", 2, "number of agent nodes") var ci = flag.Bool("ci", false, "running on CI") -var local = flag.Bool("local", false, "deploy a locally built K3s binary") +var tc *docker.TestConfig +var snapshotname string -// Environment Variables Info: -// E2E_RELEASE_VERSION=v1.27.1+k3s2 (default: latest commit from master) - -func Test_E2EToken(t *testing.T) { +func Test_DockerToken(t *testing.T) { RegisterFailHandler(Fail) flag.Parse() suiteConfig, reporterConfig := GinkgoConfiguration() - RunSpecs(t, "SnapshotRestore Test Suite", suiteConfig, reporterConfig) + RunSpecs(t, "Token Test Suite", suiteConfig, reporterConfig) } -var tc *e2e.TestConfig - -var _ = ReportAfterEach(e2e.GenReport) - var _ = Describe("Use the token CLI to create and join agents", Ordered, func() { - Context("Agent joins with permanent token:", func() { - It("Starts up with no issues", func() { + Context("Setup cluster with 3 servers", func() { + It("should provision servers and agents", func() { var err error - if *local { - tc, err = e2e.CreateLocalCluster(*nodeOS, *serverCount, *agentCount) - } else { - tc, err = e2e.CreateCluster(*nodeOS, *serverCount, *agentCount) - } - Expect(err).NotTo(HaveOccurred(), e2e.GetVagrantLog(err)) - By("CLUSTER CONFIG") - By("OS: " + *nodeOS) - By(tc.Status()) - - }) - - It("Checks node and pod status", func() { - By("Fetching Nodes status") - Eventually(func(g Gomega) { - nodes, err := e2e.ParseNodes(tc.KubeconfigFile, false) - g.Expect(err).NotTo(HaveOccurred()) - for _, node := range nodes { - g.Expect(node.Status).Should(Equal("Ready")) - } - }, "420s", "5s").Should(Succeed()) - + tc, err = docker.NewTestConfig("rancher/systemd-node") + Expect(err).NotTo(HaveOccurred()) + Expect(tc.ProvisionServers(3)).To(Succeed()) + tc.SkipStart = true + Expect(tc.ProvisionAgents(2)).To(Succeed()) Eventually(func() error { - return tests.AllPodsUp(tc.KubeconfigFile) - }, "360s", "5s").Should(Succeed()) - e2e.DumpPods(tc.KubeconfigFile) + return tests.CheckDefaultDeployments(tc.KubeconfigFile) + }, "60s", "5s").Should(Succeed()) + Eventually(func() error { + return tests.NodesReady(tc.KubeconfigFile, tc.GetServerNames()) + }, "40s", "5s").Should(Succeed()) + // Agents are opening alot of files, so expand the limit + for _, node := range tc.Agents { + _, err := node.RunCmdOnNode("sysctl -w fs.inotify.max_user_instances=8192") + Expect(err).NotTo(HaveOccurred()) + } }) - + }) + Context("Agent joins with permanent token:", func() { var permToken string It("Creates a permanent agent token", func() { permToken = "perage.s0xt4u0hl5guoyi6" @@ -80,19 +57,17 @@ var _ = Describe("Use the token CLI to create and join agents", Ordered, func() Expect(res).To(MatchRegexp(`perage\s+\s+`)) }) It("Joins an agent with the permanent token", func() { - cmd := fmt.Sprintf("echo 'token: %s' | sudo tee -a /etc/rancher/k3s/config.yaml > /dev/null", permToken) + // wrap in bash to handle pipe + cmd := fmt.Sprintf("/bin/bash -c \"echo 'token: %s' | tee -a /etc/rancher/k3s/config.yaml > /dev/null\"", permToken) _, err := tc.Agents[0].RunCmdOnNode(cmd) Expect(err).NotTo(HaveOccurred()) _, err = tc.Agents[0].RunCmdOnNode("systemctl start k3s-agent") Expect(err).NotTo(HaveOccurred()) Eventually(func(g Gomega) { - nodes, err := e2e.ParseNodes(tc.KubeconfigFile, false) + nodes, err := tests.ParseNodes(tc.KubeconfigFile) g.Expect(err).NotTo(HaveOccurred()) g.Expect(len(nodes)).Should(Equal(len(tc.Servers) + 1)) - for _, node := range nodes { - g.Expect(node.Status).Should(Equal("Ready")) - } }, "60s", "5s").Should(Succeed()) }) }) @@ -120,30 +95,29 @@ var _ = Describe("Use the token CLI to create and join agents", Ordered, func() Expect(res).To(MatchRegexp(`10mint\s+[0-9]m`)) }) It("Joins an agent with the 10m token", func() { - cmd := fmt.Sprintf("echo 'token: %s' | sudo tee -a /etc/rancher/k3s/config.yaml > /dev/null", tempToken) + cmd := fmt.Sprintf("/bin/bash -c \"echo 'token: %s' | tee -a /etc/rancher/k3s/config.yaml > /dev/null\"", tempToken) _, err := tc.Agents[1].RunCmdOnNode(cmd) Expect(err).NotTo(HaveOccurred()) _, err = tc.Agents[1].RunCmdOnNode("systemctl start k3s-agent") Expect(err).NotTo(HaveOccurred()) Eventually(func(g Gomega) { - nodes, err := e2e.ParseNodes(tc.KubeconfigFile, false) + nodes, err := tests.ParseNodes(tc.KubeconfigFile) g.Expect(err).NotTo(HaveOccurred()) g.Expect(len(nodes)).Should(Equal(len(tc.Servers) + 2)) - for _, node := range nodes { - g.Expect(node.Status).Should(Equal("Ready")) - } + g.Expect(tests.NodesReady(tc.KubeconfigFile, tc.GetNodeNames())).Should(Succeed()) }, "60s", "5s").Should(Succeed()) }) }) Context("Rotate server bootstrap token", func() { serverToken := "1234" It("Creates a new server token", func() { - Expect(tc.Servers[0].RunCmdOnNode("k3s token rotate -t vagrant --new-token=" + serverToken)). + cmd := fmt.Sprintf("k3s token rotate -t %s --new-token=%s", tc.Token, serverToken) + Expect(tc.Servers[0].RunCmdOnNode(cmd)). To(ContainSubstring("Token rotated, restart k3s nodes with new token")) }) It("Restarts servers with the new token", func() { - cmd := fmt.Sprintf("sed -i 's/token:.*/token: %s/' /etc/rancher/k3s/config.yaml", serverToken) + cmd := fmt.Sprintf("/bin/bash -c \"echo 'token: %s' | tee -a /etc/rancher/k3s/config.yaml > /dev/null\"", serverToken) for _, node := range tc.Servers { _, err := node.RunCmdOnNode(cmd) Expect(err).NotTo(HaveOccurred()) @@ -153,12 +127,10 @@ var _ = Describe("Use the token CLI to create and join agents", Ordered, func() Expect(err).NotTo(HaveOccurred()) } Eventually(func(g Gomega) { - nodes, err := e2e.ParseNodes(tc.KubeconfigFile, false) + nodes, err := tests.ParseNodes(tc.KubeconfigFile) g.Expect(err).NotTo(HaveOccurred()) g.Expect(len(nodes)).Should(Equal(len(tc.Servers) + 2)) - for _, node := range nodes { - g.Expect(node.Status).Should(Equal("Ready")) - } + g.Expect(tests.NodesReady(tc.KubeconfigFile, tc.GetNodeNames())).Should(Succeed()) }, "60s", "5s").Should(Succeed()) }) It("Rejoins an agent with the new server token", func() { @@ -169,12 +141,10 @@ var _ = Describe("Use the token CLI to create and join agents", Ordered, func() Expect(err).NotTo(HaveOccurred()) Eventually(func(g Gomega) { - nodes, err := e2e.ParseNodes(tc.KubeconfigFile, false) + nodes, err := tests.ParseNodes(tc.KubeconfigFile) g.Expect(err).NotTo(HaveOccurred()) g.Expect(len(nodes)).Should(Equal(len(tc.Servers) + 2)) - for _, node := range nodes { - g.Expect(node.Status).Should(Equal("Ready")) - } + g.Expect(tests.NodesReady(tc.KubeconfigFile, tc.GetNodeNames())).Should(Succeed()) }, "60s", "5s").Should(Succeed()) }) }) @@ -186,13 +156,7 @@ var _ = AfterEach(func() { }) var _ = AfterSuite(func() { - if failed { - AddReportEntry("journald-logs", e2e.TailJournalLogs(1000, append(tc.Servers, tc.Agents...))) - } else { - Expect(e2e.GetCoverageReport(append(tc.Servers, tc.Agents...))).To(Succeed()) - } - if !failed || *ci { - Expect(e2e.DestroyCluster()).To(Succeed()) - Expect(os.Remove(tc.KubeconfigFile)).To(Succeed()) + if *ci || (tc != nil && !failed) { + Expect(tc.Cleanup()).To(Succeed()) } }) diff --git a/tests/e2e/token/Vagrantfile b/tests/e2e/token/Vagrantfile deleted file mode 100644 index d0530b8b9c1..00000000000 --- a/tests/e2e/token/Vagrantfile +++ /dev/null @@ -1,92 +0,0 @@ -ENV['VAGRANT_NO_PARALLEL'] = 'no' -NODE_ROLES = (ENV['E2E_NODE_ROLES'] || - ["server-0", "server-1", "server-2", "agent-0", "agent-1"]) -NODE_BOXES = (ENV['E2E_NODE_BOXES'] || - ['bento/ubuntu-24.04', 'bento/ubuntu-24.04', 'bento/ubuntu-24.04']) -GITHUB_BRANCH = (ENV['E2E_GITHUB_BRANCH'] || "master") -RELEASE_VERSION = (ENV['E2E_RELEASE_VERSION'] || "") -GOCOVER = (ENV['E2E_GOCOVER'] || "") -NODE_CPUS = (ENV['E2E_NODE_CPUS'] || 2).to_i -NODE_MEMORY = (ENV['E2E_NODE_MEMORY'] || 2048).to_i -# This key must be created using tailscale web -NETWORK_PREFIX = "10.10.10" -install_type = "" - -def provision(vm, roles, role_num, node_num) - vm.box = NODE_BOXES[node_num] - vm.hostname = "#{roles[0]}-#{role_num}" - node_ip = "#{NETWORK_PREFIX}.#{100+node_num}" - vm.network "private_network", ip: node_ip, netmask: "255.255.255.0" - - scripts_location = Dir.exist?("./scripts") ? "./scripts" : "../scripts" - vagrant_defaults = File.exist?("./vagrantdefaults.rb") ? "./vagrantdefaults.rb" : "../vagrantdefaults.rb" - load vagrant_defaults - - defaultOSConfigure(vm) - addCoverageDir(vm, roles, GOCOVER) - install_type = getInstallType(vm, RELEASE_VERSION, GITHUB_BRANCH) - - vm.provision "Ping Check", type: "shell", inline: "ping -c 2 k3s.io" - - if roles.include?("server") && role_num == 0 - vm.provision :k3s, run: 'once' do |k3s| - k3s.config_mode = '0644' # side-step https://github.com/k3s-io/k3s/issues/4321 - k3s.args = "server " - k3s.config = <<~YAML - cluster-init: true - token: vagrant - node-external-ip: #{node_ip} - flannel-iface: eth1 - YAML - k3s.env = ["K3S_KUBECONFIG_MODE=0644", install_type] - end - elsif roles.include?("server") && role_num != 0 - vm.provision 'k3s-secondary-server', type: 'k3s', run: 'once' do |k3s| - k3s.config_mode = '0644' # side-step https://github.com/k3s-io/k3s/issues/4321 - k3s.args = "server" - k3s.config = <<~YAML - server: "https://#{NETWORK_PREFIX}.100:6443" - token: vagrant - node-external-ip: #{node_ip} - flannel-iface: eth1 - YAML - k3s.env = ["K3S_KUBECONFIG_MODE=0644", install_type] - end - end - if roles.include?("agent") - vm.provision :k3s, run: 'once' do |k3s| - k3s.config_mode = '0644' # side-step https://github.com/k3s-io/k3s/issues/4321 - k3s.args = "agent " - k3s.config = <<~YAML - server: "https://#{NETWORK_PREFIX}.100:6443" - node-external-ip: #{node_ip} - flannel-iface: eth1 - YAML - k3s.env = ["K3S_KUBECONFIG_MODE=0644", "INSTALL_K3S_SKIP_START=true", install_type] - end - end -end - -Vagrant.configure("2") do |config| - config.vagrant.plugins = ["vagrant-k3s", "vagrant-reload", "vagrant-libvirt", "vagrant-scp"] - config.vm.provider "libvirt" do |v| - v.cpus = NODE_CPUS - v.memory = NODE_MEMORY - # We replicate the default prefix, but add a timestamp to enable parallel runs and cleanup of old VMs - v.default_prefix = File.basename(Dir.getwd) + "_" + Time.now.to_i.to_s + "_" - end - - if NODE_ROLES.kind_of?(String) - NODE_ROLES = NODE_ROLES.split(" ", -1) - end - if NODE_BOXES.kind_of?(String) - NODE_BOXES = NODE_BOXES.split(" ", -1) - end - - NODE_ROLES.each_with_index do |role, i| - role_num = role.split("-", -1).pop.to_i - config.vm.define role do |node| - provision(node.vm, role, role_num, i) - end - end -end