vcloud-core 0.0.1

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 (40) hide show
  1. data/.gitignore +2 -0
  2. data/Gemfile +9 -0
  3. data/LICENSE.txt +20 -0
  4. data/README.md +103 -0
  5. data/Rakefile +18 -0
  6. data/bin/vcloud-query +84 -0
  7. data/jenkins.sh +10 -0
  8. data/lib/vcloud/core.rb +23 -0
  9. data/lib/vcloud/core/compute_metadata.rb +13 -0
  10. data/lib/vcloud/core/edge_gateway.rb +46 -0
  11. data/lib/vcloud/core/entity.rb +23 -0
  12. data/lib/vcloud/core/metadata_helper.rb +29 -0
  13. data/lib/vcloud/core/org_vdc_network.rb +102 -0
  14. data/lib/vcloud/core/query.rb +142 -0
  15. data/lib/vcloud/core/vapp.rb +118 -0
  16. data/lib/vcloud/core/vapp_template.rb +39 -0
  17. data/lib/vcloud/core/vdc.rb +37 -0
  18. data/lib/vcloud/core/version.rb +5 -0
  19. data/lib/vcloud/core/vm.rb +162 -0
  20. data/lib/vcloud/fog.rb +5 -0
  21. data/lib/vcloud/fog/content_types.rb +20 -0
  22. data/lib/vcloud/fog/model_interface.rb +33 -0
  23. data/lib/vcloud/fog/relation.rb +8 -0
  24. data/lib/vcloud/fog/service_interface.rb +257 -0
  25. data/spec/spec_helper.rb +26 -0
  26. data/spec/support/stub_fog_interface.rb +59 -0
  27. data/spec/vcloud/core/edge_gateway_spec.rb +79 -0
  28. data/spec/vcloud/core/metadata_helper_spec.rb +89 -0
  29. data/spec/vcloud/core/org_vdc_network_spec.rb +257 -0
  30. data/spec/vcloud/core/query_spec.rb +111 -0
  31. data/spec/vcloud/core/vapp_spec.rb +173 -0
  32. data/spec/vcloud/core/vapp_template_spec.rb +77 -0
  33. data/spec/vcloud/core/vdc_spec.rb +68 -0
  34. data/spec/vcloud/core/vm_spec.rb +290 -0
  35. data/spec/vcloud/data/basic_preamble_test.erb +8 -0
  36. data/spec/vcloud/data/basic_preamble_test.erb.OUT +8 -0
  37. data/spec/vcloud/fog/fog_model_interface_spec.rb +25 -0
  38. data/spec/vcloud/fog/service_interface_spec.rb +30 -0
  39. data/vcloud-core.gemspec +30 -0
  40. metadata +198 -0
data/.gitignore ADDED
@@ -0,0 +1,2 @@
1
+ /Gemfile.lock
2
+ /coverage/
data/Gemfile ADDED
@@ -0,0 +1,9 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
4
+
5
+ if ENV['VCLOUD_TOOLS_DEV_FOG_MASTER']
6
+ gem 'fog', :git => 'git@github.com:fog/fog.git', :branch => 'master'
7
+ elsif ENV['VCLOUD_TOOLS_DEV_FOG_LOCAL']
8
+ gem 'fog', :path => '../fog'
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,103 @@
1
+ # VCloud Core
2
+
3
+ VCloud Core is a gem that supports automatated provisioning of VMWare vCloud Director. It uses Fog under the hood. Primarily developed to support [VCloud Walker](https://github.com/alphagov/vcloud-walker) and [VCloud Tools](https://github.com/alphagov/vcloud-tools).
4
+
5
+ VCloud Core includes VCloud Query and a command-line wrapper for VCloud Query.
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ gem 'vcloud-core'
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install vcloud-core
20
+
21
+ ## Usage
22
+
23
+ TODO
24
+
25
+ ## Contributing
26
+
27
+ 1. Fork it
28
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
29
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
30
+ 4. Push to the branch (`git push origin my-new-feature`)
31
+ 5. Create new Pull Request
32
+
33
+ ## VCloud Query
34
+
35
+ ### Get results from the vCloud Query API
36
+
37
+ VCloud Query is a light wrapper around the vCloud Query API.
38
+
39
+ Any, or all, records of a particular 'type' can be returned. These types map to
40
+ entities in the vCloud system itself, eg: 'vm', 'vApp', 'orgVdc', 'edgeGateway'.
41
+
42
+ Filters can be applied, using a simple query syntax. See below for basic usage and
43
+ examples.
44
+
45
+ Run with no arguments, it outputs a list of potential entity types to query, along
46
+ with the potential record types to display (default 'records')
47
+
48
+ #### Usage:
49
+
50
+ vcloud-query [options] [queriable type]
51
+
52
+ where [queriable type] maps to a vcloud entity type, eg: vApp, vm, orgVdc
53
+
54
+ #### Examples:
55
+
56
+ NB: examples assume FOG_CREDENTIAL has been set accordingly.
57
+
58
+ # Get a list of vApps, in YAML
59
+ vcloud-query -o yaml vApp
60
+
61
+ # Get general usage info
62
+ vcloud-query --help
63
+
64
+ # Get a list of all queriable types (left column)
65
+ vcloud-query
66
+
67
+ # Get all VMs with VMware Tools less than 9282, that are not a vApp Template:
68
+ vcloud-query --filter 'vmToolsVersion=lt=9282;isVAppTemplate==false' vm
69
+
70
+ #### Supports:
71
+
72
+ * Returning a list of queriable types (eg vm, vApp, edgeGateway) from the API
73
+ * Displaying all vCloud entities of a given type
74
+ * Filtering the results of the query based on common parameters such as:
75
+ * entity name
76
+ * metadata values
77
+ * key entity parameters
78
+ * Limiting the output to certain fields (eg: name, vmToolsVersion)
79
+ * Returning results in TSV, CSV, and YAML
80
+
81
+ #### Query Syntax:
82
+
83
+ Summary of filter query syntax:
84
+
85
+ attribute==value # == to check equality
86
+ attribute!=value # != to check inequality
87
+ attribute=lt=value # =lt= less than (=le= for <=)
88
+ attribute=gt=value # =gt= greater than (=ge= for >=)
89
+ attribute==value;attribute2==value2 # ; == AND
90
+ attribute==value,attribute2==value2 # , == OR
91
+
92
+ Parentheses can be used to group sub-queries.
93
+
94
+ **Do not use spaces in the query**
95
+
96
+ Entity metadata queries have their own subsyntax incorporating the value types:
97
+
98
+ metadata:key1==STRING:value1
99
+ metadata:key1=le=NUMBER:15
100
+ metadata:key1=gt=DATETIME:2012-06-18T12:00:00-05:00
101
+
102
+ See http://pubs.vmware.com/vcd-51/topic/com.vmware.vcloud.api.doc_51/GUID-4FD71B6D-6797-4B8E-B9F0-618F4ACBEFAC.html for details.
103
+
data/Rakefile ADDED
@@ -0,0 +1,18 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new(:spec) do |task|
5
+ # Set a bogus Fog credential, otherwise it's possible for the unit
6
+ # tests to accidentially run (and succeed against!) an actual
7
+ # environment, if Fog connection is not stubbed correctly.
8
+ ENV['FOG_CREDENTIAL'] = 'random_nonsense_owiejfoweijf'
9
+ task.pattern = FileList['spec/vcloud/**/*_spec.rb']
10
+ end
11
+
12
+ task :default => [:spec]
13
+
14
+ require "gem_publisher"
15
+ task :publish_gem do |t|
16
+ gem = GemPublisher.publish_if_updated("vcloud-core.gemspec", :rubygems)
17
+ puts "Published #{gem}" if gem
18
+ end
data/bin/vcloud-query ADDED
@@ -0,0 +1,84 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'bundler/setup'
5
+ require 'optparse'
6
+ require 'methadone'
7
+
8
+ require 'vcloud/core'
9
+
10
+ class App
11
+
12
+ include Methadone::Main
13
+ include Methadone::CLILogging
14
+ include Vcloud
15
+
16
+ main do |type|
17
+ Query.new(type, options).run
18
+ end
19
+
20
+ on('-A', '--sort-asc', '=ATTRIBUTE', 'Sort ascending') do |v|
21
+ options[:sortAsc] = v
22
+ end
23
+
24
+ on('-D', '--sort-desc', '=ATTRIBUTE', 'Sort descending') do |v|
25
+ options[:sortDesc] = v
26
+ end
27
+
28
+ on('--fields', '=NAMES', 'Attribute or metadata key names') do |v|
29
+ options[:fields] = v
30
+ end
31
+
32
+ on('--format', '=ATTRIBUTE', 'Data format to retrieve: records, idrecords, references') do |v|
33
+ options[:format] = v
34
+ end
35
+
36
+ on('--filter', '=FILTER', 'Filter expression') do |v|
37
+ options[:filter] = v
38
+ end
39
+
40
+ on('-o', '--output-format', '=FORMAT', 'Output format: csv, tsv, yaml') do |v|
41
+ options[:output_format] = v.downcase
42
+ end
43
+
44
+ on("--mock", "Fog Mock mode")
45
+ on("--verbose", "Verbose output")
46
+ on("--debug", "Debugging output")
47
+
48
+ arg :type, :optional
49
+
50
+ description '
51
+ vcloud-query takes a query type and returns all vCloud entities of
52
+ that type, obeying supplied filter rules.
53
+
54
+ Query types map to vCloud entities, for example: vApp, vm, orgVdc, orgVdcNetwork.
55
+
56
+ Without a type argument, returns a list of available Entity Types to query.
57
+
58
+ See https://github.com/alphagov/vcloud-tools/blob/master/README.md for more info.
59
+
60
+ Example use:
61
+
62
+ # get a list of all vApps, returning all available parameters, in YAML
63
+
64
+ vcloud-query -o yaml vApp
65
+
66
+ # get a list of all powered off VMs return the name and containerName (vapp
67
+ # name)
68
+
69
+ vcloud-query --filter "status==POWERED_OFF" --fields name,containerName vm
70
+
71
+ # list all query types (types are left-most column, possible formats listed
72
+ # on the left (records is default, and most useful)
73
+
74
+ vcloud-query
75
+
76
+ '
77
+
78
+
79
+ version Vcloud::Core::VERSION
80
+
81
+ #use_log_level_option
82
+
83
+ go!
84
+ end
data/jenkins.sh ADDED
@@ -0,0 +1,10 @@
1
+ #!/bin/bash -x
2
+ set -e
3
+
4
+ rm -f Gemfile.lock
5
+ git clean -fdx
6
+
7
+ bundle install --path "${HOME}/bundles/${JOB_NAME}"
8
+
9
+ bundle exec rake
10
+ bundle exec rake publish_gem
@@ -0,0 +1,23 @@
1
+ require 'open3'
2
+ require 'vcloud/fog'
3
+
4
+ require 'vcloud/core/entity'
5
+ require 'vcloud/core/metadata_helper'
6
+ require 'vcloud/core/compute_metadata'
7
+ require 'vcloud/core/vdc'
8
+ require 'vcloud/core/edge_gateway'
9
+ require 'vcloud/core/vm'
10
+ require 'vcloud/core/vapp'
11
+ require 'vcloud/core/vapp_template'
12
+ require 'vcloud/core/org_vdc_network'
13
+ require 'vcloud/core/query'
14
+
15
+ module Vcloud
16
+ module Core
17
+
18
+ def self.logger
19
+ @logger ||=Logger.new(STDOUT)
20
+ end
21
+
22
+ end
23
+ end
@@ -0,0 +1,13 @@
1
+ module Vcloud
2
+ module Core
3
+ module ComputeMetadata
4
+
5
+ def get_metadata id
6
+ vcloud_compute_metadata = Vcloud::Fog::ServiceInterface.new.get_vapp_metadata(id)
7
+ MetadataHelper.extract_metadata(vcloud_compute_metadata[:MetadataEntry])
8
+ end
9
+
10
+ end
11
+ end
12
+ end
13
+
@@ -0,0 +1,46 @@
1
+ module Vcloud
2
+ module Core
3
+ class EdgeGateway
4
+
5
+ attr_reader :id
6
+
7
+ def initialize(id)
8
+ unless id =~ /^[-0-9a-f]+$/
9
+ raise "EdgeGateway id : #{id} is not in correct format"
10
+ end
11
+ @id = id
12
+ end
13
+
14
+ def self.get_ids_by_name(name)
15
+ q = Query.new('edgeGateway', :filter => "name==#{name}")
16
+ unless res = q.get_all_results
17
+ raise "Error finding edgeGateway by name #{name}"
18
+ end
19
+ res.collect do |record|
20
+ record[:href].split('/').last if record.key?(:href)
21
+ end
22
+ end
23
+
24
+ def self.get_by_name(name)
25
+ ids = self.get_ids_by_name(name)
26
+ raise "edgeGateway #{name} not found" if ids.size == 0
27
+ raise "edgeGateway #{name} is not unique" if ids.size > 1
28
+ return self.new(ids.first)
29
+ end
30
+
31
+ def vcloud_attributes
32
+ fsi = Vcloud::Fog::ServiceInterface.new
33
+ fsi.get_edge_gateway(id)
34
+ end
35
+
36
+ def href
37
+ vcloud_attributes[:href]
38
+ end
39
+
40
+ def name
41
+ vcloud_attributes[:name]
42
+ end
43
+
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,23 @@
1
+ module Vcloud
2
+ module Core
3
+ class Entity
4
+
5
+ def id_prefix;
6
+ raise 'id_prefix : method missing'
7
+ end
8
+
9
+ def id
10
+ raise 'id not found' unless @vcloud_attributes && @vcloud_attributes[:href]
11
+ extracted_id = @vcloud_attributes[:href].split('/').last
12
+ unless extracted_id =~ /^#{id_prefix}-[-0-9a-f]+$/
13
+ raise "#{id_prefix} id : #{extracted_id} is not in correct format"
14
+ end
15
+ extracted_id
16
+ end
17
+
18
+ def name
19
+ @vcloud_attributes[:name]
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,29 @@
1
+ module Vcloud
2
+ module Core
3
+ module MetadataHelper
4
+
5
+ def extract_metadata vcloud_metadata_entries
6
+ metadata = {}
7
+ vcloud_metadata_entries.each do |entry|
8
+ next unless entry[:type] == Vcloud::Fog::ContentTypes::METADATA
9
+ key = entry[:Key].to_sym
10
+ val = entry[:TypedValue][:Value]
11
+ case entry[:TypedValue][:xsi_type]
12
+ when Fog::MetadataValueType::Number
13
+ val = val.to_i
14
+ when Fog::MetadataValueType::String
15
+ val = val.to_s
16
+ when Fog::MetadataValueType::DateTime
17
+ val = DateTime.parse(val)
18
+ when Fog::MetadataValueType::Boolean
19
+ val = val == 'true' ? true : false
20
+ end
21
+ metadata[key] = val
22
+ end
23
+ metadata
24
+ end
25
+
26
+ module_function :extract_metadata
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,102 @@
1
+ module Vcloud
2
+ module Core
3
+ class OrgVdcNetwork
4
+
5
+ attr_reader :id
6
+
7
+ def initialize(id)
8
+ unless id =~ /^[-0-9a-f]+$/
9
+ raise "orgVdcNetwork id : #{id} is not in correct format"
10
+ end
11
+ @id = id
12
+ end
13
+
14
+ def self.provision(config)
15
+ raise "Must specify a name" unless name = config[:name]
16
+ raise "Must specify a vdc_name" unless vdc_name = config[:vdc_name]
17
+
18
+ unless config[:fence_mode] == 'isolated' || config[:fence_mode] == 'natRouted'
19
+ raise "fence_mode #{config[:fence_mode]} not supported. Must be 'isolated' or 'natRouted'"
20
+ end
21
+
22
+ config[:is_shared] = false unless config[:is_shared]
23
+
24
+ if config[:fence_mode] == 'natRouted'
25
+ raise "Must specify an edge_gateway to connect to" unless config.key?(:edge_gateway)
26
+ edgegw = Vcloud::Core::EdgeGateway.get_by_name(config[:edge_gateway])
27
+ end
28
+
29
+ vdc = Vcloud::Core::Vdc.get_by_name(vdc_name)
30
+
31
+ options = construct_network_options(config)
32
+ options[:EdgeGateway] = { :href => edgegw.href } if edgegw
33
+
34
+ begin
35
+ Vcloud::Core.logger.info("Provisioning new OrgVdcNetwork #{name} in vDC '#{vdc_name}'")
36
+ attrs = Vcloud::Fog::ServiceInterface.new.post_create_org_vdc_network(vdc.id, name, options)
37
+ rescue RuntimeError => e
38
+ Vcloud::Core.logger.error("Could not provision orgVdcNetwork: #{e.message}")
39
+ end
40
+
41
+ raise "Did not successfully create orgVdcNetwork" unless attrs && attrs.key?(:href)
42
+ self.new(attrs[:href].split('/').last)
43
+
44
+ end
45
+
46
+ def vcloud_attributes
47
+ Vcloud::Fog::ServiceInterface.new.get_network(id)
48
+ end
49
+
50
+ def name
51
+ vcloud_attributes[:name]
52
+ end
53
+
54
+ def href
55
+ vcloud_attributes[:href]
56
+ end
57
+
58
+ def delete
59
+ Vcloud::Fog::ServiceInterface.new.delete_network(id)
60
+ end
61
+
62
+ private
63
+
64
+ def self.construct_network_options(config)
65
+ opts = {}
66
+ opts[:Description] = config[:description] if config.key?(:description)
67
+ opts[:IsShared] = config[:is_shared]
68
+
69
+ ip_scope = {}
70
+ ip_scope[:IsInherited] = config[:is_inherited] || false
71
+ ip_scope[:Gateway] = config[:gateway] if config.key?(:gateway)
72
+ ip_scope[:Netmask] = config[:netmask] if config.key?(:netmask)
73
+ ip_scope[:Dns1] = config[:dns1] if config.key?(:dns1)
74
+ ip_scope[:Dns2] = config[:dns2] if config.key?(:dns2)
75
+ ip_scope[:DnsSuffix] = config[:dns_suffix] if config.key?(:dns_suffix)
76
+ ip_scope[:IsEnabled] = config[:is_enabled] || true
77
+
78
+ if config.key?(:ip_ranges) && config[:ip_ranges].size > 0
79
+ ip_scope[:IpRanges] = []
80
+ config[:ip_ranges].each do |range|
81
+ ip_scope[:IpRanges] << {
82
+ :IpRange => {
83
+ :StartAddress => range[:start_address],
84
+ :EndAddress => range[:end_address]
85
+ }
86
+ }
87
+ end
88
+ end
89
+
90
+ opts[:Configuration] = {
91
+ :FenceMode => config[:fence_mode],
92
+ :IpScopes => {
93
+ :IpScope => ip_scope
94
+ },
95
+ }
96
+
97
+ opts
98
+ end
99
+
100
+ end
101
+ end
102
+ end