elevage 0.1.0

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