wakame-vdc-agents 10.12.0 → 11.06.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (71) hide show
  1. data/LICENSE +164 -201
  2. data/Rakefile +6 -11
  3. data/bin/hva +11 -1351
  4. data/bin/nsa +5 -9
  5. data/bin/sta +124 -71
  6. data/config/hva.conf.example +12 -0
  7. data/config/initializers/isono.rb +7 -23
  8. data/config/initializers/sequel.rb +11 -2
  9. data/lib/dcmgr.rb +70 -11
  10. data/lib/dcmgr/cli/base.rb +74 -0
  11. data/lib/dcmgr/cli/errors.rb +59 -0
  12. data/lib/dcmgr/cli/group.rb +101 -0
  13. data/lib/dcmgr/cli/host.rb +101 -0
  14. data/lib/dcmgr/cli/image.rb +108 -0
  15. data/lib/dcmgr/cli/keypair.rb +72 -0
  16. data/lib/dcmgr/cli/network.rb +198 -0
  17. data/lib/dcmgr/cli/quota.rb +28 -0
  18. data/lib/dcmgr/cli/spec.rb +82 -0
  19. data/lib/dcmgr/cli/storage.rb +88 -0
  20. data/lib/dcmgr/cli/tag.rb +81 -0
  21. data/lib/dcmgr/cli/vlan.rb +53 -0
  22. data/lib/dcmgr/drivers/hypervisor.rb +33 -0
  23. data/lib/dcmgr/drivers/iijgio_storage.rb +37 -0
  24. data/lib/dcmgr/drivers/kvm.rb +118 -0
  25. data/lib/dcmgr/drivers/lxc.rb +167 -0
  26. data/lib/dcmgr/drivers/s3_storage.rb +39 -0
  27. data/lib/dcmgr/drivers/snapshot_storage.rb +51 -0
  28. data/lib/dcmgr/endpoints/core_api.rb +188 -324
  29. data/lib/dcmgr/endpoints/core_api_mock.rb +52 -3
  30. data/lib/dcmgr/endpoints/errors.rb +73 -32
  31. data/lib/dcmgr/endpoints/metadata.rb +163 -16
  32. data/lib/dcmgr/helpers/cli_helper.rb +1 -1
  33. data/lib/dcmgr/helpers/nic_helper.rb +35 -0
  34. data/lib/dcmgr/logger.rb +5 -1
  35. data/lib/dcmgr/messaging_client.rb +117 -0
  36. data/lib/dcmgr/models/account.rb +27 -3
  37. data/lib/dcmgr/models/base_new.rb +21 -7
  38. data/lib/dcmgr/models/host_pool.rb +27 -7
  39. data/lib/dcmgr/models/image.rb +31 -3
  40. data/lib/dcmgr/models/instance.rb +72 -23
  41. data/lib/dcmgr/models/instance_nic.rb +12 -2
  42. data/lib/dcmgr/models/instance_spec.rb +16 -0
  43. data/lib/dcmgr/models/ip_lease.rb +37 -1
  44. data/lib/dcmgr/models/netfilter_group.rb +7 -7
  45. data/lib/dcmgr/models/network.rb +42 -3
  46. data/lib/dcmgr/models/quota.rb +25 -0
  47. data/lib/dcmgr/models/request_log.rb +26 -11
  48. data/lib/dcmgr/models/ssh_key_pair.rb +14 -1
  49. data/lib/dcmgr/models/storage_pool.rb +19 -72
  50. data/lib/dcmgr/models/tag.rb +5 -0
  51. data/lib/dcmgr/models/vlan_lease.rb +8 -0
  52. data/lib/dcmgr/models/volume.rb +26 -8
  53. data/lib/dcmgr/models/volume_snapshot.rb +37 -0
  54. data/lib/dcmgr/node_modules/hva_collector.rb +56 -36
  55. data/lib/dcmgr/node_modules/instance_ha.rb +1 -1
  56. data/lib/dcmgr/node_modules/instance_monitor.rb +70 -0
  57. data/lib/dcmgr/node_modules/service_netfilter.rb +914 -0
  58. data/lib/dcmgr/node_modules/sta_collector.rb +7 -30
  59. data/lib/dcmgr/rack/request_logger.rb +60 -0
  60. data/lib/dcmgr/rack/run_initializer.rb +42 -0
  61. data/lib/dcmgr/rpc/hva_handler.rb +388 -0
  62. data/lib/dcmgr/rubygems.rb +7 -0
  63. data/lib/dcmgr/storage_service.rb +98 -0
  64. data/lib/dcmgr/tags.rb +2 -2
  65. data/lib/dcmgr/version.rb +8 -0
  66. data/lib/ext/time.rb +8 -0
  67. data/lib/sinatra/respond_to.rb +3 -0
  68. data/lib/sinatra/sequel_transaction.rb +20 -5
  69. metadata +133 -100
  70. data/lib/dcmgr/models/physical_host.rb +0 -67
  71. data/lib/dcmgr/web/base.rb +0 -21
@@ -0,0 +1,74 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ require 'thor'
4
+
5
+ module Dcmgr::Cli
6
+ class Base < Thor
7
+ protected
8
+ def self.basename
9
+ "#{super()} #{namespace}"
10
+ end
11
+
12
+ no_tasks {
13
+ public
14
+ # add before/after task hook.
15
+ def invoke_task(task, *args)
16
+ Dcmgr::Models::BaseNew.db.transaction do
17
+ before_task
18
+ super(task, *args)
19
+ after_task
20
+ end
21
+ end
22
+
23
+ protected
24
+ def before_task
25
+ end
26
+
27
+ def after_task
28
+ end
29
+ }
30
+
31
+ def add(model,options)
32
+ raise ArgumentError unless options.is_a? Hash
33
+ #TODO: Make this check a little tighter by checking that the model is either from the wakame backend or frontend
34
+ #UnknownModelError.raise(model) unless model < Dcmgr::Models::BaseNew
35
+ UnknownModelError.raise(model) unless model < Sequel::Model
36
+
37
+ fields = options.dup
38
+
39
+ if fields.has_key?("uuid") || fields.has_key?(:uuid)
40
+ fields[:uuid] = model.trim_uuid(fields[:uuid]) if model.check_uuid_format(fields[:uuid])
41
+ Error.raise("UUID syntax invalid: #{fields[:uuid]}",100) unless model.check_trimmed_uuid_format(fields[:uuid])
42
+ end
43
+
44
+ #Create database fields
45
+ new_record = model.create(fields)
46
+
47
+ #Return uuid if there is one
48
+ new_record.canonical_uuid #if model.respond_to? "canonical_uuid"
49
+ end
50
+
51
+ def del(model,uuid)
52
+ #UnknownModelError.raise(model) unless model < Dcmgr::Models::BaseNew
53
+ UnknownModelError.raise(model) unless model < Sequel::Model
54
+ to_delete = model[uuid] || UnknownUUIDError.raise(uuid)
55
+ to_delete.destroy
56
+ end
57
+
58
+ def modify(model,uuid,fields)
59
+ #UnknownModelError.raise(model) unless model < Dcmgr::Models::BaseNew
60
+ UnknownModelError.raise(model) unless model < Sequel::Model
61
+ raise ArgumentError unless fields.is_a? Hash
62
+ to_modify = model[uuid] || UnknownUUIDError.raise(uuid)
63
+
64
+ #Use a copy of the fields hash so this method can work with frozen hashes
65
+ fields_nonil = fields.merge({})
66
+ #Don't update empty fields
67
+ fields_nonil.delete_if {|key,value| value.nil?}
68
+
69
+ to_modify.set(fields_nonil)
70
+ to_modify.updated_at = Time.now.utc.iso8601 if to_modify.with_timestamps?
71
+ to_modify.save_changes
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,59 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ module Dcmgr::Cli
4
+ class Error < StandardError
5
+ attr_reader :exit_code
6
+ def initialize(msg, exit_code=1)
7
+ super(msg)
8
+ @exit_code = exit_code
9
+ end
10
+
11
+ def self.raise(msg, exit_code)
12
+ Kernel.raise(if msg.is_a?(self)
13
+ msg
14
+ else
15
+ self.new(msg, exit_code)
16
+ end)
17
+ end
18
+ end
19
+
20
+ class UnknownUUIDError < Error
21
+ def initialize(uuid,exit_code=100)
22
+ super("Unknown UUID: '#{uuid}'.")
23
+ end
24
+
25
+ def self.raise(uuid,exit_code=100)
26
+ super
27
+ end
28
+ end
29
+
30
+ class UnsupportedArchError < Error
31
+ def initialize(arch,exit_code=100)
32
+ super("Unsupported arch type: '#{arch}'.")
33
+ end
34
+
35
+ def self.raise(arch,exit_code=100)
36
+ super
37
+ end
38
+ end
39
+
40
+ class UnknownModelError < Error
41
+ def initialize(model,exit_code=100)
42
+ super("Not a sequel model: '#{model}'.")
43
+ end
44
+
45
+ def self.raise(model,exit_code=100)
46
+ super
47
+ end
48
+ end
49
+
50
+ class UnsupportedHypervisorError < Error
51
+ def initialize(arch,exit_code=100)
52
+ super("Unsupported hypervisor type: '#{arch}'.")
53
+ end
54
+
55
+ def self.raise(arch,exit_code=100)
56
+ super
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,101 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ module Dcmgr::Cli
4
+ class Group < Base
5
+ namespace :group
6
+ M = Dcmgr::Models
7
+
8
+ desc "add [options]", "Add a new security group"
9
+ method_option :uuid, :type => :string, :aliases => "-u", :desc => "The UUID for the new security group."
10
+ method_option :account_id, :type => :string, :aliases => "-a", :desc => "The UUID of the account this security group belongs to.", :required => true
11
+ method_option :name, :type => :string, :aliases => "-n", :desc => "The name for this security group.", :required => true
12
+ method_option :description, :type => :string, :aliases => "-d", :desc => "The description for this new security group."
13
+ def add
14
+ UnknownUUIDError.raise(options[:account_id]) if M::Account[options[:account_id]].nil?
15
+
16
+ puts super(M::NetfilterGroup,options)
17
+ end
18
+
19
+ desc "del UUID", "Delete a security group"
20
+ def del(uuid)
21
+ super(M::NetfilterGroup,uuid)
22
+ end
23
+
24
+ desc "show [UUID]", "Show security group(s)"
25
+ def show(uuid=nil)
26
+ if uuid
27
+ group = M::NetfilterGroup[uuid] || UnknownUUIDError.raise(uuid)
28
+ puts ERB.new(<<__END, nil, '-').result(binding)
29
+ Group UUID:
30
+ <%= group.canonical_uuid %>
31
+ Account id:
32
+ <%= group.account_id %>
33
+ <%- if group.description -%>
34
+ Description:
35
+ <%= group.description %>
36
+ <%- end -%>
37
+ <%- unless group.netfilter_rules.empty? -%>
38
+ Rules:
39
+ <%- group.netfilter_rules.each { |rule| -%>
40
+ <%= rule.permission %>
41
+ <%- } -%>
42
+ <%- end -%>
43
+ __END
44
+ else
45
+ puts ERB.new(<<__END, nil, '-').result(binding)
46
+ <%- M::NetfilterGroup.all { |row| -%>
47
+ <%= row.canonical_uuid %>\t<%= row.account_id %>\t<%= row.name %>
48
+ <%- } -%>
49
+ __END
50
+ end
51
+ end
52
+
53
+ desc "modify UUID [options]", "Modify an existing security group"
54
+ method_option :account_id, :type => :string, :aliases => "-a", :desc => "The UUID of the account this security group belongs to."
55
+ method_option :name, :type => :string, :aliases => "-n", :desc => "The name for this security group."
56
+ method_option :description, :type => :string, :aliases => "-d", :desc => "The description for this new security group."
57
+ def modify(uuid)
58
+ UnknownUUIDError.raise(options[:account_id]) if options[:account_id] && M::Account[options[:account_id]].nil?
59
+ super(M::NetfilterGroup,uuid,options)
60
+ end
61
+
62
+ desc "apply UUID [options]", "Apply a security group to an instance"
63
+ method_option :instance, :type => :string, :aliases => "-i", :required => :true, :desc => "The instance to apply the group to"
64
+ def apply(uuid)
65
+ group = M::NetfilterGroup[uuid] || UnknownUUIDError.raise(uuid)
66
+ instance = M::Instance[options[:instance]] || UnknownUUIDError.raise(options[:instance])
67
+ Error.raise("Group #{uuid} is already applied to instance #{options[:instance]}.",100) if group.instances.member?(instance)
68
+ group.add_instance(instance)
69
+ end
70
+
71
+ desc "remove UUID [options]", "Remove a security group from an instance"
72
+ method_option :instance, :type => :string, :aliases => "-i", :required => :true, :desc => "The instance to remove the group from"
73
+ def remove(uuid)
74
+ group = M::NetfilterGroup[uuid] || UnknownUUIDError.raise(uuid)
75
+ instance = M::Instance[options[:instance]] || UnknownUUIDError.raise(options[:instance])
76
+ Error.raise("Group #{uuid} is not applied to instance #{options[:instance]}.",100) unless group.instances.member?(instance)
77
+ group.remove_instance(instance)
78
+ end
79
+
80
+ desc "addrule UUID [options]", "Add a rule to a security group"
81
+ method_option :rule, :type => :string, :aliases => "-r", :desc => "The new rule to be added"
82
+ def addrule(g_uuid)
83
+ UnknownUUIDError.raise(g_uuid) if M::NetfilterGroup[g_uuid].nil?
84
+
85
+ #TODO: check rule syntax
86
+ new_rule = M::NetfilterRule.new(:permission => options[:rule])
87
+ new_rule.netfilter_group = M::NetfilterGroup[g_uuid]
88
+ new_rule.save
89
+ end
90
+
91
+ desc "delrule UUID [options]", "Delete a rule from a security group"
92
+ method_option :rule, :type => :string, :aliases => "-r", :desc => "The rule to be deleted."
93
+ def delrule(g_uuid)
94
+ UnknownUUIDError.raise(g_uuid) if M::NetfilterGroup[g_uuid].nil?
95
+ rule = M::NetfilterRule.find(:netfilter_group_id => M::NetfilterGroup[g_uuid].id,:permission => options[:rule])
96
+ Error.raise("Group '#{g_uuid}' does not contain rule '#{options[:rule]}'.",100) if rule.nil?
97
+
98
+ rule.destroy
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,101 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ require 'thor'
4
+ require 'isono'
5
+
6
+ module Dcmgr::Cli
7
+ class Host < Base
8
+ namespace :host
9
+ include Dcmgr::Models
10
+
11
+ desc "add NODE_ID [options]", "Register a new host node"
12
+ method_option :uuid, :type => :string, :aliases => "-u", :desc => "The UUID for the new host pool"
13
+ #method_option :force, :type => :boolean, :aliases => "-f", :default=>false, :desc => "Force to create new entry"
14
+ method_option :cpu_cores, :type => :numeric, :aliases => "-c", :default=>1, :desc => "Number of cpu cores to be offered"
15
+ method_option :memory_size, :type => :numeric, :aliases => "-m", :default=>1024, :desc => "Amount of memory to be offered (in MB)"
16
+ method_option :hypervisor, :type => :string, :aliases => "-p", :default=>'kvm', :desc => "The hypervisor name. [#{HostPool::SUPPORTED_HYPERVISOR.join(', ')}]"
17
+ method_option :arch, :type => :string, :aliases => "-r", :default=>'x86_64', :desc => "The CPU architecture type. [#{HostPool::SUPPORTED_ARCH.join(', ')}]"
18
+ method_option :account_id, :type => :string, :default=>'a-shpool', :aliases => "-a", :desc => "The account ID to own this"
19
+ def add(node_id)
20
+ UnknownUUIDError.raise(options[:account_id]) if Account[options[:account_id]].nil?
21
+ UnsupportedArchError.raise(options[:arch]) unless HostPool::SUPPORTED_ARCH.member?(options[:arch])
22
+ UnsupportedHypervisorError.raise(options[:hypervisor]) unless HostPool::SUPPORTED_HYPERVISOR.member?(options[:hypervisor])
23
+
24
+ if (options[:force] == false && Isono::Models::NodeState.filter(:node_id=>node_id).first == nil)
25
+ abort("Node ID is not registered yet: #{node_id}")
26
+ end
27
+
28
+ fields = {
29
+ :node_id=>node_id,
30
+ :offering_cpu_cores=>options[:cpu_cores],
31
+ :offering_memory_size=>options[:memory_size],
32
+ :hypervisor=>options[:hypervisor],
33
+ :arch=>options[:arch],
34
+ :account_id=>options[:account_id],
35
+ }
36
+ fields.merge!({:uuid => options[:uuid]}) unless options[:uuid].nil?
37
+ puts super(HostPool,fields)
38
+ end
39
+
40
+ desc "modify UUID [options]", "Modify a registered host node"
41
+ method_option :cpu_cores, :type => :numeric, :aliases => "-c", :desc => "Number of cpu cores to be offered"
42
+ method_option :account_id, :type => :string, :aliases => "-a", :desc => "The account ID to own this"
43
+ method_option :memory_size, :type => :numeric, :aliases => "-m", :desc => "Amount of memory to be offered (in MB)"
44
+ method_option :hypervisor, :type => :string, :aliases => "-p", :desc => "The hypervisor name. [#{HostPool::SUPPORTED_HYPERVISOR.join(', ')}]"
45
+ def modify(uuid)
46
+ UnknownUUIDError.raise(options[:account_id]) if options[:account_id] && Account[options[:account_id]].nil?
47
+ UnsupportedHypervisorError.raise(options[:hypervisor]) unless options[:hypervisor].nil? || HostPool::SUPPORTED_HYPERVISOR.member?(options[:hypervisor])
48
+ fields = {
49
+ :offering_memory_size=>options[:memory_size],
50
+ :offering_cpu_cores=>options[:cpu_cores],
51
+ :account_id=>options[:account_id],
52
+ :hypervisor=>options[:hypervisor]
53
+ }
54
+ super(HostPool,uuid,fields)
55
+ end
56
+
57
+ desc "del UUID", "Deregister a host node"
58
+ def del(uuid)
59
+ super(HostPool,uuid)
60
+ end
61
+
62
+ desc "show [UUID]", "Show list of host nodes and details"
63
+ def show(uuid=nil)
64
+ if uuid
65
+ host = HostPool[uuid]
66
+ puts ERB.new(<<__END, nil, '-').result(binding)
67
+ Host UUID:
68
+ <%= host.canonical_uuid %>
69
+ Node ID:
70
+ <%= host.node_id %>
71
+ CPU Cores (offerring):
72
+ <%= host.offering_cpu_cores %>
73
+ Memory (offerring):
74
+ <%= host.offering_memory_size %>MB
75
+ Hypervisor:
76
+ <%= host.hypervisor %>
77
+ __END
78
+ else
79
+ cond = {}
80
+ all = HostPool.filter(cond).all
81
+ puts ERB.new(<<__END, nil, '-').result(binding)
82
+ <%- all.each { |row| -%>
83
+ <%= "%-15s %-20s %-10s" % [row.canonical_uuid, row.node_id, row.status] %>
84
+ <%- } -%>
85
+ __END
86
+ end
87
+ end
88
+
89
+ desc "shownodes", "Show node (agents)"
90
+ def shownodes
91
+ nodes = Isono::Models::NodeState.filter.all
92
+
93
+ puts ERB.new(<<__END, nil, '-').result(binding)
94
+ Node ID State
95
+ <%- nodes.each { |row| -%>
96
+ <%= "%-20s %-10s" % [row.node_id, row.state] %>
97
+ <%- } -%>
98
+ __END
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,108 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ module Dcmgr::Cli
4
+ class Image < Base
5
+ namespace :image
6
+ M = Dcmgr::Models
7
+
8
+
9
+ class AddOperation < Base
10
+ namespace :add
11
+
12
+ desc "local IMAGE_LOCATION [options]", "Register local store machine image"
13
+ method_option :uuid, :type => :string, :aliases => "-u", :desc => "The UUID for the new machine image"
14
+ method_option :account_id, :type => :string, :aliases => "-a", :required => true, :desc => "The UUID of the account that this machine image belongs to"
15
+ method_option :arch, :type => :string, :default => 'x86_64', :aliases => "-r", :desc => "The architecture for the new machine image. [#{M::HostPool::SUPPORTED_ARCH.join(', ')}]"
16
+ method_option :is_public, :type => :boolean, :aliases => "-p", :default => false, :desc => "A flag that determines whether the new machine image is public or not"
17
+ method_option :description, :type => :string, :aliases => "-d", :desc => "An arbitrary description of the new machine image"
18
+ method_option :state, :type => :string, :aliases => "-s", :default => "init", :desc => "The state for the new machine image"
19
+ def local(location)
20
+ UnknownUUIDError.raise(options[:account_id]) if M::Account[options[:account_id]].nil?
21
+ UnsupportedArchError.raise(options[:arch]) unless M::HostPool::SUPPORTED_ARCH.member?(options[:arch])
22
+
23
+ full_path = File.expand_path(location)
24
+ File.exists?(full_path) || Error.raise("File not found: #{full_path}",100)
25
+
26
+ #TODO: Check if :state is a valid state
27
+ fields = options.dup
28
+ fields[:boot_dev_type]=M::Image::BOOT_DEV_LOCAL
29
+ fields[:source] = {
30
+ :uri => "file://#{full_path}",
31
+ }
32
+ puts add(M::Image, fields)
33
+ end
34
+
35
+ desc "volume snapshot_id [options]", "Register volume store machine image."
36
+ method_option :uuid, :type => :string, :aliases => "-u", :desc => "The UUID for the new machine image."
37
+ method_option :account_id, :type => :string, :aliases => "-a", :required => true, :desc => "The UUID of the account that this machine image belongs to."
38
+ method_option :arch, :type => :string, :default => 'x86_64', :aliases => "-r", :desc => "The architecture for the new machine image. [#{M::HostPool::SUPPORTED_ARCH.join(', ')}]"
39
+ method_option :is_public, :type => :boolean, :aliases => "-p", :default => false, :desc => "A flag that determines whether the new machine image is public or not."
40
+ method_option :description, :type => :string, :aliases => "-d", :desc => "An arbitrary description of the new machine image"
41
+ method_option :state, :type => :string, :aliases => "-s", :default => "init", :desc => "The state for the new machine image"
42
+ def volume(snapshot_id)
43
+ UnknownUUIDError.raise(options[:account_id]) if M::Account[options[:account_id]].nil?
44
+ UnsupportedArchError.raise(options[:arch]) unless M::HostPool::SUPPORTED_ARCH.member?(options[:arch])
45
+ UnknownUUIDError.raise(snapshot_id) if M::VolumeSnapshot[snapshot_id].nil?
46
+ #TODO: Check if :state is a valid state
47
+ fields = options.dup
48
+ fields[:boot_dev_type]=M::Image::BOOT_DEV_SAN
49
+ fields[:source] = {
50
+ :snapshot_id => snapshot_id,
51
+ }
52
+ puts add(M::Image, fields)
53
+ end
54
+
55
+ protected
56
+ def self.basename
57
+ "vdc-manage #{Image.namespace} #{self.namespace}"
58
+ end
59
+ end
60
+
61
+ register AddOperation, 'add', "add IMAGE_TYPE [options]", "Add image metadata [#{AddOperation.tasks.keys.join(', ')}]"
62
+
63
+ desc "modify UUID [options]", "Modify a registered machine image"
64
+ method_option :description, :type => :string, :aliases => "-d", :desc => "An arbitrary description of the machine image"
65
+ method_option :state, :type => :string, :aliases => "-s", :default => "init", :desc => "The state for the machine image"
66
+ def modify(uuid)
67
+ #TODO: Check if state is valid here too
68
+ super(M::Image,uuid,options)
69
+ end
70
+
71
+ desc "del IMAGE_ID", "Delete registered machine image"
72
+ def del(image_id)
73
+ UnknownUUIDError.raise(image_id) if M::Image[image_id].nil?
74
+ super(M::Image, image_id)
75
+ end
76
+
77
+ desc "show [IMAGE_ID]", "Show list of machine image and details"
78
+ def show(uuid=nil)
79
+ if uuid
80
+ img = M::Image[uuid]
81
+ print ERB.new(<<__END, nil, '-').result(binding)
82
+ UUID:
83
+ <%= img.canonical_uuid %>
84
+ Boot Type:
85
+ <%= img.boot_dev_type %>
86
+ Arch:
87
+ <%= img.arch %>
88
+ <%- if img.description -%>
89
+ Description:
90
+ <%= img.description %>
91
+ <%- end -%>
92
+ Is Public:
93
+ <%= img.is_public %>
94
+ State:
95
+ <%= img.state %>
96
+ __END
97
+ else
98
+ cond = {}
99
+ imgs = M::Image.filter(cond).all
100
+ print ERB.new(<<__END, nil, '-').result(binding)
101
+ <%- imgs.each { |row| -%>
102
+ <%= "%-20s %-15s %-15s" % [row.canonical_uuid, row.boot_dev_type, row.arch] %>
103
+ <%- } -%>
104
+ __END
105
+ end
106
+ end
107
+ end
108
+ end