From df2b8ccc206674f60a4b7e016cb5d9ea319ec283 Mon Sep 17 00:00:00 2001 From: niwo Date: Wed, 4 May 2016 21:58:18 +0200 Subject: [PATCH 01/36] correct offer to compute_offer in README --- README.md | 5 +++-- lib/cloudstack-cli/base.rb | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 48e0319..2a77c76 100644 --- a/README.md +++ b/README.md @@ -162,15 +162,16 @@ Completed: 2/3 (15.4s) ### Example: Sort computing offerings *Sort all computing offerings by CPU and Memory grouped by domain:* +(root admin privileges needed) ```bash -$ cloudstack-cli offering sort +$ cloudstack-cli compute_offer sort ``` ### Example: Stop all backup routers of a given project *Stop all virtual routers of project named Demo (you could filter by zone too):* -(This command is helpful if you have to deploy new versions of CloudStack when using redundant routers) +(this command is helpful if you have to deploy new major release of CloudStack when using redundant routers) ```bash $ cloudstack-cli router list --project Demo --status running --redundant-state BACKUP --command STOP diff --git a/lib/cloudstack-cli/base.rb b/lib/cloudstack-cli/base.rb index 0fd4525..32ffebf 100644 --- a/lib/cloudstack-cli/base.rb +++ b/lib/cloudstack-cli/base.rb @@ -134,5 +134,6 @@ def parse_file(file, extensions = %w(.json .yaml .yml)) end end end - end -end + + end # class +end # module From 88f5314d97d6a57240e992acfa3798e591f2f403 Mon Sep 17 00:00:00 2001 From: niwo Date: Wed, 4 May 2016 23:35:29 +0200 Subject: [PATCH 02/36] handle case when list_virtual_machines returns multiple results, improved volume detach command --- Gemfile.lock | 4 +- .../commands/virtual_machine.rb | 55 ++++++++----------- lib/cloudstack-cli/commands/volume.rb | 6 +- lib/cloudstack-cli/helper.rb | 2 +- lib/cloudstack-cli/option_resolver.rb | 17 ++++-- lib/cloudstack-cli/version.rb | 2 +- 6 files changed, 43 insertions(+), 43 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 9f38857..e032130 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -6,7 +6,7 @@ PATH PATH remote: . specs: - cloudstack-cli (1.5.2) + cloudstack-cli (1.5.3) cloudstack_client (~> 1.4) thor (~> 0.19) @@ -25,4 +25,4 @@ DEPENDENCIES rake (~> 11.1) BUNDLED WITH - 1.11.2 + 1.12.0 diff --git a/lib/cloudstack-cli/commands/virtual_machine.rb b/lib/cloudstack-cli/commands/virtual_machine.rb index b14ba13..048297b 100644 --- a/lib/cloudstack-cli/commands/virtual_machine.rb +++ b/lib/cloudstack-cli/commands/virtual_machine.rb @@ -63,15 +63,12 @@ def list_from_file(file) option :project def show(name) resolve_project - options[:name] = name - unless virtual_machine = client.list_virtual_machines({list_all: true}.merge options).first - puts "No virtual machine found." - else - table = virtual_machine.map do |key, value| - [ set_color("#{key}:", :yellow), "#{value}" ] - end - print_table table + options[:virtual_machine] = name + virtual_machine = resolve_virtual_machine(true) + table = virtual_machine.map do |key, value| + [ set_color("#{key}:", :yellow), "#{value}" ] end + print_table table end desc "create NAME [NAME2 ...]", "create virtual machine(s)" @@ -149,14 +146,13 @@ def destroy(*names) say "Please provide at least one virtual machine name.", :yellow exit 1 end - resolve_project names.each do |name| - unless virtual_machine = client.list_virtual_machines(options.merge(name: name, listall: true)).first + unless virtual_machine = find_vm_by_name(name) say "Virtual machine #{name} not found.", :red else action = options[:expunge] ? "Expunge" : "Destroy" - ask = "#{action} #{name} (#{virtual_machine['state']})? [y/N]:" + ask = "#{action} #{virtual_machine['name']} (#{virtual_machine['state']})? [y/N]:" if options[:force] || yes?(ask, :yellow) say "destroying #{name} " client.destroy_virtual_machine( @@ -179,13 +175,12 @@ def create_interactive option :force def stop(name) resolve_project - options[:name] = name - options[:listall] = true - exit unless options[:force] || yes?("Stop virtual machine #{name}? [y/N]:", :magenta) - unless virtual_machine = client.list_virtual_machines(options).first + unless virtual_machine = find_vm_by_name(name) say "Virtual machine #{name} not found.", :red exit 1 end + exit unless options[:force] || + yes?("Stop virtual machine #{virtual_machine['name']}? [y/N]:", :magenta) client.stop_virtual_machine(id: virtual_machine['id']) puts end @@ -194,13 +189,11 @@ def stop(name) option :project def start(name) resolve_project - options[:name] = name - options[:listall] = true - unless virtual_machine = client.list_virtual_machines(options).first + unless virtual_machine = find_vm_by_name(name) say "Virtual machine #{name} not found.", :red exit 1 end - say("Starting virtual machine #{name}", :magenta) + say("Starting virtual machine #{virtual_machine['name']}", :magenta) client.start_virtual_machine(id: virtual_machine['id']) puts end @@ -210,13 +203,11 @@ def start(name) option :force def reboot(name) resolve_project - options[:name] = name - options[:listall] = true - unless virtual_machine = client.list_virtual_machines(options).first + unless virtual_machine = find_vm_by_name(name) say "Virtual machine #{name} not found.", :red exit 1 end - exit unless options[:force] || yes?("Reboot virtual_machine #{name}? [y/N]:", :magenta) + exit unless options[:force] || yes?("Reboot virtual_machine #{virtual_machine["name"]}? [y/N]:", :magenta) client.reboot_virtual_machine(id: virtual_machine['id']) puts end @@ -248,30 +239,22 @@ def reboot(name) desc: "optional binary data that can be sent to the virtual machine upon a successful deployment." def update(name) resolve_project - - unless vm = client.list_virtual_machines( - name: name, project_id: options[:project_id], listall: true - ).first + unless vm = find_vm_by_name(name) say "Virtual machine #{name} not found.", :red exit 1 end - unless vm["state"].downcase == "stopped" say "Virtual machine #{name} (#{vm["state"]}) must be in a stopped state.", :red exit 1 end - unless options[:force] || yes?("Update virtual_machine #{name}? [y/N]:", :magenta) exit end - if options[:user_data] # base64 encode user_data options[:user_data] = [options[:user_data]].pack("m") end - vm = client.update_virtual_machine(options.merge(id: vm['id'])) - say "Virtual machine \"#{name}\" has been updated:", :green table = vm.select do |k, _| @@ -284,6 +267,14 @@ def update(name) no_commands do + def find_vm_by_name(name) + client.list_virtual_machines( + name: options[:virtual_machine], + listall: true, + project_id: options[:project_id] + ).find {|vm| vm["name"] == name } + end + def print_virtual_machines(virtual_machines) case options[:format].to_sym when :yaml diff --git a/lib/cloudstack-cli/commands/volume.rb b/lib/cloudstack-cli/commands/volume.rb index b5075a4..51bee10 100644 --- a/lib/cloudstack-cli/commands/volume.rb +++ b/lib/cloudstack-cli/commands/volume.rb @@ -113,7 +113,7 @@ def create(name) desc "attach NAME", "attach volume to VM" option :project, desc: 'project of volume' - option :virtual_machine, desc: 'virtual machine of volume' + option :virtual_machine, desc: 'virtual machine of volume', required: true def attach(name) resolve_project resolve_virtual_machine @@ -142,6 +142,7 @@ def attach(name) desc "detach NAME", "detach volume from VM" option :project, desc: 'project of volume' + option :force def detach(name) resolve_project @@ -158,7 +159,8 @@ def detach(name) say "Error: Volume #{name} currently not attached to any VM.", :red exit 1 end - + exit unless options[:force] || + yes?("Detach volume #{name} from virtual_machine #{volume["vmname"]}? [y/N]:", :magenta) say "Detach volume #{name} from VM #{volume["vmname"]} " client.detach_volume id: volume['id'] say " OK.", :green diff --git a/lib/cloudstack-cli/helper.rb b/lib/cloudstack-cli/helper.rb index 6b522f6..d8f8efd 100644 --- a/lib/cloudstack-cli/helper.rb +++ b/lib/cloudstack-cli/helper.rb @@ -232,7 +232,7 @@ def bootstrap_server_interactive print_options(server_offerings) service_offering = ask_number("Offering Nr.: ") - templates = client.list_templates(project_id: project_id, zone_id: zones[zone]["id"], template_filter: "all") + templates = client.list_templates(project_id: project_id, zone_id: zones[zone]["id"], template_filter: "executable") say "Select a template:", :yellow print_options(templates) template = ask_number("Template Nr.: ") diff --git a/lib/cloudstack-cli/option_resolver.rb b/lib/cloudstack-cli/option_resolver.rb index 7551c2d..2541b5d 100644 --- a/lib/cloudstack-cli/option_resolver.rb +++ b/lib/cloudstack-cli/option_resolver.rb @@ -195,15 +195,22 @@ def resolve_disk_offering options end - def resolve_virtual_machine + def resolve_virtual_machine(return_vm = false) if options[:virtual_machine] - args = { name: options[:virtual_machine], listall: true } - args[:project_id] = options[:project_id] - unless vm = client.list_virtual_machines(args).first + unless vm = client.list_virtual_machines( + name: options[:virtual_machine], + listall: true, + project_id: options[:project_id] + ).find {|vm| vm["name"] == options[:virtual_machine] } say "Error: VM '#{options[:virtual_machine]}' not found.", :red exit 1 end - options[:virtual_machine_id] = vm['id'] + + if return_vm + return vm + else + options[:virtual_machine_id] = vm["id"] + end end options end diff --git a/lib/cloudstack-cli/version.rb b/lib/cloudstack-cli/version.rb index 667124d..7793055 100644 --- a/lib/cloudstack-cli/version.rb +++ b/lib/cloudstack-cli/version.rb @@ -1,3 +1,3 @@ module CloudstackCli - VERSION = "1.5.2" + VERSION = "1.5.3" end From 047b59aa963c562ef1af83dc3f7c84193165b625 Mon Sep 17 00:00:00 2001 From: niwo Date: Sun, 12 Jun 2016 00:35:15 +0200 Subject: [PATCH 03/36] improving pf_rule creation and adding limit option to stack commands --- Gemfile.lock | 8 +- cloudstack-cli.gemspec | 2 +- lib/cloudstack-cli/commands/stack.rb | 91 +++++++------ .../commands/virtual_machine.rb | 12 +- lib/cloudstack-cli/helper.rb | 128 ++++++++---------- lib/cloudstack-cli/version.rb | 2 +- 6 files changed, 120 insertions(+), 123 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index e032130..e1dbe4a 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,7 +1,7 @@ PATH remote: ../cloudstack_client/ specs: - cloudstack_client (1.4.1) + cloudstack_client (1.4.3) PATH remote: . @@ -13,7 +13,7 @@ PATH GEM remote: https://rubygems.org/ specs: - rake (11.1.2) + rake (11.2.0) thor (0.19.1) PLATFORMS @@ -22,7 +22,7 @@ PLATFORMS DEPENDENCIES cloudstack-cli! cloudstack_client! - rake (~> 11.1) + rake (~> 11.2) BUNDLED WITH - 1.12.0 + 1.12.4 diff --git a/cloudstack-cli.gemspec b/cloudstack-cli.gemspec index 26ae52d..90df66b 100644 --- a/cloudstack-cli.gemspec +++ b/cloudstack-cli.gemspec @@ -21,7 +21,7 @@ Gem::Specification.new do |gem| gem.require_paths = %w(lib) gem.rdoc_options = %w[--line-numbers --inline-source] - gem.add_development_dependency('rake', '~> 11.1') + gem.add_development_dependency('rake', '~> 11.2') gem.add_dependency('cloudstack_client', '~> 1.4') gem.add_dependency('thor', '~> 0.19') diff --git a/lib/cloudstack-cli/commands/stack.rb b/lib/cloudstack-cli/commands/stack.rb index 8c2428e..904affb 100644 --- a/lib/cloudstack-cli/commands/stack.rb +++ b/lib/cloudstack-cli/commands/stack.rb @@ -1,49 +1,52 @@ class Stack < CloudstackCli::Base - desc "create STACKFILE", "create a stack of VMs" + desc "create STACKFILE", "create a stack of VM's" + option :limit, type: :array, aliases: '-l', + desc: "Limit on specific server names." option :skip_forwarding_rules, default: false, type: :boolean, aliases: '-s', desc: "Skip creation of port forwarding rules." def create(stackfile) stack = parse_file(stackfile) project_id = find_project_by_name(stack["project"]) - say "Create stack #{stack["name"]}...", :green jobs = [] stack["servers"].each do |instance| string_to_array(instance["name"]).each do |name| - server = client.list_virtual_machines(name: name, project_id: project_id).first - if server - say "VM #{name} (#{server["state"]}) already exists.", :yellow - jobs << { - id: 0, - name: "Create VM #{name}", - status: 1 - } - else - options.merge!({ - name: name, - displayname: instance["decription"], - zone: instance["zone"] || stack["zone"], - project: stack["project"], - template: instance["template"], - iso: instance["iso"] , - offering: instance["offering"], - networks: load_string_or_array(instance["networks"]), - ip_network_list: instance["ip_network_list"], - disk_offering: instance["disk_offering"], - size: instance["disk_size"], - group: instance["group"] || stack["group"], - keypair: instance["keypair"] || stack["keypair"], - ip_address: instance["ip_address"] - }) - jobs << { - id: client.deploy_virtual_machine( - vm_options_to_params, - {sync: true} - )['jobid'], - name: "Create VM #{name}" - } + if options[:limit].include?(name) + server = client.list_virtual_machines(name: name, project_id: project_id).first + if server + say "VM #{name} (#{server["state"]}) already exists.", :yellow + jobs << { + id: 0, + name: "Create VM #{name}", + status: 1 + } + else + options.merge!({ + name: name, + displayname: instance["decription"], + zone: instance["zone"] || stack["zone"], + project: stack["project"], + template: instance["template"], + iso: instance["iso"] , + offering: instance["offering"], + networks: load_string_or_array(instance["networks"]), + ip_network_list: instance["ip_network_list"], + disk_offering: instance["disk_offering"], + size: instance["disk_size"], + group: instance["group"] || stack["group"], + keypair: instance["keypair"] || stack["keypair"], + ip_address: instance["ip_address"] + }) + jobs << { + id: client.deploy_virtual_machine( + vm_options_to_params, + {sync: true} + )['jobid'], + name: "Create VM #{name}" + } + end end end end @@ -54,20 +57,17 @@ def create(stackfile) jobs = [] stack["servers"].each do |instance| string_to_array(instance["name"]).each do |name| - if port_rules = string_to_array(instance["port_rules"]) + if options[:limit].include?(name) && port_rules = string_to_array(instance["port_rules"]) server = client.list_virtual_machines(name: name, project_id: project_id).first create_port_rules(server, port_rules, false).each_with_index do |job_id, index| - jobs << { - id: job_id, - name: "Create port forwarding rules (#{port_rules[index]}) for VM #{name}" - } + job_name = "Create port forwarding rules (#{port_rules[index]}) for VM #{name}" + jobs << {id: job_id, name: job_name} end end end end watch_jobs(jobs) end - say "Finished.", :green end @@ -82,12 +82,21 @@ def create(stackfile) type: :boolean, default: false, aliases: '-E' + option :limit, type: :array, aliases: '-l', + desc: "Limit on specific server names." def destroy(stackfile) stack = parse_file(stackfile) project_id = find_project_by_name(stack["project"]) servers = [] stack["servers"].each do |server| - string_to_array(server["name"]).each {|name| servers << name} + string_to_array(server["name"]).each do |name| + servers << name if options[:limit].include?(name) + end + end + + if servers.size == 0 + say "No servers in stack selected.", :yellow + exit end if options[:force] || yes?("Destroy the following VM #{servers.join(', ')}? [y/N]:", :yellow) diff --git a/lib/cloudstack-cli/commands/virtual_machine.rb b/lib/cloudstack-cli/commands/virtual_machine.rb index 048297b..33eba8b 100644 --- a/lib/cloudstack-cli/commands/virtual_machine.rb +++ b/lib/cloudstack-cli/commands/virtual_machine.rb @@ -102,15 +102,13 @@ def create(*names) end vm_options_to_params - say "Start deploying virtual machine#{ "s" if names.size > 1 }...", :green + say "Start deploying virtual machine#{"s" if names.size > 1}...", :green jobs = names.map do |name| - if virtual_machine = client.list_virtual_machines(name: name, project_id: options[:project_id]).first + if virtual_machine = client.list_virtual_machines( + name: name, project_id: options[:project_id] + ).first say "virtual machine #{name} (#{virtual_machine["state"]}) already exists.", :yellow - job = { - id: 0, - name: "Create virtual machine #{name}", - status: 1 - } + job = {id: 0, name: "Create virtual machine #{name}", status: 1} else job = { id: client.deploy_virtual_machine(options.merge(name: name), {sync: true})['jobid'], diff --git a/lib/cloudstack-cli/helper.rb b/lib/cloudstack-cli/helper.rb index d8f8efd..e8256d4 100644 --- a/lib/cloudstack-cli/helper.rb +++ b/lib/cloudstack-cli/helper.rb @@ -166,37 +166,63 @@ def create_server(args = {}) end def create_port_rules(server, port_rules, async = true) - frontendip = nil + frontendip_id = nil jobs = [] client.verbose = async project_id = server['projectid'] || nil port_rules.each do |pf_rule| - ip = pf_rule.split(":")[0] - if ip != '' - ip_addr = client.get_public_ip_address(ip, project_id) - unless ip_addr - say "Error: IP #{ip} not found.", :red + pf_rule = pf_rule_to_object(pf_rule) + if pf_rule[:ipaddress] + pub_ip = client.list_public_ip_addresses( + network_id: get_server_default_nic(server)["networkid"], + project_id: project_id, + ipaddress: pf_rule[:ipaddress] + ) + ip_addr = pub_ip.find { |addr| addr['ipaddress'] == pf_rule[:ipaddress]} if pub_ip + if ip_addr + frontendip = ip_addr['id'] + else + say "Error: IP #{pf_rule[:ipaddress]} not found.", :red next end - else - ip_addr = frontendip ||= client.associate_ip_address( - network_id: server["nic"].first["networkid"] - )["ipaddress"] end - port = pf_rule.split(":")[1] - args = { - ipaddressid: ip_addr["id"], - publicport: port, - privateport: port, - protocol: 'TCP', - virtualmachineid: server["id"] - } - if async - say "Create port forwarding rule #{ip_addr['ipaddress']}:#{port} for server #{server["name"]}.", :yellow - client.create_port_forwarding_rule(args) - return + + # check if there is already an existing rule + rules = client.list_port_forwarding_rules( + networkid: get_server_default_nic(server)["networkid"], + ipaddressid: frontendip_id, + projectid: project_id + ) + existing_pf_rules = rules.find do |rule| + # remember matching address for additional rules + frontendip_id = rule['ipaddressid'] if rule['virtualmachineid'] == server['id'] + + rule['virtualmachineid'] == server['id'] && + rule['publicport'] == pf_rule[:publicport] && + rule['privateport'] == pf_rule[:privateport] && + rule['protocol'] == pf_rule[:protocol] + end + + if existing_pf_rules + say "Port forwarding rule on port #{pf_rule[:privateport]} for VM #{server["name"]} already exists.", :yellow else - jobs << client.create_port_forwarding_rule(args, {sync: true})['jobid'] + unless frontendip_id + frontendip_id = client.associate_ip_address( + network_id: get_server_default_nic(server)["networkid"], + project_id: project_id + )['ipaddress']['id'] + end + args = pf_rule.merge({ + ipaddressid: frontendip_id, + virtualmachineid: server["id"] + }) + if async + say "Create port forwarding rule #{pf_rule[:ipaddress]}:#{port} for VM #{server["name"]}.", :yellow + client.create_port_forwarding_rule(args) + return + else + jobs << client.create_port_forwarding_rule(args, {sync: true})['jobid'] + end end end jobs @@ -267,57 +293,21 @@ def bootstrap_server_interactive end end - ## - # Finds the public ip for a server - - def get_server_public_ip(server, cached_rules=nil) - return nil unless server - - # find the public ip - nic = get_server_default_nic(server) || {} - if nic['type'] == 'Virtual' - ssh_rule = get_ssh_port_forwarding_rule(server, cached_rules) - ssh_rule ? ssh_rule['ipaddress'] : nil - else - nic['ipaddress'] - end - end - - ## - # Gets the SSH port forwarding rule for the specified server. - - def get_ssh_port_forwarding_rule(server, cached_rules=nil) - rules = cached_rules || client.list_port_forwarding_rules(project_id: server["projectid"]) || [] - rules.find_all { |r| - r['virtualmachineid'] == server['id'] && - r['privateport'] == '22'&& - r['publicport'] == '22' - }.first - end - - ## - # Returns the fully qualified domain name for a server. - - def get_server_fqdn(server) - return nil unless server - - nic = get_server_default_nic(server) || {} - networks = client.list_networks(project_id: server['projectid']) || {} - - id = nic['networkid'] - network = networks.select { |net| - net['id'] == id - }.first - return nil unless network - - "#{server['name']}.#{network['networkdomain']}" - end - def get_server_default_nic(server) server['nic'].each do |nic| return nic if nic['isdefault'] end end + def pf_rule_to_object(pf_rule) + pf_rule = pf_rule.split(":") + { + ipaddress: (pf_rule[0] == '' ? nil : pf_rule[0]), + privateport: pf_rule[1], + publicport: (pf_rule[2] || pf_rule[1]), + protocol: (pf_rule[3] || 'tcp').downcase + } + end + end end diff --git a/lib/cloudstack-cli/version.rb b/lib/cloudstack-cli/version.rb index 7793055..d5ec278 100644 --- a/lib/cloudstack-cli/version.rb +++ b/lib/cloudstack-cli/version.rb @@ -1,3 +1,3 @@ module CloudstackCli - VERSION = "1.5.3" + VERSION = "1.5.4" end From b544660cce39ed1c0ccadb749b0ba5ac4e30ac1c Mon Sep 17 00:00:00 2001 From: niwo Date: Thu, 4 Aug 2016 22:56:43 +0200 Subject: [PATCH 04/36] updated gems and fix issue with limit option in stack command --- Gemfile.lock | 6 +++--- lib/cloudstack-cli/commands/stack.rb | 4 ++-- lib/cloudstack-cli/version.rb | 2 +- test/ma-test.yml | 10 ++++++++++ 4 files changed, 16 insertions(+), 6 deletions(-) create mode 100644 test/ma-test.yml diff --git a/Gemfile.lock b/Gemfile.lock index e1dbe4a..de8f1a7 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -6,14 +6,14 @@ PATH PATH remote: . specs: - cloudstack-cli (1.5.3) + cloudstack-cli (1.5.4) cloudstack_client (~> 1.4) thor (~> 0.19) GEM remote: https://rubygems.org/ specs: - rake (11.2.0) + rake (11.2.2) thor (0.19.1) PLATFORMS @@ -25,4 +25,4 @@ DEPENDENCIES rake (~> 11.2) BUNDLED WITH - 1.12.4 + 1.12.5 diff --git a/lib/cloudstack-cli/commands/stack.rb b/lib/cloudstack-cli/commands/stack.rb index 904affb..d1f6677 100644 --- a/lib/cloudstack-cli/commands/stack.rb +++ b/lib/cloudstack-cli/commands/stack.rb @@ -13,7 +13,7 @@ def create(stackfile) jobs = [] stack["servers"].each do |instance| string_to_array(instance["name"]).each do |name| - if options[:limit].include?(name) + if !options[:limit] || options[:limit].include?(name) server = client.list_virtual_machines(name: name, project_id: project_id).first if server say "VM #{name} (#{server["state"]}) already exists.", :yellow @@ -57,7 +57,7 @@ def create(stackfile) jobs = [] stack["servers"].each do |instance| string_to_array(instance["name"]).each do |name| - if options[:limit].include?(name) && port_rules = string_to_array(instance["port_rules"]) + if !options[:limit] || options[:limit].include?(name) && port_rules = string_to_array(instance["port_rules"]) server = client.list_virtual_machines(name: name, project_id: project_id).first create_port_rules(server, port_rules, false).each_with_index do |job_id, index| job_name = "Create port forwarding rules (#{port_rules[index]}) for VM #{name}" diff --git a/lib/cloudstack-cli/version.rb b/lib/cloudstack-cli/version.rb index d5ec278..a45cc93 100644 --- a/lib/cloudstack-cli/version.rb +++ b/lib/cloudstack-cli/version.rb @@ -1,3 +1,3 @@ module CloudstackCli - VERSION = "1.5.4" + VERSION = "1.5.5" end diff --git a/test/ma-test.yml b/test/ma-test.yml new file mode 100644 index 0000000..9770f53 --- /dev/null +++ b/test/ma-test.yml @@ -0,0 +1,10 @@ +--- + name: test-from-templ + description: Testinstall from Template + version: 1.0 + zone: ZUERICH_IX + servers: + - name: test-01 + template: web-d2-2015-07-16 + offering: 1cpu_1gb + networks: wolfgrni From 6dff2c23002602af8163586a4ef95f7a4d3f7422 Mon Sep 17 00:00:00 2001 From: niwo Date: Thu, 4 Aug 2016 23:00:52 +0200 Subject: [PATCH 05/36] updated README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2a77c76..9a2355d 100644 --- a/README.md +++ b/README.md @@ -140,7 +140,7 @@ CloudStack CLI does support stack files in YAML or JSON. ip: 10.102.1.11 ``` -*Create the stack of servers from the definition above: +*Create the stack of servers from the definition above:* ```bash $ cloudstack-cli stack create my_stackfile.yml From bd44f6bf981c9522ee994f64e9d7d3d15a13e8d9 Mon Sep 17 00:00:00 2001 From: niwo Date: Fri, 5 Aug 2016 14:08:02 +0200 Subject: [PATCH 06/36] fix limit conditions in stack commands --- Gemfile.lock | 2 +- lib/cloudstack-cli/commands/stack.rb | 6 ++++-- lib/cloudstack-cli/version.rb | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index de8f1a7..fb64b6c 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -6,7 +6,7 @@ PATH PATH remote: . specs: - cloudstack-cli (1.5.4) + cloudstack-cli (1.5.6) cloudstack_client (~> 1.4) thor (~> 0.19) diff --git a/lib/cloudstack-cli/commands/stack.rb b/lib/cloudstack-cli/commands/stack.rb index d1f6677..e166ff9 100644 --- a/lib/cloudstack-cli/commands/stack.rb +++ b/lib/cloudstack-cli/commands/stack.rb @@ -57,7 +57,7 @@ def create(stackfile) jobs = [] stack["servers"].each do |instance| string_to_array(instance["name"]).each do |name| - if !options[:limit] || options[:limit].include?(name) && port_rules = string_to_array(instance["port_rules"]) + if (!options[:limit] || options[:limit].include?(name)) && port_rules = string_to_array(instance["port_rules"]) server = client.list_virtual_machines(name: name, project_id: project_id).first create_port_rules(server, port_rules, false).each_with_index do |job_id, index| job_name = "Create port forwarding rules (#{port_rules[index]}) for VM #{name}" @@ -90,7 +90,9 @@ def destroy(stackfile) servers = [] stack["servers"].each do |server| string_to_array(server["name"]).each do |name| - servers << name if options[:limit].include?(name) + if !options[:limit] || options[:limit].include?(name) + servers << name + end end end diff --git a/lib/cloudstack-cli/version.rb b/lib/cloudstack-cli/version.rb index a45cc93..9d7af1a 100644 --- a/lib/cloudstack-cli/version.rb +++ b/lib/cloudstack-cli/version.rb @@ -1,3 +1,3 @@ module CloudstackCli - VERSION = "1.5.5" + VERSION = "1.5.6" end From 83521fd434439448a4ebb1b06e1010d4eedcb0a2 Mon Sep 17 00:00:00 2001 From: niwo Date: Fri, 21 Oct 2016 22:57:03 +0200 Subject: [PATCH 07/36] add cluster option to list capacity command --- Gemfile.lock | 10 +++++----- README.md | 2 +- cloudstack-cli.gemspec | 4 ++-- lib/cloudstack-cli/commands/capacity.rb | 25 +++++++++++++++---------- lib/cloudstack-cli/option_resolver.rb | 11 +++++++++++ lib/cloudstack-cli/version.rb | 2 +- 6 files changed, 35 insertions(+), 19 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index fb64b6c..f74f329 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -6,14 +6,14 @@ PATH PATH remote: . specs: - cloudstack-cli (1.5.6) - cloudstack_client (~> 1.4) + cloudstack-cli (1.5.7) + cloudstack_client (~> 1.4.3) thor (~> 0.19) GEM remote: https://rubygems.org/ specs: - rake (11.2.2) + rake (11.3.0) thor (0.19.1) PLATFORMS @@ -22,7 +22,7 @@ PLATFORMS DEPENDENCIES cloudstack-cli! cloudstack_client! - rake (~> 11.2) + rake (~> 11.3) BUNDLED WITH - 1.12.5 + 1.13.2 diff --git a/README.md b/README.md index 9a2355d..4aab0f7 100644 --- a/README.md +++ b/README.md @@ -162,7 +162,7 @@ Completed: 2/3 (15.4s) ### Example: Sort computing offerings *Sort all computing offerings by CPU and Memory grouped by domain:* -(root admin privileges needed) +(root admin privileges required) ```bash $ cloudstack-cli compute_offer sort diff --git a/cloudstack-cli.gemspec b/cloudstack-cli.gemspec index 90df66b..d45c8ca 100644 --- a/cloudstack-cli.gemspec +++ b/cloudstack-cli.gemspec @@ -21,8 +21,8 @@ Gem::Specification.new do |gem| gem.require_paths = %w(lib) gem.rdoc_options = %w[--line-numbers --inline-source] - gem.add_development_dependency('rake', '~> 11.2') + gem.add_development_dependency('rake', '~> 11.3') - gem.add_dependency('cloudstack_client', '~> 1.4') + gem.add_dependency('cloudstack_client', '~> 1.4.3') gem.add_dependency('thor', '~> 0.19') end diff --git a/lib/cloudstack-cli/commands/capacity.rb b/lib/cloudstack-cli/commands/capacity.rb index eb6d621..90cc6e2 100644 --- a/lib/cloudstack-cli/commands/capacity.rb +++ b/lib/cloudstack-cli/commands/capacity.rb @@ -14,23 +14,28 @@ class Capacity < CloudstackCli::Base desc "list", "list system capacity" option :zone, desc: "list capacity by zone" + option :cluster, desc: "list capacity by cluster" option :type, desc: "specify type, see types for a list of types" def list - resolve_zone if options[:zone] + resolve_zone + resolve_cluster capacities = client.list_capacity(options) table = [] header = ["Zone", "Type", "Capacity Used", "Capacity Total", "Used"] + header[0] = "Cluster" if options[:cluster_id] capacities.each do |c| - table << [ - c['zonename'], - CAPACITY_TYPES[c['type']][:name], - capacity_to_s(c, 'capacityused'), - capacity_to_s(c, 'capacitytotal'), - "#{c['percentused']}%" - ] + if CAPACITY_TYPES.include? c['type'] + table << [ + c['clustername'] || c['zonename'], + CAPACITY_TYPES[c['type']][:name], + capacity_to_s(c, 'capacityused'), + capacity_to_s(c, 'capacitytotal'), + "#{c['percentused']}%" + ] + end end - table = table.sort {|a, b| [a[0], a[1]] <=> [b[0], b[1]]}.insert(0, header) - print_table table + table = table.sort {|a, b| [a[0], a[1]] <=> [b[0], b[1]]} + print_table table.insert(0, header) end desc "types", "show capacity types" diff --git a/lib/cloudstack-cli/option_resolver.rb b/lib/cloudstack-cli/option_resolver.rb index 2541b5d..b3fa1ff 100644 --- a/lib/cloudstack-cli/option_resolver.rb +++ b/lib/cloudstack-cli/option_resolver.rb @@ -240,5 +240,16 @@ def resolve_host(type = "routing") options end + def resolve_cluster + if options[:cluster] + unless cluster = client.list_clusters(name: options[:cluster]).first + say "Error: Cluster '#{options[:cluster]}' not found.", :red + exit 1 + end + options[:cluster_id] = cluster['id'] + end + options + end + end end diff --git a/lib/cloudstack-cli/version.rb b/lib/cloudstack-cli/version.rb index 9d7af1a..2858884 100644 --- a/lib/cloudstack-cli/version.rb +++ b/lib/cloudstack-cli/version.rb @@ -1,3 +1,3 @@ module CloudstackCli - VERSION = "1.5.6" + VERSION = "1.5.7" end From 045b53ed6e53f1299232f7de8816dee76683f266 Mon Sep 17 00:00:00 2001 From: niwo Date: Sat, 22 Oct 2016 00:30:37 +0200 Subject: [PATCH 08/36] Optionally display password after VM creation --- Gemfile.lock | 2 +- lib/cloudstack-cli/commands/virtual_machine.rb | 16 ++++++++++++---- lib/cloudstack-cli/helper.rb | 5 +++-- lib/cloudstack-cli/version.rb | 2 +- 4 files changed, 17 insertions(+), 8 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index f74f329..7443508 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -6,7 +6,7 @@ PATH PATH remote: . specs: - cloudstack-cli (1.5.7) + cloudstack-cli (1.5.8) cloudstack_client (~> 1.4.3) thor (~> 0.19) diff --git a/lib/cloudstack-cli/commands/virtual_machine.rb b/lib/cloudstack-cli/commands/virtual_machine.rb index 33eba8b..7a89780 100644 --- a/lib/cloudstack-cli/commands/virtual_machine.rb +++ b/lib/cloudstack-cli/commands/virtual_machine.rb @@ -108,7 +108,7 @@ def create(*names) name: name, project_id: options[:project_id] ).first say "virtual machine #{name} (#{virtual_machine["state"]}) already exists.", :yellow - job = {id: 0, name: "Create virtual machine #{name}", status: 1} + job = {id: 0, name: "Create virtual machine #{name}", status: 3} else job = { id: client.deploy_virtual_machine(options.merge(name: name), {sync: true})['jobid'], @@ -120,19 +120,27 @@ def create(*names) watch_jobs(jobs) if options[:port_rules].size > 0 say "Create port forwarding rules...", :green - jobs = [] + pjobs = [] names.each do |name| virtual_machine = client.list_virtual_machine(name: name, project_id: options[:project_id]).first create_port_rules(virtual_machine, options[:port_rules], false).each_with_index do |job_id, index| - jobs << { + pjobs << { id: job_id, name: "Create port forwarding ##{index + 1} rules for virtual machine #{virtual_machine['name']}" } end end - watch_jobs(jobs) + watch_jobs(pjobs) end say "Finished.", :green + if (jobs.count {|job| job[:status] == 1 } > 0) && yes?("Display password(s) for VM(s)? [y/N]:", :yellow) + table = [] + jobs.each do |job| + data = client.query_async_job_result(jobid: job[:id])["jobresult"]["virtualmachine"] rescue nil + table << [data["name"], data["password"]] if data + end + print_table table + end end desc "destroy NAME [NAME2 ..]", "destroy virtual machine(s)" diff --git a/lib/cloudstack-cli/helper.rb b/lib/cloudstack-cli/helper.rb index e8256d4..85b62e7 100644 --- a/lib/cloudstack-cli/helper.rb +++ b/lib/cloudstack-cli/helper.rb @@ -15,7 +15,8 @@ def ask_number(question) -1 => "waiting", 0 => "running", 1 => "completed", - 2 => "error" + 2 => "error", + 3 => "aborted" } def watch_jobs(jobs) @@ -120,7 +121,7 @@ def print_job_status(jobs, spinner, opts = {t_start: Time.now}) end t_elapsed = opts[:t_start] ? (Time.now - opts[:t_start]).round(1) : 0 completed = jobs.select{|j| j[:status] == 1}.size - say "Completed: #{completed}/#{jobs.size} (#{t_elapsed}s)", :magenta + say "Completed: #{completed} of #{jobs.size} (#{t_elapsed}s)", :magenta sleep opts[:sleeptime] || 0.1 spinner.push spinner.shift spinner diff --git a/lib/cloudstack-cli/version.rb b/lib/cloudstack-cli/version.rb index 2858884..31f770f 100644 --- a/lib/cloudstack-cli/version.rb +++ b/lib/cloudstack-cli/version.rb @@ -1,3 +1,3 @@ module CloudstackCli - VERSION = "1.5.7" + VERSION = "1.5.8" end From c1867c2ee8e632840319df7f79d46bb0776cdfbd Mon Sep 17 00:00:00 2001 From: niwo Date: Sat, 22 Oct 2016 10:43:29 +0200 Subject: [PATCH 09/36] fix vm lookup in vm#create port-rules block --- Gemfile.lock | 2 +- lib/cloudstack-cli/commands/virtual_machine.rb | 17 ++++++++--------- lib/cloudstack-cli/version.rb | 2 +- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 7443508..250aa7f 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -6,7 +6,7 @@ PATH PATH remote: . specs: - cloudstack-cli (1.5.8) + cloudstack-cli (1.5.9) cloudstack_client (~> 1.4.3) thor (~> 0.19) diff --git a/lib/cloudstack-cli/commands/virtual_machine.rb b/lib/cloudstack-cli/commands/virtual_machine.rb index 7a89780..9b4861b 100644 --- a/lib/cloudstack-cli/commands/virtual_machine.rb +++ b/lib/cloudstack-cli/commands/virtual_machine.rb @@ -104,9 +104,7 @@ def create(*names) vm_options_to_params say "Start deploying virtual machine#{"s" if names.size > 1}...", :green jobs = names.map do |name| - if virtual_machine = client.list_virtual_machines( - name: name, project_id: options[:project_id] - ).first + if virtual_machine = find_vm_by_name(name) say "virtual machine #{name} (#{virtual_machine["state"]}) already exists.", :yellow job = {id: 0, name: "Create virtual machine #{name}", status: 3} else @@ -118,26 +116,27 @@ def create(*names) job end watch_jobs(jobs) - if options[:port_rules].size > 0 + successful_jobs = jobs.count {|job| job[:status] == 1 } + if options[:port_rules].size > 0 && successful_jobs > 0 say "Create port forwarding rules...", :green pjobs = [] names.each do |name| - virtual_machine = client.list_virtual_machine(name: name, project_id: options[:project_id]).first - create_port_rules(virtual_machine, options[:port_rules], false).each_with_index do |job_id, index| + vm = client.list_virtual_machines(name: name, project_id: options[:project_id]).first + create_port_rules(vm, options[:port_rules], false).each_with_index do |job_id, index| pjobs << { id: job_id, - name: "Create port forwarding ##{index + 1} rules for virtual machine #{virtual_machine['name']}" + name: "Create port forwarding ##{index + 1} rules for VM #{vm['name']}" } end end watch_jobs(pjobs) end say "Finished.", :green - if (jobs.count {|job| job[:status] == 1 } > 0) && yes?("Display password(s) for VM(s)? [y/N]:", :yellow) + if successful_jobs > 0 && yes?("Display password(s) for VM(s)? [y/N]:", :yellow) table = [] jobs.each do |job| data = client.query_async_job_result(jobid: job[:id])["jobresult"]["virtualmachine"] rescue nil - table << [data["name"], data["password"]] if data + table << ["#{data["name"]}:", data["password"]] if data end print_table table end diff --git a/lib/cloudstack-cli/version.rb b/lib/cloudstack-cli/version.rb index 31f770f..30444c6 100644 --- a/lib/cloudstack-cli/version.rb +++ b/lib/cloudstack-cli/version.rb @@ -1,3 +1,3 @@ module CloudstackCli - VERSION = "1.5.8" + VERSION = "1.5.9" end From 4841b49bd9b684dc91f7de64f8cb67834f90f3fe Mon Sep 17 00:00:00 2001 From: niwo Date: Sun, 23 Oct 2016 11:26:41 +0200 Subject: [PATCH 10/36] add password diplay support to stack command --- lib/cloudstack-cli/commands/stack.rb | 32 +++++++++++++++++++++------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/lib/cloudstack-cli/commands/stack.rb b/lib/cloudstack-cli/commands/stack.rb index e166ff9..b079f9b 100644 --- a/lib/cloudstack-cli/commands/stack.rb +++ b/lib/cloudstack-cli/commands/stack.rb @@ -14,13 +14,14 @@ def create(stackfile) stack["servers"].each do |instance| string_to_array(instance["name"]).each do |name| if !options[:limit] || options[:limit].include?(name) - server = client.list_virtual_machines(name: name, project_id: project_id).first - if server + if server = client.list_virtual_machines( + name: name, project_id: project_id, listall: true + ).find {|vm| vm["name"] == name } say "VM #{name} (#{server["state"]}) already exists.", :yellow jobs << { id: 0, name: "Create VM #{name}", - status: 1 + status: 3 } else options.merge!({ @@ -52,23 +53,37 @@ def create(stackfile) end watch_jobs(jobs) - unless options[:skip_forwarding_rules] + # count jobs with status 1 => Completed + successful_jobs = jobs.count {|job| job[:status] == 1 } + pw_table = [] + if successful_jobs > 0 && + jobs.each do |job| + data = client.query_async_job_result(jobid: job[:id])["jobresult"]["virtualmachine"] rescue nil + pw_table << ["#{data["name"]}:", data["password"]] if data + end + end + + unless successful_jobs == 0 || options[:skip_forwarding_rules] say "Check for port forwarding rules...", :green - jobs = [] + pjobs = [] stack["servers"].each do |instance| string_to_array(instance["name"]).each do |name| if (!options[:limit] || options[:limit].include?(name)) && port_rules = string_to_array(instance["port_rules"]) server = client.list_virtual_machines(name: name, project_id: project_id).first create_port_rules(server, port_rules, false).each_with_index do |job_id, index| job_name = "Create port forwarding rules (#{port_rules[index]}) for VM #{name}" - jobs << {id: job_id, name: job_name} + pjobs << {id: job_id, name: job_name} end end end end - watch_jobs(jobs) + watch_jobs(pjobs) end say "Finished.", :green + + if pw_table.size > 0 && yes?("Display password(s) for VM(s)? [y/N]:", :yellow) + print_table pw_table + end end desc "destroy STACKFILE", "destroy a stack of VMs" @@ -101,7 +116,8 @@ def destroy(stackfile) exit end - if options[:force] || yes?("Destroy the following VM #{servers.join(', ')}? [y/N]:", :yellow) + if options[:force] || + yes?("Destroy #{'and expunge ' if options[:expunge]}the following VM(s)? #{servers.join(', ')} [y/N]:", :yellow) jobs = [] servers.each do |name| if server = client.list_virtual_machines(name: name, project_id: project_id).first From 777594c66052ceee1f1fa26ff6a0c932a9d6b10a Mon Sep 17 00:00:00 2001 From: niwo Date: Sun, 23 Oct 2016 21:14:28 +0200 Subject: [PATCH 11/36] improved create commands for vm and stack, fixed pf_rule#create --- Gemfile.lock | 4 +- lib/cloudstack-cli/commands/port_rule.rb | 16 ++--- lib/cloudstack-cli/commands/router.rb | 6 +- lib/cloudstack-cli/commands/stack.rb | 69 ++++++++++++------- .../commands/virtual_machine.rb | 38 ++++++---- lib/cloudstack-cli/helper.rb | 23 +++++-- lib/cloudstack-cli/option_resolver.rb | 1 + lib/cloudstack-cli/version.rb | 2 +- test/stack_example_b.yml | 14 ++++ 9 files changed, 111 insertions(+), 62 deletions(-) create mode 100644 test/stack_example_b.yml diff --git a/Gemfile.lock b/Gemfile.lock index 250aa7f..b427604 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -6,7 +6,7 @@ PATH PATH remote: . specs: - cloudstack-cli (1.5.9) + cloudstack-cli (1.5.10) cloudstack_client (~> 1.4.3) thor (~> 0.19) @@ -25,4 +25,4 @@ DEPENDENCIES rake (~> 11.3) BUNDLED WITH - 1.13.2 + 1.13.6 diff --git a/lib/cloudstack-cli/commands/port_rule.rb b/lib/cloudstack-cli/commands/port_rule.rb index 6ecb7bc..c0f6c70 100644 --- a/lib/cloudstack-cli/commands/port_rule.rb +++ b/lib/cloudstack-cli/commands/port_rule.rb @@ -10,10 +10,13 @@ class PortRule < CloudstackCli::Base option :keyword, desc: "list by keyword" def create(server_name) resolve_project - unless server = client.list_virtual_machines(name: server_name, project_id: options[:project_id]).first + unless server = client.list_virtual_machines( + name: server_name, project_id: options[:project_id], listall: true + ).find {|vm| vm["name"] == server_name } error "Server #{server_name} not found." exit 1 end + ip_addr = nil options[:rules].each do |pf_rule| ip = pf_rule.split(":")[0] unless ip == '' @@ -23,16 +26,13 @@ def create(server_name) end else say "Assign a new IP address ", :yellow - say(" OK", :green) if ip_addr = client.associate_ip_address( - networkid: client.list_networks( - project_id: options[:project_id] - ).find {|n| n['name'] == options[:network]}['id'], - project_id: options[:project_id] - ) + net_id = client.list_networks(project_id: options[:project_id]).find {|n| n['name'] == options[:network]}['id'] + say(" OK", :green) if ip_addr = client.associate_ip_address(networkid: net_id)["ipaddress"] end port = pf_rule.split(":")[1] say "Create port forwarding rule #{ip_addr["ipaddress"]}:#{port} for server #{server_name} ", :yellow - say(" OK.", :green) if client.create_port_forwarding_rule( + + say(" OK", :green) if client.create_port_forwarding_rule( ipaddress_id: ip_addr["id"], public_port: port, private_port: port, diff --git a/lib/cloudstack-cli/commands/router.rb b/lib/cloudstack-cli/commands/router.rb index c41bc48..6b31f2f 100644 --- a/lib/cloudstack-cli/commands/router.rb +++ b/lib/cloudstack-cli/commands/router.rb @@ -13,7 +13,7 @@ class Router < CloudstackCli::Base desc: "command to execute for each router", enum: %w(START STOP REBOOT STOP_START) option :concurrency, type: :numeric, default: 10, aliases: '-C', - desc: "number of concurrent command to execute" + desc: "number of concurrent commands to execute" option :format, default: "table", enum: %w(table json yaml) option :showid, type: :boolean, desc: "display the router ID" @@ -43,7 +43,7 @@ def list desc: "command to execute for each router", enum: %w(START STOP REBOOT) option :concurrency, type: :numeric, default: 10, aliases: '-C', - desc: "number of concurrent command to execute" + desc: "number of concurrent commands to execute" option :format, default: "table", enum: %w(table json yaml) def list_from_file(file) @@ -219,7 +219,7 @@ def execute_router_commands(command, routers) jobs = routers.map do |router| { job_id: nil, - object_id: router["id"], + args: { id: router["id"] }, name: "#{cmd.capitalize} router #{router['name']}", status: -1 } diff --git a/lib/cloudstack-cli/commands/stack.rb b/lib/cloudstack-cli/commands/stack.rb index b079f9b..a2b568a 100644 --- a/lib/cloudstack-cli/commands/stack.rb +++ b/lib/cloudstack-cli/commands/stack.rb @@ -6,9 +6,12 @@ class Stack < CloudstackCli::Base option :skip_forwarding_rules, default: false, type: :boolean, aliases: '-s', desc: "Skip creation of port forwarding rules." + option :concurrency, type: :numeric, default: 10, aliases: '-C', + desc: "number of concurrent commands to execute" def create(stackfile) stack = parse_file(stackfile) project_id = find_project_by_name(stack["project"]) + say "Create stack #{stack["name"]}...", :green jobs = [] stack["servers"].each do |instance| @@ -25,7 +28,6 @@ def create(stackfile) } else options.merge!({ - name: name, displayname: instance["decription"], zone: instance["zone"] || stack["zone"], project: stack["project"], @@ -40,49 +42,54 @@ def create(stackfile) keypair: instance["keypair"] || stack["keypair"], ip_address: instance["ip_address"] }) + vm_options_to_params jobs << { - id: client.deploy_virtual_machine( - vm_options_to_params, - {sync: true} - )['jobid'], - name: "Create VM #{name}" + job_id: nil, + args: options.merge(name: name), + name: "Create VM #{name}", + status: -1 } end end end end - watch_jobs(jobs) - # count jobs with status 1 => Completed - successful_jobs = jobs.count {|job| job[:status] == 1 } - pw_table = [] - if successful_jobs > 0 && - jobs.each do |job| - data = client.query_async_job_result(jobid: job[:id])["jobresult"]["virtualmachine"] rescue nil - pw_table << ["#{data["name"]}:", data["password"]] if data - end + if jobs.count{|job| job[:status] < 1 } > 0 + run_background_jobs(jobs, "deploy_virtual_machine") end + # count jobs with status 1 => Completed + successful_jobs = jobs.count {|job| job[:status] == 1 } unless successful_jobs == 0 || options[:skip_forwarding_rules] say "Check for port forwarding rules...", :green pjobs = [] - stack["servers"].each do |instance| - string_to_array(instance["name"]).each do |name| - if (!options[:limit] || options[:limit].include?(name)) && port_rules = string_to_array(instance["port_rules"]) - server = client.list_virtual_machines(name: name, project_id: project_id).first - create_port_rules(server, port_rules, false).each_with_index do |job_id, index| - job_name = "Create port forwarding rules (#{port_rules[index]}) for VM #{name}" - pjobs << {id: job_id, name: job_name} - end + jobs.select{|job| job[:status] == 1}.each do |job| + vm = job[:result]["virtualmachine"] + vm_def = find_vm_in_stack(vm["name"], stack) + if port_rules = string_to_array(vm_def["port_rules"]) + create_port_rules(vm, port_rules, false).each_with_index do |job_id, index| + job_name = "Create port forwarding rules (#{port_rules[index]}) for VM #{vm["name"]}" + pjobs << {id: job_id, name: job_name} end end end watch_jobs(pjobs) + pjobs.each do |job| + if job[:result] + result = job[:result]["portforwardingrule"] + puts "Created port forwarding rule #{result['ipaddress']}:#{result['publicport']} => #{result['privateport']} for VM #{result['virtualmachinename']}" + end + end end say "Finished.", :green - if pw_table.size > 0 && yes?("Display password(s) for VM(s)? [y/N]:", :yellow) - print_table pw_table + if successful_jobs > 0 && yes?("Display password(s) for VM(s)? [y/N]:", :yellow) + pw_table = jobs.select {|job| job[:status] == 1 && job[:result] }.map do |job| + if result = job[:result]["virtualmachine"] + ["#{result["name"]}:", result["password"] || "n/a"] + end + end + print_table(pw_table) if pw_table.size > 0 end end @@ -120,7 +127,9 @@ def destroy(stackfile) yes?("Destroy #{'and expunge ' if options[:expunge]}the following VM(s)? #{servers.join(', ')} [y/N]:", :yellow) jobs = [] servers.each do |name| - if server = client.list_virtual_machines(name: name, project_id: project_id).first + if server = client.list_virtual_machines( + name: name, project_id: project_id, listall: true + ).find {|vm| vm["name"] == name } jobs << { id: client.destroy_virtual_machine( { id: server['id'], expunge: options[:expunge] }, @@ -158,6 +167,14 @@ def string_to_array(string) string ? string.gsub(', ', ',').split(',') : nil end + def find_vm_in_stack(name, stack) + stack["servers"].each do |server| + if string_to_array(server["name"]).find{|n| n == name } + return server + end + end + end + end # no_commands end diff --git a/lib/cloudstack-cli/commands/virtual_machine.rb b/lib/cloudstack-cli/commands/virtual_machine.rb index 9b4861b..0869193 100644 --- a/lib/cloudstack-cli/commands/virtual_machine.rb +++ b/lib/cloudstack-cli/commands/virtual_machine.rb @@ -15,7 +15,7 @@ class VirtualMachine < CloudstackCli::Base desc: "command to execute for the given virtual machines", enum: %w(START STOP REBOOT) option :concurrency, type: :numeric, default: 10, aliases: '-C', - desc: "number of concurrent command to execute" + desc: "number of concurrent commands to execute" option :format, default: "table", enum: %w(table json yaml) def list @@ -78,7 +78,7 @@ def show(name) option :zone, aliases: '-z', required: true, desc: "availability zone name" option :networks, aliases: '-n', type: :array, desc: "network names" option :project, aliases: '-p', desc: "project name" - option :port_rules, aliases: '-pr', type: :array, + option :port_rules, type: :array, default: [], desc: "Port Forwarding Rules [public_ip]:port ..." option :disk_offering, desc: "disk offering (data disk for template, root disk for iso)" @@ -91,6 +91,8 @@ def show(name) option :ip_network_list, desc: "ip_network_list (net1:ip net2:ip...)", type: :array option :user_data, desc: "optional binary data that can be sent to the virtual machine upon a successful deployment." + option :concurrency, type: :numeric, default: 10, aliases: '-C', + desc: "number of concurrent commands to execute" def create(*names) if names.size == 0 say "Please provide at least one virtual machine name.", :yellow @@ -106,39 +108,45 @@ def create(*names) jobs = names.map do |name| if virtual_machine = find_vm_by_name(name) say "virtual machine #{name} (#{virtual_machine["state"]}) already exists.", :yellow - job = {id: 0, name: "Create virtual machine #{name}", status: 3} + job = {name: "Create virtual machine #{name}", status: 3} else job = { - id: client.deploy_virtual_machine(options.merge(name: name), {sync: true})['jobid'], - name: "Create virtual machine #{name}" + args: options.merge(name: name), + name: "Create VM #{name}", + status: -1 } end job end - watch_jobs(jobs) + + if jobs.count{|job| job[:status] < 1 } > 0 + run_background_jobs(jobs, "deploy_virtual_machine") + end + successful_jobs = jobs.count {|job| job[:status] == 1 } if options[:port_rules].size > 0 && successful_jobs > 0 say "Create port forwarding rules...", :green pjobs = [] - names.each do |name| - vm = client.list_virtual_machines(name: name, project_id: options[:project_id]).first + jobs.select{|job| job[:status] == 1}.each do |job| + vm = job[:result]["virtualmachine"] create_port_rules(vm, options[:port_rules], false).each_with_index do |job_id, index| pjobs << { id: job_id, - name: "Create port forwarding ##{index + 1} rules for VM #{vm['name']}" + name: "Create port forwarding rule #{options[:port_rules][index]} for VM #{vm['name']}" } end end watch_jobs(pjobs) end say "Finished.", :green + if successful_jobs > 0 && yes?("Display password(s) for VM(s)? [y/N]:", :yellow) - table = [] - jobs.each do |job| - data = client.query_async_job_result(jobid: job[:id])["jobresult"]["virtualmachine"] rescue nil - table << ["#{data["name"]}:", data["password"]] if data + pw_table = jobs.select {|job| job[:status] == 1 && job[:result] }.map do |job| + if result = job[:result]["virtualmachine"] + ["#{result["name"]}:", result["password"] || "n/a"] + end end - print_table table + print_table(pw_table) if pw_table.size > 0 end end @@ -319,7 +327,7 @@ def execute_virtual_machines_commands(command, virtual_machines) jobs = virtual_machines.map do |vm| { job_id: nil, - object_id: vm["id"], + args: { id: vm["id"] }, name: "#{command.capitalize} virtual machine #{vm['name']}", status: -1 } diff --git a/lib/cloudstack-cli/helper.rb b/lib/cloudstack-cli/helper.rb index 85b62e7..cab77af 100644 --- a/lib/cloudstack-cli/helper.rb +++ b/lib/cloudstack-cli/helper.rb @@ -24,7 +24,7 @@ def watch_jobs(jobs) call = 0 opts = {t_start: Time.now} jobs = update_job_status(jobs) - while jobs.select{|job| job[:status].to_i < 1 }.size > 0 do + while jobs.count{|job| job[:status].to_i < 1 } > 0 do if call.modulo(40) == 0 t = Thread.new { jobs = update_job_status(jobs) } while t.alive? @@ -50,7 +50,12 @@ def update_job_status(jobs) jobs.each do |job| job[:status] = 0 unless job[:status] if job[:status] == 0 - job[:status] = client.query_async_job_result(job_id: job[:id])['jobstatus'] + result = client.query_async_job_result(job_id: job[:id]) + job[:status] = result["jobstatus"] + # add result information for terminated jobs + if job[:status].between?(1, 2) + job[:result] = result["jobresult"] + end end end jobs @@ -62,7 +67,7 @@ def run_background_jobs(jobs, command) call = 0 opts = {t_start: Time.now} - while jobs.select{|job| job[:status] < 1 }.size > 0 do + while jobs.count{|job| job[:status] < 1 } > 0 do if call.modulo(40) == 0 t = Thread.new { jobs = update_jobs(jobs, command) } while t.alive? @@ -90,19 +95,23 @@ def update_jobs(jobs, command) # update running job status threads = jobs.select{|job| job[:status] == 0 }.map do |job| Thread.new do - job[:status] = client.query_async_job_result(job_id: job[:job_id])['jobstatus'] + result = client.query_async_job_result(job_id: job[:job_id]) + job[:status] = result['jobstatus'] + if job[:status].between?(1, 2) + job[:result] = result["jobresult"] + end end end threads.each(&:join) # launch new jobs if required and possible - launch_capacity = options[:concurrency] - jobs.select{|job| job[:status] == 0 }.count + launch_capacity = (options[:concurrency] ||= 10) - jobs.count{|job| job[:status] == 0 } threads = [] jobs.select{|job| job[:status] == -1 }.each do |job| if launch_capacity > 0 threads << Thread.new do job[:job_id] = client.send( - command, { id: job[:object_id] }, { sync: true } + command, job[:args], { sync: true } )['jobid'] job[:status] = 0 end @@ -120,7 +129,7 @@ def print_job_status(jobs, spinner, opts = {t_start: Time.now}) puts job[:status] == 0 ? spinner.first : "" end t_elapsed = opts[:t_start] ? (Time.now - opts[:t_start]).round(1) : 0 - completed = jobs.select{|j| j[:status] == 1}.size + completed = jobs.count{|j| j[:status] == 1 } say "Completed: #{completed} of #{jobs.size} (#{t_elapsed}s)", :magenta sleep opts[:sleeptime] || 0.1 spinner.push spinner.shift diff --git a/lib/cloudstack-cli/option_resolver.rb b/lib/cloudstack-cli/option_resolver.rb index b3fa1ff..d90b378 100644 --- a/lib/cloudstack-cli/option_resolver.rb +++ b/lib/cloudstack-cli/option_resolver.rb @@ -18,6 +18,7 @@ def vm_options_to_params else resolve_networks end + options end def resolve_zone diff --git a/lib/cloudstack-cli/version.rb b/lib/cloudstack-cli/version.rb index 30444c6..2ea0156 100644 --- a/lib/cloudstack-cli/version.rb +++ b/lib/cloudstack-cli/version.rb @@ -1,3 +1,3 @@ module CloudstackCli - VERSION = "1.5.9" + VERSION = "1.5.10" end diff --git a/test/stack_example_b.yml b/test/stack_example_b.yml new file mode 100644 index 0000000..210ff43 --- /dev/null +++ b/test/stack_example_b.yml @@ -0,0 +1,14 @@ +--- + name: "web_stack_b" + description: "Web Application Stack" + version: "1.0" + zone: "ZUERICH_EQ" + project: "Playground" + group: "my_web_stack" + servers: + - name: "webx-01, webx-02" + description: "Web nodes" + template: "CentOS-7-x86_64" + offering: "1cpu_1gb" + networks: "M_PLAY" + port_rules: ":80, :443" From 3eafca0fc9c2f8aaa5805a71bc46910519b77e0f Mon Sep 17 00:00:00 2001 From: niwo Date: Tue, 25 Oct 2016 00:33:14 +0200 Subject: [PATCH 12/36] adding vm specs --- Gemfile.lock | 4 +- Rakefile | 10 ++++ cloudstack-cli.gemspec | 1 + {test => examples}/ma-test.yml | 0 examples/stack-dev.yml | 20 ++++++++ {test => examples}/stack_example.json | 0 {test => examples}/stack_example.yml | 0 {test => examples}/stack_example_b.yml | 0 lib/cloudstack-cli/commands/stack.rb | 15 ++++-- .../commands/virtual_machine.rb | 17 ++++--- lib/cloudstack-cli/version.rb | 2 +- spec/cloudstack-cli.yml | 6 +++ .../commands/virtual_machine_spec.rb | 51 +++++++++++++++++++ spec/fixtures/stack.yml | 20 ++++++++ spec/spec_helper.rb | 8 +++ 15 files changed, 141 insertions(+), 13 deletions(-) rename {test => examples}/ma-test.yml (100%) create mode 100644 examples/stack-dev.yml rename {test => examples}/stack_example.json (100%) rename {test => examples}/stack_example.yml (100%) rename {test => examples}/stack_example_b.yml (100%) create mode 100644 spec/cloudstack-cli.yml create mode 100644 spec/cloudstack-cli/commands/virtual_machine_spec.rb create mode 100644 spec/fixtures/stack.yml create mode 100644 spec/spec_helper.rb diff --git a/Gemfile.lock b/Gemfile.lock index b427604..f9826c7 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -6,13 +6,14 @@ PATH PATH remote: . specs: - cloudstack-cli (1.5.10) + cloudstack-cli (1.5.11) cloudstack_client (~> 1.4.3) thor (~> 0.19) GEM remote: https://rubygems.org/ specs: + minitest (5.9.1) rake (11.3.0) thor (0.19.1) @@ -22,6 +23,7 @@ PLATFORMS DEPENDENCIES cloudstack-cli! cloudstack_client! + minitest (~> 5.9) rake (~> 11.3) BUNDLED WITH diff --git a/Rakefile b/Rakefile index 2995527..2a8ffe6 100644 --- a/Rakefile +++ b/Rakefile @@ -1 +1,11 @@ require "bundler/gem_tasks" +require "rake/testtask" + + +Rake::TestTask.new do |t| + t.libs << "spec" + t.pattern = "spec/**/*_spec.rb" + t.warning = false +end + +task default: :test diff --git a/cloudstack-cli.gemspec b/cloudstack-cli.gemspec index d45c8ca..97494d6 100644 --- a/cloudstack-cli.gemspec +++ b/cloudstack-cli.gemspec @@ -22,6 +22,7 @@ Gem::Specification.new do |gem| gem.rdoc_options = %w[--line-numbers --inline-source] gem.add_development_dependency('rake', '~> 11.3') + gem.add_development_dependency('minitest', '~> 5.9') gem.add_dependency('cloudstack_client', '~> 1.4.3') gem.add_dependency('thor', '~> 0.19') diff --git a/test/ma-test.yml b/examples/ma-test.yml similarity index 100% rename from test/ma-test.yml rename to examples/ma-test.yml diff --git a/examples/stack-dev.yml b/examples/stack-dev.yml new file mode 100644 index 0000000..f26f98e --- /dev/null +++ b/examples/stack-dev.yml @@ -0,0 +1,20 @@ +--- + name: "web_stack_a" + description: "Web Application Stack" + version: "1.0" + zone: "Sandbox-simulator" + group: "my_web_stack" + servers: + - name: "web-01, web-02" + description: "Web nodes" + template: "CentOS 5.3(64-bit) no GUI (Simulator)" + offering: "Small Instance" + networks: "test-network" + port_rules: ":80, :443" + - name: "db-01" + description: "PostgreSQL Master" + template: "CentOS 5.3(64-bit) no GUI (Simulator)" + offering: "Medium Instance" + ip_network_list: + - name: "test-network" + ip: 10.1.1.11 diff --git a/test/stack_example.json b/examples/stack_example.json similarity index 100% rename from test/stack_example.json rename to examples/stack_example.json diff --git a/test/stack_example.yml b/examples/stack_example.yml similarity index 100% rename from test/stack_example.yml rename to examples/stack_example.yml diff --git a/test/stack_example_b.yml b/examples/stack_example_b.yml similarity index 100% rename from test/stack_example_b.yml rename to examples/stack_example_b.yml diff --git a/lib/cloudstack-cli/commands/stack.rb b/lib/cloudstack-cli/commands/stack.rb index a2b568a..99ba578 100644 --- a/lib/cloudstack-cli/commands/stack.rb +++ b/lib/cloudstack-cli/commands/stack.rb @@ -8,6 +8,8 @@ class Stack < CloudstackCli::Base desc: "Skip creation of port forwarding rules." option :concurrency, type: :numeric, default: 10, aliases: '-C', desc: "number of concurrent commands to execute" + option :assumeyes, type: :boolean, default: false, aliases: '-y', + desc: "answer yes for all questions" def create(stackfile) stack = parse_file(stackfile) project_id = find_project_by_name(stack["project"]) @@ -83,13 +85,16 @@ def create(stackfile) end say "Finished.", :green - if successful_jobs > 0 && yes?("Display password(s) for VM(s)? [y/N]:", :yellow) - pw_table = jobs.select {|job| job[:status] == 1 && job[:result] }.map do |job| - if result = job[:result]["virtualmachine"] - ["#{result["name"]}:", result["password"] || "n/a"] + if successful_jobs > 0 + if options[:assumeyes] || yes?("Display password(s) for VM(s)? [y/N]:", :yellow) + pw_table = [%w(VM Password)] + jobs.select {|job| job[:status] == 1 && job[:result] }.each do |job| + if result = job[:result]["virtualmachine"] + pw_table << ["#{result["name"]}:", result["password"] || "n/a"] + end end + print_table(pw_table) if pw_table.size > 0 end - print_table(pw_table) if pw_table.size > 0 end end diff --git a/lib/cloudstack-cli/commands/virtual_machine.rb b/lib/cloudstack-cli/commands/virtual_machine.rb index 0869193..9fc7ce8 100644 --- a/lib/cloudstack-cli/commands/virtual_machine.rb +++ b/lib/cloudstack-cli/commands/virtual_machine.rb @@ -32,7 +32,7 @@ def list virtual_machines = client.list_virtual_machines(options) virtual_machines = filter_objects(virtual_machines) if options[:filter] if virtual_machines.size < 1 - puts "No virtual_machines found." + puts "No virtual machines found." else print_virtual_machines(virtual_machines) execute_virtual_machines_commands(command, virtual_machines) if command @@ -93,6 +93,8 @@ def show(name) desc: "optional binary data that can be sent to the virtual machine upon a successful deployment." option :concurrency, type: :numeric, default: 10, aliases: '-C', desc: "number of concurrent commands to execute" + option :assumeyes, type: :boolean, default: false, aliases: '-y', + desc: "answer yes for all questions" def create(*names) if names.size == 0 say "Please provide at least one virtual machine name.", :yellow @@ -140,13 +142,16 @@ def create(*names) end say "Finished.", :green - if successful_jobs > 0 && yes?("Display password(s) for VM(s)? [y/N]:", :yellow) - pw_table = jobs.select {|job| job[:status] == 1 && job[:result] }.map do |job| - if result = job[:result]["virtualmachine"] - ["#{result["name"]}:", result["password"] || "n/a"] + if successful_jobs > 0 + if options[:assumeyes] || yes?("Display password(s) for VM(s)? [y/N]:", :yellow) + pw_table = [%w(VM Password)] + jobs.select {|job| job[:status] == 1 && job[:result] }.each do |job| + if result = job[:result]["virtualmachine"] + pw_table << ["#{result["name"]}:", result["password"] || "n/a"] + end end + print_table(pw_table) if pw_table.size > 0 end - print_table(pw_table) if pw_table.size > 0 end end diff --git a/lib/cloudstack-cli/version.rb b/lib/cloudstack-cli/version.rb index 2ea0156..778dbb0 100644 --- a/lib/cloudstack-cli/version.rb +++ b/lib/cloudstack-cli/version.rb @@ -1,3 +1,3 @@ module CloudstackCli - VERSION = "1.5.10" + VERSION = "1.5.11" end diff --git a/spec/cloudstack-cli.yml b/spec/cloudstack-cli.yml new file mode 100644 index 0000000..c8f771d --- /dev/null +++ b/spec/cloudstack-cli.yml @@ -0,0 +1,6 @@ +--- +:default: development +development: + :url: http://127.0.0.1:8080/client/api + :api_key: 3B1lE0C33ceSOUg0jaIo8STNZ55I-mdvza0LXpZA8mrvtpBpgzJgE9YSsURBcQ6qKX090w5vv_AgGRZeYS9AiQ + :secret_key: mneyw6fg__Gt-ENg0E_9BfxcuiMJPSThe701Kuz7f5_EsJ0POoN4z9eoslECP5V9oDzB6XOlsCw1FuBqPjMmLg diff --git a/spec/cloudstack-cli/commands/virtual_machine_spec.rb b/spec/cloudstack-cli/commands/virtual_machine_spec.rb new file mode 100644 index 0000000..df0d9a1 --- /dev/null +++ b/spec/cloudstack-cli/commands/virtual_machine_spec.rb @@ -0,0 +1,51 @@ +require "spec_helper" +require "cloudstack-cli" + +describe VirtualMachine do + + it "should be able to run vm list" do + out = capture_io{ CloudstackCli::Cli.start [ + "vm", + "list", + CONFIG + ]}.join "" + out.lines.last.must_match( + /.*(No virtual machines found.|Total number of virtual machines: \d)/ + ) + end + + it "should successfully create a vm" do + out, err = capture_io do + startvm = CloudstackCli::Cli.start [ + "vm", + "create", + "testvm1", + "--zone=Sandbox-simulator", + "--template=CentOS 5.3(64-bit) no GUI (Simulator)", + "--offering=Small Instance", + "--networks=test-network", + "--port-rules=:80", + "--assumeyes", + CONFIG, + ] + end + puts out + err.must_equal "" + end + + it "should destroy a vm" do + out, err = capture_io do + startvm = CloudstackCli::Cli.start [ + "vm", + "destroy", + "testvm1", + "--expunge", + "--force", + CONFIG, + ] + end + puts out + err.must_equal "" + end + +end diff --git a/spec/fixtures/stack.yml b/spec/fixtures/stack.yml new file mode 100644 index 0000000..f26f98e --- /dev/null +++ b/spec/fixtures/stack.yml @@ -0,0 +1,20 @@ +--- + name: "web_stack_a" + description: "Web Application Stack" + version: "1.0" + zone: "Sandbox-simulator" + group: "my_web_stack" + servers: + - name: "web-01, web-02" + description: "Web nodes" + template: "CentOS 5.3(64-bit) no GUI (Simulator)" + offering: "Small Instance" + networks: "test-network" + port_rules: ":80, :443" + - name: "db-01" + description: "PostgreSQL Master" + template: "CentOS 5.3(64-bit) no GUI (Simulator)" + offering: "Medium Instance" + ip_network_list: + - name: "test-network" + ip: 10.1.1.11 diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb new file mode 100644 index 0000000..75fe836 --- /dev/null +++ b/spec/spec_helper.rb @@ -0,0 +1,8 @@ +require "cloudstack-cli" + +require "minitest/spec" +require "minitest/autorun" +require "minitest/pride" + +# make the config file setup awailable to all specs +CONFIG = "--config-file=#{File.expand_path('cloudstack-cli.yml', File.dirname(__FILE__))}" From 659f2f6364a96eca5697dcc6bcfabdffe2ea3ba3 Mon Sep 17 00:00:00 2001 From: niwo Date: Tue, 25 Oct 2016 19:27:23 +0200 Subject: [PATCH 13/36] adding more vm specs, add network_offer command --- lib/cloudstack-cli/commands/network_offer.rb | 50 ++++++++ .../commands/virtual_machine_spec.rb | 120 +++++++++++++----- spec/spec_helper.rb | 4 + 3 files changed, 139 insertions(+), 35 deletions(-) create mode 100644 lib/cloudstack-cli/commands/network_offer.rb diff --git a/lib/cloudstack-cli/commands/network_offer.rb b/lib/cloudstack-cli/commands/network_offer.rb new file mode 100644 index 0000000..2bc0b55 --- /dev/null +++ b/lib/cloudstack-cli/commands/network_offer.rb @@ -0,0 +1,50 @@ +class NetworkOffer < CloudstackCli::Base + + desc 'list', 'list network offerings' + option :guest_ip_type, enum: %w(isolated shared), + desc: "list network offerings by guest type." + option :format, default: "table", + enum: %w(table json yaml) + def list + offerings = client.list_network_offerings(options) + if offerings.size < 1 + puts "No offerings found." + else + case options[:format].to_sym + when :yaml + puts({network_offers: offerings}.to_yaml) + when :json + puts JSON.pretty_generate(network_offers: offerings) + else + table = [%w(Name Display_Text Default? Guest_IP_Type State)] + offerings.each do |offer| + table << [ + offer['name'], + offer['displaytext'], + offer['isdefault'], + offer['guestiptype'], + offer['state'], + ] + end + print_table table + end + end + end + + desc "show NAME", "show detailed infos about a network offering" + def show(name) + unless offer = client.list_network_offerings(name: name).first + say "Error: No network offering with name '#{name}' found.", :red + else + table = offer.map do |key, value| + if key == "service" + [ set_color("services", :yellow), value.map{|s| s["name"]}.join(", ") ] + else + [ set_color("#{key}", :yellow), "#{value}" ] + end + end + print_table table + end + end + +end diff --git a/spec/cloudstack-cli/commands/virtual_machine_spec.rb b/spec/cloudstack-cli/commands/virtual_machine_spec.rb index df0d9a1..cfee7f1 100644 --- a/spec/cloudstack-cli/commands/virtual_machine_spec.rb +++ b/spec/cloudstack-cli/commands/virtual_machine_spec.rb @@ -3,49 +3,99 @@ describe VirtualMachine do - it "should be able to run vm list" do - out = capture_io{ CloudstackCli::Cli.start [ + it "should support all CRUD actions" do + vmname = "testvm1" + + # CREATE + out, err = capture_io{ CloudstackCli::Cli.start [ + "vm", + "create", + vmname, + "--zone=#{ZONE}", + "--template=#{TEMPLATE}", + "--offering=#{OFFERING_S}", + "--networks=test-network", + "--port-rules=:80", + "--assumeyes", + CONFIG, + ]} + err.must_equal "" + + # READ - LIST + out, err = capture_io{ CloudstackCli::Cli.start [ "vm", "list", CONFIG - ]}.join "" - out.lines.last.must_match( - /.*(No virtual machines found.|Total number of virtual machines: \d)/ + ]} + err.must_equal "" + out.must_match( + /.*(#{vmname}).*/ ) - end - it "should successfully create a vm" do - out, err = capture_io do - startvm = CloudstackCli::Cli.start [ - "vm", - "create", - "testvm1", - "--zone=Sandbox-simulator", - "--template=CentOS 5.3(64-bit) no GUI (Simulator)", - "--offering=Small Instance", - "--networks=test-network", - "--port-rules=:80", - "--assumeyes", - CONFIG, - ] - end - puts out + # READ - SHOW + out, err = capture_io{ CloudstackCli::Cli.start [ + "vm", + "show", + vmname, + CONFIG + ]} err.must_equal "" - end + out.must_match( + /.*(#{vmname}).*/ + ) - it "should destroy a vm" do - out, err = capture_io do - startvm = CloudstackCli::Cli.start [ - "vm", - "destroy", - "testvm1", - "--expunge", - "--force", - CONFIG, - ] - end - puts out + # UPDATE - STOP + out, err = capture_io{ CloudstackCli::Cli.start [ + "vm", + "stop", + vmname, + "--force", + CONFIG, + ]} + err.must_equal "" + + # UPDATE - UPDATE ;-) + new_vmname = "testvm11" + out, err = capture_io{ CloudstackCli::Cli.start [ + "vm", + "update", + vmname, + "--name=#{new_vmname}", + "--force", + CONFIG, + ]} + err.must_equal "" + + # UPDATE - START + out, err = capture_io{ CloudstackCli::Cli.start [ + "vm", + "start", + new_vmname, + CONFIG, + ]} + err.must_equal "" + + # UPDATE - REBOOT + out, err = capture_io{ CloudstackCli::Cli.start [ + "vm", + "reboot", + new_vmname, + "--force", + CONFIG, + ]} + err.must_equal "" + + # DELETE + out, err = capture_io{ CloudstackCli::Cli.start [ + "vm", + "destroy", + new_vmname, + "--expunge", + "--force", + CONFIG, + ]} err.must_equal "" + end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 75fe836..525dbd4 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -6,3 +6,7 @@ # make the config file setup awailable to all specs CONFIG = "--config-file=#{File.expand_path('cloudstack-cli.yml', File.dirname(__FILE__))}" +ZONE = "Sandbox-simulator" +TEMPLATE = "CentOS 5.3(64-bit) no GUI (Simulator)" +OFFERING_S = "Small Instance" +OFFERING_M = "Medium Instance" From 0e7fe63426ba8d53b7fa94408bcd2f5a39c7b617 Mon Sep 17 00:00:00 2001 From: niwo Date: Wed, 30 Nov 2016 12:57:00 +0100 Subject: [PATCH 14/36] updated and fixed issues with thor 0.19.4 --- Gemfile.lock | 6 +++--- cloudstack-cli.gemspec | 2 +- lib/cloudstack-cli/commands/account.rb | 2 +- lib/cloudstack-cli/commands/affinity_group.rb | 2 +- lib/cloudstack-cli/commands/ip_address.rb | 2 +- lib/cloudstack-cli/commands/router.rb | 4 ++-- lib/cloudstack-cli/commands/snapshot.rb | 2 +- lib/cloudstack-cli/commands/ssh_key_pair.rb | 2 +- lib/cloudstack-cli/commands/user.rb | 2 +- lib/cloudstack-cli/commands/virtual_machine.rb | 2 +- lib/cloudstack-cli/version.rb | 2 +- 11 files changed, 14 insertions(+), 14 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index f9826c7..761e253 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -6,16 +6,16 @@ PATH PATH remote: . specs: - cloudstack-cli (1.5.11) + cloudstack-cli (1.5.12) cloudstack_client (~> 1.4.3) - thor (~> 0.19) + thor (~> 0.19.4) GEM remote: https://rubygems.org/ specs: minitest (5.9.1) rake (11.3.0) - thor (0.19.1) + thor (0.19.4) PLATFORMS ruby diff --git a/cloudstack-cli.gemspec b/cloudstack-cli.gemspec index 97494d6..272305d 100644 --- a/cloudstack-cli.gemspec +++ b/cloudstack-cli.gemspec @@ -25,5 +25,5 @@ Gem::Specification.new do |gem| gem.add_development_dependency('minitest', '~> 5.9') gem.add_dependency('cloudstack_client', '~> 1.4.3') - gem.add_dependency('thor', '~> 0.19') + gem.add_dependency('thor', '~> 0.19.4') end diff --git a/lib/cloudstack-cli/commands/account.rb b/lib/cloudstack-cli/commands/account.rb index fcc563a..ff45ea2 100644 --- a/lib/cloudstack-cli/commands/account.rb +++ b/lib/cloudstack-cli/commands/account.rb @@ -20,7 +20,7 @@ def show(name) end end - desc 'list', 'list accounts' + desc "list", "list accounts" option :format, default: "table", enum: %w(table json yaml) def list diff --git a/lib/cloudstack-cli/commands/affinity_group.rb b/lib/cloudstack-cli/commands/affinity_group.rb index 672a84f..3052a77 100644 --- a/lib/cloudstack-cli/commands/affinity_group.rb +++ b/lib/cloudstack-cli/commands/affinity_group.rb @@ -4,7 +4,7 @@ class AffinityGroup < CloudstackCli::Base option :account option :name option :type - option :listall + option :listall, type: :boolean, default: true option :keyword option :format, default: "table", enum: %w(table json yaml) diff --git a/lib/cloudstack-cli/commands/ip_address.rb b/lib/cloudstack-cli/commands/ip_address.rb index 9956d62..5bebc95 100644 --- a/lib/cloudstack-cli/commands/ip_address.rb +++ b/lib/cloudstack-cli/commands/ip_address.rb @@ -28,7 +28,7 @@ def assign(network) desc "list", "list public IP address" option :project option :account - option :listall + option :listall, type: :boolean, default: true option :format, default: "table", enum: %w(table json yaml) def list diff --git a/lib/cloudstack-cli/commands/router.rb b/lib/cloudstack-cli/commands/router.rb index 6b31f2f..834696f 100644 --- a/lib/cloudstack-cli/commands/router.rb +++ b/lib/cloudstack-cli/commands/router.rb @@ -7,7 +7,6 @@ class Router < CloudstackCli::Base option :state, desc: "the status of the router" option :redundant_state, desc: "the state of redundant virtual router", enum: %w(master backup fault unknown) - option :listall, type: :boolean, desc: "list all routers", default: true option :reverse, type: :boolean, default: false, desc: "reverse listing of routers" option :command, desc: "command to execute for each router", @@ -26,13 +25,14 @@ def list routers = client.list_routers(options) # show all routers unless project or account is set - if options[:listall] && !options[:project] && !options[:account] + if !options[:project] && !options[:account] client.list_projects(listall: true).each do |project| routers = routers + client.list_routers( options.merge(projectid: project['id']) ) end end + options[:listall] = true print_routers(routers, options) execute_router_commands(options[:command].downcase, routers) if options[:command] end diff --git a/lib/cloudstack-cli/commands/snapshot.rb b/lib/cloudstack-cli/commands/snapshot.rb index 2fe658f..adb63af 100644 --- a/lib/cloudstack-cli/commands/snapshot.rb +++ b/lib/cloudstack-cli/commands/snapshot.rb @@ -4,7 +4,7 @@ class Snapshot < CloudstackCli::Base option :account, desc: "the account associated with the snapshot" option :project, desc: "the project associated with the snapshot" option :domain, desc: "the domain name of the snapshot's account" - option :listall, default: true, desc: "list all resources the caller has rights on" + option :listall, type: :boolean, default: true, desc: "list all resources the caller has rights on" option :state, desc: "filter snapshots by state" option :format, default: "table", enum: %w(table json yaml) diff --git a/lib/cloudstack-cli/commands/ssh_key_pair.rb b/lib/cloudstack-cli/commands/ssh_key_pair.rb index 163e61f..ca42d0c 100644 --- a/lib/cloudstack-cli/commands/ssh_key_pair.rb +++ b/lib/cloudstack-cli/commands/ssh_key_pair.rb @@ -1,7 +1,7 @@ class SshKeyPair < CloudstackCli::Base desc "list", 'list ssh key pairs' - option :listall, default: true + option :listall, type: :boolean, default: true option :account, desc: "name of the account" option :project, desc: "name of the project" option :format, default: "table", diff --git a/lib/cloudstack-cli/commands/user.rb b/lib/cloudstack-cli/commands/user.rb index 9136da8..6d3b7ef 100644 --- a/lib/cloudstack-cli/commands/user.rb +++ b/lib/cloudstack-cli/commands/user.rb @@ -1,7 +1,7 @@ class User < CloudstackCli::Base desc 'list', 'list users' - option :listall + option :listall, type: :boolean, default: true option :account option :format, default: "table", enum: %w(table json yaml) diff --git a/lib/cloudstack-cli/commands/virtual_machine.rb b/lib/cloudstack-cli/commands/virtual_machine.rb index 9fc7ce8..f75a2b4 100644 --- a/lib/cloudstack-cli/commands/virtual_machine.rb +++ b/lib/cloudstack-cli/commands/virtual_machine.rb @@ -10,7 +10,7 @@ class VirtualMachine < CloudstackCli::Base option :host, desc: "the name of the hypervisor host the VM belong to" option :filter, type: :hash, desc: "filter objects based on arrtibutes: (attr1:regex attr2:regex ...)" - option :listall, desc: "list all virtual machines", default: true + option :listall, desc: "list all virtual machines", type: :boolean, default: true option :command, desc: "command to execute for the given virtual machines", enum: %w(START STOP REBOOT) diff --git a/lib/cloudstack-cli/version.rb b/lib/cloudstack-cli/version.rb index 778dbb0..9731878 100644 --- a/lib/cloudstack-cli/version.rb +++ b/lib/cloudstack-cli/version.rb @@ -1,3 +1,3 @@ module CloudstackCli - VERSION = "1.5.11" + VERSION = "1.5.12" end From 77fcf68fc012d483c131f084bfdff2fb482d3e3c Mon Sep 17 00:00:00 2001 From: niwo Date: Fri, 6 Jan 2017 14:01:20 +0100 Subject: [PATCH 15/36] enhanced compute_offer sort --- Gemfile.lock | 8 ++++---- cloudstack-cli.gemspec | 2 +- lib/cloudstack-cli/commands/compute_offer.rb | 2 +- lib/cloudstack-cli/version.rb | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 761e253..1ee8c53 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -13,8 +13,8 @@ PATH GEM remote: https://rubygems.org/ specs: - minitest (5.9.1) - rake (11.3.0) + minitest (5.10.1) + rake (12.0.0) thor (0.19.4) PLATFORMS @@ -24,7 +24,7 @@ DEPENDENCIES cloudstack-cli! cloudstack_client! minitest (~> 5.9) - rake (~> 11.3) + rake (~> 12.0) BUNDLED WITH - 1.13.6 + 1.13.7 diff --git a/cloudstack-cli.gemspec b/cloudstack-cli.gemspec index 272305d..8c19359 100644 --- a/cloudstack-cli.gemspec +++ b/cloudstack-cli.gemspec @@ -21,7 +21,7 @@ Gem::Specification.new do |gem| gem.require_paths = %w(lib) gem.rdoc_options = %w[--line-numbers --inline-source] - gem.add_development_dependency('rake', '~> 11.3') + gem.add_development_dependency('rake', '~> 12.0') gem.add_development_dependency('minitest', '~> 5.9') gem.add_dependency('cloudstack_client', '~> 1.4.3') diff --git a/lib/cloudstack-cli/commands/compute_offer.rb b/lib/cloudstack-cli/commands/compute_offer.rb index bbcbb99..9146644 100644 --- a/lib/cloudstack-cli/commands/compute_offer.rb +++ b/lib/cloudstack-cli/commands/compute_offer.rb @@ -60,7 +60,7 @@ def sort sortkey = -1 offerings.group_by{|o| o["domain"]}.each_value do |offers| offers.sort { - |oa, ob| [oa["cpunumber"], oa["memory"]] <=> [ob["cpunumber"], ob["memory"]] + |oa, ob| [oa["cpunumber"], oa["memory"], oa["name"]] <=> [ob["cpunumber"], ob["memory"], ob["name"]] }.each do |offer| puts "#{sortkey.abs} #{offer['domain']} - #{offer["displaytext"]}" client.update_service_offering( diff --git a/lib/cloudstack-cli/version.rb b/lib/cloudstack-cli/version.rb index 9731878..9e8aafe 100644 --- a/lib/cloudstack-cli/version.rb +++ b/lib/cloudstack-cli/version.rb @@ -1,3 +1,3 @@ module CloudstackCli - VERSION = "1.5.12" + VERSION = "1.5.13" end From 99dcbb211b5ccabf2fedf83927c30c4bab25673a Mon Sep 17 00:00:00 2001 From: niwo Date: Tue, 21 Feb 2017 10:23:40 +0100 Subject: [PATCH 16/36] adding username to user list --- Gemfile.lock | 2 +- lib/cloudstack-cli/commands/user.rb | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 1ee8c53..aba88ee 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -6,7 +6,7 @@ PATH PATH remote: . specs: - cloudstack-cli (1.5.12) + cloudstack-cli (1.5.13) cloudstack_client (~> 1.4.3) thor (~> 0.19.4) diff --git a/lib/cloudstack-cli/commands/user.rb b/lib/cloudstack-cli/commands/user.rb index 6d3b7ef..4b30f76 100644 --- a/lib/cloudstack-cli/commands/user.rb +++ b/lib/cloudstack-cli/commands/user.rb @@ -17,11 +17,14 @@ def list when :json puts JSON.pretty_generate(users: users) else - table = [["Account", "Type", "Name", "Email", "State", "Domain"]] + table = [%w(Account Type Name Username Email State Domain)] users.each do |user| table << [ - user['account'], Account::TYPES[user['accounttype']], "#{user['firstname']} #{user['lastname']}", - user['email'], user['state'], user['domain'] + user['account'], + Account::TYPES[user['accounttype']], + "#{user['firstname']} #{user['lastname']}", + user['username'], user['email'], + user['state'], user['domain'] ] end print_table table From e72681a60a38e75505834cf2458dec5c84c41fc8 Mon Sep 17 00:00:00 2001 From: niwo Date: Sat, 1 Jul 2017 23:33:57 +0200 Subject: [PATCH 17/36] using configuration module from CloudstackClient --- Gemfile.lock | 8 ++-- README.md | 23 ++++++---- cloudstack-cli.gemspec | 2 +- lib/cloudstack-cli.rb | 1 + lib/cloudstack-cli/base.rb | 49 +++++++-------------- lib/cloudstack-cli/cli.rb | 4 +- lib/cloudstack-cli/version.rb | 2 +- spec/{cloudstack-cli.yml => cloudstack.yml} | 1 - spec/spec_helper.rb | 2 +- 9 files changed, 40 insertions(+), 52 deletions(-) rename spec/{cloudstack-cli.yml => cloudstack.yml} (98%) diff --git a/Gemfile.lock b/Gemfile.lock index aba88ee..78848db 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,19 +1,19 @@ PATH remote: ../cloudstack_client/ specs: - cloudstack_client (1.4.3) + cloudstack_client (1.5.3) PATH remote: . specs: - cloudstack-cli (1.5.13) - cloudstack_client (~> 1.4.3) + cloudstack-cli (1.6.0) + cloudstack_client (~> 1.5.3) thor (~> 0.19.4) GEM remote: https://rubygems.org/ specs: - minitest (5.10.1) + minitest (5.10.2) rake (12.0.0) thor (0.19.4) diff --git a/README.md b/README.md index 4aab0f7..064123b 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,8 @@ $ gem install cloudstack-cli ### Create a cloudstack-cli environment -cloudstack-cli expects to find a configuration file with the API URL and your CloudStack credentials in your home directory named .cloudstack-cli.yml. If the file is located elsewhere you can specify the location using the --config option. +cloudstack-cli expects to find a configuration file with the API URL and your CloudStack credentials in your home directory named .cloudstack.yml (or .cloudstack-cli.yml). +If the file is located elsewhere you can specify the location using the --config-file option. *Create your initial environment, which defines your connection options:* @@ -48,17 +49,23 @@ $ cloudstack-cli environment default [environment-name] see `cloudstack-cli help environment` for more options. -Example content of the configuration file: +Example configuration file: ```yaml -:url: "https://my-cloudstack-server/client/api/" -:api_key: "cloudstack-api-key" -:secret_key: "cloudstack-api-secret" +# default environment +:default: production +# production environment +production: + :url: "https://my-cloudstack-server/client/api/" + :api_key: "cloudstack-api-key" + :secret_key: "cloudstack-api-secret" + +# test environment test: - :url: "http://my-cloudstack-testserver/client/api/" - :api_key: "cloudstack-api-key" - :secret_key: "cloudstack-api-secret" + :url: "http://my-cloudstack-testserver/client/api/" + :api_key: "cloudstack-api-key" + :secret_key: "cloudstack-api-secret" ``` ### Shell tab auto-completion diff --git a/cloudstack-cli.gemspec b/cloudstack-cli.gemspec index 8c19359..72d45d9 100644 --- a/cloudstack-cli.gemspec +++ b/cloudstack-cli.gemspec @@ -24,6 +24,6 @@ Gem::Specification.new do |gem| gem.add_development_dependency('rake', '~> 12.0') gem.add_development_dependency('minitest', '~> 5.9') - gem.add_dependency('cloudstack_client', '~> 1.4.3') + gem.add_dependency('cloudstack_client', '~> 1.5.3') gem.add_dependency('thor', '~> 0.19.4') end diff --git a/lib/cloudstack-cli.rb b/lib/cloudstack-cli.rb index 0e86eea..b886d59 100644 --- a/lib/cloudstack-cli.rb +++ b/lib/cloudstack-cli.rb @@ -1,4 +1,5 @@ require "cloudstack_client" +require "cloudstack_client/configuration" require "cloudstack-cli/version" require "cloudstack-cli/helper" diff --git a/lib/cloudstack-cli/base.rb b/lib/cloudstack-cli/base.rb index 32ffebf..6e460f2 100644 --- a/lib/cloudstack-cli/base.rb +++ b/lib/cloudstack-cli/base.rb @@ -49,34 +49,12 @@ def client @client end - def load_configuration(config_file = options[:config_file], env = options[:env]) - unless File.exists?(config_file) - say "Configuration file #{config_file} not found.", :red - say "Please run \'cs environment add\' to create one." - exit 1 - end - - begin - config = YAML::load(IO.read(config_file)) - rescue - say "Can't load configuration from file #{config_file}.", :red - exit 1 - end - - env ||= config[:default] - if env - unless config = config[env] - say "Can't find environment #{env}.", :red - exit 1 - end - end - - unless config.key?(:url) && config.key?(:api_key) && config.key?(:secret_key) - say "The environment #{env || '\'-\''} does not contain all required keys.", :red - say "Please check with 'cloudstack-cli environment list' and set a valid default environment." - exit 1 - end - config + def load_configuration + CloudstackClient::Configuration.load(options) + rescue CloudstackClient::ConfigurationError => e + say "Error: ", :red + say e.message + exit 1 end def filter_by(objects, key, value) @@ -91,7 +69,8 @@ def filter_by(objects, key, value) object[key.to_s].to_s =~ /#{value}/i end rescue RegexpError => e - say "ERROR: Invalid regular expression in filter - #{e.message}", :red + say "ERROR: ", :red + say "Invalid regular expression in filter - #{e.message}" exit 1 end @@ -119,21 +98,23 @@ def parse_file(file, extensions = %w(.json .yaml .yml)) when ".yaml", ".yml" Object.const_get "YAML" else - say "File extension #{File.extname(file)} not supported. Supported extensions are #{extensions.join(', ')}", :red + say "ERROR: ", :red + say "File extension #{File.extname(file)} not supported. Supported extensions are #{extensions.join(', ')}" exit end begin return handler.load open(file){|f| f.read} rescue SystemCallError - say "Can't find the file #{file}.", :red + say "ERROR: ", :red + say "Can't find the file '#{file}'." exit 1 rescue => e - say "Error parsing #{File.extname(file)} file:", :red - say e.message + say "ERROR: ", :red + say "Can't parse file '#{file}': #{e.message}" exit 1 end end end - + end # class end # module diff --git a/lib/cloudstack-cli/cli.rb b/lib/cloudstack-cli/cli.rb index 594bb27..50fc903 100644 --- a/lib/cloudstack-cli/cli.rb +++ b/lib/cloudstack-cli/cli.rb @@ -5,9 +5,9 @@ class Cli < CloudstackCli::Base package_name "cloudstack-cli" class_option :config_file, - default: File.join(Dir.home, '.cloudstack-cli.yml'), + default: CloudstackClient::Configuration.locate_config_file, aliases: '-c', - desc: 'Location of your cloudstack-cli configuration file' + desc: 'Location of your cloudstack configuration file' class_option :env, aliases: '-e', diff --git a/lib/cloudstack-cli/version.rb b/lib/cloudstack-cli/version.rb index 9e8aafe..1dc5a9a 100644 --- a/lib/cloudstack-cli/version.rb +++ b/lib/cloudstack-cli/version.rb @@ -1,3 +1,3 @@ module CloudstackCli - VERSION = "1.5.13" + VERSION = "1.6.0" end diff --git a/spec/cloudstack-cli.yml b/spec/cloudstack.yml similarity index 98% rename from spec/cloudstack-cli.yml rename to spec/cloudstack.yml index c8f771d..426c02c 100644 --- a/spec/cloudstack-cli.yml +++ b/spec/cloudstack.yml @@ -1,4 +1,3 @@ ---- :default: development development: :url: http://127.0.0.1:8080/client/api diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 525dbd4..f15d66c 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -5,7 +5,7 @@ require "minitest/pride" # make the config file setup awailable to all specs -CONFIG = "--config-file=#{File.expand_path('cloudstack-cli.yml', File.dirname(__FILE__))}" +CONFIG = "--config-file=#{File.expand_path('cloudstack.yml', File.dirname(__FILE__))}" ZONE = "Sandbox-simulator" TEMPLATE = "CentOS 5.3(64-bit) no GUI (Simulator)" OFFERING_S = "Small Instance" From 35b4c0669a9a5e7d1294dc15a433fa94b2fc843a Mon Sep 17 00:00:00 2001 From: niwo Date: Thu, 17 Aug 2017 21:01:55 +0200 Subject: [PATCH 18/36] fix default config_file path --- Gemfile.lock | 8 ++++---- cloudstack-cli.gemspec | 2 +- lib/cloudstack-cli/cli.rb | 3 ++- lib/cloudstack-cli/version.rb | 2 +- 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 78848db..7afc6c5 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -6,16 +6,16 @@ PATH PATH remote: . specs: - cloudstack-cli (1.6.0) + cloudstack-cli (1.6.1) cloudstack_client (~> 1.5.3) - thor (~> 0.19.4) + thor (~> 0.20.0) GEM remote: https://rubygems.org/ specs: - minitest (5.10.2) + minitest (5.10.3) rake (12.0.0) - thor (0.19.4) + thor (0.20.0) PLATFORMS ruby diff --git a/cloudstack-cli.gemspec b/cloudstack-cli.gemspec index 72d45d9..f776f9d 100644 --- a/cloudstack-cli.gemspec +++ b/cloudstack-cli.gemspec @@ -25,5 +25,5 @@ Gem::Specification.new do |gem| gem.add_development_dependency('minitest', '~> 5.9') gem.add_dependency('cloudstack_client', '~> 1.5.3') - gem.add_dependency('thor', '~> 0.19.4') + gem.add_dependency('thor', '~> 0.20.0') end diff --git a/lib/cloudstack-cli/cli.rb b/lib/cloudstack-cli/cli.rb index 50fc903..9158fdc 100644 --- a/lib/cloudstack-cli/cli.rb +++ b/lib/cloudstack-cli/cli.rb @@ -5,7 +5,8 @@ class Cli < CloudstackCli::Base package_name "cloudstack-cli" class_option :config_file, - default: CloudstackClient::Configuration.locate_config_file, + default: CloudstackClient::Configuration.locate_config_file || + File.join(Dir.home, ".cloudstack.yml"), aliases: '-c', desc: 'Location of your cloudstack configuration file' diff --git a/lib/cloudstack-cli/version.rb b/lib/cloudstack-cli/version.rb index 1dc5a9a..62fd373 100644 --- a/lib/cloudstack-cli/version.rb +++ b/lib/cloudstack-cli/version.rb @@ -1,3 +1,3 @@ module CloudstackCli - VERSION = "1.6.0" + VERSION = "1.6.1" end From c55ac881eef0649de5c29837f36132cbdf77b707 Mon Sep 17 00:00:00 2001 From: Nik Wolfgramm Date: Mon, 11 Dec 2017 18:12:46 +0100 Subject: [PATCH 19/36] adding force options for list vm commands --- Gemfile | 10 +++++----- Gemfile.lock | 13 ++++--------- lib/cloudstack-cli/commands/virtual_machine.rb | 12 ++++++++---- lib/cloudstack-cli/version.rb | 2 +- 4 files changed, 18 insertions(+), 19 deletions(-) diff --git a/Gemfile b/Gemfile index 9333b2b..431f18b 100644 --- a/Gemfile +++ b/Gemfile @@ -1,10 +1,10 @@ source 'https://rubygems.org' -group :development do - gem 'cloudstack_client', - path: '../cloudstack_client/', - branch: 'master' -end +# group :development do +# gem 'cloudstack_client', +# path: '../cloudstack_client/', +# branch: 'master' +# end # Specify your gem's dependencies in cloudstack-cli.gemspec gemspec diff --git a/Gemfile.lock b/Gemfile.lock index 7afc6c5..678b37c 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,20 +1,16 @@ -PATH - remote: ../cloudstack_client/ - specs: - cloudstack_client (1.5.3) - PATH remote: . specs: - cloudstack-cli (1.6.1) + cloudstack-cli (1.6.2) cloudstack_client (~> 1.5.3) thor (~> 0.20.0) GEM remote: https://rubygems.org/ specs: + cloudstack_client (1.5.3) minitest (5.10.3) - rake (12.0.0) + rake (12.3.0) thor (0.20.0) PLATFORMS @@ -22,9 +18,8 @@ PLATFORMS DEPENDENCIES cloudstack-cli! - cloudstack_client! minitest (~> 5.9) rake (~> 12.0) BUNDLED WITH - 1.13.7 + 1.16.0 diff --git a/lib/cloudstack-cli/commands/virtual_machine.rb b/lib/cloudstack-cli/commands/virtual_machine.rb index f75a2b4..20681d7 100644 --- a/lib/cloudstack-cli/commands/virtual_machine.rb +++ b/lib/cloudstack-cli/commands/virtual_machine.rb @@ -18,6 +18,7 @@ class VirtualMachine < CloudstackCli::Base desc: "number of concurrent commands to execute" option :format, default: "table", enum: %w(table json yaml) + option :force, desc: "execute command without confirmation", type: :boolean, aliases: '-f' def list add_filters_to_options("listVirtualMachines") if options[:filter] resolve_account @@ -35,7 +36,7 @@ def list puts "No virtual machines found." else print_virtual_machines(virtual_machines) - execute_virtual_machines_commands(command, virtual_machines) if command + execute_virtual_machines_commands(command, virtual_machines, options) if command end end @@ -46,6 +47,7 @@ def list option :concurrency, type: :numeric, default: 10, aliases: '-C', desc: "number of concurrent command to execute" option :format, default: :table, enum: %w(table json yaml) + option :force, desc: "execute command without confirmation", type: :boolean, aliases: '-f' def list_from_file(file) virtual_machines = parse_file(file)["virtual_machines"] if virtual_machines.size < 1 @@ -54,7 +56,8 @@ def list_from_file(file) print_virtual_machines(virtual_machines) execute_virtual_machines_commands( options[:command].downcase, - virtual_machines + virtual_machines, + options ) if options[:command] end end @@ -322,12 +325,13 @@ def print_virtual_machines(virtual_machines) end end - def execute_virtual_machines_commands(command, virtual_machines) + def execute_virtual_machines_commands(command, virtual_machines, options = {}) unless %w(start stop reboot).include?(command) say "\nCommand #{options[:command]} not supported.", :red exit 1 end - exit unless yes?("\n#{command.capitalize} the virtual machine(s) above? [y/N]:", :magenta) + exit unless options[:force] || + yes?("\n#{command.capitalize} the virtual machine(s) above? [y/N]:", :magenta) jobs = virtual_machines.map do |vm| { diff --git a/lib/cloudstack-cli/version.rb b/lib/cloudstack-cli/version.rb index 62fd373..e31da70 100644 --- a/lib/cloudstack-cli/version.rb +++ b/lib/cloudstack-cli/version.rb @@ -1,3 +1,3 @@ module CloudstackCli - VERSION = "1.6.1" + VERSION = "1.6.2" end From 2c5b7c4c32cfb715349bfad164ce2a43c1529435 Mon Sep 17 00:00:00 2001 From: niwo Date: Fri, 4 May 2018 16:57:22 +0200 Subject: [PATCH 20/36] updated dependencies --- Gemfile.lock | 14 +++++++------- cloudstack-cli.gemspec | 4 ++-- lib/cloudstack-cli/version.rb | 2 +- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 678b37c..35ae801 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,16 +1,16 @@ PATH remote: . specs: - cloudstack-cli (1.6.2) + cloudstack-cli (1.6.3) cloudstack_client (~> 1.5.3) thor (~> 0.20.0) GEM remote: https://rubygems.org/ specs: - cloudstack_client (1.5.3) - minitest (5.10.3) - rake (12.3.0) + cloudstack_client (1.5.4) + minitest (5.11.3) + rake (12.3.1) thor (0.20.0) PLATFORMS @@ -18,8 +18,8 @@ PLATFORMS DEPENDENCIES cloudstack-cli! - minitest (~> 5.9) - rake (~> 12.0) + minitest (~> 5.11) + rake (~> 12.3) BUNDLED WITH - 1.16.0 + 1.16.1 diff --git a/cloudstack-cli.gemspec b/cloudstack-cli.gemspec index f776f9d..2b89101 100644 --- a/cloudstack-cli.gemspec +++ b/cloudstack-cli.gemspec @@ -21,8 +21,8 @@ Gem::Specification.new do |gem| gem.require_paths = %w(lib) gem.rdoc_options = %w[--line-numbers --inline-source] - gem.add_development_dependency('rake', '~> 12.0') - gem.add_development_dependency('minitest', '~> 5.9') + gem.add_development_dependency('rake', '~> 12.3') + gem.add_development_dependency('minitest', '~> 5.11') gem.add_dependency('cloudstack_client', '~> 1.5.3') gem.add_dependency('thor', '~> 0.20.0') diff --git a/lib/cloudstack-cli/version.rb b/lib/cloudstack-cli/version.rb index e31da70..b0783ee 100644 --- a/lib/cloudstack-cli/version.rb +++ b/lib/cloudstack-cli/version.rb @@ -1,3 +1,3 @@ module CloudstackCli - VERSION = "1.6.2" + VERSION = "1.6.3" end From 1d0a720eca77024da8a8b76344857baf19e3e1a6 Mon Sep 17 00:00:00 2001 From: niwo Date: Sun, 25 Nov 2018 01:29:43 +0100 Subject: [PATCH 21/36] updated gems, rescue template date exceptions --- Gemfile.lock | 4 ++-- lib/cloudstack-cli/commands/template.rb | 2 +- lib/cloudstack-cli/version.rb | 2 +- spec/cloudstack.yml | 6 +++--- spec/spec_helper.rb | 4 ++-- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 35ae801..831eb63 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,7 +1,7 @@ PATH remote: . specs: - cloudstack-cli (1.6.3) + cloudstack-cli (1.6.4) cloudstack_client (~> 1.5.3) thor (~> 0.20.0) @@ -11,7 +11,7 @@ GEM cloudstack_client (1.5.4) minitest (5.11.3) rake (12.3.1) - thor (0.20.0) + thor (0.20.3) PLATFORMS ruby diff --git a/lib/cloudstack-cli/commands/template.rb b/lib/cloudstack-cli/commands/template.rb index 3f668f4..9d74394 100644 --- a/lib/cloudstack-cli/commands/template.rb +++ b/lib/cloudstack-cli/commands/template.rb @@ -26,7 +26,7 @@ def list(type='featured') templates.each do |template| table << [ template['name'], - Time.parse(template['created']).strftime("%F"), + (Time.parse(template['created']).strftime("%F") rescue "-"), template['zonename'], template['isfeatured'], template['ispublic'], diff --git a/lib/cloudstack-cli/version.rb b/lib/cloudstack-cli/version.rb index b0783ee..cdc07d2 100644 --- a/lib/cloudstack-cli/version.rb +++ b/lib/cloudstack-cli/version.rb @@ -1,3 +1,3 @@ module CloudstackCli - VERSION = "1.6.3" + VERSION = "1.6.4" end diff --git a/spec/cloudstack.yml b/spec/cloudstack.yml index 426c02c..8804ced 100644 --- a/spec/cloudstack.yml +++ b/spec/cloudstack.yml @@ -1,5 +1,5 @@ :default: development development: - :url: http://127.0.0.1:8080/client/api - :api_key: 3B1lE0C33ceSOUg0jaIo8STNZ55I-mdvza0LXpZA8mrvtpBpgzJgE9YSsURBcQ6qKX090w5vv_AgGRZeYS9AiQ - :secret_key: mneyw6fg__Gt-ENg0E_9BfxcuiMJPSThe701Kuz7f5_EsJ0POoN4z9eoslECP5V9oDzB6XOlsCw1FuBqPjMmLg + :url: http://localhost:8080/client/api + :api_key: oCyplGVQ0i64XLm6LATWSrcX_oMnH3BuTl9P2QR0VoD6obi1fcVTa5niOvRSlVnVwEjNwOpfNwXtUgueCEKrfg + :secret_key: OA-kVaw4QxYceWebDuBpwiQz2c9r0tpny6E4MwAUb8-IFIFXiIGdPKxTneuoP-vE-l9MUMoSLE1UwO0yAzaM8Q diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index f15d66c..a6e2595 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -4,9 +4,9 @@ require "minitest/autorun" require "minitest/pride" -# make the config file setup awailable to all specs +# make the config file setup available to all specs CONFIG = "--config-file=#{File.expand_path('cloudstack.yml', File.dirname(__FILE__))}" ZONE = "Sandbox-simulator" -TEMPLATE = "CentOS 5.3(64-bit) no GUI (Simulator)" +TEMPLATE = "CentOS 5.6 (64-bit) no GUI (Simulator)" OFFERING_S = "Small Instance" OFFERING_M = "Medium Instance" From 04d506d7f9561f231b4fa81c466f4549b590fcd0 Mon Sep 17 00:00:00 2001 From: niwo Date: Sun, 25 Nov 2018 01:54:42 +0100 Subject: [PATCH 22/36] remove test env --- Gemfile.lock | 2 +- cloudstack-cli.gemspec | 2 +- .../commands/virtual_machine_spec.rb | 24 +++++++------------ spec/cloudstack.yml | 5 ---- spec/spec_helper.rb | 1 - 5 files changed, 10 insertions(+), 24 deletions(-) delete mode 100644 spec/cloudstack.yml diff --git a/Gemfile.lock b/Gemfile.lock index 831eb63..356e645 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -2,7 +2,7 @@ PATH remote: . specs: cloudstack-cli (1.6.4) - cloudstack_client (~> 1.5.3) + cloudstack_client (~> 1.5.4) thor (~> 0.20.0) GEM diff --git a/cloudstack-cli.gemspec b/cloudstack-cli.gemspec index 2b89101..8f8ade4 100644 --- a/cloudstack-cli.gemspec +++ b/cloudstack-cli.gemspec @@ -24,6 +24,6 @@ Gem::Specification.new do |gem| gem.add_development_dependency('rake', '~> 12.3') gem.add_development_dependency('minitest', '~> 5.11') - gem.add_dependency('cloudstack_client', '~> 1.5.3') + gem.add_dependency('cloudstack_client', '~> 1.5.4') gem.add_dependency('thor', '~> 0.20.0') end diff --git a/spec/cloudstack-cli/commands/virtual_machine_spec.rb b/spec/cloudstack-cli/commands/virtual_machine_spec.rb index cfee7f1..49dcecd 100644 --- a/spec/cloudstack-cli/commands/virtual_machine_spec.rb +++ b/spec/cloudstack-cli/commands/virtual_machine_spec.rb @@ -16,16 +16,14 @@ "--offering=#{OFFERING_S}", "--networks=test-network", "--port-rules=:80", - "--assumeyes", - CONFIG, + "--assumeyes" ]} err.must_equal "" # READ - LIST out, err = capture_io{ CloudstackCli::Cli.start [ "vm", - "list", - CONFIG + "list" ]} err.must_equal "" out.must_match( @@ -36,8 +34,7 @@ out, err = capture_io{ CloudstackCli::Cli.start [ "vm", "show", - vmname, - CONFIG + vmname ]} err.must_equal "" out.must_match( @@ -49,8 +46,7 @@ "vm", "stop", vmname, - "--force", - CONFIG, + "--force" ]} err.must_equal "" @@ -61,8 +57,7 @@ "update", vmname, "--name=#{new_vmname}", - "--force", - CONFIG, + "--force" ]} err.must_equal "" @@ -70,8 +65,7 @@ out, err = capture_io{ CloudstackCli::Cli.start [ "vm", "start", - new_vmname, - CONFIG, + new_vmname ]} err.must_equal "" @@ -80,8 +74,7 @@ "vm", "reboot", new_vmname, - "--force", - CONFIG, + "--force" ]} err.must_equal "" @@ -91,8 +84,7 @@ "destroy", new_vmname, "--expunge", - "--force", - CONFIG, + "--force" ]} err.must_equal "" diff --git a/spec/cloudstack.yml b/spec/cloudstack.yml deleted file mode 100644 index 8804ced..0000000 --- a/spec/cloudstack.yml +++ /dev/null @@ -1,5 +0,0 @@ -:default: development -development: - :url: http://localhost:8080/client/api - :api_key: oCyplGVQ0i64XLm6LATWSrcX_oMnH3BuTl9P2QR0VoD6obi1fcVTa5niOvRSlVnVwEjNwOpfNwXtUgueCEKrfg - :secret_key: OA-kVaw4QxYceWebDuBpwiQz2c9r0tpny6E4MwAUb8-IFIFXiIGdPKxTneuoP-vE-l9MUMoSLE1UwO0yAzaM8Q diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index a6e2595..cdee578 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -5,7 +5,6 @@ require "minitest/pride" # make the config file setup available to all specs -CONFIG = "--config-file=#{File.expand_path('cloudstack.yml', File.dirname(__FILE__))}" ZONE = "Sandbox-simulator" TEMPLATE = "CentOS 5.6 (64-bit) no GUI (Simulator)" OFFERING_S = "Small Instance" From b2898c63ddddd11b5d54b03b2399dd3f352f3235 Mon Sep 17 00:00:00 2001 From: Nik Wolfgramm Date: Mon, 3 Dec 2018 14:41:07 +0100 Subject: [PATCH 23/36] using cloudstack_client 1.5.5 and adding template spec --- Gemfile.lock | 10 +++---- LICENSE.txt | 4 +-- README.md | 2 +- cloudstack-cli.gemspec | 2 +- lib/cloudstack-cli/version.rb | 2 +- spec/cloudstack-cli/commands/template_spec.rb | 18 +++++++++++ .../commands/virtual_machine_spec.rb | 30 +++++++++++-------- spec/cloudstack.yml | 8 ++--- spec/spec_helper.rb | 2 +- 9 files changed, 50 insertions(+), 28 deletions(-) create mode 100644 spec/cloudstack-cli/commands/template_spec.rb diff --git a/Gemfile.lock b/Gemfile.lock index 35ae801..887f0d8 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,17 +1,17 @@ PATH remote: . specs: - cloudstack-cli (1.6.3) - cloudstack_client (~> 1.5.3) + cloudstack-cli (1.6.4) + cloudstack_client (~> 1.5.5) thor (~> 0.20.0) GEM remote: https://rubygems.org/ specs: - cloudstack_client (1.5.4) + cloudstack_client (1.5.5) minitest (5.11.3) rake (12.3.1) - thor (0.20.0) + thor (0.20.3) PLATFORMS ruby @@ -22,4 +22,4 @@ DEPENDENCIES rake (~> 12.3) BUNDLED WITH - 1.16.1 + 1.17.1 diff --git a/LICENSE.txt b/LICENSE.txt index 4f3aa33..5ca13fa 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2013 Nik Wolfgramm +Copyright (c) 2013-2018 Nik Wolfgramm Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -18,4 +18,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. \ No newline at end of file +THE SOFTWARE. diff --git a/README.md b/README.md index 064123b..41629a0 100644 --- a/README.md +++ b/README.md @@ -102,7 +102,7 @@ $ cloudstack-cli vm help list *Bootstraps a server using a template and creating port-forwarding rules for port 22 and 80:* ```bash -$ cloudstack-cli server create server-01 --template CentOS-6.4-x64-v1.4 --zone DC1 --offering 1cpu_1gb --port-rules :22 :80 +$ cloudstack-cli server create web-01 --template CentOS-7.5-x64 --zone DC1 --offering 2cpu_2gb --port-rules :22 :80 ``` ### Example: Run any custom API command diff --git a/cloudstack-cli.gemspec b/cloudstack-cli.gemspec index 2b89101..6d7f16c 100644 --- a/cloudstack-cli.gemspec +++ b/cloudstack-cli.gemspec @@ -24,6 +24,6 @@ Gem::Specification.new do |gem| gem.add_development_dependency('rake', '~> 12.3') gem.add_development_dependency('minitest', '~> 5.11') - gem.add_dependency('cloudstack_client', '~> 1.5.3') + gem.add_dependency('cloudstack_client', '~> 1.5.5') gem.add_dependency('thor', '~> 0.20.0') end diff --git a/lib/cloudstack-cli/version.rb b/lib/cloudstack-cli/version.rb index b0783ee..cdc07d2 100644 --- a/lib/cloudstack-cli/version.rb +++ b/lib/cloudstack-cli/version.rb @@ -1,3 +1,3 @@ module CloudstackCli - VERSION = "1.6.3" + VERSION = "1.6.4" end diff --git a/spec/cloudstack-cli/commands/template_spec.rb b/spec/cloudstack-cli/commands/template_spec.rb new file mode 100644 index 0000000..d9b339b --- /dev/null +++ b/spec/cloudstack-cli/commands/template_spec.rb @@ -0,0 +1,18 @@ +require "spec_helper" +require "cloudstack-cli" + +describe Template do + + it "should list templates" do + + out, err = capture_io{ CloudstackCli::Cli.start [ + "template", + "list", + "--zone=#{ZONE}", + CONFIG, + ]} + err.must_equal "" + out.must_include TEMPLATE + end + +end diff --git a/spec/cloudstack-cli/commands/virtual_machine_spec.rb b/spec/cloudstack-cli/commands/virtual_machine_spec.rb index cfee7f1..c3eb065 100644 --- a/spec/cloudstack-cli/commands/virtual_machine_spec.rb +++ b/spec/cloudstack-cli/commands/virtual_machine_spec.rb @@ -3,22 +3,26 @@ describe VirtualMachine do + #TODO: test-network must be created beforehand + it "should support all CRUD actions" do vmname = "testvm1" # CREATE - out, err = capture_io{ CloudstackCli::Cli.start [ - "vm", - "create", - vmname, - "--zone=#{ZONE}", - "--template=#{TEMPLATE}", - "--offering=#{OFFERING_S}", - "--networks=test-network", - "--port-rules=:80", - "--assumeyes", - CONFIG, - ]} + out, err = capture_io do + CloudstackCli::Cli.start [ + "vm", + "create", + vmname, + "--zone=#{ZONE}", + "--template=#{TEMPLATE}", + "--offering=#{OFFERING_S}", + "--networks=test-network", + "--port-rules=:80", + "--assumeyes", + CONFIG, + ] + end err.must_equal "" # READ - LIST @@ -95,7 +99,7 @@ CONFIG, ]} err.must_equal "" - + end end diff --git a/spec/cloudstack.yml b/spec/cloudstack.yml index 426c02c..cd2d523 100644 --- a/spec/cloudstack.yml +++ b/spec/cloudstack.yml @@ -1,5 +1,5 @@ -:default: development -development: +:default: test +test: :url: http://127.0.0.1:8080/client/api - :api_key: 3B1lE0C33ceSOUg0jaIo8STNZ55I-mdvza0LXpZA8mrvtpBpgzJgE9YSsURBcQ6qKX090w5vv_AgGRZeYS9AiQ - :secret_key: mneyw6fg__Gt-ENg0E_9BfxcuiMJPSThe701Kuz7f5_EsJ0POoN4z9eoslECP5V9oDzB6XOlsCw1FuBqPjMmLg + :api_key: _BEmrXaVKbW-LWSGfMjOojsWZW41HXMYK8kiygOLA1jy952NK6gNm8c-vW0u7OBadmGjsEjDld9KxO4JbVKpxA + :secret_key: 8qI-fCeF-Awf-aU3NQ6mPJOgC2iv4woeuazfL4OvHNxAt10s-y0sd7s8W99V2f3gRWT3po_jSExd3gmhGBZzlA diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index f15d66c..bae6a50 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -7,6 +7,6 @@ # make the config file setup awailable to all specs CONFIG = "--config-file=#{File.expand_path('cloudstack.yml', File.dirname(__FILE__))}" ZONE = "Sandbox-simulator" -TEMPLATE = "CentOS 5.3(64-bit) no GUI (Simulator)" +TEMPLATE = "CentOS 5.6 (64-bit) no GUI (Simulator)" OFFERING_S = "Small Instance" OFFERING_M = "Medium Instance" From 699b00a0e477ea3f2eb7ee593e7479610c174fd7 Mon Sep 17 00:00:00 2001 From: Nik Wolfgramm Date: Mon, 3 Dec 2018 14:56:49 +0100 Subject: [PATCH 24/36] using local cs env and describe testing in README --- spec/cloudstack-cli/commands/template_spec.rb | 14 +++++++------- .../commands/virtual_machine_spec.rb | 3 +-- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/spec/cloudstack-cli/commands/template_spec.rb b/spec/cloudstack-cli/commands/template_spec.rb index d9b339b..ab8b74f 100644 --- a/spec/cloudstack-cli/commands/template_spec.rb +++ b/spec/cloudstack-cli/commands/template_spec.rb @@ -4,13 +4,13 @@ describe Template do it "should list templates" do - - out, err = capture_io{ CloudstackCli::Cli.start [ - "template", - "list", - "--zone=#{ZONE}", - CONFIG, - ]} + out, err = capture_io do + CloudstackCli::Cli.start [ + "template", + "list", + "--zone=#{ZONE}" + ] + end err.must_equal "" out.must_include TEMPLATE end diff --git a/spec/cloudstack-cli/commands/virtual_machine_spec.rb b/spec/cloudstack-cli/commands/virtual_machine_spec.rb index 1625e04..34522b2 100644 --- a/spec/cloudstack-cli/commands/virtual_machine_spec.rb +++ b/spec/cloudstack-cli/commands/virtual_machine_spec.rb @@ -19,8 +19,7 @@ "--offering=#{OFFERING_S}", "--networks=test-network", "--port-rules=:80", - "--assumeyes", - CONFIG, + "--assumeyes" ] end err.must_equal "" From dcc14a465427b8f98c8d0334e57d90035984d529 Mon Sep 17 00:00:00 2001 From: Nik Wolfgramm Date: Mon, 3 Dec 2018 14:58:11 +0100 Subject: [PATCH 25/36] describe testing in README --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.md b/README.md index 41629a0..0b011e1 100644 --- a/README.md +++ b/README.md @@ -190,6 +190,13 @@ $ cloudstack-cli router list --project Demo --status running --redundant-state B - This tool was inspired by the Knife extension for Cloudstack: [knife-cloudstack](https://github.com/CloudStack-extras/knife-cloudstack) +## Test + +1. Requires the [cloudstack-simulator](https://hub.docker.com/r/cloudstack/simulator/) docker images running on your local machine +2. You need to add the admin secrets to your local cloudstack environment an make it default +3. Currently you need to create a isolated network named "test-network" manually on the simulator +4. Run `bundle exec rake test` + ## Contributing 1. Fork it From 9190a349045defce6f7447d8b33e86f9a2906a30 Mon Sep 17 00:00:00 2001 From: Nik Wolfgramm Date: Mon, 3 Dec 2018 15:00:32 +0100 Subject: [PATCH 26/36] v1.6.5 --- lib/cloudstack-cli/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cloudstack-cli/version.rb b/lib/cloudstack-cli/version.rb index cdc07d2..e87ab5a 100644 --- a/lib/cloudstack-cli/version.rb +++ b/lib/cloudstack-cli/version.rb @@ -1,3 +1,3 @@ module CloudstackCli - VERSION = "1.6.4" + VERSION = "1.6.5" end From d3e54b6f0c6543b80dd31959f110e8ad3bff4f1a Mon Sep 17 00:00:00 2001 From: Nik Wolfgramm Date: Mon, 3 Dec 2018 15:00:54 +0100 Subject: [PATCH 27/36] v1.6.5 --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index 887f0d8..e80051f 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,7 +1,7 @@ PATH remote: . specs: - cloudstack-cli (1.6.4) + cloudstack-cli (1.6.5) cloudstack_client (~> 1.5.5) thor (~> 0.20.0) From 8a558362884f5ff2d7ec4a2ed6a3644033e88e1e Mon Sep 17 00:00:00 2001 From: Nik Wolfgramm Date: Tue, 23 Jul 2019 09:58:13 +0200 Subject: [PATCH 28/36] updated dependencies --- Gemfile.lock | 6 +++--- cloudstack-cli.gemspec | 2 +- lib/cloudstack-cli/version.rb | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index e80051f..815c3b4 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -2,15 +2,15 @@ PATH remote: . specs: cloudstack-cli (1.6.5) - cloudstack_client (~> 1.5.5) + cloudstack_client (~> 1.5.6) thor (~> 0.20.0) GEM remote: https://rubygems.org/ specs: - cloudstack_client (1.5.5) + cloudstack_client (1.5.6) minitest (5.11.3) - rake (12.3.1) + rake (12.3.3) thor (0.20.3) PLATFORMS diff --git a/cloudstack-cli.gemspec b/cloudstack-cli.gemspec index 6d7f16c..42e0e6d 100644 --- a/cloudstack-cli.gemspec +++ b/cloudstack-cli.gemspec @@ -24,6 +24,6 @@ Gem::Specification.new do |gem| gem.add_development_dependency('rake', '~> 12.3') gem.add_development_dependency('minitest', '~> 5.11') - gem.add_dependency('cloudstack_client', '~> 1.5.5') + gem.add_dependency('cloudstack_client', '~> 1.5.6') gem.add_dependency('thor', '~> 0.20.0') end diff --git a/lib/cloudstack-cli/version.rb b/lib/cloudstack-cli/version.rb index e87ab5a..610f491 100644 --- a/lib/cloudstack-cli/version.rb +++ b/lib/cloudstack-cli/version.rb @@ -1,3 +1,3 @@ module CloudstackCli - VERSION = "1.6.5" + VERSION = "1.6.6" end From aa7220f9d41885d4eebba043b99e4af650efbe83 Mon Sep 17 00:00:00 2001 From: Nik Wolfgramm Date: Thu, 8 Jul 2021 18:19:48 +0200 Subject: [PATCH 29/36] updated gems --- Gemfile.lock | 18 +++++++++--------- cloudstack-cli.gemspec | 4 ++-- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 815c3b4..505db8a 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,25 +1,25 @@ PATH remote: . specs: - cloudstack-cli (1.6.5) + cloudstack-cli (1.6.6) cloudstack_client (~> 1.5.6) - thor (~> 0.20.0) + thor (~> 1.1.0) GEM remote: https://rubygems.org/ specs: - cloudstack_client (1.5.6) - minitest (5.11.3) - rake (12.3.3) - thor (0.20.3) + cloudstack_client (1.5.8) + minitest (5.14.4) + rake (13.0.5) + thor (1.1.0) PLATFORMS - ruby + x86_64-linux DEPENDENCIES cloudstack-cli! minitest (~> 5.11) - rake (~> 12.3) + rake (~> 13.0) BUNDLED WITH - 1.17.1 + 2.2.15 diff --git a/cloudstack-cli.gemspec b/cloudstack-cli.gemspec index 42e0e6d..fb082af 100644 --- a/cloudstack-cli.gemspec +++ b/cloudstack-cli.gemspec @@ -21,9 +21,9 @@ Gem::Specification.new do |gem| gem.require_paths = %w(lib) gem.rdoc_options = %w[--line-numbers --inline-source] - gem.add_development_dependency('rake', '~> 12.3') + gem.add_development_dependency('rake', '~> 13.0') gem.add_development_dependency('minitest', '~> 5.11') gem.add_dependency('cloudstack_client', '~> 1.5.6') - gem.add_dependency('thor', '~> 0.20.0') + gem.add_dependency('thor', '~> 1.1.0') end From d291eec94736fb71a923db7bd154ff3b76816771 Mon Sep 17 00:00:00 2001 From: Nik Wolfgramm Date: Thu, 8 Jul 2021 18:20:51 +0200 Subject: [PATCH 30/36] version bump --- lib/cloudstack-cli/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cloudstack-cli/version.rb b/lib/cloudstack-cli/version.rb index 610f491..e0deebb 100644 --- a/lib/cloudstack-cli/version.rb +++ b/lib/cloudstack-cli/version.rb @@ -1,3 +1,3 @@ module CloudstackCli - VERSION = "1.6.6" + VERSION = "1.6.7" end From 69d05da23fffff7d2bab7d0b8444e00cbfab4039 Mon Sep 17 00:00:00 2001 From: Nik Wolfgramm Date: Sat, 6 Jul 2024 18:02:23 +0200 Subject: [PATCH 31/36] updated gems --- Gemfile.lock | 12 ++++++------ cloudstack-cli.gemspec | 2 +- lib/cloudstack-cli/version.rb | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 505db8a..6d8d0bf 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,16 +1,16 @@ PATH remote: . specs: - cloudstack-cli (1.6.6) - cloudstack_client (~> 1.5.6) + cloudstack-cli (1.6.8) + cloudstack_client (~> 1.5.9) thor (~> 1.1.0) GEM remote: https://rubygems.org/ specs: - cloudstack_client (1.5.8) - minitest (5.14.4) - rake (13.0.5) + cloudstack_client (1.5.9) + minitest (5.24.1) + rake (13.2.1) thor (1.1.0) PLATFORMS @@ -22,4 +22,4 @@ DEPENDENCIES rake (~> 13.0) BUNDLED WITH - 2.2.15 + 2.3.14 diff --git a/cloudstack-cli.gemspec b/cloudstack-cli.gemspec index fb082af..58efa0e 100644 --- a/cloudstack-cli.gemspec +++ b/cloudstack-cli.gemspec @@ -24,6 +24,6 @@ Gem::Specification.new do |gem| gem.add_development_dependency('rake', '~> 13.0') gem.add_development_dependency('minitest', '~> 5.11') - gem.add_dependency('cloudstack_client', '~> 1.5.6') + gem.add_dependency('cloudstack_client', '~> 1.5.9') gem.add_dependency('thor', '~> 1.1.0') end diff --git a/lib/cloudstack-cli/version.rb b/lib/cloudstack-cli/version.rb index e0deebb..13ce687 100644 --- a/lib/cloudstack-cli/version.rb +++ b/lib/cloudstack-cli/version.rb @@ -1,3 +1,3 @@ module CloudstackCli - VERSION = "1.6.7" + VERSION = "1.6.8" end From 90e43e25363b59b7ed44dcd2b9746290b0235927 Mon Sep 17 00:00:00 2001 From: Nik Wolfgramm Date: Fri, 24 Jan 2025 08:14:21 +0100 Subject: [PATCH 32/36] updated gems and Ruby 3.2 compatibility --- Gemfile.lock | 8 ++++---- lib/cloudstack-cli/commands/environment.rb | 4 ++-- lib/cloudstack-cli/version.rb | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 6d8d0bf..6a341c5 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,15 +1,15 @@ PATH remote: . specs: - cloudstack-cli (1.6.8) + cloudstack-cli (1.6.9) cloudstack_client (~> 1.5.9) thor (~> 1.1.0) GEM remote: https://rubygems.org/ specs: - cloudstack_client (1.5.9) - minitest (5.24.1) + cloudstack_client (1.5.10) + minitest (5.25.4) rake (13.2.1) thor (1.1.0) @@ -22,4 +22,4 @@ DEPENDENCIES rake (~> 13.0) BUNDLED WITH - 2.3.14 + 2.5.22 diff --git a/lib/cloudstack-cli/commands/environment.rb b/lib/cloudstack-cli/commands/environment.rb index 3e6a859..73a3569 100644 --- a/lib/cloudstack-cli/commands/environment.rb +++ b/lib/cloudstack-cli/commands/environment.rb @@ -45,7 +45,7 @@ def add(env = options[:environment]) config[:default] = env if options[:default] end - if File.exists? options[:config_file] + if File.exist? options[:config_file] old_config = parse_config_file if !env || old_config.has_key?(env) say "This environment already exists!", :red @@ -117,7 +117,7 @@ def default(env = nil) no_commands do def parse_config_file - if File.exists? options[:config_file] + if File.exist? options[:config_file] begin return YAML::load(IO.read(options[:config_file])) rescue diff --git a/lib/cloudstack-cli/version.rb b/lib/cloudstack-cli/version.rb index 13ce687..0466ef1 100644 --- a/lib/cloudstack-cli/version.rb +++ b/lib/cloudstack-cli/version.rb @@ -1,3 +1,3 @@ module CloudstackCli - VERSION = "1.6.8" + VERSION = "1.6.9" end From 0a31be78060dd3b55eee9d73d31a64040d7b9356 Mon Sep 17 00:00:00 2001 From: Nik Wolfgramm Date: Fri, 24 Jan 2025 08:34:49 +0100 Subject: [PATCH 33/36] updated cloudstack_clint gem --- cloudstack-cli.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cloudstack-cli.gemspec b/cloudstack-cli.gemspec index 58efa0e..1540577 100644 --- a/cloudstack-cli.gemspec +++ b/cloudstack-cli.gemspec @@ -24,6 +24,6 @@ Gem::Specification.new do |gem| gem.add_development_dependency('rake', '~> 13.0') gem.add_development_dependency('minitest', '~> 5.11') - gem.add_dependency('cloudstack_client', '~> 1.5.9') + gem.add_dependency('cloudstack_client', '~> 1.5.10') gem.add_dependency('thor', '~> 1.1.0') end From ac2aaff6f953c0dbbdf9b270e25d0f0a8c65639d Mon Sep 17 00:00:00 2001 From: Nik Wolfgramm Date: Fri, 24 Jan 2025 08:37:19 +0100 Subject: [PATCH 34/36] updated cloudstack_clint gem --- Gemfile.lock | 4 ++-- lib/cloudstack-cli/version.rb | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 6a341c5..48c2012 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,8 +1,8 @@ PATH remote: . specs: - cloudstack-cli (1.6.9) - cloudstack_client (~> 1.5.9) + cloudstack-cli (1.6.10) + cloudstack_client (~> 1.5.10) thor (~> 1.1.0) GEM diff --git a/lib/cloudstack-cli/version.rb b/lib/cloudstack-cli/version.rb index 0466ef1..69144f4 100644 --- a/lib/cloudstack-cli/version.rb +++ b/lib/cloudstack-cli/version.rb @@ -1,3 +1,3 @@ module CloudstackCli - VERSION = "1.6.9" + VERSION = "1.6.10" end From 139d88c389adc5108c308f2024e27b072422d266 Mon Sep 17 00:00:00 2001 From: Nik Wolfgramm Date: Sun, 16 Nov 2025 13:34:49 +0100 Subject: [PATCH 35/36] Updated gems --- Gemfile.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 48c2012..228bede 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -8,9 +8,9 @@ PATH GEM remote: https://rubygems.org/ specs: - cloudstack_client (1.5.10) - minitest (5.25.4) - rake (13.2.1) + cloudstack_client (1.5.11) + minitest (5.26.1) + rake (13.3.1) thor (1.1.0) PLATFORMS From c7fe3cdcea153a548a51582585716f0751ae5bf2 Mon Sep 17 00:00:00 2001 From: Nik Wolfgramm Date: Sun, 16 Nov 2025 13:35:44 +0100 Subject: [PATCH 36/36] Release 1.6.11 --- lib/cloudstack-cli/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cloudstack-cli/version.rb b/lib/cloudstack-cli/version.rb index 69144f4..3b8d630 100644 --- a/lib/cloudstack-cli/version.rb +++ b/lib/cloudstack-cli/version.rb @@ -1,3 +1,3 @@ module CloudstackCli - VERSION = "1.6.10" + VERSION = "1.6.11" end