cloudconfig 0.1.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.
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.travis.yml ADDED
@@ -0,0 +1,7 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.3
4
+ install:
5
+ - bundle install
6
+ script: |
7
+ bundle exec ruby test/test.rb
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in cloudconfig.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,13 @@
1
+ Copyright 2014 Klarna AB
2
+
3
+ Licensed under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License.
5
+ You may obtain a copy of the License at
6
+
7
+ http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ Unless required by applicable law or agreed to in writing, software
10
+ distributed under the License is distributed on an "AS IS" BASIS,
11
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ See the License for the specific language governing permissions and
13
+ limitations under the License.
data/README.md ADDED
@@ -0,0 +1,109 @@
1
+ # Cloudconfig
2
+
3
+ [![Build Status](https://travis-ci.org/klarna/cloudconfig.png?branch=master)](https://travis-ci.org/klarna/cloudconfig)
4
+
5
+ Cloudconfig is an application that manages configurations for resources in Cloudstack.
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ gem 'cloudconfig'
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install cloudconfig
20
+
21
+ ## Usage
22
+
23
+ Cloudconfig will configure resources in Cloudstack.
24
+
25
+ To use the application:
26
+
27
+ cloudconfig --help
28
+
29
+ Create config:
30
+
31
+ cloudconfig config URL API_KEY SECRET_KEY RESOURCE_DIRECTORY
32
+
33
+ Dryrun can be performed to view potential changes:
34
+
35
+ cloudconfig update hosts --dryrun
36
+
37
+ ### Configuration of resources
38
+
39
+ Cloudconfig will configure resources in Cloudstack according to resources in yaml files in specified directory.
40
+
41
+ Resources that currently are handled by cloudconfig:
42
+
43
+ - Compute offerings (create, update, delete)
44
+ - Disk offerings (update)
45
+ - Host tags (create, delete)
46
+ - Storage tags (create, delete)
47
+
48
+ Resource files are expected to be structured in following manner in configured resource directory:
49
+
50
+ .
51
+ ├── diskofferings.yaml
52
+ ├── hosts.yaml
53
+ ├── serviceofferings.yaml
54
+ └── storages.yaml
55
+
56
+ diskofferings.yaml:
57
+
58
+ DiskOfferings:
59
+ 20gb: { tags: "SSD",
60
+ displaytext: "20GB SSD Drive",
61
+ disksize: 200 }
62
+
63
+ 50GB: { tags: "SSD",
64
+ displaytext: "50GB SSD Drive",
65
+ disksize: 50 }
66
+
67
+ hosts.yaml:
68
+
69
+ Hosts:
70
+ host1.example.com: { hosttags: "small,medium",
71
+ zonename: "example" }
72
+
73
+ host2.example.com: { hosttags: "small,medium,large",
74
+ zonename: "example" }
75
+
76
+ serviceofferings.yaml:
77
+
78
+ ServiceOfferings:
79
+ small: { displaytext: "1vCPU, 1GHz, 1GB RAM",
80
+ storagetype: "shared",
81
+ cpunumber: 1,
82
+ cpuspeed: 1000,
83
+ memory: 1024,
84
+ tags: "disk",
85
+ hosttags: "small" }
86
+
87
+ storage.yaml:
88
+
89
+ Storages:
90
+ ssd: { tags: "ssd",
91
+ zonename: "example" }
92
+
93
+ ssd: { tags: "ssd",
94
+ zonename: "example" }
95
+
96
+ ### Testing
97
+
98
+ Currently only unit testing:
99
+
100
+ bundle install
101
+ bundle exec ruby test/test.rb
102
+
103
+ ## Contributing
104
+
105
+ 1. Fork it
106
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
107
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
108
+ 4. Push to the branch (`git push origin my-new-feature`)
109
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
data/bin/cloudconfig ADDED
@@ -0,0 +1,52 @@
1
+ #!/usr/bin/env ruby
2
+ require "thor"
3
+ require "user_config"
4
+ require "cloudconfig/resources"
5
+
6
+ module Cloudconfig
7
+ class CLI < Thor
8
+ desc "config URL API_KEY SECRET_KEY RESOURCE_DIRECTORY", "Create configuration file ~/.cloudconfig/config, with url, api_key, secret_key and path to directory containing resource files as /path/to/directory ."
9
+ def config(url, api_key, secret_key, resource_directory)
10
+ UserConfig.default('config.yaml', {
11
+ 'url' => url,
12
+ 'api_key' => api_key,
13
+ 'secret_key' => secret_key,
14
+ 'resource_directory' => resource_directory
15
+ })
16
+ uconfig = UserConfig.new('.cloudconfig')
17
+ uconfig.create('config.yaml')
18
+ end
19
+ desc "list RESOURCE", "Lists RESOURCE, currently existing in CloudPlatform."
20
+ def list(resource)
21
+ r = Resources.new(resource)
22
+ r.list_resources
23
+ end
24
+ desc "comparison", "Compares all resources available for update."
25
+ def comparison()
26
+ # resource set to serviceofferings, but method will check all resources.
27
+ r = Resources.new("serviceofferings")
28
+ r.compare_resources
29
+ end
30
+ desc "update RESOURCE", "Updates RESOURCE from configuration yaml file."
31
+ long_desc <<-LONGDESC
32
+ `update serviceofferings` will configure service offerings.
33
+ \x5`update hosts` will configure hosts.
34
+ \x5`update storages` will configure storage pools.
35
+ \x5`update diskofferings` will configure disk offerings.
36
+ LONGDESC
37
+ option :delete, :desc => "delete option for service offerings, resources existing in CloudPlatform but not in configuation yaml file are deleted in CloudPlatform."
38
+ option :dryrun, :desc => "dry run option, changes that should be made are listed, but not performed."
39
+ def update(resource)
40
+ r = Resources.new(resource)
41
+ if options[:delete]
42
+ r.delete = true
43
+ end
44
+ if options[:dryrun]
45
+ r.dryrun = true
46
+ end
47
+ r.update
48
+ end
49
+ end
50
+ end
51
+
52
+ Cloudconfig::CLI.start(ARGV)
@@ -0,0 +1,27 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'cloudconfig/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "cloudconfig"
8
+ spec.version = Cloudconfig::VERSION
9
+ spec.authors = ["Katrin Nilsson", "Carl Loa Odin", "Olle Lundberg"]
10
+ spec.email = ["katrin.nilsson@klarna.com", "carl.loa.odin@klarna.com", "olle.lundberg@klarna.com"]
11
+ spec.description = %q{Cloudconfig is an application that manages configurations for resources in Cloudstack.}
12
+ spec.summary = %q{Resource configuration manager for Cloudstack.}
13
+ spec.homepage = ""
14
+ spec.license = "Apache License, Version 2.0"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.3"
22
+ spec.add_development_dependency "rake", "~> 10.3.2"
23
+
24
+ spec.add_runtime_dependency "thor", "~> 0.19.1"
25
+ spec.add_runtime_dependency "user_config", "~> 0.0.4"
26
+ spec.add_runtime_dependency "cloudstack_ruby_client", "~> 1.0.1"
27
+ end
@@ -0,0 +1,174 @@
1
+ require 'yaml'
2
+ require 'json'
3
+ require 'net/http'
4
+ require 'cloudstack_ruby_client'
5
+ require 'user_config'
6
+
7
+ module Cloudconfig
8
+ class Resources
9
+
10
+
11
+ attr_accessor :config, :delete, :dryrun, :resource, :client, :config_file
12
+
13
+
14
+ def initialize(resource)
15
+ @delete = false
16
+ @dryrun = false
17
+ @resource = resource
18
+ uconfig = UserConfig.new('.cloudconfig')
19
+ @config_file = uconfig['config.yaml']
20
+ end
21
+
22
+
23
+ def update()
24
+ @client = create_cloudstack_client()
25
+ resource_file, resource_cloud = define_yamlfile_and_cloudresource()
26
+ r_updated, r_created, r_deleted = check_resource(resource_file, resource_cloud)
27
+ feedback = ""
28
+ if @dryrun
29
+ feedback = "The following actions would be performed with this command:\n"
30
+ else
31
+ for r in r_updated
32
+ r_diff = Hash[(r[0].to_a) - (r[1].to_a)]
33
+ r_union = Hash[r[0].to_a | r_diff.to_a]
34
+ update_resource(r_union)
35
+ end
36
+ r_created.each{ |r| create_resource(r) }
37
+ r_deleted.each{ |r| delete_resource(r) }
38
+ end
39
+ for r in r_updated
40
+ # r_diff represents the parameters that should be changed in resource
41
+ r_diff = Hash[(r[0].to_a) - (r[1].to_a)]
42
+ feedback += "Some values has been changed in #{@resource} named #{r[0]["name"]}.\nOld values were:\n#{JSON.pretty_generate(r[1])}\nNew values are:\n#{JSON.pretty_generate(r_diff)}\n"
43
+ end
44
+ r_created.each{ |r| feedback += "#{@resource} named #{r["name"]} has been created\n" }
45
+ r_deleted.each{ |r| feedback += "#{@resource} named #{r["name"]} has been deleted\n" }
46
+ puts feedback
47
+ end
48
+
49
+
50
+ def create_cloudstack_client()
51
+ client = CloudstackRubyClient::Client.new(@config_file["url"], @config_file["api_key"], @config_file["secret_key"], true)
52
+ return client
53
+ end
54
+
55
+
56
+ # Save the current list of resources in resource_cloud, and the ones in the yaml file in resource_file
57
+ def define_yamlfile_and_cloudresource()
58
+ if @resource == "serviceofferings"
59
+ resource_title = "ServiceOfferings"
60
+ resource_cloud = @client.list_service_offerings()["serviceoffering"]
61
+ elsif @resource == "hosts"
62
+ resource_title = "Hosts"
63
+ resource_cloud = @client.list_hosts()["host"]
64
+ elsif @resource == "storages"
65
+ resource_title = "Storages"
66
+ resource_cloud = @client.list_storage_pools()["storagepool"]
67
+ elsif @resource == "diskofferings"
68
+ resource_title = "DiskOfferings"
69
+ resource_cloud = @client.list_disk_offerings()["diskoffering"]
70
+ end
71
+ resource_file = YAML.load_file("#{@config_file["resource_directory"]}/#{@resource}.yaml")["#{resource_title}"]
72
+ return resource_file, resource_cloud
73
+ end
74
+
75
+
76
+ # Compare resources in cloud and yaml file
77
+ def check_resource(resource_file, resource_cloud)
78
+ updated = Array.new
79
+ created = Array.new
80
+ deleted = Array.new
81
+ for r in resource_file
82
+ r_total = r[1].merge({"name" => "#{r[0]}"})
83
+ found = false
84
+ i = 0
85
+ # If the resource has not yet been found, compare names and update resource if names match but other parameters don't
86
+ while !found && i < resource_cloud.length
87
+ if resource_cloud[i]["name"] == r[0]
88
+ new_resource = resource_cloud[i].merge(r[1])
89
+ if resource_cloud[i] != new_resource
90
+ r_total = r_total.merge({"id" => "#{resource_cloud[i]["id"]}"})
91
+ # Update resource with new values, in first parameter, and send old values in second parameter
92
+ updated.push([r_total, resource_cloud[i]])
93
+ end
94
+ resource_cloud.delete_at(i)
95
+ found = true
96
+ else
97
+ i += 1
98
+ end
99
+ end
100
+ if (!found) && (@resource == "serviceofferings")
101
+ # Create resources. (Only works for service offerings at the moment)
102
+ created.push(r_total)
103
+ end
104
+ end
105
+ if delete && (resource_cloud.length > 0) && (@resource == "serviceofferings")
106
+ # Remove all resources that are not included in yaml file. (Only works for service offerings at the moment)
107
+ for r in resource_cloud
108
+ deleted.push(r)
109
+ end
110
+ end
111
+ # Return resources that should be updated, created and deleted
112
+ return updated, created, deleted
113
+ end
114
+
115
+
116
+ def update_resource(res)
117
+ if @resource == "serviceofferings"
118
+ @client.delete_service_offering({"id" => "#{res["id"]}"})
119
+ @client.create_service_offering(res)
120
+ elsif @resource == "hosts"
121
+ @client.update_host(res)
122
+ elsif @resource == "storages"
123
+ @client.update_storage_pool(res)
124
+ elsif @resource == "diskofferings"
125
+ # Parameter iscustomized has different name (customized) when creating resource, and parameter disksize create error if iscustomized is true.
126
+ if res["iscustomized"] == true
127
+ res.delete("disksize")
128
+ end
129
+ res = res.merge({"customized" => res["iscustomized"]})
130
+ res.delete("iscustomized")
131
+ @client.delete_disk_offering({"id" => "#{res["id"]}"})
132
+ @client.create_disk_offering(res)
133
+ end
134
+ end
135
+
136
+
137
+ def create_resource(res)
138
+ if @resource == "serviceofferings"
139
+ @client.create_service_offering(res)
140
+ end
141
+ end
142
+
143
+
144
+ def delete_resource(res)
145
+ if @resource == "serviceofferings"
146
+ @client.delete_service_offering({"id" => "#{res["id"]}"})
147
+ end
148
+ end
149
+
150
+ def list_resources()
151
+ @client = create_cloudstack_client()
152
+ resource_file, resource_cloud = define_yamlfile_and_cloudresource()
153
+ puts JSON.pretty_generate(resource_cloud)
154
+ end
155
+
156
+ def compare_resources()
157
+ @delete = true
158
+ @client = create_cloudstack_client()
159
+ resources = ["serviceofferings", "hosts", "storages", "diskofferings"]
160
+ for r in resources
161
+ @res = r
162
+ resource_file, resource_cloud = define_yamlfile_and_cloudresource()
163
+ r_updated, r_created, r_deleted = check_resource(resource_file, resource_cloud)
164
+ puts "The following #{r} will be updated:"
165
+ r_updated.each{ |re| puts "\n#{re[0]["name"]}" }
166
+ puts "The following #{r} will be created:"
167
+ r_created.each{ |re| puts "\n#{re["name"]}" }
168
+ puts "The following #{r} will be deleted:"
169
+ r_deleted.each{ |re| puts "\n#{re["name"]}" }
170
+ end
171
+ end
172
+
173
+ end
174
+ end
@@ -0,0 +1,3 @@
1
+ module Cloudconfig
2
+ VERSION = "0.1.1"
3
+ end
@@ -0,0 +1,39 @@
1
+ class TestHelper
2
+
3
+ def get_resource_cloud()
4
+ resource_cloud = [
5
+ { "name" => "Resource-01",
6
+ "id" => 111,
7
+ "tag" => "RES"
8
+ },
9
+ { "name" => "Resource-02",
10
+ "id" => 222,
11
+ "tag" => "RES"
12
+ },
13
+ { "name" => "Resource-03",
14
+ "id" => 333,
15
+ "tag" => "RAN"
16
+ }
17
+ ]
18
+ return resource_cloud.to_a
19
+ end
20
+
21
+ def get_resource_file()
22
+ resource_file = {
23
+ "Resource-01" => {
24
+ "id" => 111,
25
+ "tag" => "RES"
26
+ },
27
+ "Resource-02" => {
28
+ "id" => 222,
29
+ "tag" => "RAN"
30
+ },
31
+ "Resource-04" => {
32
+ "id" => 444,
33
+ "tag" => "RAN"
34
+ }
35
+ }
36
+ return resource_file
37
+ end
38
+
39
+ end
data/test/test.rb ADDED
@@ -0,0 +1,104 @@
1
+ require "test/unit"
2
+ require "cloudstack_ruby_client"
3
+ require_relative "../lib/cloudconfig/resources"
4
+ require_relative "helper/test_helper"
5
+
6
+
7
+
8
+ class TestResources < Test::Unit::TestCase
9
+
10
+ def setup
11
+ @res = [Cloudconfig::Resources.new("serviceofferings"),
12
+ Cloudconfig::Resources.new("hosts"),
13
+ Cloudconfig::Resources.new("storages"),
14
+ Cloudconfig::Resources.new("diskofferings")]
15
+
16
+ for r in @res
17
+ r.delete = false
18
+ r.dryrun = true
19
+ end
20
+
21
+ @r_test_file = TestHelper.new().get_resource_file()
22
+ @r_test_cloud = TestHelper.new().get_resource_cloud()
23
+ end
24
+
25
+ def test_update_serviceofferings_delete_is_false
26
+ # Test array and hash in test_helper.rb, with delete option set to false in setup
27
+ upd, cre, del = @res[0].check_resource(@r_test_file, @r_test_cloud)
28
+ assert_equal(1, upd.length)
29
+ assert_equal("Resource-02", "#{upd[0][0]["name"]}")
30
+ assert_equal(1, cre.length)
31
+ assert_equal("Resource-04", "#{cre[0]["name"]}")
32
+ assert_equal(0, del.length)
33
+ end
34
+
35
+ # Same test, with delete set to true
36
+ def test_update_serviceofferings_delete_is_true
37
+ @res[0].delete = true
38
+ upd, cre, del = @res[0].check_resource(@r_test_file, @r_test_cloud)
39
+ assert_equal(1, upd.length)
40
+ assert_equal("Resource-02", "#{upd[0][0]["name"]}")
41
+ assert_equal(1, cre.length)
42
+ assert_equal("Resource-04", "#{cre[0]["name"]}")
43
+ assert_equal(1, del.length)
44
+ assert_equal("Resource-03", "#{del[0]["name"]}")
45
+ end
46
+
47
+ def test_update_hosts_delete_is_false
48
+ # Test array and hash in test_helper.rb, with delete option set to false in setup
49
+ upd, cre, del = @res[1].check_resource(@r_test_file, @r_test_cloud)
50
+ assert_equal(1, upd.length)
51
+ assert_equal("Resource-02", "#{upd[0][0]["name"]}")
52
+ assert_equal(0, cre.length)
53
+ assert_equal(0, del.length)
54
+ end
55
+
56
+ # Same test, with delete set to true
57
+ def test_update_hosts_delete_is_true
58
+ @res[1].delete = true
59
+ upd, cre, del = @res[1].check_resource(@r_test_file, @r_test_cloud)
60
+ assert_equal(1, upd.length)
61
+ assert_equal("Resource-02", "#{upd[0][0]["name"]}")
62
+ assert_equal(0, cre.length)
63
+ assert_equal(0, del.length)
64
+ end
65
+
66
+ def test_update_storages_delete_is_false
67
+ # Test array and hash in test_helper.rb, with delete option set to false in setup
68
+ upd, cre, del = @res[2].check_resource(@r_test_file, @r_test_cloud)
69
+ assert_equal(1, upd.length)
70
+ assert_equal("Resource-02", "#{upd[0][0]["name"]}")
71
+ assert_equal(0, cre.length)
72
+ assert_equal(0, del.length)
73
+ end
74
+
75
+ # Same test, with delete set to true
76
+ def test_update_storages_delete_is_true
77
+ @res[2].delete = true
78
+ upd, cre, del = @res[2].check_resource(@r_test_file, @r_test_cloud)
79
+ assert_equal(1, upd.length)
80
+ assert_equal("Resource-02", "#{upd[0][0]["name"]}")
81
+ assert_equal(0, cre.length)
82
+ assert_equal(0, del.length)
83
+ end
84
+
85
+ def test_update_diskofferings_delete_is_false
86
+ # Test array and hash in test_helper.rb, with delete option set to false in setup
87
+ upd, cre, del = @res[3].check_resource(@r_test_file, @r_test_cloud)
88
+ assert_equal(1, upd.length)
89
+ assert_equal("Resource-02", "#{upd[0][0]["name"]}")
90
+ assert_equal(0, cre.length)
91
+ assert_equal(0, del.length)
92
+ end
93
+
94
+ # Same test, with delete set to true
95
+ def test_update_diskofferings_delete_is_true
96
+ @res[3].delete = true
97
+ upd, cre, del = @res[3].check_resource(@r_test_file, @r_test_cloud)
98
+ assert_equal(1, upd.length)
99
+ assert_equal("Resource-02", "#{upd[0][0]["name"]}")
100
+ assert_equal(0, cre.length)
101
+ assert_equal(0, del.length)
102
+ end
103
+
104
+ end
metadata ADDED
@@ -0,0 +1,121 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: cloudconfig
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Katrin Nilsson
9
+ - Carl Loa Odin
10
+ - Olle Lundberg
11
+ autorequire:
12
+ bindir: bin
13
+ cert_chain: []
14
+ date: 2014-06-25 00:00:00.000000000 Z
15
+ dependencies:
16
+ - !ruby/object:Gem::Dependency
17
+ name: bundler
18
+ requirement: &17262780 !ruby/object:Gem::Requirement
19
+ none: false
20
+ requirements:
21
+ - - ~>
22
+ - !ruby/object:Gem::Version
23
+ version: '1.3'
24
+ type: :development
25
+ prerelease: false
26
+ version_requirements: *17262780
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: &17261260 !ruby/object:Gem::Requirement
30
+ none: false
31
+ requirements:
32
+ - - ~>
33
+ - !ruby/object:Gem::Version
34
+ version: 10.3.2
35
+ type: :development
36
+ prerelease: false
37
+ version_requirements: *17261260
38
+ - !ruby/object:Gem::Dependency
39
+ name: thor
40
+ requirement: &17260780 !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: 0.19.1
46
+ type: :runtime
47
+ prerelease: false
48
+ version_requirements: *17260780
49
+ - !ruby/object:Gem::Dependency
50
+ name: user_config
51
+ requirement: &17260320 !ruby/object:Gem::Requirement
52
+ none: false
53
+ requirements:
54
+ - - ~>
55
+ - !ruby/object:Gem::Version
56
+ version: 0.0.4
57
+ type: :runtime
58
+ prerelease: false
59
+ version_requirements: *17260320
60
+ - !ruby/object:Gem::Dependency
61
+ name: cloudstack_ruby_client
62
+ requirement: &17259860 !ruby/object:Gem::Requirement
63
+ none: false
64
+ requirements:
65
+ - - ~>
66
+ - !ruby/object:Gem::Version
67
+ version: 1.0.1
68
+ type: :runtime
69
+ prerelease: false
70
+ version_requirements: *17259860
71
+ description: Cloudconfig is an application that manages configurations for resources
72
+ in Cloudstack.
73
+ email:
74
+ - katrin.nilsson@klarna.com
75
+ - carl.loa.odin@klarna.com
76
+ - olle.lundberg@klarna.com
77
+ executables:
78
+ - cloudconfig
79
+ extensions: []
80
+ extra_rdoc_files: []
81
+ files:
82
+ - .gitignore
83
+ - .travis.yml
84
+ - Gemfile
85
+ - LICENSE.txt
86
+ - README.md
87
+ - Rakefile
88
+ - bin/cloudconfig
89
+ - cloudconfig.gemspec
90
+ - lib/cloudconfig/resources.rb
91
+ - lib/cloudconfig/version.rb
92
+ - test/helper/test_helper.rb
93
+ - test/test.rb
94
+ homepage: ''
95
+ licenses:
96
+ - Apache License, Version 2.0
97
+ post_install_message:
98
+ rdoc_options: []
99
+ require_paths:
100
+ - lib
101
+ required_ruby_version: !ruby/object:Gem::Requirement
102
+ none: false
103
+ requirements:
104
+ - - ! '>='
105
+ - !ruby/object:Gem::Version
106
+ version: '0'
107
+ required_rubygems_version: !ruby/object:Gem::Requirement
108
+ none: false
109
+ requirements:
110
+ - - ! '>='
111
+ - !ruby/object:Gem::Version
112
+ version: '0'
113
+ requirements: []
114
+ rubyforge_project:
115
+ rubygems_version: 1.8.11
116
+ signing_key:
117
+ specification_version: 3
118
+ summary: Resource configuration manager for Cloudstack.
119
+ test_files:
120
+ - test/helper/test_helper.rb
121
+ - test/test.rb