elevage 0.1.0 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +3 -1
  3. data/README.md +33 -11
  4. data/elevage.gemspec +15 -15
  5. data/features/archive +3 -22
  6. data/features/build.feature +2 -1
  7. data/features/generate.feature +3 -9
  8. data/features/health_env_failure.feature +2 -8
  9. data/features/health_failure.feature +1 -2
  10. data/features/health_success.feature +3 -9
  11. data/features/list.feature +3 -9
  12. data/features/step_definitions/elevage_steps.rb +2 -2
  13. data/lib/elevage/build.rb +4 -1
  14. data/lib/elevage/constants.rb +2 -2
  15. data/lib/elevage/environment.rb +66 -39
  16. data/lib/elevage/generate.rb +4 -3
  17. data/lib/elevage/health.rb +4 -0
  18. data/lib/elevage/new.rb +4 -2
  19. data/lib/elevage/platform.rb +11 -3
  20. data/lib/elevage/provisioner.rb +61 -21
  21. data/lib/elevage/provisionerrunqueue.rb +25 -10
  22. data/lib/elevage/templates/vcenter.yml.tt +7 -12
  23. data/lib/elevage/version.rb +1 -1
  24. data/lib/elevage.rb +5 -0
  25. metadata +58 -88
  26. data/.ruby-version +0 -1
  27. data/.yardoc/checksums +0 -12
  28. data/.yardoc/object_types +0 -0
  29. data/.yardoc/objects/root.dat +0 -0
  30. data/.yardoc/proxy_types +0 -0
  31. data/doc/Elevage/Build.html +0 -435
  32. data/doc/Elevage/CLI.html +0 -282
  33. data/doc/Elevage/Environment.html +0 -950
  34. data/doc/Elevage/Generate.html +0 -346
  35. data/doc/Elevage/Health.html +0 -359
  36. data/doc/Elevage/New.html +0 -411
  37. data/doc/Elevage/Platform.html +0 -1119
  38. data/doc/Elevage/Provisioner.html +0 -804
  39. data/doc/Elevage/ProvisionerRunQueue.html +0 -765
  40. data/doc/Elevage/Runner.html +0 -319
  41. data/doc/Elevage.html +0 -501
  42. data/doc/_index.html +0 -239
  43. data/doc/class_list.html +0 -58
  44. data/doc/css/common.css +0 -1
  45. data/doc/css/full_list.css +0 -57
  46. data/doc/css/style.css +0 -339
  47. data/doc/file.README.html +0 -187
  48. data/doc/file_list.html +0 -60
  49. data/doc/frames.html +0 -26
  50. data/doc/index.html +0 -187
  51. data/doc/js/app.js +0 -219
  52. data/doc/js/full_list.js +0 -181
  53. data/doc/js/jquery.js +0 -4
  54. data/doc/method_list.html +0 -369
  55. data/doc/top-level-namespace.html +0 -112
@@ -5,6 +5,8 @@ require 'English'
5
5
 
6
6
  module Elevage
7
7
  # Platform class
8
+ #
9
+ # This represents the overall description of the platform
8
10
  class Platform
9
11
  attr_accessor :name, :description
10
12
  attr_accessor :environments
@@ -17,6 +19,9 @@ module Elevage
17
19
  attr_accessor :compute
18
20
 
19
21
  # rubocop:disable MethodLength
22
+
23
+ # Create a new platform object
24
+ # @return [Elevage::Platform]
20
25
  def initialize
21
26
  fail unless platform_files_exists?
22
27
  platform = YAML.load_file(YML_PLATFORM).fetch('platform')
@@ -34,6 +39,9 @@ module Elevage
34
39
  # rubocop:enable MethodLength
35
40
 
36
41
  # rubocop:disable MethodLength, LineLength, CyclomaticComplexity, PerceivedComplexity, AmbiguousOperator
42
+
43
+ # Determine whether the platform definition is considered correct
44
+ # return [Boolean]
37
45
  def healthy?
38
46
  health = ''
39
47
  # Array of string checked for empty values
@@ -60,7 +68,7 @@ module Elevage
60
68
  health += MSG[:invalid_destfolder] if v['destfolder'].nil?
61
69
  health += MSG[:invalid_appendenv] unless v['appendenv'] == true || v['appendenv'] == false
62
70
  health += MSG[:invalid_appenddomain] unless v['appenddomain'] == true || v['appenddomain'] == false
63
- health += MSG[:empty_datastores] unless v['datastores'].all?
71
+ health += MSG[:empty_datastores] if v['datastore'].nil?
64
72
  health += MSG[:invalid_domain] if v['domain'].nil?
65
73
  v['dnsips'].each { |ip| health += MSG[:invalid_ip] unless Resolv::IPv4::Regex.match(ip) }
66
74
  end
@@ -85,8 +93,8 @@ module Elevage
85
93
 
86
94
  private
87
95
 
88
- # Private: confirms existence of the standard platform definition files
89
- # Returns true if all standard files present
96
+ # Confirm existence of the standard platform definition files
97
+ # @return [Boolean] True if all standard files present
90
98
  def platform_files_exists?
91
99
  fail(IOError, ERR[:no_platform_file]) unless File.file?(YML_PLATFORM)
92
100
  fail(IOError, ERR[:no_vcenter_file]) unless File.file?(YML_VCENTER)
@@ -5,7 +5,10 @@ require_relative 'platform'
5
5
  require_relative 'provisionerrunqueue'
6
6
 
7
7
  module Elevage
8
- # Provisioner class
8
+ # rubocop:disable ClassLength
9
+
10
+ # Provisioner is responsible for the actual execution of the commands to
11
+ # create the requested virtual machine.
9
12
  class Provisioner
10
13
  attr_accessor :name
11
14
  attr_accessor :component
@@ -13,7 +16,14 @@ module Elevage
13
16
  attr_accessor :environment
14
17
  attr_accessor :vcenter
15
18
 
16
- # Set us up to build the specified instance of component
19
+ # Create the Provisioner object for the requested virtual machine
20
+ # @param [String] name Name of the node to create
21
+ # @param [String] component Name of the platform component node is part of
22
+ # @param [String] instance Number representing which instance of
23
+ # `component` this node is
24
+ # @param [String] environment Name of the environnment we're provisioning to
25
+ # @param [String] options Thor `options` hash
26
+ # @return [Elevage::Provisioner]
17
27
  def initialize(name, component, instance, environment, options)
18
28
  @name = name
19
29
  @component = component
@@ -23,6 +33,8 @@ module Elevage
23
33
  @vcenter = @environment.vcenter
24
34
  end
25
35
 
36
+ # Stringify the Provisioner
37
+ # @return [String]
26
38
  def to_s
27
39
  puts "Name: #{@name}"
28
40
  puts "Instance: #{@instance}"
@@ -32,8 +44,9 @@ module Elevage
32
44
  puts @environment.to_yaml
33
45
  end
34
46
 
35
- # Public: Build the node
36
- # rubocop:disable MethodLength, LineLength, GlobalVars, CyclomaticComplexity
47
+ # rubocop:disable MethodLength, CyclomaticComplexity
48
+
49
+ # Build the the virtual machine
37
50
  def build
38
51
  knife_cmd = generate_knife_cmd
39
52
 
@@ -60,12 +73,18 @@ module Elevage
60
73
  # err_thread = Thread.new do
61
74
  Thread.new do
62
75
  while (line = stderr.gets)
63
- sem.synchronize { logfile.puts line }
76
+ sem.synchronize do
77
+ logfile.puts line
78
+ logfile.sync
79
+ end
64
80
  end
65
81
  end
66
82
  out_thread = Thread.new do
67
83
  while (line = stdout.gets)
68
- sem.synchronize { logfile.puts line }
84
+ sem.synchronize do
85
+ logfile.puts line
86
+ logfile.sync
87
+ end
69
88
  end
70
89
  end
71
90
  out_thread.join
@@ -80,22 +99,41 @@ module Elevage
80
99
  # exit status is a failure, and the details will be in the logfile
81
100
  status.exitstatus == 0 ? true : false
82
101
  end
83
- # rubocop:enable MethodLength, LineLength, GlobalVars, CyclomaticComplexity
102
+ # rubocop:enable MethodLength, CyclomaticComplexity
84
103
 
85
104
  private
86
105
 
87
- # Private: Determine which datastore to use for this specific
88
- # provisioning.
106
+ # rubocop:disable LineLength
107
+
108
+ # Private
109
+ #
110
+ # Determine which datastore to use for this specific provisioning.
111
+ # @return [String] Name of datastore
89
112
  def select_datastore
90
- if @options['dry-run']
91
- @vcenter['datastores'][0]
92
- else
93
- @vcenter['datastores'][rand(@vcenter['datastores'].count)]
94
- end
113
+ knife_cmd = 'knife vsphere datastore maxfree --vsinsecure'
114
+
115
+ # Authentication and host
116
+ knife_cmd << " --vsuser #{@options[:vsuser]}"
117
+ knife_cmd << " --vspass #{@options[:vspass]}"
118
+ knife_cmd << " --vshost #{@vcenter['host']}"
119
+
120
+ # vSphere destination information (where the clone will end up)
121
+ knife_cmd << " --vsdc '#{@vcenter['datacenter']}'"
122
+
123
+ # datastore prefix
124
+ knife_cmd << " --regex #{@vcenter['datastore']}"
125
+
126
+ # get result and clean up
127
+ @options['dry-run'] ? @vcenter['datastore'] : `#{knife_cmd}`.to_s.gsub!("\n", '')
95
128
  end
129
+ # rubocop:enable LineLength
96
130
 
97
- # Private: Build the knife command that will do the provisioning.
98
131
  # rubocop:disable MethodLength, LineLength
132
+
133
+ # Private
134
+ #
135
+ # Build the knife command that will do the provisioning.
136
+ # @return [String] knife command line string
99
137
  def generate_knife_cmd
100
138
  knife_cmd = 'knife vsphere vm clone --vsinsecure --start'
101
139
 
@@ -110,7 +148,9 @@ module Elevage
110
148
 
111
149
  # vSphere destination information (where the clone will end up)
112
150
  knife_cmd << " --vsdc '#{@vcenter['datacenter']}'"
113
- knife_cmd << " --dest-folder '#{@vcenter['destfolder']}'"
151
+ knife_cmd << " --dest-folder '#{@vcenter['destfolder']}"
152
+ knife_cmd << "/#{@component['tier']}" if @vcenter['appendtier']
153
+ knife_cmd << '\''
114
154
  knife_cmd << " --resource-pool '#{@vcenter['resourcepool']}'"
115
155
  knife_cmd << " --datastore '#{select_datastore}'"
116
156
 
@@ -143,7 +183,6 @@ module Elevage
143
183
 
144
184
  # What the node should be identified as in Chef
145
185
  nodename = String.new(@name)
146
- nodename << '.' << @environment.name if @vcenter['appendenv']
147
186
  nodename << @vcenter['domain'] if @vcenter['appenddomain']
148
187
  knife_cmd << " --node-name '#{nodename}'"
149
188
 
@@ -153,17 +192,18 @@ module Elevage
153
192
  # Assign the Chef environment
154
193
  knife_cmd << " --environment '#{@environment.name}'"
155
194
 
156
- # What version of chef-client are we bootstrapping (not sure this is necessary)
195
+ # What version of chef-client are we bootstrapping (not sure
196
+ # this is necessary)
157
197
  knife_cmd << " --bootstrap-version #{@options['bootstrap-version']}"
158
198
 
159
199
  # Finally, the name of the VM as seen by vSphere.
160
- # Whereas nodename will optionally append the domain name, VM names should *always* have the domain name
161
- # appended. The only optional bit is including the chef environment in the name.
200
+ # Whereas nodename will optionally append the domain name, VM names
201
+ # should *always* have the domain name appended.
162
202
  vmname = String.new(@name)
163
- vmname << '.' << @environment.name if @vcenter['appendenv']
164
203
  vmname << @vcenter['domain']
165
204
  knife_cmd << " #{vmname}"
166
205
  end
167
206
  # rubocop:enable MethodLength, LineLength
168
207
  end
208
+ # rubocop:enable ClassLength
169
209
  end
@@ -1,7 +1,9 @@
1
1
  require_relative 'constants'
2
2
 
3
3
  module Elevage
4
- # ProvisionerRunQueue class
4
+ # ProvisionerRunQueue
5
+ #
6
+ # Manage multiple queued and running `Elevage::Provisioner` objects/threads
5
7
  class ProvisionerRunQueue
6
8
  attr_reader :running_tasks
7
9
  attr_accessor :provisioners
@@ -9,7 +11,8 @@ module Elevage
9
11
  attr_accessor :busy_wait_timeout
10
12
  attr_accessor :build_status_interval
11
13
 
12
- # Public: Initialize the object
14
+ # Create a new run queue
15
+ # @return [Elevage::ProvisionerRunQueue]
13
16
  def initialize
14
17
  @running_tasks = 0 # We start out with nothing running
15
18
  @max_concurrent = BUILD_CONCURRENT_DEFAULT
@@ -19,8 +22,9 @@ module Elevage
19
22
  @children = {}
20
23
  end
21
24
 
22
- # Public: run() - Process the queue
23
25
  # rubocop:disable MethodLength
26
+
27
+ # Process the queue
24
28
  def run
25
29
  puts "#{Time.now} [#{$$}]: Provisioning started."
26
30
  @provisioners.each do |provisioner|
@@ -38,8 +42,10 @@ module Elevage
38
42
  end
39
43
  # rubocop:enable MethodLength
40
44
 
41
- # Public: Display a string representation
42
45
  # rubocop:disable MethodLength
46
+
47
+ # Display a string representation
48
+ # @return [String]
43
49
  def to_s
44
50
  puts "Running Tasks: #{@running_tasks}"
45
51
  puts "Max Concurrency: #{@max_concurrent}"
@@ -57,9 +63,13 @@ module Elevage
57
63
 
58
64
  private
59
65
 
60
- # rubocop:disable LineLength, GlobalVars
61
- # Private: provision_task is the method that should execute in the child
66
+ # rubocop:disable LineLength
67
+
68
+ # Private
69
+ #
70
+ # provision_task is the method that should execute in the child
62
71
  # process, and contain all the logic for the child process.
72
+ # @param [Elevage::Provisioner] task a Provisioner from the queue
63
73
  def provision_task(task: nil)
64
74
  start_time = Time.now
65
75
  print "#{Time.now} [#{$$}]: #{task.name} Provisioning...\n"
@@ -67,15 +77,20 @@ module Elevage
67
77
  run_time = Time.now - start_time
68
78
  print "#{Time.now} [#{$$}]: #{task.name} #{status} in #{run_time.round(2)} seconds.\n"
69
79
  end
70
- # rubocop:enable LineLength, GlobalVars
80
+ # rubocop:enable LineLength
81
+
82
+ # rubocop:disable MethodLength, LineLength, CyclomaticComplexity
71
83
 
72
- # rubocop:disable MethodLength, LineLength, CyclomaticComplexity, GlobalVars
73
- # Private: Wait for child tasks to return
84
+ # Private
85
+ #
86
+ # Wait for child tasks to return
74
87
  # Since our trap for SIGCHLD will clean up the @running_tasks count and
75
88
  # the children hash, here we can just keep checking until @running_tasks
76
89
  # is 0.
77
90
  # If we've been waiting at least a minute, print out a notice of what
78
91
  # we're still waiting for.
92
+ # @param [String] state Disposition; whether we are still `:running` or
93
+ # are trying to `:collect` still-running tasks
79
94
  def wait_for_tasks(state: :running)
80
95
  i = interval = @build_status_interval / @busy_wait_timeout
81
96
 
@@ -109,6 +124,6 @@ module Elevage
109
124
  sleep @busy_wait_timeout
110
125
  end
111
126
  end
112
- # rubocop:enable MethodLength, LineLength, CyclomaticComplexity, GlobalVars
127
+ # rubocop:enable MethodLength, LineLength, CyclomaticComplexity
113
128
  end
114
129
  end
@@ -13,7 +13,7 @@ vcenter:
13
13
  # resourcepool vcenter resource pool for the provisioned vms
14
14
  # appendenv if true the destfolder path will be appended with the environment name
15
15
  # appenddomain if true the domain will be pre-pended with environment name
16
- # datastores array list of available datastores. Elevage will attempt to evenly distribute
16
+ # datastore prefix of desired datastorecluster. knife vsphere datastorecluster maxfree will determine
17
17
  # domain domain for fqdn of host
18
18
  # dnsips ips of dns servers
19
19
  #
@@ -31,11 +31,8 @@ vcenter:
31
31
  # resourcepool: 'App-Web Linux/Corporate'
32
32
  # appendenv: true
33
33
  # appenddomain: true
34
- # datastores:
35
- # - NonProd_Cor_25
36
- # - NonProd_Cor_26
37
- # - NonProd_Cor_38
38
- # - NonProd_Cor_39
34
+ # appendtier: false
35
+ # datastore: 'NonProd_Cor_PlaSer'
39
36
  #
40
37
  # domain: dev.corp.local
41
38
  # dnsips:
@@ -46,9 +43,7 @@ vcenter:
46
43
  # <<: *vcenter
47
44
  #
48
45
  # datacenter: 'WCDC Prod'
49
- # datastores:
50
- # - Prod_Cor_03
51
- # - Prod_Cor_04
46
+ # datastore: 'Prod_Cor_PlaSer'
52
47
  #
53
48
  # domain: corp.local
54
49
  # dnsips:
@@ -66,12 +61,12 @@ vcenter:
66
61
  resourcepool:
67
62
  appendenv: false
68
63
  appenddomain: false
69
- datastores:
70
- -
64
+ appendtier: false
65
+ datastore:
71
66
 
72
67
  domain:
73
68
  dnsips:
74
69
  -
75
70
 
76
71
  prod:
77
- <<: *default
72
+ <<: *default
@@ -1,4 +1,4 @@
1
1
  # simple gem version number tracking
2
2
  module Elevage
3
- VERSION = '0.1.0'
3
+ VERSION = '0.1.2'
4
4
  end
data/lib/elevage.rb CHANGED
@@ -17,13 +17,17 @@ module Elevage
17
17
  map '-v' => :version
18
18
 
19
19
  desc 'version', DESC_VERSION
20
+ # Display the version
20
21
  def version
21
22
  puts VERSION
22
23
  end
23
24
 
24
25
  desc 'list ITEM', DESC_LIST
25
26
  method_option :nodes, aliases: '-n', desc: DESC_LIST_NODES
27
+
26
28
  # rubocop:disable LineLength
29
+
30
+ # Process the `list` command
27
31
  def list(item)
28
32
  # errors handled in class methods
29
33
  if LIST_CMDS.include?(item)
@@ -34,6 +38,7 @@ module Elevage
34
38
  puts options[:nodes] ? environment.list_nodes : environment
35
39
  end
36
40
  end
41
+
37
42
  # rubocop:enable LineLength
38
43
 
39
44
  # subcommand in Thor called as registered class