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.
Files changed (74) hide show
  1. checksums.yaml +7 -0
  2. data/.coveralls.yml +1 -0
  3. data/.gitignore +21 -0
  4. data/.rubocop.yml +8 -0
  5. data/.ruby-version +1 -0
  6. data/.simplecov +8 -0
  7. data/.travis.yml +3 -0
  8. data/.yardoc/checksums +12 -0
  9. data/.yardoc/object_types +0 -0
  10. data/.yardoc/objects/root.dat +0 -0
  11. data/.yardoc/proxy_types +0 -0
  12. data/Gemfile +4 -0
  13. data/Guardfile +10 -0
  14. data/LICENSE.txt +203 -0
  15. data/README.md +112 -0
  16. data/Rakefile +20 -0
  17. data/bin/elevage +4 -0
  18. data/coverage/.resultset.json.lock +0 -0
  19. data/doc/Elevage/Build.html +435 -0
  20. data/doc/Elevage/CLI.html +282 -0
  21. data/doc/Elevage/Environment.html +950 -0
  22. data/doc/Elevage/Generate.html +346 -0
  23. data/doc/Elevage/Health.html +359 -0
  24. data/doc/Elevage/New.html +411 -0
  25. data/doc/Elevage/Platform.html +1119 -0
  26. data/doc/Elevage/Provisioner.html +804 -0
  27. data/doc/Elevage/ProvisionerRunQueue.html +765 -0
  28. data/doc/Elevage/Runner.html +319 -0
  29. data/doc/Elevage.html +501 -0
  30. data/doc/_index.html +239 -0
  31. data/doc/class_list.html +58 -0
  32. data/doc/css/common.css +1 -0
  33. data/doc/css/full_list.css +57 -0
  34. data/doc/css/style.css +339 -0
  35. data/doc/file.README.html +187 -0
  36. data/doc/file_list.html +60 -0
  37. data/doc/frames.html +26 -0
  38. data/doc/index.html +187 -0
  39. data/doc/js/app.js +219 -0
  40. data/doc/js/full_list.js +181 -0
  41. data/doc/js/jquery.js +4 -0
  42. data/doc/method_list.html +369 -0
  43. data/doc/top-level-namespace.html +112 -0
  44. data/elevage.gemspec +39 -0
  45. data/features/archive +314 -0
  46. data/features/build.feature +237 -0
  47. data/features/elevage.feature +24 -0
  48. data/features/generate.feature +235 -0
  49. data/features/health_env_failure.feature +292 -0
  50. data/features/health_failure.feature +291 -0
  51. data/features/health_success.feature +279 -0
  52. data/features/list.feature +315 -0
  53. data/features/new.feature +68 -0
  54. data/features/step_definitions/elevage_steps.rb +27 -0
  55. data/features/support/env.rb +9 -0
  56. data/lib/elevage/build.rb +109 -0
  57. data/lib/elevage/constants.rb +113 -0
  58. data/lib/elevage/environment.rb +223 -0
  59. data/lib/elevage/generate.rb +48 -0
  60. data/lib/elevage/health.rb +27 -0
  61. data/lib/elevage/new.rb +30 -0
  62. data/lib/elevage/platform.rb +105 -0
  63. data/lib/elevage/provisioner.rb +169 -0
  64. data/lib/elevage/provisionerrunqueue.rb +114 -0
  65. data/lib/elevage/runner.rb +39 -0
  66. data/lib/elevage/templates/compute.yml.tt +18 -0
  67. data/lib/elevage/templates/environment.yml.tt +20 -0
  68. data/lib/elevage/templates/network.yml.tt +16 -0
  69. data/lib/elevage/templates/platform.yml.tt +110 -0
  70. data/lib/elevage/templates/vcenter.yml.tt +77 -0
  71. data/lib/elevage/version.rb +4 -0
  72. data/lib/elevage.rb +45 -0
  73. data/spec/spec_helper.rb +4 -0
  74. 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
@@ -0,0 +1,4 @@
1
+ # simple gem version number tracking
2
+ module Elevage
3
+ VERSION = '0.1.0'
4
+ end
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
@@ -0,0 +1,4 @@
1
+ # $LOAD_PATH << '../../lib'
2
+ #
3
+ # require 'coveralls'
4
+ # Coveralls.wear!