elevage 0.1.0
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 +7 -0
- data/.coveralls.yml +1 -0
- data/.gitignore +21 -0
- data/.rubocop.yml +8 -0
- data/.ruby-version +1 -0
- data/.simplecov +8 -0
- data/.travis.yml +3 -0
- data/.yardoc/checksums +12 -0
- data/.yardoc/object_types +0 -0
- data/.yardoc/objects/root.dat +0 -0
- data/.yardoc/proxy_types +0 -0
- data/Gemfile +4 -0
- data/Guardfile +10 -0
- data/LICENSE.txt +203 -0
- data/README.md +112 -0
- data/Rakefile +20 -0
- data/bin/elevage +4 -0
- data/coverage/.resultset.json.lock +0 -0
- data/doc/Elevage/Build.html +435 -0
- data/doc/Elevage/CLI.html +282 -0
- data/doc/Elevage/Environment.html +950 -0
- data/doc/Elevage/Generate.html +346 -0
- data/doc/Elevage/Health.html +359 -0
- data/doc/Elevage/New.html +411 -0
- data/doc/Elevage/Platform.html +1119 -0
- data/doc/Elevage/Provisioner.html +804 -0
- data/doc/Elevage/ProvisionerRunQueue.html +765 -0
- data/doc/Elevage/Runner.html +319 -0
- data/doc/Elevage.html +501 -0
- data/doc/_index.html +239 -0
- data/doc/class_list.html +58 -0
- data/doc/css/common.css +1 -0
- data/doc/css/full_list.css +57 -0
- data/doc/css/style.css +339 -0
- data/doc/file.README.html +187 -0
- data/doc/file_list.html +60 -0
- data/doc/frames.html +26 -0
- data/doc/index.html +187 -0
- data/doc/js/app.js +219 -0
- data/doc/js/full_list.js +181 -0
- data/doc/js/jquery.js +4 -0
- data/doc/method_list.html +369 -0
- data/doc/top-level-namespace.html +112 -0
- data/elevage.gemspec +39 -0
- data/features/archive +314 -0
- data/features/build.feature +237 -0
- data/features/elevage.feature +24 -0
- data/features/generate.feature +235 -0
- data/features/health_env_failure.feature +292 -0
- data/features/health_failure.feature +291 -0
- data/features/health_success.feature +279 -0
- data/features/list.feature +315 -0
- data/features/new.feature +68 -0
- data/features/step_definitions/elevage_steps.rb +27 -0
- data/features/support/env.rb +9 -0
- data/lib/elevage/build.rb +109 -0
- data/lib/elevage/constants.rb +113 -0
- data/lib/elevage/environment.rb +223 -0
- data/lib/elevage/generate.rb +48 -0
- data/lib/elevage/health.rb +27 -0
- data/lib/elevage/new.rb +30 -0
- data/lib/elevage/platform.rb +105 -0
- data/lib/elevage/provisioner.rb +169 -0
- data/lib/elevage/provisionerrunqueue.rb +114 -0
- data/lib/elevage/runner.rb +39 -0
- data/lib/elevage/templates/compute.yml.tt +18 -0
- data/lib/elevage/templates/environment.yml.tt +20 -0
- data/lib/elevage/templates/network.yml.tt +16 -0
- data/lib/elevage/templates/platform.yml.tt +110 -0
- data/lib/elevage/templates/vcenter.yml.tt +77 -0
- data/lib/elevage/version.rb +4 -0
- data/lib/elevage.rb +45 -0
- data/spec/spec_helper.rb +4 -0
- metadata +357 -0
@@ -0,0 +1,114 @@
|
|
1
|
+
require_relative 'constants'
|
2
|
+
|
3
|
+
module Elevage
|
4
|
+
# ProvisionerRunQueue class
|
5
|
+
class ProvisionerRunQueue
|
6
|
+
attr_reader :running_tasks
|
7
|
+
attr_accessor :provisioners
|
8
|
+
attr_accessor :max_concurrent
|
9
|
+
attr_accessor :busy_wait_timeout
|
10
|
+
attr_accessor :build_status_interval
|
11
|
+
|
12
|
+
# Public: Initialize the object
|
13
|
+
def initialize
|
14
|
+
@running_tasks = 0 # We start out with nothing running
|
15
|
+
@max_concurrent = BUILD_CONCURRENT_DEFAULT
|
16
|
+
@busy_wait_timeout = BUILD_CHILD_WAIT_TIMEOUT
|
17
|
+
@build_status_interval = BUILD_STATUS_INTERVAL
|
18
|
+
@provisioners = []
|
19
|
+
@children = {}
|
20
|
+
end
|
21
|
+
|
22
|
+
# Public: run() - Process the queue
|
23
|
+
# rubocop:disable MethodLength
|
24
|
+
def run
|
25
|
+
puts "#{Time.now} [#{$$}]: Provisioning started."
|
26
|
+
@provisioners.each do |provisioner|
|
27
|
+
# Make sure we're not running more jobs than we're allowed
|
28
|
+
wait_for_tasks
|
29
|
+
child_pid = fork do
|
30
|
+
provision_task task: provisioner
|
31
|
+
end
|
32
|
+
@children[child_pid] = provisioner.name
|
33
|
+
@running_tasks += 1
|
34
|
+
end
|
35
|
+
# Hang around until we collect all the rest of the children
|
36
|
+
wait_for_tasks state: :collect
|
37
|
+
puts "#{Time.now} [#{$$}]: Provisioning completed."
|
38
|
+
end
|
39
|
+
# rubocop:enable MethodLength
|
40
|
+
|
41
|
+
# Public: Display a string representation
|
42
|
+
# rubocop:disable MethodLength
|
43
|
+
def to_s
|
44
|
+
puts "Running Tasks: #{@running_tasks}"
|
45
|
+
puts "Max Concurrency: #{@max_concurrent}"
|
46
|
+
puts "Wait status interval: #{@build_status_interval}"
|
47
|
+
puts 'Current Child processes:'
|
48
|
+
@children.each do |pid, name|
|
49
|
+
puts " - [#{pid}]: #{name}"
|
50
|
+
end
|
51
|
+
puts 'Queued Provisioners:'
|
52
|
+
@provisioners.each do |provisioner|
|
53
|
+
puts " - #{provisioner.name}"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
# rubocop:enable MethodLength
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
# rubocop:disable LineLength, GlobalVars
|
61
|
+
# Private: provision_task is the method that should execute in the child
|
62
|
+
# process, and contain all the logic for the child process.
|
63
|
+
def provision_task(task: nil)
|
64
|
+
start_time = Time.now
|
65
|
+
print "#{Time.now} [#{$$}]: #{task.name} Provisioning...\n"
|
66
|
+
status = task.build ? 'succeeded' : 'FAILED'
|
67
|
+
run_time = Time.now - start_time
|
68
|
+
print "#{Time.now} [#{$$}]: #{task.name} #{status} in #{run_time.round(2)} seconds.\n"
|
69
|
+
end
|
70
|
+
# rubocop:enable LineLength, GlobalVars
|
71
|
+
|
72
|
+
# rubocop:disable MethodLength, LineLength, CyclomaticComplexity, GlobalVars
|
73
|
+
# Private: Wait for child tasks to return
|
74
|
+
# Since our trap for SIGCHLD will clean up the @running_tasks count and
|
75
|
+
# the children hash, here we can just keep checking until @running_tasks
|
76
|
+
# is 0.
|
77
|
+
# If we've been waiting at least a minute, print out a notice of what
|
78
|
+
# we're still waiting for.
|
79
|
+
def wait_for_tasks(state: :running)
|
80
|
+
i = interval = @build_status_interval / @busy_wait_timeout
|
81
|
+
|
82
|
+
# We are either "running", and waiting for a child to return so we can
|
83
|
+
# dispatch a new child, or we are "collecting", in which case we have
|
84
|
+
# no more children waiting to be dispatched, and are waiting for them
|
85
|
+
# all to finish.
|
86
|
+
while @running_tasks >= @max_concurrent && state.eql?(:running) || @running_tasks > 0 && state.eql?(:collect)
|
87
|
+
|
88
|
+
# Always having to clean up after our children...
|
89
|
+
@children.keys.each do |pid|
|
90
|
+
childpid = Process.wait(pid, Process::WNOHANG | Process::WUNTRACED)
|
91
|
+
unless childpid.nil?
|
92
|
+
@children.delete(childpid)
|
93
|
+
@running_tasks -= 1
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
# Is it time for a status update yet?
|
98
|
+
if i <= 0
|
99
|
+
print "#{Time.now} [#{$$}]: Waiting for #{@children.size} jobs:\n"
|
100
|
+
@children.each do |pid, name|
|
101
|
+
print " - #{pid}: #{name}\n"
|
102
|
+
end
|
103
|
+
# reset the status counter
|
104
|
+
i = interval
|
105
|
+
end
|
106
|
+
|
107
|
+
# tick the status counter
|
108
|
+
i -= 1
|
109
|
+
sleep @busy_wait_timeout
|
110
|
+
end
|
111
|
+
end
|
112
|
+
# rubocop:enable MethodLength, LineLength, CyclomaticComplexity, GlobalVars
|
113
|
+
end
|
114
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'elevage'
|
2
|
+
# rubocop:disable all
|
3
|
+
module Elevage
|
4
|
+
# wrapper to assist aruba in single process execution
|
5
|
+
class Runner
|
6
|
+
# Allow everything fun to be injected from the outside while defaulting to normal implementations.
|
7
|
+
def initialize(argv, stdin = STDIN, stdout = STDOUT, stderr = STDERR, kernel = Kernel)
|
8
|
+
@argv, @stdin, @stdout, @stderr, @kernel = argv, stdin, stdout, stderr, kernel
|
9
|
+
end
|
10
|
+
|
11
|
+
def execute!
|
12
|
+
exit_code = begin
|
13
|
+
# Thor accesses these streams directly rather than letting them be injected, so we replace them...
|
14
|
+
$stderr = @stderr
|
15
|
+
$stdin = @stdin
|
16
|
+
$stdout = @stdout
|
17
|
+
|
18
|
+
Elevage::CLI.start(@argv)
|
19
|
+
|
20
|
+
# Thor::Base#start does not have a return value, assume success if no exception is raised.
|
21
|
+
0
|
22
|
+
rescue StandardError => e
|
23
|
+
# The ruby interpreter would pipe this to STDERR and exit 1 in the case of an unhandled exception
|
24
|
+
b = e.backtrace
|
25
|
+
b.unshift("#{b.shift}: #{e.message} (#{e.class})")
|
26
|
+
@stderr.puts(b.map { |s| "\tfrom #{s}" }.join("\n"))
|
27
|
+
1
|
28
|
+
ensure
|
29
|
+
# put them back.
|
30
|
+
$stderr = STDERR
|
31
|
+
$stdin = STDIN
|
32
|
+
$stdout = STDOUT
|
33
|
+
end
|
34
|
+
# Proxy exit code back to the injected kernel.
|
35
|
+
@kernel.exit(exit_code)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
# rubocop:enable all
|
@@ -0,0 +1,18 @@
|
|
1
|
+
? "%YAML 1.2"
|
2
|
+
compute:
|
3
|
+
# The compute name is used to specify the compute resources used in the provsion of the component node.
|
4
|
+
# Currently available options are cpu and ram. Ram is an integer value representing Gb.
|
5
|
+
#
|
6
|
+
# Example:
|
7
|
+
#
|
8
|
+
# dev:
|
9
|
+
# cpu: 2
|
10
|
+
# ram: 1
|
11
|
+
#
|
12
|
+
# prod:
|
13
|
+
# cpu: 2
|
14
|
+
# ram: 12
|
15
|
+
#
|
16
|
+
default: &default
|
17
|
+
cpu:
|
18
|
+
ram:
|
@@ -0,0 +1,20 @@
|
|
1
|
+
? "%YAML 1.2"
|
2
|
+
environment:
|
3
|
+
vcenter:
|
4
|
+
# Environment files are generated from the platform.yml defintion.
|
5
|
+
#
|
6
|
+
# You can override any of the default values based on the requirements
|
7
|
+
# of this particular environment. Though typically you will only
|
8
|
+
# want to override things like:
|
9
|
+
#
|
10
|
+
# count The number of components in the load balance pool
|
11
|
+
# compute Size of compute resource to assign, defined in the compute.yml file
|
12
|
+
# network vlan the component nodes are attached
|
13
|
+
#
|
14
|
+
# Additionally, you must specify IP addresses for each node. The generate
|
15
|
+
# command will create array placeholders based on the default Count
|
16
|
+
#
|
17
|
+
pools:
|
18
|
+
<%= @env_pools %>
|
19
|
+
components:
|
20
|
+
<%= @env_components %>
|
@@ -0,0 +1,16 @@
|
|
1
|
+
? "%YAML 1.2"
|
2
|
+
network:
|
3
|
+
# Any number of networks may be specified. Networks are assigned to components as part
|
4
|
+
# of the component definition. The vcenter vlan id is used to specify the network.
|
5
|
+
#
|
6
|
+
# Example:
|
7
|
+
#
|
8
|
+
# devweb:
|
9
|
+
# vlanid: DEV_WEB_NET
|
10
|
+
# gateway: 10.10.128.1
|
11
|
+
# netmask: 19
|
12
|
+
#
|
13
|
+
networkname:
|
14
|
+
vlanid:
|
15
|
+
gateway:
|
16
|
+
netmask:
|
@@ -0,0 +1,110 @@
|
|
1
|
+
? "%YAML 1.2"
|
2
|
+
platform:
|
3
|
+
name: <%= platform.downcase %>
|
4
|
+
description: platform desired state definition files
|
5
|
+
# Environments are listed as individual yml array elements such as
|
6
|
+
#
|
7
|
+
# Example
|
8
|
+
#
|
9
|
+
# environments:
|
10
|
+
# - INT
|
11
|
+
# - QA
|
12
|
+
# - STAGE
|
13
|
+
# - PROD
|
14
|
+
#
|
15
|
+
environments:
|
16
|
+
-
|
17
|
+
# Components are grouped into tiers. You may define a single tier or multiple.
|
18
|
+
# Tier names may be appended to vcenter resource folders. A typical platform may
|
19
|
+
# be tiered as follows:
|
20
|
+
#
|
21
|
+
# Example
|
22
|
+
#
|
23
|
+
# tiers:
|
24
|
+
# - web
|
25
|
+
# - app
|
26
|
+
# - db
|
27
|
+
#
|
28
|
+
tiers:
|
29
|
+
-
|
30
|
+
# Individual node name are constructed at provision time based on the pattern
|
31
|
+
# you define here. Available options from the platform or environment yml keys are
|
32
|
+
# environment
|
33
|
+
# component
|
34
|
+
# instance single leading zero 0..9, up to count of component pool
|
35
|
+
# geo first letter of geo key value
|
36
|
+
# 'string' any single quoted string, escape char not evaluated
|
37
|
+
#
|
38
|
+
# Example
|
39
|
+
#
|
40
|
+
# nodenameconvention:
|
41
|
+
# - environment
|
42
|
+
# - '-'
|
43
|
+
# - component
|
44
|
+
# - instance
|
45
|
+
#
|
46
|
+
# => "dev-api01"
|
47
|
+
#
|
48
|
+
nodenameconvention:
|
49
|
+
- 'node'
|
50
|
+
- instance
|
51
|
+
# Components are defined as part of a pool. The pool is where you assign a component
|
52
|
+
# the following required items:
|
53
|
+
#
|
54
|
+
# count The number of components in the load balance pool
|
55
|
+
# tier Which platform tier the component is built on
|
56
|
+
# image The vmware image to clone for the nodes in this pool
|
57
|
+
# compute Size of compute resource to assign, defined in the compute.yml file
|
58
|
+
# port service comm port
|
59
|
+
# runlist Chef runlist(s) for the node
|
60
|
+
# componentrole optional custom role created by substituting the component name for # in the supplied string
|
61
|
+
#
|
62
|
+
# you may define any number of pools which may inherit based on yml default indicators.
|
63
|
+
# Each component may share a pool definition or have a unique one.
|
64
|
+
#
|
65
|
+
# Example
|
66
|
+
#
|
67
|
+
# pools:
|
68
|
+
# vmdefaults: &vmdefaults
|
69
|
+
# count: 4
|
70
|
+
# tier: Web
|
71
|
+
# image: 'centos-6.5-x86_64-20140714'
|
72
|
+
# compute: dev
|
73
|
+
# port: 80
|
74
|
+
# runlist:
|
75
|
+
# - 'role[base]'
|
76
|
+
# componentrole: 'role[myapp-#]'
|
77
|
+
#
|
78
|
+
pools:
|
79
|
+
vmdefaults: &vmdefaults
|
80
|
+
count:
|
81
|
+
tier:
|
82
|
+
image:
|
83
|
+
compute:
|
84
|
+
port:
|
85
|
+
runlist:
|
86
|
+
-
|
87
|
+
componentrole: false
|
88
|
+
# Components inherit all the key values from the assigned pool, which may be overridden
|
89
|
+
# in addition you can define a service port number for individual service pools
|
90
|
+
#
|
91
|
+
# Example
|
92
|
+
#
|
93
|
+
# components:
|
94
|
+
# api:
|
95
|
+
# <<: *vmdefaults
|
96
|
+
# port: 8080
|
97
|
+
#
|
98
|
+
# cui:
|
99
|
+
# <<: *vmdefaults
|
100
|
+
# port: 8082
|
101
|
+
#
|
102
|
+
# terracotta:
|
103
|
+
# <<: *vmdefaults
|
104
|
+
# compute: prodtc
|
105
|
+
# image: 'centos32g-6.5-x86_64-20140714'
|
106
|
+
#
|
107
|
+
components:
|
108
|
+
|
109
|
+
component:
|
110
|
+
<<: *vmdefaults
|
@@ -0,0 +1,77 @@
|
|
1
|
+
? "%YAML 1.2"
|
2
|
+
vcenter:
|
3
|
+
# you can add as many vcenter definitions as required. The default file configuratioon
|
4
|
+
# includes two in the form of a production and non production datacenter.
|
5
|
+
# Key elements are as follows:
|
6
|
+
#
|
7
|
+
# geo geographic location of a physical data center. Primarily for use in DR defintions
|
8
|
+
# timezone node timezone setting
|
9
|
+
# host hostname of vcenter management server
|
10
|
+
# datacenter vcenter 'datacenter' folder
|
11
|
+
# imagefolder vcenter resource folder where the clone image is located
|
12
|
+
# destfolder vcenter resource folder destination for provisioned vms
|
13
|
+
# resourcepool vcenter resource pool for the provisioned vms
|
14
|
+
# appendenv if true the destfolder path will be appended with the environment name
|
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
|
17
|
+
# domain domain for fqdn of host
|
18
|
+
# dnsips ips of dns servers
|
19
|
+
#
|
20
|
+
# Example
|
21
|
+
#
|
22
|
+
# locations:
|
23
|
+
# nonprod: &vcenter
|
24
|
+
# geo: west
|
25
|
+
# timezone: 085
|
26
|
+
#
|
27
|
+
# host: 'vcwest.corp.local'
|
28
|
+
# datacenter: 'WCDC NonProd'
|
29
|
+
# imagefolder: 'Corporate/Platform Services/Templates'
|
30
|
+
# destfolder: 'Corporate/Platform Services/app'
|
31
|
+
# resourcepool: 'App-Web Linux/Corporate'
|
32
|
+
# appendenv: true
|
33
|
+
# appenddomain: true
|
34
|
+
# datastores:
|
35
|
+
# - NonProd_Cor_25
|
36
|
+
# - NonProd_Cor_26
|
37
|
+
# - NonProd_Cor_38
|
38
|
+
# - NonProd_Cor_39
|
39
|
+
#
|
40
|
+
# domain: dev.corp.local
|
41
|
+
# dnsips:
|
42
|
+
# - 10.10.10.5
|
43
|
+
# - 10.10.10.6
|
44
|
+
#
|
45
|
+
# prod:
|
46
|
+
# <<: *vcenter
|
47
|
+
#
|
48
|
+
# datacenter: 'WCDC Prod'
|
49
|
+
# datastores:
|
50
|
+
# - Prod_Cor_03
|
51
|
+
# - Prod_Cor_04
|
52
|
+
#
|
53
|
+
# domain: corp.local
|
54
|
+
# dnsips:
|
55
|
+
# - 10.20.100.5
|
56
|
+
# - 10.20.100.6
|
57
|
+
#
|
58
|
+
nonprod: &default
|
59
|
+
geo:
|
60
|
+
timezone:
|
61
|
+
|
62
|
+
host:
|
63
|
+
datacenter:
|
64
|
+
imagefolder:
|
65
|
+
destfolder:
|
66
|
+
resourcepool:
|
67
|
+
appendenv: false
|
68
|
+
appenddomain: false
|
69
|
+
datastores:
|
70
|
+
-
|
71
|
+
|
72
|
+
domain:
|
73
|
+
dnsips:
|
74
|
+
-
|
75
|
+
|
76
|
+
prod:
|
77
|
+
<<: *default
|
data/lib/elevage.rb
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'thor'
|
2
|
+
require 'elevage/version'
|
3
|
+
require 'elevage/constants'
|
4
|
+
require 'elevage/new'
|
5
|
+
require 'elevage/platform'
|
6
|
+
require 'elevage/environment'
|
7
|
+
require 'elevage/health'
|
8
|
+
require 'elevage/generate'
|
9
|
+
require 'elevage/build'
|
10
|
+
|
11
|
+
# Refer to README.md for use instructions
|
12
|
+
module Elevage
|
13
|
+
# Start of main CLI
|
14
|
+
class CLI < Thor
|
15
|
+
package_name 'elevage'
|
16
|
+
map '--version' => :version
|
17
|
+
map '-v' => :version
|
18
|
+
|
19
|
+
desc 'version', DESC_VERSION
|
20
|
+
def version
|
21
|
+
puts VERSION
|
22
|
+
end
|
23
|
+
|
24
|
+
desc 'list ITEM', DESC_LIST
|
25
|
+
method_option :nodes, aliases: '-n', desc: DESC_LIST_NODES
|
26
|
+
# rubocop:disable LineLength
|
27
|
+
def list(item)
|
28
|
+
# errors handled in class methods
|
29
|
+
if LIST_CMDS.include?(item)
|
30
|
+
puts Elevage::Platform.new.send(item).to_yaml
|
31
|
+
else
|
32
|
+
fail(IOError, ERR[:not_list_cmd]) unless File.file?(ENV_FOLDER + item + '.yml')
|
33
|
+
environment = Elevage::Environment.new(item)
|
34
|
+
puts options[:nodes] ? environment.list_nodes : environment
|
35
|
+
end
|
36
|
+
end
|
37
|
+
# rubocop:enable LineLength
|
38
|
+
|
39
|
+
# subcommand in Thor called as registered class
|
40
|
+
register(Elevage::New, 'new', 'new PLATFORM', DESC_NEW)
|
41
|
+
register(Elevage::Health, 'health', 'health', DESC_HEALTH)
|
42
|
+
register(Elevage::Generate, 'generate', 'generate ENV', DESC_GENERATE)
|
43
|
+
register(Elevage::Build, 'build', 'build TARGET', DESC_BUILD)
|
44
|
+
end
|
45
|
+
end
|
data/spec/spec_helper.rb
ADDED