cloudconfig 0.1.1

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