elevage 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +3 -1
- data/README.md +33 -11
- data/elevage.gemspec +15 -15
- data/features/archive +3 -22
- data/features/build.feature +2 -1
- data/features/generate.feature +3 -9
- data/features/health_env_failure.feature +2 -8
- data/features/health_failure.feature +1 -2
- data/features/health_success.feature +3 -9
- data/features/list.feature +3 -9
- data/features/step_definitions/elevage_steps.rb +2 -2
- data/lib/elevage/build.rb +4 -1
- data/lib/elevage/constants.rb +2 -2
- data/lib/elevage/environment.rb +66 -39
- data/lib/elevage/generate.rb +4 -3
- data/lib/elevage/health.rb +4 -0
- data/lib/elevage/new.rb +4 -2
- data/lib/elevage/platform.rb +11 -3
- data/lib/elevage/provisioner.rb +61 -21
- data/lib/elevage/provisionerrunqueue.rb +25 -10
- data/lib/elevage/templates/vcenter.yml.tt +7 -12
- data/lib/elevage/version.rb +1 -1
- data/lib/elevage.rb +5 -0
- metadata +58 -88
- data/.ruby-version +0 -1
- data/.yardoc/checksums +0 -12
- data/.yardoc/object_types +0 -0
- data/.yardoc/objects/root.dat +0 -0
- data/.yardoc/proxy_types +0 -0
- data/doc/Elevage/Build.html +0 -435
- data/doc/Elevage/CLI.html +0 -282
- data/doc/Elevage/Environment.html +0 -950
- data/doc/Elevage/Generate.html +0 -346
- data/doc/Elevage/Health.html +0 -359
- data/doc/Elevage/New.html +0 -411
- data/doc/Elevage/Platform.html +0 -1119
- data/doc/Elevage/Provisioner.html +0 -804
- data/doc/Elevage/ProvisionerRunQueue.html +0 -765
- data/doc/Elevage/Runner.html +0 -319
- data/doc/Elevage.html +0 -501
- data/doc/_index.html +0 -239
- data/doc/class_list.html +0 -58
- data/doc/css/common.css +0 -1
- data/doc/css/full_list.css +0 -57
- data/doc/css/style.css +0 -339
- data/doc/file.README.html +0 -187
- data/doc/file_list.html +0 -60
- data/doc/frames.html +0 -26
- data/doc/index.html +0 -187
- data/doc/js/app.js +0 -219
- data/doc/js/full_list.js +0 -181
- data/doc/js/jquery.js +0 -4
- data/doc/method_list.html +0 -369
- data/doc/top-level-namespace.html +0 -112
data/lib/elevage/platform.rb
CHANGED
@@ -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]
|
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
|
-
#
|
89
|
-
#
|
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)
|
data/lib/elevage/provisioner.rb
CHANGED
@@ -5,7 +5,10 @@ require_relative 'platform'
|
|
5
5
|
require_relative 'provisionerrunqueue'
|
6
6
|
|
7
7
|
module Elevage
|
8
|
-
#
|
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
|
-
#
|
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
|
-
#
|
36
|
-
|
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
|
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
|
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,
|
102
|
+
# rubocop:enable MethodLength, CyclomaticComplexity
|
84
103
|
|
85
104
|
private
|
86
105
|
|
87
|
-
#
|
88
|
-
|
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
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
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
|
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
|
161
|
-
#
|
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
|
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
|
-
#
|
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
|
61
|
-
|
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
|
80
|
+
# rubocop:enable LineLength
|
81
|
+
|
82
|
+
# rubocop:disable MethodLength, LineLength, CyclomaticComplexity
|
71
83
|
|
72
|
-
#
|
73
|
-
#
|
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
|
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
|
-
#
|
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
|
-
#
|
35
|
-
#
|
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
|
-
#
|
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
|
-
|
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
|
data/lib/elevage/version.rb
CHANGED
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
|