vcloud-core 0.0.1

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