elevage 0.1.0 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|