vcloud-launcher 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. data/.gitignore +16 -0
  2. data/Gemfile +9 -0
  3. data/LICENSE.txt +20 -0
  4. data/README.md +127 -0
  5. data/Rakefile +47 -0
  6. data/bin/vcloud-launch +47 -0
  7. data/examples/.fog-example.fog +15 -0
  8. data/examples/vcloud-launch/basic_preamble.erb +8 -0
  9. data/examples/vcloud-launch/complete_vapp_config.yaml +58 -0
  10. data/examples/vcloud-launch/minimal_vapp_config.yaml +11 -0
  11. data/examples/vcloud-launch/multiple_vapps_simple.yaml +45 -0
  12. data/examples/vcloud-launch/yaml_anchors_example.yaml +87 -0
  13. data/features/step_definitions/vcloud-launch_steps.rb +3 -0
  14. data/features/support/env.rb +16 -0
  15. data/features/vcloud-launch.feature +16 -0
  16. data/jenkins.sh +11 -0
  17. data/jenkins_integration_tests.sh +7 -0
  18. data/lib/vcloud/launcher.rb +22 -0
  19. data/lib/vcloud/launcher/launch.rb +46 -0
  20. data/lib/vcloud/launcher/vapp_orchestrator.rb +44 -0
  21. data/lib/vcloud/launcher/version.rb +5 -0
  22. data/lib/vcloud/launcher/vm_orchestrator.rb +85 -0
  23. data/scripts/basic.erb +13 -0
  24. data/scripts/generate_fog_conf_file.sh +6 -0
  25. data/spec/erb_helper.rb +11 -0
  26. data/spec/integration/launcher/data/basic_preamble_test.erb +8 -0
  27. data/spec/integration/launcher/data/happy_path.yaml.erb +32 -0
  28. data/spec/integration/launcher/data/minimum_data_setup.yaml.erb +6 -0
  29. data/spec/integration/launcher/data/storage_profile.yaml.erb +24 -0
  30. data/spec/integration/launcher/storage_profile_integration_spec.rb +90 -0
  31. data/spec/integration/launcher/vcloud_launcher_spec.rb +157 -0
  32. data/spec/spec_helper.rb +3 -0
  33. data/spec/support/stub_fog_interface.rb +59 -0
  34. data/spec/vcloud/launcher/launch_spec.rb +48 -0
  35. data/spec/vcloud/launcher/vapp_orchestrator_spec.rb +57 -0
  36. data/spec/vcloud/launcher/vm_orchestrator_spec.rb +80 -0
  37. data/vcloud-launcher.gemspec +30 -0
  38. metadata +214 -0
data/.gitignore ADDED
@@ -0,0 +1,16 @@
1
+ *.gem
2
+ *.rbc
3
+ *.swp
4
+ *.un~
5
+ vcloud_env.sh
6
+ replace_variables.sh
7
+ /.bundle/
8
+ /.ruby-version
9
+ /Gemfile.lock
10
+ /bundle/
11
+ /pkg/
12
+ vendor/
13
+ coverage/
14
+ results.html
15
+ fog_integration_test.config
16
+ .idea
data/Gemfile ADDED
@@ -0,0 +1,9 @@
1
+ source 'http://rubygems.org'
2
+
3
+ gemspec
4
+
5
+ if ENV['VCLOUD_CORE_DEV_MASTER']
6
+ gem 'vcloud-core', :git => 'git@github.com:alphagov/vcloud-core.git', :branch => 'master'
7
+ elsif ENV['VCLOUD_CORE_DEV_LOCAL']
8
+ gem 'vcloud-core', :path => '../vcloud-core'
9
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2014 HM Government (Government Digital Service)
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
6
+ this software and associated documentation files (the "Software"), to deal in
7
+ the Software without restriction, including without limitation the rights to
8
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9
+ the Software, and to permit persons to whom the Software is furnished to do so,
10
+ subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,127 @@
1
+ vCloud Launcher
2
+ ===============
3
+ A tool that takes a YAML or JSON configuration file describing a vDC, and provisions
4
+ the vApps and VMs contained within.
5
+
6
+ ### Supports
7
+
8
+ Configuration of multiple vApps/VMs with:
9
+ multiple NICs
10
+ custom CPU and memory size
11
+ multiple additional disks
12
+ custom VM metadata
13
+ Basic idempotent operation - vApps that already exist are skipped.
14
+
15
+ ### Limitations
16
+
17
+ Source vApp Template must contain a single VM. This is VMware's recommended 'simple' method of vApp creation. Complex multi-VM vApps are not supported.
18
+ Org vDC Networks must be precreated.
19
+ IP addresses are assigned manually (recommended) or via DHCP. VM IP pools are not supported.
20
+ vCloud has some interesting ideas about the size of potential 'guest customisation scripts' (aka preambles). You may need to use an external minify tool to reduce the size, or speak to your provider to up the limit. 2048 bytes seems to be a practical default maximum.
21
+
22
+ ## Installation
23
+
24
+ Add this line to your application's Gemfile:
25
+
26
+ gem 'vcloud-launcher'
27
+
28
+ And then execute:
29
+
30
+ $ bundle
31
+
32
+ Or install it yourself as:
33
+
34
+ $ gem install vcloud-launcher
35
+
36
+
37
+ ## Usage
38
+
39
+ vCloud Launcher uses [Fog](http://fog.io/).
40
+
41
+ To use it you need a .fog file in your home directory.
42
+
43
+ For example:
44
+
45
+ test:
46
+ vcloud_director_username: 'username@org_name'
47
+ vcloud_director_password: 'password'
48
+ vcloud_director_host: 'host.api.example.com'
49
+
50
+ Unfortunately current usage of fog requires the password in this file. Multiple sets of credentials can be specified in the fog file, using the following format:
51
+
52
+ test:
53
+ vcloud_director_username: 'username@org_name'
54
+ vcloud_director_password: 'password'
55
+ vcloud_director_host: 'host.api.example.com'
56
+
57
+ test2:
58
+ vcloud_director_username: 'username@org_name'
59
+ vcloud_director_password: 'password'
60
+ vcloud_director_host: 'host.api.vendor.net'
61
+
62
+ You can then pass the FOG_CREDENTIAL environment variable at the start of your command. The value of the FOG_CREDENTIAL environment variable is the name of the credential set in your fog file which you wish to use. For instance:
63
+
64
+ FOG_CREDENTIAL=test2 vcloud-launch node.yaml
65
+
66
+ An example configuration file is located in examples/vcloud-launch
67
+
68
+ ## Contributing
69
+
70
+ 1. Fork it
71
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
72
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
73
+ 4. Push to the branch (`git push origin my-new-feature`)
74
+ 5. Create new Pull Request
75
+
76
+ ## Other settings
77
+
78
+ vCloud Launcher uses vCloud Core. If you want to use the latest version of vCloud Core, or a local version, you can export some variables. See the Gemfile for details.
79
+
80
+ ## Testing
81
+
82
+ Default target: `bundle exec rake`
83
+ Runs the unit and feature tests (pretty quick right now)
84
+
85
+ * Unit tests only: `bundle exec rake spec`
86
+ * Integration tests ('quick' tests): `bundle exec rake integration:quick`
87
+ * Integration tests (all tests - takes 20mins+): `bundle exec rake integration:all`
88
+
89
+ You need access to a suitable vCloud Director organization to run the
90
+ integration tests. It is not necessarily safe to run them against an existing
91
+ environment, unless care is taken with the entities being tested.
92
+
93
+ The easiest thing to do is create a local shell script called
94
+ `vcloud_env.sh` and set the contents:
95
+
96
+ export FOG\_CREDENTIAL=test
97
+ export VCLOUD\_VDC\_NAME="Name of the VDC"
98
+ export VCLOUD\_CATALOG\_NAME="catalog-name"
99
+ export VCLOUD\_TEMPLATE\_NAME="name-of-template"
100
+ export VCLOUD\_NETWORK1\_NAME="name-of-primary-network"
101
+ export VCLOUD\_NETWORK2\_NAME="name-of-secondary-network"
102
+ export VCLOUD\_NETWORK1\_IP="ip-on-primary-network"
103
+ export VCLOUD\_NETWORK2\_IP="ip-on-secondary-network"
104
+ export VCLOUD\_TEST\_STORAGE\_PROFILE="storage-profile-name"
105
+ export VCLOUD\_EDGE\_GATEWAY="name-of-edge-gateway-in-vdc"
106
+
107
+ Then run this before you run the integration tests.
108
+
109
+ ### Specific integration tests
110
+
111
+ #### Storage profile tests
112
+
113
+ There is an integration test to check storage profile behaviour, but it requires a lot of set-up so it is not called by the rake task. If you wish to run it you need access to an environment that has two VDCs, each one containing a storage profile with the same name. This named storage profile needs to be different from teh default storage profile.
114
+
115
+ You will need to set the following environment variables:
116
+
117
+ export VDC\_NAME\_1="Name of the first vDC"
118
+ export VDC\_NAME\_2="Name of the second vDC"
119
+ export VCLOUD\_CATALOG\_NAME="Catalog name" # Can be the same as above settings if appropriate
120
+ export VCLOUD\_TEMPLATE\_NAME="Template name" # Can be the same as above setting if appropriate
121
+ export VCLOUD\_STORAGE\_PROFILE\_NAME="Storage profile name" # This needs to exist in both vDCs
122
+ export VDC\_1\_STORAGE\_PROFILE\_HREF="Href of the named storage profile in vDC 1"
123
+ export VDC\_2\_STORAGE\_PROFILE\_HREF="Href of the named storage profile in vDC 2"
124
+ export DEFAULT\_STORAGE\_PROFILE\_NAME="Default storage profile name"
125
+ export DEFAULT\_STORAGE\_PROFILE\_HREF="Href of default storage profile"
126
+
127
+ To run this test: `rspec spec/integration/launcher/storage_profile_integration_test.rb`
data/Rakefile ADDED
@@ -0,0 +1,47 @@
1
+ require 'rake/clean'
2
+ require 'rake/testtask'
3
+ require 'cucumber/rake/task'
4
+ require 'rspec/core/rake_task'
5
+
6
+ require 'vcloud/launcher/version'
7
+
8
+ include Rake::DSL
9
+
10
+ Bundler::GemHelper.install_tasks
11
+
12
+ Rake::TestTask.new do |t|
13
+ t.pattern = 'test/tc_*.rb'
14
+ end
15
+
16
+ CUKE_RESULTS = 'results.html'
17
+ CLEAN << CUKE_RESULTS
18
+
19
+ Cucumber::Rake::Task.new(:features) do |t|
20
+ t.cucumber_opts = "features --format html -o #{CUKE_RESULTS} --format pretty --no-source -x"
21
+ t.fork = false
22
+ end
23
+
24
+ RSpec::Core::RakeTask.new(:spec) do |task|
25
+ # Set a bogus Fog credential, otherwise it's possible for the unit
26
+ # tests to accidentially run (and succeed against!) an actual
27
+ # environment, if Fog connection is not stubbed correctly.
28
+ ENV['FOG_CREDENTIAL'] = 'random_nonsense_owiejfoweijf'
29
+ task.pattern = FileList['spec/vcloud/**/*_spec.rb']
30
+ end
31
+
32
+ RSpec::Core::RakeTask.new('integration:quick') do |t|
33
+ t.rspec_opts = %w(--tag ~take_too_long)
34
+ t.pattern = FileList['spec/integration/**/*_spec.rb']
35
+ end
36
+
37
+ RSpec::Core::RakeTask.new('integration:all') do |t|
38
+ t.pattern = FileList['spec/integration/**/*_spec.rb']
39
+ end
40
+
41
+ task :default => [:spec,:features]
42
+
43
+ require "gem_publisher"
44
+ task :publish_gem do |t|
45
+ gem = GemPublisher.publish_if_updated("vcloud-launcher.gemspec", :rubygems)
46
+ puts "Published #{gem}" if gem
47
+ end
data/bin/vcloud-launch ADDED
@@ -0,0 +1,47 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'bundler/setup'
5
+ require 'optparse'
6
+ require 'methadone'
7
+
8
+ require 'vcloud/launcher/launch'
9
+
10
+ class App
11
+ include Methadone::Main
12
+ include Methadone::CLILogging
13
+ include Vcloud
14
+
15
+ main do |org_config_file|
16
+ Launch.new.run(org_config_file, options)
17
+ end
18
+
19
+ on("-x", "--dont-power-on", "Do not power on vApps (default is to power on)")
20
+ on("-c", "--continue-on-error", "Continue on error ( default is false) ")
21
+
22
+ arg :org_config_file
23
+
24
+ examples_dir = File.absolute_path(
25
+ File.join(
26
+ File.dirname(__FILE__),
27
+ "..",
28
+ "examples",
29
+ File.basename(__FILE__),
30
+ ))
31
+
32
+ description "
33
+ vcloud-launch takes a configuration describing a vCloud Org,
34
+ and tries to make it a reality.
35
+
36
+ See https://github.com/alphagov/vcloud-tools for more info
37
+
38
+ Example configuration files can be found in:
39
+ #{examples_dir}
40
+ "
41
+
42
+ version Vcloud::Launcher::VERSION
43
+
44
+ #use_log_level_option
45
+
46
+ go!
47
+ end
@@ -0,0 +1,15 @@
1
+ p1-production:
2
+ vcloud_director_username: '<username_from_top_right_of_skyscape_flash_ui>@<org_id_from_url_in_skyscape_flash_ui>'
3
+ vcloud_director_password: '<your_skyscape_password>'
4
+ vcloud_director_host: 'vcd.portal.skyscapecloud.com'
5
+
6
+ # You can extract this information by logging into skyscape portal
7
+ performance-platform-production:
8
+ vcloud_director_username: '<xxx.x.xxxxxx>@<x-x-xx-xxxxxx>'
9
+ vcloud_director_password: '<your_skyscape_password>'
10
+ vcloud_director_host: 'vcd.portal.skyscapecloud.com'
11
+
12
+ carrenza-preview:
13
+ vcloud_director_username: '<email>@<org_id>'
14
+ vcloud_director_password: ''
15
+ vcloud_director_host: 'myvdc.carrenza.net'
@@ -0,0 +1,8 @@
1
+ #!/bin/bash
2
+
3
+ # Default preamble
4
+
5
+ (
6
+ echo "in $*"
7
+ echo "message: <%= vars[:message] -%>"
8
+ ) >> /PREAMBLE_OUTPUT
@@ -0,0 +1,58 @@
1
+ # 'Complete single vapp' vcloud-launch configuration example
2
+ #
3
+ # Each of the vm: subsections (hardware_config, network_connections, etc)
4
+ # are optional, if not specified the defaults as set in the vAppTemplate
5
+ # will be used.
6
+ #
7
+ # Specifically in this example, the instantiated VM will have:
8
+ #
9
+ # * its memory reconfigured to 4096MB
10
+ # * its cpu count reconfigured to be 2.
11
+ # * The Primary NIC will be moved to FrontendNetwork, and given a manual ip
12
+ # of 192.0.2.10
13
+ # * A Secondary NIC will be created on BackendNetwork and given an IP address
14
+ # via DHCP (the result of not supplying an ip_address parameter)
15
+ # * a bootstrap 'guest customization script' is provided, which will be
16
+ # interpolated via ERB.
17
+ # * Two additional extra_disks are supplied, sized at 10GB and 20GB respectively.
18
+ # These are in addition to the existing system disk in the templated VM.
19
+ # * 'vars' are supplied, which will be available to ERB when interpolating
20
+ # * This output will be run through 'script_post_processor' - generally only
21
+ # needed if the interpolated bootstrap script is 'large' (2048 bytes-ish)
22
+ # * metadata is supplied which will be applied to the VM and the parent vApp
23
+ # entities in vCloud Director. This is not available inside the VM itself :(
24
+ # * A storage_profile is provided. The VM will be moved to this named storage
25
+ # profile (which must be available in its vDC), if it is different to its
26
+ # current SP.
27
+ #
28
+ ---
29
+ vapps:
30
+ - name: 'vapp-example-complete'
31
+ vdc_name: 'Our vDC 1'
32
+ catalog: 'our-catalog'
33
+ catalog_item: 'our-template-vapp'
34
+ vm:
35
+ hardware_config:
36
+ memory: 4096
37
+ cpu: 2
38
+ network_connections:
39
+ - name: 'FrontendNetwork'
40
+ ip_address: '192.0.2.10'
41
+ - name: 'BackendNetwork'
42
+ extra_disks:
43
+ - name: logs-disk
44
+ size: 10240
45
+ - name: data-disk
46
+ size: 20480
47
+ bootstrap:
48
+ script_path: 'scripts/bootstrap_preamble.erb'
49
+ script_post_processor: 'scripts/minify_bash.py'
50
+ vars:
51
+ message: hello world
52
+ role: webserver
53
+ environment: example
54
+ metadata:
55
+ role: webserver
56
+ environment: example
57
+ storage_profile: 'our-updated-storage-profile'
58
+
@@ -0,0 +1,11 @@
1
+ # Minimum configuration required to instantiate a vApp via vcloud-launch
2
+ #
3
+ # This will instantiate 'our-vapp-template' into 'vapp-example-1', keeping
4
+ # the settings of any contained VM as-is.
5
+ #
6
+ ---
7
+ vapps:
8
+ - name: 'vapp-example-1'
9
+ vdc_name: 'vDC Example [1]'
10
+ catalog: 'example-catalog'
11
+ catalog_item: 'our-vapp-template'
@@ -0,0 +1,45 @@
1
+ # Multiple vApps can be defined. Running vcloud-launch will only instantiate
2
+ # vApps that do not already exist, so it is possible to add additional vApps
3
+ # to this configuration, and rerun the tool to add the new vApps.
4
+ #
5
+ # There is a lot of repetition however. YAML anchors can be used to
6
+ # reduce this - see yaml_anchors_example.yaml for more details.
7
+ #
8
+ ---
9
+ vapps:
10
+
11
+ - name: vapp-example-1
12
+ vdc_name: "Our VDC1"
13
+ catalog: our-catalog
14
+ catalog_item: our-vapp-template
15
+ vm:
16
+ hardware_config:
17
+ memory: '4096'
18
+ cpu: '2'
19
+ network_connections:
20
+ - name: Default
21
+ ip_address: 192.0.2.11
22
+
23
+ - name: vapp-example-2
24
+ vdc_name: "Our VDC1"
25
+ catalog: our-catalog
26
+ catalog_item: our-vapp-template
27
+ vm:
28
+ hardware_config:
29
+ memory: '4096'
30
+ cpu: '2'
31
+ network_connections:
32
+ - name: Default
33
+ ip_address: 192.0.2.12
34
+
35
+ - name: vapp-example-3
36
+ vdc_name: "Our VDC1"
37
+ catalog: our-catalog
38
+ catalog_item: our-vapp-template
39
+ vm:
40
+ hardware_config:
41
+ memory: '4096'
42
+ cpu: '2'
43
+ network_connections:
44
+ - name: Default
45
+ ip_address: 192.0.2.13
@@ -0,0 +1,87 @@
1
+ # A pretty complete example of using YAML Anchors to reduce
2
+ # repetition when creating multiple vApps.
3
+ #
4
+ # This example defines 4 vapps:
5
+ # * frontend-1
6
+ # * frontend-2
7
+ # * backend-1
8
+ # * backend-2
9
+ #
10
+ ---
11
+ anchors:
12
+
13
+ - &VAPP_TEMPLATE our-vapp-template
14
+
15
+ - &ENVIRONMENT example
16
+ - &VDC_NAME example-vdc
17
+
18
+ - &APP_NETWORK example-app-net
19
+ - &MGMT_NETWORK example-mgmt-net
20
+
21
+ - &BASE_VAPP
22
+ vdc_name: *VDC_NAME
23
+ catalog: our-catalog
24
+ catalog_item: *VAPP_TEMPLATE
25
+
26
+ - &BASE_VM
27
+ metadata:
28
+ environment: *ENVIRONMENT
29
+ vapp_template: *VAPP_TEMPLATE
30
+ bootstrap: &BASE_VM_BOOTSTRAP
31
+ script_path: basic_preamble.erb
32
+ vars: &BASE_VM_VARS
33
+ environment: *ENVIRONMENT
34
+ vapp_template: *VAPP_TEMPLATE
35
+ vdc: *VDC_NAME
36
+
37
+ - &SMALL_VM
38
+ <<: *BASE_VM
39
+ hardware_config: { memory: 4096, cpu: 2 }
40
+
41
+ - &MEDIUM_VM
42
+ <<: *BASE_VM
43
+ hardware_config: { memory: 8192, cpu: 4 }
44
+
45
+ vapps:
46
+
47
+ - &frontend_vapp
48
+ <<: *BASE_VAPP
49
+ name: frontend-example-1
50
+ vm: &frontend_vm
51
+ <<: *SMALL_VM
52
+ bootstrap:
53
+ <<: *BASE_VM_BOOTSTRAP
54
+ vars:
55
+ <<: *BASE_VM_VARS
56
+ role: frontend
57
+ network_connections:
58
+ - { name: *APP_NETWORK, ip_address: 192.0.2.11 }
59
+ - { name: *MGMT_NETWORK, ip_address: 198.51.100.11 }
60
+ - <<: *frontend_vapp
61
+ name: frontend-example-2
62
+ vm:
63
+ <<: *frontend_vm
64
+ network_connections:
65
+ - { name: *APP_NETWORK, ip_address: 192.0.2.12 }
66
+ - { name: *MGMT_NETWORK, ip_address: 198.51.100.12 }
67
+
68
+ - &backend_vapp
69
+ <<: *BASE_VAPP
70
+ name: backend-example-1
71
+ vm: &backend_vm
72
+ <<: *MEDIUM_VM
73
+ bootstrap:
74
+ <<: *BASE_VM_BOOTSTRAP
75
+ vars:
76
+ <<: *BASE_VM_VARS
77
+ role: backend
78
+ network_connections:
79
+ - { name: *APP_NETWORK, ip_address: 192.0.2.51 }
80
+ - { name: *MGMT_NETWORK, ip_address: 198.51.100.51 }
81
+ - <<: *backend_vapp
82
+ name: backend-example-2
83
+ vm:
84
+ <<: *backend_vm
85
+ network_connections:
86
+ - { name: *APP_NETWORK, ip_address: 192.0.2.52 }
87
+ - { name: *MGMT_NETWORK, ip_address: 198.51.100.52 }