chef-provisioning-opennebula 0.4.4 → 0.4.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (110) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +273 -4
  3. data/lib/chef/provider/one_flow_service.rb +346 -0
  4. data/lib/chef/provider/one_flow_template.rb +175 -0
  5. data/lib/chef/provider/one_image.rb +6 -6
  6. data/lib/chef/provider/one_template.rb +4 -6
  7. data/lib/chef/provider/one_user.rb +11 -14
  8. data/lib/chef/provider/one_vnet.rb +6 -9
  9. data/lib/chef/provider/one_vnet_lease.rb +3 -3
  10. data/lib/chef/provisioning/driver_init/opennebula.rb +1 -1
  11. data/lib/chef/provisioning/driver_init/server_version.rb +28 -0
  12. data/lib/chef/provisioning/opennebula_driver.rb +1 -1
  13. data/lib/chef/provisioning/opennebula_driver/credentials.rb +2 -2
  14. data/lib/chef/provisioning/opennebula_driver/driver.rb +132 -34
  15. data/lib/chef/provisioning/opennebula_driver/flow_lib.rb +491 -0
  16. data/lib/chef/provisioning/opennebula_driver/one_lib.rb +39 -49
  17. data/lib/chef/provisioning/opennebula_driver/resources.rb +2 -2
  18. data/lib/chef/provisioning/opennebula_driver/version.rb +2 -2
  19. data/lib/chef/resource/one_flow_service.rb +61 -0
  20. data/lib/chef/resource/one_flow_template.rb +53 -0
  21. data/lib/chef/resource/one_image.rb +2 -2
  22. data/lib/chef/resource/one_template.rb +1 -1
  23. data/lib/chef/resource/one_user.rb +1 -1
  24. data/lib/chef/resource/one_vnet.rb +2 -2
  25. data/lib/chef/resource/one_vnet_lease.rb +1 -1
  26. data/spec/config_sample.rb +12 -3
  27. data/spec/integration/test_all_integration_spec.rb +6 -272
  28. data/spec/integration/test_one_driver.rb +177 -0
  29. data/spec/integration/test_one_flow.rb +546 -0
  30. data/spec/recipes/OneDriver/{instantiate_one_template_spec.rb → allocate_change_profile.rb} +5 -7
  31. data/spec/recipes/OneDriver/{converge_back_two_vm_spec.rb → attach_one_image.rb} +4 -5
  32. data/spec/recipes/OneDriver/create_one_image.rb +20 -0
  33. data/spec/recipes/OneDriver/{create_one_template_int_spec.rb → create_one_template_ints.rb} +21 -4
  34. data/spec/recipes/OneDriver/create_one_template_mix.rb +51 -0
  35. data/spec/recipes/OneDriver/{create_one_image_spec.rb → create_one_template_strings.rb} +18 -7
  36. data/spec/recipes/OneDriver/{converge_back_one_vm_spec.rb → create_one_vnet.rb} +5 -5
  37. data/spec/recipes/OneDriver/delete/{OpenNebula-tpl-1-vm.rb → OpenNebula-test-img.rb} +2 -4
  38. data/spec/recipes/OneDriver/delete/{OpenNebula-back-1-vm.rb → OpenNebula-test-snap-img.rb} +2 -4
  39. data/spec/recipes/OneDriver/delete/OpenNebula-test-tpl-ints.rb +2 -4
  40. data/spec/recipes/OneDriver/delete/{OpenNebula-test-tpl.rb → OpenNebula-test-tpl-mix.rb} +2 -4
  41. data/spec/recipes/OneDriver/delete/OpenNebula-test-tpl-strings.rb +17 -0
  42. data/spec/recipes/OneDriver/delete/{OpenNebula-back-2-vm.rb → OpenNebula-test-vm-vnet.rb} +2 -4
  43. data/spec/recipes/OneDriver/delete/{OpenNebula-bootstrap-vm.rb → OpenNebula-test-vm.rb} +2 -4
  44. data/spec/recipes/OneDriver/delete/OpenNebula-test-vnet.rb +17 -0
  45. data/spec/recipes/OneDriver/{attach_back_one_vm_spec.rb → instantiate_one_template.rb} +7 -6
  46. data/spec/recipes/OneDriver/{converge_bootstrap_vm_spec.rb → instantiate_one_template_vnet.rb} +10 -8
  47. data/spec/recipes/OneDriver/snapshot_one_image.rb +19 -0
  48. data/spec/recipes/OneFlowService/action/boot.rb +19 -0
  49. data/spec/recipes/OneFlowService/action/delete.rb +18 -0
  50. data/spec/recipes/OneFlowService/action/delete_recreate.rb +18 -0
  51. data/spec/recipes/OneFlowService/action/hold.rb +19 -0
  52. data/spec/recipes/OneFlowService/action/poweroff.rb +18 -0
  53. data/spec/recipes/OneFlowService/action/poweroff_hard.rb +18 -0
  54. data/spec/recipes/OneFlowService/action/reboot.rb +18 -0
  55. data/spec/recipes/OneFlowService/action/reboot_hard.rb +18 -0
  56. data/spec/recipes/OneFlowService/action/release.rb +19 -0
  57. data/spec/recipes/OneFlowService/action/resume.rb +18 -0
  58. data/spec/recipes/OneFlowService/action/scale.rb +19 -0
  59. data/spec/recipes/OneFlowService/action/shutdown.rb +18 -0
  60. data/spec/recipes/OneFlowService/action/shutdown_hard.rb +18 -0
  61. data/spec/recipes/OneFlowService/action/shutdown_service.rb +17 -0
  62. data/spec/recipes/OneFlowService/action/snapshot_create.rb +18 -0
  63. data/spec/recipes/OneFlowService/action/stop.rb +18 -0
  64. data/spec/recipes/OneFlowService/action/suspend.rb +18 -0
  65. data/spec/recipes/OneFlowService/action/undeploy.rb +18 -0
  66. data/spec/recipes/OneFlowService/action/undeploy_hard.rb +18 -0
  67. data/spec/recipes/OneFlowService/chmod_simple_by_name.rb +19 -0
  68. data/spec/recipes/OneFlowService/chmod_simple_by_name_2.rb +18 -0
  69. data/spec/recipes/OneFlowService/chmod_tpl_opts.rb +31 -0
  70. data/spec/recipes/OneFlowService/delete/test_instance_template_options.rb +17 -0
  71. data/spec/recipes/OneFlowService/delete/test_role_action.rb +17 -0
  72. data/spec/recipes/OneFlowService/delete/test_simple_instance.rb +17 -0
  73. data/spec/recipes/OneFlowService/delete/test_simple_instance_by_id.rb +17 -0
  74. data/spec/recipes/{OneDriver/create_bootstrap_vm_spec.rb → OneFlowService/instance_role_action.rb} +19 -11
  75. data/spec/recipes/OneFlowService/instance_simple_by_id.rb +20 -0
  76. data/spec/recipes/OneFlowService/instance_simple_by_name.rb +18 -0
  77. data/spec/recipes/OneFlowService/instance_tpl_opts.rb +30 -0
  78. data/spec/recipes/OneFlowTemplate/chmod_simple_from_hash.rb +17 -0
  79. data/spec/recipes/OneFlowTemplate/chmod_update_simple_from_file.rb +19 -0
  80. data/spec/recipes/OneFlowTemplate/create_branch_from_one_id.rb +43 -0
  81. data/spec/recipes/OneFlowTemplate/create_branch_from_one_name.rb +20 -0
  82. data/spec/recipes/OneFlowTemplate/create_role_action_instance.rb +99 -0
  83. data/spec/recipes/OneFlowTemplate/create_simple_from_file.rb +18 -0
  84. data/spec/recipes/{OneDriver/attach_back_two_vm_spec.rb → OneFlowTemplate/create_simple_from_hash.rb} +8 -6
  85. data/spec/recipes/OneFlowTemplate/create_simple_from_web.rb +17 -0
  86. data/spec/recipes/{OneDriver/attach_one_image_spec.rb → OneFlowTemplate/create_simple_instance_tpl.rb} +8 -6
  87. data/spec/recipes/OneFlowTemplate/create_tpl_opts_from_file.rb +30 -0
  88. data/spec/recipes/OneFlowTemplate/create_tpl_opts_from_hash.rb +35 -0
  89. data/spec/recipes/OneFlowTemplate/delete/branch_from_one_id.rb +17 -0
  90. data/spec/recipes/OneFlowTemplate/delete/branch_from_one_name.rb +17 -0
  91. data/spec/recipes/OneFlowTemplate/delete/role_action_instance.rb +17 -0
  92. data/spec/recipes/OneFlowTemplate/delete/simple_from_file.rb +17 -0
  93. data/spec/recipes/OneFlowTemplate/delete/simple_from_hash.rb +17 -0
  94. data/spec/recipes/OneFlowTemplate/delete/simple_from_web.rb +17 -0
  95. data/spec/recipes/OneFlowTemplate/delete/simple_instance_tpl.rb +17 -0
  96. data/spec/recipes/OneFlowTemplate/delete/tpl_opts_from_file.rb +17 -0
  97. data/spec/recipes/OneFlowTemplate/delete/tpl_opts_from_hash.rb +17 -0
  98. data/spec/recipes/OneFlowTemplate/update_simple_from_hash.rb +57 -0
  99. data/spec/recipes/{driver_options_spec.rb → common.rb} +9 -3
  100. data/spec/spec_helper.rb +22 -17
  101. data/spec/support/opennebula_support.rb +75 -45
  102. metadata +114 -27
  103. data/spec/recipes/OneDriver/create_back_one_vm_spec.rb +0 -20
  104. data/spec/recipes/OneDriver/create_back_two_vm_spec.rb +0 -20
  105. data/spec/recipes/OneDriver/create_one_template_spec.rb +0 -21
  106. data/spec/recipes/OneDriver/delete/OpenNebula-bootstrap-img.rb +0 -19
  107. data/spec/recipes/OneDriver/delete/OpenNebula-snap-1-img.rb +0 -19
  108. data/spec/recipes/OneDriver/delete/OpenNebula-snap-2-img.rb +0 -19
  109. data/spec/recipes/OneDriver/snapshot_one_image_spec.rb +0 -21
  110. data/spec/recipes/OneDriver/snapshot_two_image_spec.rb +0 -21
@@ -0,0 +1,175 @@
1
+ # Copyright 2016, BlackBerry Limited
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ require 'rest-client'
16
+ require 'json'
17
+
18
+ #
19
+ # Implementation of Provider class.
20
+ #
21
+ class Chef
22
+ #
23
+ # Implementation of Provider class.
24
+ #
25
+ class Provider
26
+ #
27
+ # Implementation of Provider class.
28
+ #
29
+ class OneFlowTemplate < Chef::Provider::LWRPBase
30
+ use_inline_resources
31
+
32
+ provides :one_flow_template
33
+
34
+ def initialize(*args)
35
+ super
36
+ if !@new_resource.flow_url.nil?
37
+ flow_url = @new_resource.flow_url
38
+ elsif !run_context.chef_provisioning.flow_url.nil?
39
+ flow_url = run_context.chef_provisioning.flow_url
40
+ elsif !ENV['ONE_FLOW_URL'].nil?
41
+ flow_url = ENV['ONE_FLOW_URL']
42
+ else
43
+ fail 'OneFlow API URL must be specified.'
44
+ end
45
+ @flow_lib = Chef::Provisioning::OpenNebulaDriver::FlowLib.new(flow_url, driver.one.client.one_auth)
46
+ end
47
+
48
+ def whyrun_supported?
49
+ true
50
+ end
51
+
52
+ def load_current_resource
53
+ @current_resource = Chef::Resource::OneFlowTemplate.new(@new_resource.name, run_context)
54
+
55
+ template_name = @new_resource.name
56
+
57
+ unless @new_resource.template.nil?
58
+ tpl = load_template_hash
59
+ if tpl.nil?
60
+ @current_resource.exists = false
61
+ return
62
+ end
63
+ tpl = @flow_lib.merge_template(tpl, @new_resource.template_options, true, false)
64
+ template_name = tpl[:name] if tpl.key?(:name)
65
+ end
66
+
67
+ template_id = @flow_lib.get_unique_template_id(template_name, true)
68
+
69
+ @current_resource.exists = !template_id.nil?
70
+ return unless @current_resource.exists
71
+
72
+ @current_resource.template(@flow_lib.get_template(template_id))
73
+ @current_resource.mode(@flow_lib.get_template_permissions(template_id))
74
+
75
+ @current_resource.template_equal = @new_resource.template.nil? ? true : @flow_lib.hash_eq?(
76
+ @current_resource.template,
77
+ @flow_lib.normalize_template(@new_resource.name, driver, @flow_lib.merge_template(@current_resource.template, tpl), true)
78
+ )
79
+ @current_resource.mode_equal = @current_resource.mode == @new_resource.mode
80
+ @current_resource.equal = @current_resource.template_equal && @current_resource.mode_equal
81
+ end
82
+
83
+ def load_template_hash
84
+ template = {}
85
+ case @new_resource.template
86
+ when Hash
87
+ template = @new_resource.template
88
+ when Fixnum
89
+ template = @flow_lib.get_template(@new_resource.template)
90
+ when String
91
+ case @new_resource.template
92
+ when %r{^file://(.*)$}
93
+ template = JSON.parse(::File.read(Regexp.last_match[1]), :symbolize_names => true)
94
+ when %r{^(?:(\w+)(?::(.*?))?@)?(https?://.*)$}
95
+ response = RestClient::Request.execute(
96
+ method: :get,
97
+ url: Regexp.last_match[3],
98
+ user: Regexp.last_match[1],
99
+ password: Regexp.last_match[2]
100
+ )
101
+ template = JSON.parse(response, :symbolize_names => true)
102
+ else
103
+ tid = @flow_lib.get_unique_template_id(@new_resource.template)
104
+ template = @flow_lib.get_template(tid)
105
+ end
106
+ end
107
+ template
108
+ end
109
+
110
+ action :create do
111
+ fail 'Cannot specify template_options without a template' if !@current_resource.template_options.empty? && @current_resource.template_options.nil?
112
+
113
+ template_name = @new_resource.name
114
+
115
+ unless @new_resource.template.nil?
116
+ template = load_template_hash
117
+
118
+ if @new_resource.template_options.key?(:name)
119
+ template_name = @new_resource.template_options[:name]
120
+ elsif template.key?(:name)
121
+ template_name = template[:name]
122
+ end
123
+ end
124
+
125
+ if @current_resource.exists
126
+ unless @current_resource.equal
127
+ converge_by "updated template '#{template_name}'" do
128
+ template_id = @flow_lib.get_unique_template_id(template_name)
129
+ unless @new_resource.template.nil? && @current_resource.template_equal
130
+ template = @flow_lib.normalize_template(
131
+ @new_resource.name,
132
+ driver,
133
+ @flow_lib.merge_template(template, @new_resource.template_options, true, false),
134
+ true,
135
+ true
136
+ )
137
+ template = @flow_lib.normalize_template(@new_resource.name, driver, @flow_lib.merge_template(@current_resource.template, template))
138
+ @flow_lib.update_template(template_name, template)
139
+ end
140
+ unless @current_resource.mode_equal
141
+ @flow_lib.chmod_template(template_id, @new_resource.mode)
142
+ end
143
+ @new_resource.updated_by_last_action(true)
144
+ end
145
+ end
146
+ else
147
+ fail 'Cannot create template without template attribute' if @new_resource.template.nil?
148
+ converge_by "created template '#{template_name}'" do
149
+ template = @flow_lib.normalize_template(@new_resource.name, driver, @flow_lib.merge_template(template, @new_resource.template_options, true))
150
+ @flow_lib.create_template(template)
151
+ template_id = @flow_lib.get_unique_template_id(template_name)
152
+ @flow_lib.chmod_template(template_id, @new_resource.mode)
153
+ @new_resource.updated_by_last_action(true)
154
+ end
155
+ end
156
+ end
157
+
158
+ action :delete do
159
+ if @current_resource.exists
160
+ template_id = @flow_lib.get_unique_template_id(@new_resource.name, true)
161
+ converge_by "deleted template '#{@new_resource.name}'" do
162
+ @flow_lib.delete_template(template_id)
163
+ @new_resource.updated_by_last_action(true)
164
+ end
165
+ end
166
+ end
167
+
168
+ protected
169
+
170
+ def driver
171
+ @new_resource.driver.nil? ? run_context.chef_provisioning.current_driver : run_context.chef_provisioning.driver_for(@new_resource.driver)
172
+ end
173
+ end
174
+ end
175
+ end
@@ -1,4 +1,4 @@
1
- # Copyright 2015, BlackBerry, Inc.
1
+ # Copyright 2016, BlackBerry Limited
2
2
  #
3
3
  # Licensed under the Apache License, Version 2.0 (the "License");
4
4
  # you may not use this file except in compliance with the License.
@@ -49,7 +49,7 @@ class Chef
49
49
 
50
50
  action :allocate do
51
51
  if exists?
52
- action_handler.report_progress "image '#{new_resource.name}' already exists - nothing to do"
52
+ action_handler.report_progress "image '#{new_resource.name}' already exists - (up to date)"
53
53
  else
54
54
  fail "'size' must be specified" unless new_resource.size
55
55
  fail "'datastore_id' must be specified" unless new_resource.datastore_id
@@ -81,7 +81,7 @@ class Chef
81
81
  @new_resource.updated_by_last_action(true)
82
82
  end
83
83
  when 'READY', 'USED', 'USED_PERS'
84
- action_handler.report_progress "image '#{new_resource.name}' is already in #{@image.state_str} state - nothing to do"
84
+ action_handler.report_progress "image '#{new_resource.name}' is already in #{@image.state_str} state - (up to date)"
85
85
  else
86
86
  fail "Image #{new_resource.name} is in unexpected state '#{@image.state_str}'"
87
87
  end
@@ -99,7 +99,7 @@ class Chef
99
99
  @new_resource.updated_by_last_action(true)
100
100
  end
101
101
  else
102
- action_handler.report_progress "image '#{new_resource.name}' does not exist - nothing to do"
102
+ action_handler.report_progress "image '#{new_resource.name}' does not exist - (up to date)"
103
103
  end
104
104
  end
105
105
 
@@ -120,7 +120,7 @@ class Chef
120
120
 
121
121
  disk_id = new_driver.one.get_disk_id(vm, disk_hash['IMAGE']['NAME'])
122
122
  if !disk_id.nil?
123
- action_handler.report_progress "disk is already attached" unless disk_id.nil?
123
+ action_handler.report_progress "disk is already attached - (up to date)" unless disk_id.nil?
124
124
  elsif disk_id.nil?
125
125
  action_handler.report_progress "disk not attached, attaching..."
126
126
  rc = vm.disk_attach(disk_tpl)
@@ -187,7 +187,7 @@ class Chef
187
187
  @image['TEMPLATE/DRIVER'] == image_config[:driver] &&
188
188
  @image['TEMPLATE/DESCRIPTION'] == image_config[:description] &&
189
189
  @image['DATASTORE_ID'] == image_config[:datastore_id]
190
- action_handler.report_progress("image '#{@new_resource.name}' (ID: #{@image.id}) already exists - nothing to do")
190
+ action_handler.report_progress("image '#{@new_resource.name}' (ID: #{@image.id}) already exists - (up to date)")
191
191
  else
192
192
  fail "image '#{new_resource.name}' already exists, but it is not the same image"
193
193
  end
@@ -1,4 +1,4 @@
1
- # Copyright 2015, BlackBerry, Ltd.
1
+ # Copyright 2016, BlackBerry Limited
2
2
  #
3
3
  # Licensed under the Apache License, Version 2.0 (the "License");
4
4
  # you may not use this file except in compliance with the License.
@@ -139,12 +139,10 @@ class Chef
139
139
  end
140
140
 
141
141
  def create_template
142
- if new_resource.template_file && new_resource.template.size > 0
143
- fail("Attributes 'template_file' and 'template' are mutually " \
144
- 'exclusive.')
145
- elsif new_resource.template_file
142
+ fail("Attributes 'template_file' and 'template' are mutually 'exclusive.'") if new_resource.template_file && !new_resource.template.empty?
143
+ if new_resource.template_file
146
144
  ::File.read(new_resource.template_file)
147
- elsif new_resource.template.size > 0
145
+ elsif !new_resource.template.empty?
148
146
  driver.one.create_template(new_resource.template)
149
147
  else
150
148
  fail("Missing attribute 'template_file' or 'template' in " \
@@ -1,4 +1,4 @@
1
- # Copyright 2015, BlackBerry, Inc.
1
+ # Copyright 2016, BlackBerry Limited
2
2
  #
3
3
  # Licensed under the Apache License, Version 2.0 (the "License");
4
4
  # you may not use this file except in compliance with the License.
@@ -45,7 +45,7 @@ class Chef
45
45
  fail "Missing attribute 'password'" unless @new_resource.password
46
46
 
47
47
  if exists?(:name => @new_resource.name)
48
- action_handler.report_progress "user '#{@new_resource.name}' already exists - nothing to do"
48
+ action_handler.report_progress "user '#{@new_resource.name}' already exists - (up to date)"
49
49
  else
50
50
  action_handler.perform_action "create user '#{@new_resource.name}'" do
51
51
  user = OpenNebula::User.new(OpenNebula::User.build_xml, @client)
@@ -65,22 +65,19 @@ class Chef
65
65
  @new_resource.updated_by_last_action(true)
66
66
  end
67
67
  else
68
- action_handler.report_progress "user '#{new_resource.name}' does not exists - nothing to do"
68
+ action_handler.report_progress "user '#{new_resource.name}' does not exists - (up to date)"
69
69
  end
70
70
  end
71
71
 
72
72
  action :update do
73
- if exists?(:id => @new_resource.user_id, :name => @new_resource.name)
74
- fail "':template' or ':template_file' attribute missing" if !@new_resource.template && !@new_resource.template_file
75
- # hash = @current_user.to_hash
76
- tpl = new_driver.one.create_template(@new_resource.template) if @new_resource.template
77
- tpl = ::File.read(@new_resource.template_file) if @new_resource.template_file
73
+ fail "user '#{new_resource.name}' does not exists" unless exists?(:id => @new_resource.user_id, :name => @new_resource.name)
74
+ fail "':template' or ':template_file' attribute missing" unless @new_resource.template || @new_resource.template_file
78
75
 
79
- rc = @current_user.update(tpl, true)
80
- fail "failed to update user '#{@new_resource.name}': #{rc.message}" if OpenNebula.is_error?(rc)
81
- else
82
- fail "user '#{new_resource.name}' does not exists"
83
- end
76
+ tpl = new_driver.one.create_template(@new_resource.template) if @new_resource.template
77
+ tpl = ::File.read(@new_resource.template_file) if @new_resource.template_file
78
+
79
+ rc = @current_user.update(tpl, true)
80
+ fail "failed to update user '#{@new_resource.name}': #{rc.message}" if OpenNebula.is_error?(rc)
84
81
  end
85
82
 
86
83
  protected
@@ -89,7 +86,7 @@ class Chef
89
86
  if current_driver && current_driver.driver_url != new_driver.driver_url
90
87
  fail "Cannot move '#{machine_spec.name}' from #{current_driver.driver_url} to #{new_driver.driver_url}: machine moving is not supported. Destroy and recreate."
91
88
  end
92
- fail "Driver not specified for one_image #{new_resource.name}" unless new_driver
89
+ fail "Driver not specified for one_user #{new_resource.name}" unless new_driver
93
90
  new_driver
94
91
  end
95
92
 
@@ -1,4 +1,4 @@
1
- # Copyright 2015, BlackBerry, Inc.
1
+ # Copyright 2016, BlackBerry Limited
2
2
  #
3
3
  # Licensed under the Apache License, Version 2.0 (the "License");
4
4
  # you may not use this file except in compliance with the License.
@@ -46,7 +46,7 @@ class Chef
46
46
  fail "Missing attribute 'cluster_id'" unless @new_resource.cluster_id
47
47
 
48
48
  if exists?(:name => @new_resource.name)
49
- action_handler.report_progress "vnet '#{@new_resource.name}' already exists - nothing to do"
49
+ action_handler.report_progress "vnet '#{@new_resource.name}' already exists - (up to date)"
50
50
  else
51
51
  action_handler.perform_action "created vnet '#{@new_resource.name}' from '#{@new_resource.template_file}'" do
52
52
  template_str = ::File.read(@new_resource.template_file) + "\nNAME=\"#{@new_resource.name}\""
@@ -67,7 +67,7 @@ class Chef
67
67
  @new_resource.updated_by_last_action(true)
68
68
  end
69
69
  else
70
- action_handler.report_progress "vnet '#{new_resource.name}' does not exists - nothing to do"
70
+ action_handler.report_progress "vnet '#{new_resource.name}' does not exists - (up to date)"
71
71
  end
72
72
  end
73
73
 
@@ -86,11 +86,8 @@ class Chef
86
86
  else
87
87
  same = ar_pool[0]['AR']['SIZE'].to_i == @new_resource.size
88
88
  end
89
- if same
90
- action_handler.report_progress "vnet '#{@new_resource.name}' already exists - nothing to do"
91
- else
92
- fail "vnet '#{@new_resource.name}' exists with different configuration"
93
- end
89
+ fail "vnet '#{@new_resource.name}' exists with different configuration" unless same
90
+ action_handler.report_progress "vnet '#{@new_resource.name}' already exists - (up to date)"
94
91
  else
95
92
  fail "parent network '#{@new_resource.network}' does not exist" unless exists?(:id => @new_resource.network)
96
93
  action_handler.perform_action "reserved vnet '#{@new_resource.name}'" do
@@ -107,7 +104,7 @@ class Chef
107
104
  if current_driver && current_driver.driver_url != new_driver.driver_url
108
105
  fail "Cannot move '#{machine_spec.name}' from #{current_driver.driver_url} to #{new_driver.driver_url}: machine moving is not supported. Destroy and recreate."
109
106
  end
110
- fail "Driver not specified for one_image #{new_resource.name}" unless new_driver
107
+ fail "Driver not specified for one_vnet #{new_resource.name}" unless new_driver
111
108
  new_driver
112
109
  end
113
110
 
@@ -1,4 +1,4 @@
1
- # Copyright 2015, BlackBerry, Inc.
1
+ # Copyright 2016, BlackBerry Limited
2
2
  #
3
3
  # Licensed under the Apache License, Version 2.0 (the "License");
4
4
  # you may not use this file except in compliance with the License.
@@ -72,7 +72,7 @@ class Chef
72
72
  @new_resource.updated_by_last_action(true)
73
73
  end
74
74
  else
75
- action_handler.report_progress("#{@new_resource.name} is not present - nothing do to")
75
+ action_handler.report_progress("#{@new_resource.name} is not present - (up to date)")
76
76
  end
77
77
  end
78
78
 
@@ -102,7 +102,7 @@ class Chef
102
102
  if current_driver && current_driver.driver_url != new_driver.driver_url
103
103
  fail "Cannot move '#{machine_spec.name}' from #{current_driver.driver_url} to #{new_driver.driver_url}: machine moving is not supported. Destroy and recreate."
104
104
  end
105
- fail "Driver not specified for one_image #{new_resource.name}" unless new_driver
105
+ fail "Driver not specified for one_vnet_lease #{new_resource.name}" unless new_driver
106
106
  new_driver
107
107
  end
108
108
 
@@ -1,4 +1,4 @@
1
- # Copyright 2015, BlackBerry, Inc.
1
+ # Copyright 2016, BlackBerry Limited
2
2
  #
3
3
  # Licensed under the Apache License, Version 2.0 (the "License");
4
4
  # you may not use this file except in compliance with the License.
@@ -0,0 +1,28 @@
1
+ # Copyright 2016, BlackBerry Limited
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ require 'opennebula'
16
+ require 'json'
17
+
18
+ endpoint = ARGV[0].dup
19
+ credentials = ARGV[1].dup
20
+ options = JSON.parse(ARGV[2].dup)
21
+
22
+ version = OpenNebula::Client.new(credentials, endpoint, options).get_version
23
+
24
+ if version.is_a?(String)
25
+ puts version
26
+ else
27
+ puts version.inspect
28
+ end
@@ -1,4 +1,4 @@
1
- # Copyright 2015, BlackBerry, Inc.
1
+ # Copyright 2016, BlackBerry Limited
2
2
  #
3
3
  # Licensed under the Apache License, Version 2.0 (the "License");
4
4
  # you may not use this file except in compliance with the License.
@@ -1,4 +1,4 @@
1
- # Copyright 2015, BlackBerry, Inc.
1
+ # Copyright 2016, BlackBerry Limited
2
2
  #
3
3
  # Licensed under the Apache License, Version 2.0 (the "License");
4
4
  # you may not use this file except in compliance with the License.
@@ -37,7 +37,7 @@ class Chef
37
37
  end
38
38
 
39
39
  def default
40
- fail 'No credentials loaded! Do you have a ~/.one/one_auth file?' if @credentials.size == 0
40
+ fail 'No credentials loaded! Do you have a ~/.one/one_auth file?' if @credentials.empty?
41
41
  @credentials[ENV['ONE_DEFAULT_PROFILE'] || 'default'] || @credentials.first[1]
42
42
  end
43
43
 
@@ -1,4 +1,4 @@
1
- # Copyright 2015, BlackBerry, Inc.
1
+ # Copyright 2016, BlackBerry Limited
2
2
  #
3
3
  # Licensed under the Apache License, Version 2.0 (the "License");
4
4
  # you may not use this file except in compliance with the License.
@@ -19,13 +19,88 @@ require 'chef/provisioning/convergence_strategy/install_sh'
19
19
  require 'chef/provisioning/convergence_strategy/no_converge'
20
20
  require 'chef/provisioning/transport/ssh'
21
21
  require 'chef/provisioning/opennebula_driver/version'
22
- require 'chef/provisioning/opennebula_driver/one_lib'
23
22
  require 'chef/provisioning/opennebula_driver/credentials'
24
23
  require 'net/ssh/proxy/command'
24
+ require 'json'
25
+ require 'open3'
26
+
27
+ class Chef
28
+ module DSL
29
+ #
30
+ # Module extension.
31
+ #
32
+ module Recipe
33
+ def with_flow_url(url)
34
+ run_context.chef_provisioning.with_flow_url(url)
35
+ end
36
+ end
37
+ end
38
+ end
39
+
40
+ class Chef
41
+ module Provisioning
42
+ #
43
+ # Class extension.
44
+ #
45
+ class ChefRunData
46
+ attr_accessor :flow_url
47
+ def with_flow_url(url)
48
+ @flow_url = url
49
+ end
50
+ end
51
+ end
52
+ end
25
53
 
26
54
  class Chef
27
55
  module Provisioning
56
+ # OpenNebulaDriver module.
28
57
  module OpenNebulaDriver
58
+ def self.match_driver_url(url, allow_nil_profile = false)
59
+ scan = url.match(%r/opennebula:(https?:\/\/[^:\/]+ (?::[0-9]{2,5})? (?:\/[^:\s]+) ) :?([^:\s]+)?/x)
60
+ fail "'driver_url' option has invalid format: #{url}" if scan.nil?
61
+ endpoint = scan[1]
62
+ profile = scan[2]
63
+ fail "'driver_url' option is missing an endpoint: #{url}" if endpoint.nil?
64
+ fail "'driver_url' option is missing a profile: #{url}" if profile.nil? && !allow_nil_profile
65
+ [endpoint, profile]
66
+ end
67
+
68
+ def self.get_onelib(args)
69
+ endpoint = args[:endpoint]
70
+ credentials = args[:credentials]
71
+ options = args[:options] || {}
72
+ if args[:driver_url]
73
+ fail "OpenNebula driver_url cannot be #{args[:driver_url].class}, it must be a String" unless args[:driver_url].is_a?(String)
74
+ endpoint, profile = Chef::Provisioning::OpenNebulaDriver.match_driver_url(args[:driver_url])
75
+ one_profile = Chef::Provisioning::OpenNebulaDriver::Credentials.new[profile]
76
+ credentials = one_profile[:credentials]
77
+ options = one_profile[:options] || {}
78
+ end
79
+ fail "OpenNebula credentials cannot be #{credentials.class}, it must be a String" unless credentials.is_a?(String)
80
+ fail "OpenNebula endpoint cannot be #{endpoint.class}, it must be a String" unless endpoint.is_a?(String)
81
+ fail "OpenNebula options cannot be #{options.class}, it must be a Hash" unless options.is_a?(Hash)
82
+ server_version, = Open3.capture2e("ruby #{File.dirname(__FILE__)}/../driver_init/server_version.rb #{endpoint} #{credentials} #{options.to_json.inspect}")
83
+ server_version.strip!
84
+ fail server_version unless server_version =~ /^\d+\.\d+(?:\.\d+)?$/
85
+ begin
86
+ gem 'opennebula', "~> #{server_version}"
87
+ require 'opennebula'
88
+ rescue Gem::LoadError => e
89
+ e_inspect = e.inspect
90
+ raise e unless e_inspect.include?('already activated')
91
+ end
92
+ require 'chef/provisioning/opennebula_driver/one_lib'
93
+ gem_version = Gem.loaded_specs['opennebula'].version.to_s
94
+ if gem_version == server_version
95
+ Chef::Log.debug("You are using OpenNebula gem version #{gem_version} against OpenNebula server version #{server_version}")
96
+ else
97
+ Chef::Log.warn('OPENNEBULA GEM / SERVER VERSION MISMATCH')
98
+ Chef::Log.warn("You are using OpenNebula gem version #{gem_version} against OpenNebula server version #{server_version}")
99
+ Chef::Log.warn('Users may experience issues with this gem.')
100
+ end
101
+ OneLib.new(:credentials => credentials, :endpoint => endpoint, :options => options)
102
+ end
103
+
29
104
  #
30
105
  # A Driver instance represents a place where machines can be created
31
106
  # and found, and contains methods to create, delete, start, stop, and
@@ -81,11 +156,14 @@ class Chef
81
156
  #
82
157
  # driver_options:
83
158
  # credentials: bbsl-auto:text_pass credentials has precedence over secret_file
84
- # secret_file: local_path_to_one_auth_file
159
+ # endpoint: opennebula endpoint
160
+ # options: additional options for OpenNebula::Client
85
161
  #
86
162
  def initialize(driver_url, config)
87
163
  super
88
- @one = OneLib.new(:driver_url => driver_url)
164
+ @one = Chef::Provisioning::OpenNebulaDriver.get_onelib(:driver_url => driver_url)
165
+ @driver_url_with_profile = driver_url
166
+ @driver_url = @one.client.one_endpoint
89
167
  end
90
168
 
91
169
  def self.from_url(driver_url, config)
@@ -124,17 +202,17 @@ class Chef
124
202
  instance = instance_for(machine_spec)
125
203
  return machine_spec unless instance.nil?
126
204
 
127
- unless machine_options.bootstrap_options
205
+ unless machine_options[:bootstrap_options]
128
206
  fail "'bootstrap_options' must be specified"
129
207
  end
130
208
  check_unique_names(machine_options, machine_spec)
131
209
  action_handler.perform_action "created vm '#{machine_spec.name}'" do
132
210
  Chef::Log.debug(machine_options)
133
211
  tpl = @one.get_template(machine_spec.name,
134
- machine_options.bootstrap_options)
212
+ machine_options[:bootstrap_options])
135
213
  vm = @one.allocate_vm(tpl)
136
214
  populate_node_object(machine_spec, machine_options, vm)
137
- @one.chmod_resource(vm, machine_options.bootstrap_options[:mode])
215
+ @one.chmod_resource(vm, machine_options[:bootstrap_options][:mode])
138
216
 
139
217
  # This option allows to manipulate how the machine shows up
140
218
  # in the OpenNebula UI and CLI tools. We either set the VM
@@ -224,11 +302,17 @@ class Chef
224
302
  end
225
303
  fail "Failed to destroy '#{instance.name}'. Current state: #{instance.state_str}" if instance.state_str != 'DONE'
226
304
  end
305
+ elsif machine_spec.reference
306
+ Chef::Log.info("vm #{machine_spec.name} (#{machine_spec.reference['instance_id']}) does not exist - (up to date)")
227
307
  else
228
- Chef::Log.info("vm #{machine_spec.name} (#{machine_spec.reference['instance_id']}) does not exist - nothing to do")
308
+ Chef::Log.info("vm #{machine_spec.name} does not exist - (up to date)")
309
+ end
310
+ begin
311
+ strategy = convergence_strategy_for(machine_spec, machine_options)
312
+ strategy.cleanup_convergence(action_handler, machine_spec)
313
+ rescue Net::HTTPServerException => e
314
+ raise unless e.response.code == '404'
229
315
  end
230
- strategy = convergence_strategy_for(machine_spec, machine_options)
231
- strategy.cleanup_convergence(action_handler, machine_spec)
232
316
  end
233
317
 
234
318
  # Stop the given machine.
@@ -251,7 +335,7 @@ class Chef
251
335
  end
252
336
  end
253
337
  else
254
- Chef::Log.info("vm #{machine_spec.name} (#{machine_spec.reference['instance_id']}) does not exist - nothing to do")
338
+ Chef::Log.info("vm #{machine_spec.name} (#{machine_spec.reference['instance_id']}) does not exist - (up to date)")
255
339
  end
256
340
  end
257
341
 
@@ -314,7 +398,7 @@ class Chef
314
398
  def destroy_image(action_handler, image_spec, _image_options)
315
399
  img = @one.get_resource(:image, :id => image_spec.location['image_id'].to_i)
316
400
  if img.nil?
317
- action_handler.report_progress "image #{image_spec.name} (#{image_spec.location['image_id']}) does not exist - nothing to do"
401
+ action_handler.report_progress "image #{image_spec.name} (#{image_spec.location['image_id']}) does not exist - (up to date)"
318
402
  else
319
403
  action_handler.perform_action "deleted image #{image_spec.name} (#{image_spec.location['image_id']})" do
320
404
  rc = img.delete
@@ -413,6 +497,7 @@ class Chef
413
497
  # @param [Array[ChefMetal::MachineSpec]] machine_specs
414
498
  # An array of machine specs the load balancer should have
415
499
  def allocate_load_balancer(_action_handler, _lb_spec, _lb_options, _machine_specs)
500
+ fail "'allocate_load_balancer' is not implemented"
416
501
  end
417
502
 
418
503
  # Make the load balancer ready
@@ -420,6 +505,7 @@ class Chef
420
505
  # @param [ChefMetal::LoadBalancerSpec] lb_spec Frozen LB specification
421
506
  # @param [Hash] lb_options A hash of options to pass the LB
422
507
  def ready_load_balancer(_action_handler, _lb_spec, _lb_options, _machine_specs)
508
+ fail "'ready_load_balancer' is not implemented"
423
509
  end
424
510
 
425
511
  # Destroy the load balancer
@@ -427,6 +513,7 @@ class Chef
427
513
  # @param [ChefMetal::LoadBalancerSpec] lb_spec Frozen LB specification
428
514
  # @param [Hash] lb_options A hash of options to pass the LB
429
515
  def destroy_load_balancer(_action_handler, _lb_spec, _lb_options)
516
+ fail "'destroy_load_balancer' is not implemented"
430
517
  end
431
518
 
432
519
  protected
@@ -444,7 +531,7 @@ class Chef
444
531
  end
445
532
 
446
533
  def check_unique_names(machine_options, machine_spec)
447
- return unless machine_options.bootstrap_options[:unique_names]
534
+ return unless machine_options[:bootstrap_options][:unique_names]
448
535
  hostname = if machine_options[:vm_name] == :short
449
536
  machine_spec.name.split('.').first
450
537
  elsif machine_options[:vm_name].is_a?(String)
@@ -458,13 +545,13 @@ class Chef
458
545
  end
459
546
 
460
547
  def populate_node_object(machine_spec, machine_options, vm)
461
- machine_spec.driver_url = driver_url
548
+ machine_spec.driver_url = @driver_url_with_profile
462
549
  machine_spec.reference = {
463
550
  'driver_version' => Chef::Provisioning::OpenNebulaDriver::VERSION,
464
551
  'allocated_at' => Time.now.utc.to_s,
465
- 'image_id' => machine_options.bootstrap_options[:image_id] || nil,
466
- 'is_shutdown' => machine_options.bootstrap_options[:is_shutdown] || false,
467
- 'shutdown_hard' => machine_options.bootstrap_options[:shutdown_hard] || false,
552
+ 'image_id' => machine_options[:bootstrap_options][:image_id] || nil,
553
+ 'is_shutdown' => machine_options[:bootstrap_options][:is_shutdown] || false,
554
+ 'shutdown_hard' => machine_options[:bootstrap_options][:shutdown_hard] || false,
468
555
  'instance_id' => vm.id,
469
556
  'name' => vm.name,
470
557
  'state' => vm.state_str
@@ -478,7 +565,7 @@ class Chef
478
565
  end
479
566
 
480
567
  def populate_img_object(image_spec, new_image)
481
- image_spec.driver_url = driver_url
568
+ image_spec.driver_url = @driver_url_with_profile
482
569
  image_spec.reference = {
483
570
  'driver_version' => Chef::Provisioning::OpenNebulaDriver::VERSION,
484
571
  'image_id' => new_image,
@@ -492,13 +579,15 @@ class Chef
492
579
  def instance_for(machine_spec)
493
580
  instance = nil
494
581
  if machine_spec.reference
495
- fail "Switching a machine's driver from #{machine_spec.driver_url} to #{driver_url} is not supported!" \
496
- " Use machine :destroy and then :create the machine on the new driver." if machine_spec.driver_url != driver_url
582
+ current_endpoint, = Chef::Provisioning::OpenNebulaDriver.match_driver_url(machine_spec.driver_url, true)
583
+ fail "Cannot move '#{machine_spec.name}' from #{current_endpoint} to #{driver_url}: machine moving is not supported. Destroy and recreate." if current_endpoint != driver_url
497
584
  instance = @one.get_resource(:virtualmachine, :id => machine_spec.reference['instance_id'].to_i)
585
+ machine_spec.driver_url = @driver_url_with_profile
498
586
  elsif machine_spec.location
499
- fail "Switching a machine's driver from #{machine_spec.driver_url} to #{driver_url} is not supported!" \
500
- " Use machine :destroy and then :create the machine on the new driver." if machine_spec.driver_url != driver_url
587
+ current_endpoint, = Chef::Provisioning::OpenNebulaDriver.match_driver_url(machine_spec.driver_url, true)
588
+ fail "Cannot move '#{machine_spec.name}' from #{current_endpoint} to #{driver_url}: machine moving is not supported. Destroy and recreate." if current_endpoint != driver_url
501
589
  instance = @one.get_resource(:virtualmachine, :id => machine_spec.location['server_id'].to_i)
590
+ machine_spec.driver_url = @driver_url_with_profile
502
591
  unless instance.nil?
503
592
  # Convert from previous driver
504
593
  machine_spec.reference = {
@@ -518,9 +607,11 @@ class Chef
518
607
  instance = instance_for(machine_spec)
519
608
  fail "#{machine_spec.name} (#{machine_spec.reference['instance_id']}) does not exist!" if instance.nil?
520
609
  # TODO: Support Windoze VMs (see chef-provisioning-vagrant)
521
- Chef::Provisioning::Machine::UnixMachine.new(machine_spec,
522
- transport_for(machine_spec, machine_options, instance),
523
- convergence_strategy_for(machine_spec, machine_options))
610
+ Chef::Provisioning::Machine::UnixMachine.new(
611
+ machine_spec,
612
+ transport_for(machine_spec, machine_options, instance),
613
+ convergence_strategy_for(machine_spec, machine_options)
614
+ )
524
615
  end
525
616
 
526
617
  def get_ssh_user(machine_spec, machine_options)
@@ -539,7 +630,7 @@ class Chef
539
630
  }.merge(machine_options[:ssh_options] || {})
540
631
  ssh_options[:proxy] = Net::SSH::Proxy::Command.new(ssh_options[:proxy]) if ssh_options.key?(:proxy)
541
632
 
542
- connection_timeout = machine_options[:connection_timeout] || 300
633
+ connection_timeout = machine_options[:connection_timeout] || 300 # default is 5 min
543
634
  username = get_ssh_user(machine_spec, machine_options)
544
635
 
545
636
  options = {}
@@ -552,21 +643,28 @@ class Chef
552
643
 
553
644
  transport = Chef::Provisioning::Transport::SSH.new(machine_spec.reference['ip'], username, ssh_options, options, config)
554
645
 
555
- # wait up to 5 min to establish SSH connection
556
- connect_sleep = 3
646
+ rc = retryable_operation("Waiting for SSH connection", connection_timeout.to_i) { transport.available? }
647
+ fail "Failed to establish SSH connection to '#{machine_spec.name}'" if rc.nil?
648
+ transport
649
+ end
650
+
651
+ # Retry an operation until the timeout expires. Will always try at least once.
652
+ def retryable_operation(msg = "operation", timeout = 15, delay = 3)
653
+ return nil unless block_given?
557
654
  start = Time.now
558
655
  loop do
559
- break if transport.available?
560
- fail "Failed to establish SSH connection to '#{machine_spec.name}'" if Time.now > start + connection_timeout.to_i
561
- Chef::Log.info("Waiting for SSH server ...")
562
- sleep connect_sleep
656
+ return true if yield
657
+ Chef::Log.info(msg)
658
+ sleep delay
659
+ break if (Time.now - start) > timeout
563
660
  end
564
- transport
661
+ Chef::Log.error("Timed out waiting for operation to complete: '#{msg}'")
662
+ nil
565
663
  end
566
664
 
567
665
  def convergence_strategy_for(machine_spec, machine_options)
568
666
  # TODO: Support Windoze VMs (see chef-provisioning-vagrant)
569
- convergence_options = Cheffish::MergedConfig.new(machine_options[:convergence_options] || {})
667
+ convergence_options = Cheffish::MergedConfig.new(machine_options ? machine_options[:convergence_options] || {} : {})
570
668
 
571
669
  if !machine_spec.reference
572
670
  Chef::Provisioning::ConvergenceStrategy::NoConverge.new(convergence_options, config)