cloudkeeper-one 1.0.0

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 (62) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +11 -0
  3. data/.gitmodules +3 -0
  4. data/.rspec +2 -0
  5. data/.rubocop.yml +48 -0
  6. data/.travis.yml +22 -0
  7. data/CODE_OF_CONDUCT.md +49 -0
  8. data/Gemfile +4 -0
  9. data/LICENSE.txt +17 -0
  10. data/README.md +98 -0
  11. data/Rakefile +17 -0
  12. data/bin/cloudkeeper-one +5 -0
  13. data/cloudkeeper-one.gemspec +44 -0
  14. data/config/cloudkeeper-one.yml +23 -0
  15. data/config/templates/image.erb +20 -0
  16. data/config/templates/template.erb +19 -0
  17. data/lib/cloudkeeper/one/appliance_actions/list.rb +68 -0
  18. data/lib/cloudkeeper/one/appliance_actions/registration.rb +73 -0
  19. data/lib/cloudkeeper/one/appliance_actions/removal.rb +57 -0
  20. data/lib/cloudkeeper/one/appliance_actions/update.rb +34 -0
  21. data/lib/cloudkeeper/one/appliance_actions/utils/image_download.rb +43 -0
  22. data/lib/cloudkeeper/one/appliance_actions/utils/template_preparation.rb +36 -0
  23. data/lib/cloudkeeper/one/appliance_actions/utils/templates/attributes.erb +23 -0
  24. data/lib/cloudkeeper/one/appliance_actions/utils.rb +10 -0
  25. data/lib/cloudkeeper/one/appliance_actions.rb +11 -0
  26. data/lib/cloudkeeper/one/cli.rb +185 -0
  27. data/lib/cloudkeeper/one/core_connector.rb +106 -0
  28. data/lib/cloudkeeper/one/errors/actions/action_error.rb +9 -0
  29. data/lib/cloudkeeper/one/errors/actions/listing_error.rb +9 -0
  30. data/lib/cloudkeeper/one/errors/actions/registration_error.rb +9 -0
  31. data/lib/cloudkeeper/one/errors/actions/update_error.rb +9 -0
  32. data/lib/cloudkeeper/one/errors/actions.rb +12 -0
  33. data/lib/cloudkeeper/one/errors/argument_error.rb +7 -0
  34. data/lib/cloudkeeper/one/errors/invalid_configuration_error.rb +7 -0
  35. data/lib/cloudkeeper/one/errors/multi_error.rb +25 -0
  36. data/lib/cloudkeeper/one/errors/network_connection_error.rb +7 -0
  37. data/lib/cloudkeeper/one/errors/opennebula/api_call_timeout_error.rb +9 -0
  38. data/lib/cloudkeeper/one/errors/opennebula/authentication_error.rb +9 -0
  39. data/lib/cloudkeeper/one/errors/opennebula/missing_pool_error.rb +9 -0
  40. data/lib/cloudkeeper/one/errors/opennebula/opennebula_error.rb +9 -0
  41. data/lib/cloudkeeper/one/errors/opennebula/resource_not_found_error.rb +9 -0
  42. data/lib/cloudkeeper/one/errors/opennebula/resource_retrieval_error.rb +9 -0
  43. data/lib/cloudkeeper/one/errors/opennebula/resource_state_error.rb +9 -0
  44. data/lib/cloudkeeper/one/errors/opennebula/stub_error.rb +9 -0
  45. data/lib/cloudkeeper/one/errors/opennebula/user_not_authorized_error.rb +9 -0
  46. data/lib/cloudkeeper/one/errors/opennebula.rb +17 -0
  47. data/lib/cloudkeeper/one/errors/standard_error.rb +7 -0
  48. data/lib/cloudkeeper/one/errors.rb +14 -0
  49. data/lib/cloudkeeper/one/opennebula/appliance_handler.rb +91 -0
  50. data/lib/cloudkeeper/one/opennebula/datastore_handler.rb +16 -0
  51. data/lib/cloudkeeper/one/opennebula/group_handler.rb +12 -0
  52. data/lib/cloudkeeper/one/opennebula/handler.rb +59 -0
  53. data/lib/cloudkeeper/one/opennebula/helper.rb +27 -0
  54. data/lib/cloudkeeper/one/opennebula/image_handler.rb +133 -0
  55. data/lib/cloudkeeper/one/opennebula/tags.rb +34 -0
  56. data/lib/cloudkeeper/one/opennebula/template_handler.rb +24 -0
  57. data/lib/cloudkeeper/one/opennebula.rb +14 -0
  58. data/lib/cloudkeeper/one/settings.rb +21 -0
  59. data/lib/cloudkeeper/one/version.rb +5 -0
  60. data/lib/cloudkeeper/one.rb +19 -0
  61. data/lib/cloudkeeper_grpc.rb +5 -0
  62. metadata +385 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 80c6557ac7af41b218ad41f06b64af4c4fb61a41
4
+ data.tar.gz: ae771fedc4a03c3a095e5014c99b06605f62fee7
5
+ SHA512:
6
+ metadata.gz: c6fe27e275de9f507b048c9e38970da28906982ec7ce59cef8fb4d5e9725479cbed7d2b611351a600e623abeca68d8c8bb6e2be205768f0fc3c2c7995c8b19e7
7
+ data.tar.gz: c0abb7b25aaa6053109f230f26fdf89dcbe05078a41513fef690f535cc83633e66278200840f0009751f308dcfb9dea3e028b16456513aa6fd01a7f3f069d87c
data/.gitignore ADDED
@@ -0,0 +1,11 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ example
11
+ /vendor/
data/.gitmodules ADDED
@@ -0,0 +1,3 @@
1
+ [submodule "lib/cloudkeeper_grpc"]
2
+ path = lib/cloudkeeper_grpc
3
+ url = https://github.com/the-cloudkeeper-project/cloudkeeper-grpc-ruby.git
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
data/.rubocop.yml ADDED
@@ -0,0 +1,48 @@
1
+ require: rubocop-rspec
2
+
3
+ AllCops:
4
+ TargetRubyVersion: 2.0
5
+ Exclude:
6
+ - 'vendor/**/*'
7
+ - 'lib/cloudkeeper_grpc/*'
8
+
9
+ Metrics/LineLength:
10
+ Max: 135
11
+ Exclude:
12
+ - 'lib/cloudkeeper/one/appliance_actions/list.rb'
13
+
14
+ Style/Documentation:
15
+ Enabled: false
16
+
17
+ Metrics/MethodLength:
18
+ Max: 15
19
+
20
+ Metrics/AbcSize:
21
+ Max: 20
22
+ Exclude:
23
+ - 'lib/cloudkeeper/one/appliance_actions/list.rb'
24
+
25
+ Metrics/ClassLength:
26
+ Max: 120
27
+ Exclude:
28
+ - 'lib/cloudkeeper/one/cli.rb'
29
+
30
+ RSpec/MultipleExpectations:
31
+ Enabled: false
32
+
33
+ RSpec/ExampleLength:
34
+ Enabled: false
35
+
36
+ RSpec/NestedGroups:
37
+ Max: 3
38
+
39
+ RSpec/NestedGroups:
40
+ Max: 4
41
+
42
+ Metrics/BlockLength:
43
+ Exclude:
44
+ - 'Rakefile'
45
+ - '**/*.rake'
46
+ - 'spec/**/*.rb'
47
+ - '*.gemspec'
48
+ - 'lib/cloudkeeper/grpc/*'
data/.travis.yml ADDED
@@ -0,0 +1,22 @@
1
+ sudo: false
2
+
3
+ language: ruby
4
+ rvm:
5
+ - ruby-head
6
+ - 2.2.6
7
+ - 2.3.3
8
+ - 2.4.0
9
+
10
+ matrix:
11
+ allow_failures:
12
+ - rvm: ruby-head
13
+ - rvm: 2.4.0
14
+ fast_finish: true
15
+
16
+ branches:
17
+ only:
18
+ - master
19
+
20
+ before_install: 'gem install bundler -v 1.14.0'
21
+
22
+ script: 'bundle exec rake acceptance'
@@ -0,0 +1,49 @@
1
+ # Contributor Code of Conduct
2
+
3
+ As contributors and maintainers of this project, and in the interest of
4
+ fostering an open and welcoming community, we pledge to respect all people who
5
+ contribute through reporting issues, posting feature requests, updating
6
+ documentation, submitting pull requests or patches, and other activities.
7
+
8
+ We are committed to making participation in this project a harassment-free
9
+ experience for everyone, regardless of level of experience, gender, gender
10
+ identity and expression, sexual orientation, disability, personal appearance,
11
+ body size, race, ethnicity, age, religion, or nationality.
12
+
13
+ Examples of unacceptable behavior by participants include:
14
+
15
+ * The use of sexualized language or imagery
16
+ * Personal attacks
17
+ * Trolling or insulting/derogatory comments
18
+ * Public or private harassment
19
+ * Publishing other's private information, such as physical or electronic
20
+ addresses, without explicit permission
21
+ * Other unethical or unprofessional conduct
22
+
23
+ Project maintainers have the right and responsibility to remove, edit, or
24
+ reject comments, commits, code, wiki edits, issues, and other contributions
25
+ that are not aligned to this Code of Conduct, or to ban temporarily or
26
+ permanently any contributor for other behaviors that they deem inappropriate,
27
+ threatening, offensive, or harmful.
28
+
29
+ By adopting this Code of Conduct, project maintainers commit themselves to
30
+ fairly and consistently applying these principles to every aspect of managing
31
+ this project. Project maintainers who do not follow or enforce the Code of
32
+ Conduct may be permanently removed from the project team.
33
+
34
+ This code of conduct applies both within project spaces and in public spaces
35
+ when an individual is representing the project or its community.
36
+
37
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
38
+ reported by contacting a project maintainer at kimle.michal@gmail.com. All
39
+ complaints will be reviewed and investigated and will result in a response that
40
+ is deemed necessary and appropriate to the circumstances. Maintainers are
41
+ obligated to maintain confidentiality with regard to the reporter of an
42
+ incident.
43
+
44
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage],
45
+ version 1.3.0, available at
46
+ [http://contributor-covenant.org/version/1/3/0/][version]
47
+
48
+ [homepage]: http://contributor-covenant.org
49
+ [version]: http://contributor-covenant.org/version/1/3/0/
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in cloudkeeper-one.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,17 @@
1
+ The work represented by this source file was partially or entirely
2
+ funded by the EGI-Engage project co-funded by the European Union (EU)
3
+ Horizon 2020 program under Grant number 654142.
4
+
5
+ Copyright (c) 2017 CESNET
6
+
7
+ Licensed under the Apache License, Version 2.0 (the "License");
8
+ you may not use this file except in compliance with the License.
9
+ You may obtain a copy of the License at
10
+
11
+ http://www.apache.org/licenses/LICENSE-2.0
12
+
13
+ Unless required by applicable law or agreed to in writing, software
14
+ distributed under the License is distributed on an "AS IS" BASIS,
15
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ See the License for the specific language governing permissions and
17
+ limitations under the License.
data/README.md ADDED
@@ -0,0 +1,98 @@
1
+ # cloudkeeper-one
2
+ OpenNebula backend for [cloudkeeper](https://github.com/the-cloudkeeper-project/cloudkeeper)
3
+
4
+ [![Build Status](https://secure.travis-ci.org/the-cloudkeeper-project/cloudkeeper-one.png)](http://travis-ci.org/the-cloudkeeper-project/cloudkeeper-one)
5
+ [![Dependency Status](https://gemnasium.com/the-cloudkeeper-project/cloudkeeper-one.png)](https://gemnasium.com/the-cloudkeeper-project/cloudkeeper-one)
6
+ [![Gem Version](https://fury-badge.herokuapp.com/rb/cloudkeeper-one.png)](https://badge.fury.io/rb/cloudkeeper-one)
7
+ [![Code Climate](https://codeclimate.com/github/the-cloudkeeper-project/cloudkeeper-one.png)](https://codeclimate.com/github/the-cloudkeeper-project/cloudkeeper-one)
8
+
9
+ ## What does cloudkeeper-one do?
10
+ cloudkeeper-one is able to manage [OpenNebula](https://opennebula.org/) cloud - upload, update and remove images and templates representing EGI AppDB appliances. cloudkeeper-one runs as a server listening for [gRPC](http://www.grpc.io/) communication usually from core [cloudkeeper](https://github.com/the-cloudkeeper-project/cloudkeeper) component.
11
+
12
+ ##Requirements
13
+ * Ruby >= 2.0.0
14
+ * Rubygems
15
+ * OpenNebula >= 5.2 (doesn't have to be present on the same machine)
16
+
17
+ ## Installation
18
+
19
+ ###From RubyGems.org
20
+ To install the most recent stable version
21
+ ```bash
22
+ gem install cloudkeeper-one
23
+ ```
24
+
25
+ ###From source (dev)
26
+ **Installation from source should never be your first choice! Especially, if you are not
27
+ familiar with RVM, Bundler, Rake and other dev tools for Ruby!**
28
+
29
+ **However, if you wish to contribute to our project, this is the right way to start.**
30
+
31
+ To build and install the bleeding edge version from master
32
+
33
+ ```bash
34
+ git clone git://github.com/the-cloudkeeper-project/cloudkeeper-one.git
35
+ cd cloudkeeper-one
36
+ gem install bundler
37
+ bundle install
38
+ bundle exec rake spec
39
+ ```
40
+
41
+ ##Configuration
42
+ ###Create a configuration file for cloudkeeper-one
43
+ Configuration file can be read by cloudkeeper-one from these
44
+ three locations:
45
+
46
+ * `~/.cloudkeeper-one/cloudkeeper-one.yml`
47
+ * `/etc/cloudkeeper-one/cloudkeeper-one.yml`
48
+ * `PATH_TO_GEM_DIR/config/cloudkeeper-one.yml`
49
+
50
+ The default configuration file can be found at the last location
51
+ `PATH_TO_GEM_DIR/config/cloudkeeper-one.yml`.
52
+
53
+ ## Usage
54
+ cloudkeeper-one is run with executable `cloudkeeper-one`. For further assistance run `cloudkeeper-one help sync`:
55
+ ```bash
56
+ Usage:
57
+ cloudkeeper-one sync --appliances-permissions=APPLIANCES-PERMISSIONS --appliances-tmp-dir=APPLIANCES-TMP-DIR --identifier=IDENTIFIER --listen-address=LISTEN-ADDRESS --opennebula-api-call-timeout=OPENNEBULA-API-CALL-TIMEOUT --opennebula-datastores=one two three --opennebula-endpoint=OPENNEBULA-ENDPOINT --opennebula-secret=OPENNEBULA-SECRET
58
+
59
+ Options:
60
+ --listen-address=LISTEN-ADDRESS # IP address gRPC server will listen on
61
+ # Default: 127.0.0.1:50051
62
+ [--authentication], [--no-authentication] # Client <-> server authentication
63
+ [--certificate=CERTIFICATE] # Backend's host certificate
64
+ # Default: /etc/grid-security/hostcert.pem
65
+ [--key=KEY] # Backend's host key
66
+ # Default: /etc/grid-security/hostkey.pem
67
+ --identifier=IDENTIFIER # Instance identifier
68
+ # Default: cloudkeeper-one
69
+ [--core-certificate=CORE-CERTIFICATE] # Core's certificate
70
+ # Default: /etc/grid-security/corecert.pem
71
+ --appliances-tmp-dir=APPLIANCES-TMP-DIR # Directory where to temporarily store appliances
72
+ # Default: /var/spool/cloudkeeper/appliances
73
+ [--appliances-template-dir=APPLIANCES-TEMPLATE-DIR] # If set, templates within this directory are used to construct images and templates in OpenNebula
74
+ --appliances-permissions=APPLIANCES-PERMISSIONS # UNIX-like permissions appliances will have within OpenNebula
75
+ # Default: 640
76
+ --opennebula-secret=OPENNEBULA-SECRET # OpenNebula authentication secret
77
+ # Default: oneadmin:opennebula
78
+ --opennebula-endpoint=OPENNEBULA-ENDPOINT # OpenNebula XML-RPC endpoint
79
+ # Default: http://localhost:2633/RPC2
80
+ --opennebula-datastores=one two three # OpenNebula datastores images will be uploaded to
81
+ # Default: ["default"]
82
+ [--opennebula-users=one two three] # Handle only images/templates of specified users
83
+ --opennebula-api-call-timeout=OPENNEBULA-API-CALL-TIMEOUT # How long will cloudkeeper-one wait for image/template operations to finish in OpenNebula
84
+ # Default: 3h
85
+ --logging-level=LOGGING-LEVEL
86
+ # Default: ERROR
87
+ # Possible values: DEBUG, INFO, WARN, ERROR, FATAL, UNKNOWN
88
+ [--logging-file=LOGGING-FILE] # File to write logs to
89
+ # Default: /var/log/cloudkeeper/cloudkeeper-one.log
90
+ [--debug], [--no-debug] # Runs cloudkeeper in debug mode
91
+ ```
92
+
93
+ ## Contributing
94
+ 1. Fork it ( https://github.com/the-cloudkeeper-project/cloudkeeper-one/fork )
95
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
96
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
97
+ 4. Push to the branch (`git push origin my-new-feature`)
98
+ 5. Create a new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,17 @@
1
+ require 'rspec/core/rake_task'
2
+ require 'rubocop/rake_task'
3
+ require 'bundler/gem_tasks'
4
+
5
+ RSpec::Core::RakeTask.new(:spec)
6
+ RuboCop::RakeTask.new
7
+
8
+ task default: :spec
9
+
10
+ desc 'Run acceptance tests (RSpec + Rubocop)'
11
+ task test: 'acceptance'
12
+
13
+ desc 'Run acceptance tests (RSpec + Rubocop)'
14
+ task :acceptance do |_t|
15
+ Rake::Task['spec'].invoke
16
+ Rake::Task['rubocop'].invoke
17
+ end
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+ require 'cloudkeeper_grpc'
3
+ require 'cloudkeeper/one'
4
+
5
+ Cloudkeeper::One::CLI.start(ARGV)
@@ -0,0 +1,44 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'cloudkeeper/one/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'cloudkeeper-one'
8
+ spec.version = Cloudkeeper::One::VERSION
9
+ spec.authors = ['Michal Kimle']
10
+ spec.email = ['kimle.michal@gmail.com']
11
+
12
+ spec.summary = 'OpenNebula backend for cloudkeeper'
13
+ spec.description = 'OpenNebula backend for cloudkeeper'
14
+ spec.homepage = 'https://github.com/Misenko/cloudkeeper-one'
15
+ spec.license = 'Apache License, Version 2.0'
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
18
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
19
+ spec.require_paths = ['lib']
20
+
21
+ spec.add_development_dependency 'bundler', '~> 1.14'
22
+ spec.add_development_dependency 'rake', '~> 11.2'
23
+ spec.add_development_dependency 'rspec', '~> 3.5'
24
+ spec.add_development_dependency 'rubocop', '~> 0.42'
25
+ spec.add_development_dependency 'rubocop-rspec', '~> 1.7'
26
+ spec.add_development_dependency 'rspec-collection_matchers', '~> 1.1'
27
+ spec.add_development_dependency 'simplecov', '~> 0.12'
28
+ spec.add_development_dependency 'pry', '~> 0.10'
29
+ spec.add_development_dependency 'pry-byebug', '~> 3.4'
30
+ spec.add_development_dependency 'vcr', '~> 3.0'
31
+ spec.add_development_dependency 'webmock', '~> 2.1'
32
+ spec.add_development_dependency 'grpc-tools', '~> 1.0'
33
+
34
+ spec.add_runtime_dependency 'thor', '~> 0.19'
35
+ spec.add_runtime_dependency 'yell', '~> 2.0'
36
+ spec.add_runtime_dependency 'grpc', '~> 1.0'
37
+ spec.add_runtime_dependency 'settingslogic', '~> 2.0'
38
+ spec.add_runtime_dependency 'activesupport', '~> 4.0'
39
+ spec.add_runtime_dependency 'tilt', '~> 2.0'
40
+ spec.add_runtime_dependency 'opennebula', '~> 5.2'
41
+ spec.add_runtime_dependency 'chronic_duration', '~> 0.10'
42
+
43
+ spec.required_ruby_version = '>= 2.2.0'
44
+ end
@@ -0,0 +1,23 @@
1
+ cloudkeeper-one:
2
+ listen-address: 127.0.0.1:50051 # IP address gRPC server will listen on
3
+ authentication: false # core (client) <-> backend (server) authentication (certificate, key and core-certificate options)
4
+ certificate: /etc/grid-security/hostcert.pem # Backend's host certificate
5
+ key: /etc/grid-security/hostkey.pem # Backend's host key
6
+ identifier: cloudkeeper-one # Instance identifier
7
+ core:
8
+ certificate: /etc/grid-security/corecert.pem # Core's certificate
9
+ appliances:
10
+ tmp-dir: /var/spool/cloudkeeper/appliances # Directory where to temporarily store appliances
11
+ template-dir: # If set, templates within this directory are used to construct images and templates in OpenNebula
12
+ permissions: "640" # UNIX-like permissions appliances will have within OpenNebula
13
+ opennebula:
14
+ secret: oneadmin:opennebula # If not specified, looking for secret in environment variable ONE_AUTH and file ~/.one/one_auth
15
+ endpoint: http://localhost:2633/RPC2 # If not specified, looking for endpoint in environment variable ONE_XMLRPC and file ~/.one/one_endpoint
16
+ datastores: # Array of OpenNebula datastores images will be uploaded to
17
+ - default
18
+ users: # Handle only images/templates of specified users
19
+ api-call-timeout: 3h # How long will cloudkeeper-one wait for image/template operations to finish in OpenNebula
20
+ logging:
21
+ level: ERROR # Logging level
22
+ file: /var/log/cloudkeeper/cloudkeeper-one.log # File to write log to. To turn off file logging leave this field empty.
23
+ debug: false # Debug mode
@@ -0,0 +1,20 @@
1
+ NAME = "<%= name %>"
2
+
3
+ <% if appliance.description %>
4
+ DESCRIPTION = "<%= "#{appliance.title} - #{appliance.description}" %>"
5
+ <% else %>
6
+ DESCRIPTION = "<%= appliance.title %>"
7
+ <% end %>
8
+
9
+ <% if image %>
10
+ TYPE = "OS"
11
+ DISK_TYPE = "BLOCK"
12
+ PATH = "<%= image.location %>"
13
+
14
+ <% case image.format %>
15
+ <% when :QCOW2 %>
16
+ DRIVER = "qcow2"
17
+ <% else %>
18
+ DRIVER = "raw"
19
+ <% end %>
20
+ <% end %>
@@ -0,0 +1,19 @@
1
+ NAME = "<%= name %>"
2
+
3
+ <% if appliance.description %>
4
+ DESCRIPTION = "<%= "#{appliance.title} - #{appliance.description}" %>"
5
+ <% else %>
6
+ DESCRIPTION = "<%= appliance.title %>"
7
+ <% end %>
8
+
9
+ MEMORY = "<%= appliance.ram || 1024 %>"
10
+ CPU = "<%= appliance.core || 0.25 %>"
11
+ VCPU = "<%= appliance.core || 1 %>"
12
+
13
+ OS = [
14
+ ARCH = "<%= appliance.architecture || "x86_64" %>"
15
+ ]
16
+
17
+ DISK = [
18
+ IMAGE_ID = "<%= image_id %>"
19
+ ]
@@ -0,0 +1,68 @@
1
+ module Cloudkeeper
2
+ module One
3
+ module ApplianceActions
4
+ module List
5
+ def list_image_lists
6
+ logger.debug 'Listing all image lists available in OpenNebula'
7
+ image_list_identifiers = template_handler.find_all.map do |template|
8
+ image_list_identifier = template["TEMPLATE/#{Cloudkeeper::One::Opennebula::Tags::APPLIANCE_IMAGE_LIST_ID}"]
9
+ unless image_list_identifier
10
+ logger.warn "Managed template #{template.id.inspect} is missing image list identifier"
11
+ next
12
+ end
13
+ image_list_identifier
14
+ end.compact.uniq.sort
15
+
16
+ logger.debug "Image lists available in OpenNebula: #{image_list_identifiers.inspect}"
17
+ image_list_identifiers.map { |ili| CloudkeeperGrpc::ImageListIdentifier.new image_list_identifier: ili }
18
+ end
19
+
20
+ def list_appliances(image_list_id)
21
+ logger.debug "Listing appliances with image list id #{image_list_id.inspect}"
22
+ templates = template_handler.find_by_image_list_id image_list_id
23
+ templates.uniq! { |template| template["TEMPLATE/#{Cloudkeeper::One::Opennebula::Tags::APPLIANCE_ID}"] }
24
+
25
+ templates.map do |template|
26
+ image = find_image_for_template template
27
+ populate_proto_appliance template, image
28
+ end
29
+ end
30
+
31
+ private
32
+
33
+ def find_image_for_template(template)
34
+ image = image_handler.find_by_name template.name
35
+ raise Cloudkeeper::One::Errors::Actions::ListingError, "Missing coresponding image for template #{template.id.inspect}" \
36
+ unless image
37
+ image
38
+ end
39
+
40
+ def populate_proto_appliance(template, image)
41
+ CloudkeeperGrpc::Appliance.new identifier: template["TEMPLATE/#{Cloudkeeper::One::Opennebula::Tags::APPLIANCE_ID}"].to_s,
42
+ description: template["TEMPLATE/#{Cloudkeeper::One::Opennebula::Tags::APPLIANCE_DESCRIPTION}"].to_s,
43
+ mpuri: template["TEMPLATE/#{Cloudkeeper::One::Opennebula::Tags::APPLIANCE_MPURI}"].to_s,
44
+ title: template["TEMPLATE/#{Cloudkeeper::One::Opennebula::Tags::APPLIANCE_TITLE}"].to_s,
45
+ group: template["TEMPLATE/#{Cloudkeeper::One::Opennebula::Tags::APPLIANCE_GROUP}"].to_s,
46
+ ram: template["TEMPLATE/#{Cloudkeeper::One::Opennebula::Tags::APPLIANCE_RAM}"].to_i,
47
+ core: template["TEMPLATE/#{Cloudkeeper::One::Opennebula::Tags::APPLIANCE_CORE}"].to_i,
48
+ version: template["TEMPLATE/#{Cloudkeeper::One::Opennebula::Tags::APPLIANCE_VERSION}"].to_s,
49
+ architecture: template["TEMPLATE/#{Cloudkeeper::One::Opennebula::Tags::APPLIANCE_ARCHITECTURE}"].to_s,
50
+ operating_system: template["TEMPLATE/#{Cloudkeeper::One::Opennebula::Tags::APPLIANCE_OPERATING_SYSTEM}"].to_s,
51
+ vo: template["TEMPLATE/#{Cloudkeeper::One::Opennebula::Tags::APPLIANCE_VO}"].to_s,
52
+ image: populate_proto_image(image),
53
+ expiration_date: template["TEMPLATE/#{Cloudkeeper::One::Opennebula::Tags::APPLIANCE_EXPIRATION_DATE}"].to_i,
54
+ image_list_identifier: template["TEMPLATE/#{Cloudkeeper::One::Opennebula::Tags::APPLIANCE_IMAGE_LIST_ID}"].to_s,
55
+ attributes: JSON.parse(Base64.strict_decode64(template["TEMPLATE/#{Cloudkeeper::One::Opennebula::Tags::APPLIANCE_ATTRIBUTES}"]))
56
+ end
57
+
58
+ def populate_proto_image(image)
59
+ CloudkeeperGrpc::Image.new mode: :LOCAL, location: '',
60
+ format: image["TEMPLATE/#{Cloudkeeper::One::Opennebula::Tags::IMAGE_FORMAT}"].upcase.to_sym,
61
+ checksum: image["TEMPLATE/#{Cloudkeeper::One::Opennebula::Tags::IMAGE_CHECKSUM}"].to_s,
62
+ size: image["TEMPLATE/#{Cloudkeeper::One::Opennebula::Tags::IMAGE_SIZE}"].to_i,
63
+ uri: image["TEMPLATE/#{Cloudkeeper::One::Opennebula::Tags::IMAGE_URI}"].to_s
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,73 @@
1
+ module Cloudkeeper
2
+ module One
3
+ module ApplianceActions
4
+ module Registration
5
+ include Utils::ImageDownload
6
+ include Utils::TemplatePreparation
7
+ include Cloudkeeper::One::ApplianceActions::Update
8
+ include Cloudkeeper::One::ApplianceActions::Removal
9
+
10
+ def register_or_update_appliance(proto_appliance)
11
+ raise Cloudkeeper::One::Errors::ArgumentError, 'appliance cannot be nil' unless proto_appliance
12
+
13
+ group = group_handler.find_by_name proto_appliance.vo
14
+ raise Cloudkeeper::One::Errors::Actions::RegistrationError, "Missing group with name #{proto_appliance.vo}" unless group
15
+
16
+ remove_images :find_by_appliance_id, proto_appliance.identifier
17
+
18
+ datastores = datastore_handler.find_by_names Cloudkeeper::One::Settings[:'opennebula-datastores']
19
+ datastores.each do |datastore|
20
+ image = register_image proto_appliance, datastore, group
21
+ register_or_update_template proto_appliance, image, group
22
+ end
23
+ end
24
+
25
+ private
26
+
27
+ def register_or_update_template(proto_appliance, image, group)
28
+ template = template_handler.find_by_name image.name
29
+ if template
30
+ update_template template, image, proto_appliance
31
+ return
32
+ end
33
+
34
+ register_template proto_appliance, image.id, image.name, group
35
+ end
36
+
37
+ def register_image(proto_appliance, datastore, group)
38
+ raise Cloudkeeper::One::Errors::ArgumentError, 'appliance and image cannot be nil' \
39
+ unless proto_appliance && proto_appliance.image
40
+
41
+ logger.debug "Registering image for appliance #{proto_appliance.identifier}, datastore #{datastore.name.inspect} and " \
42
+ "group #{group.name.inspect}"
43
+
44
+ proto_image = prepare_image proto_appliance
45
+ name = "#{proto_appliance.identifier}@#{datastore.name}"
46
+ template = prepare_template 'image.erb', appliance: proto_appliance, image: proto_image, name: name
47
+ image_handler.register template, datastore, group
48
+ end
49
+
50
+ def register_template(proto_appliance, image_id, name, group)
51
+ raise Cloudkeeper::One::Errors::ArgumentError, 'appliance cannot be nil' \
52
+ unless proto_appliance
53
+
54
+ logger.debug "Registering template for appliance #{proto_appliance.identifier}, image #{image_id.inspect} and " \
55
+ "group #{group.name.inspect}"
56
+
57
+ proto_image = proto_appliance.image
58
+ template = prepare_template 'template.erb', appliance: proto_appliance, image: proto_image,
59
+ name: name, image_id: image_id
60
+ template_handler.register template, group
61
+ end
62
+
63
+ def prepare_image(proto_appliance)
64
+ proto_image = proto_appliance.image
65
+ proto_image.location = download_image(proto_image.location, proto_image.username, proto_image.password) \
66
+ if proto_image.mode == :REMOTE
67
+
68
+ proto_image
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,57 @@
1
+ module Cloudkeeper
2
+ module One
3
+ module ApplianceActions
4
+ module Removal
5
+ def remove_appliance(appliance_id)
6
+ logger.debug "Removing templates for appliance #{appliance_id.inspect}"
7
+ remove_templates :find_by_appliance_id, appliance_id
8
+ logger.debug "Removing images for appliance #{appliance_id.inspect}"
9
+ remove_images :find_by_appliance_id, appliance_id
10
+ end
11
+
12
+ def remove_image_list(image_list_id)
13
+ logger.debug "Removing templates for image list #{image_list_id.inspect}"
14
+ remove_templates :find_by_image_list_id, image_list_id
15
+ logger.debug "Removing images for image list #{image_list_id.inspect}"
16
+ remove_images :find_by_image_list_id, image_list_id
17
+ end
18
+
19
+ def remove_expired
20
+ logger.debug 'Removing expired images...'
21
+ handle_iteration(image_handler.expired) { |item| image_handler.delete item }
22
+ end
23
+
24
+ def remove_templates(method, value)
25
+ handle_iteration(template_handler.send(method, value)) { |item| template_handler.delete item }
26
+ end
27
+
28
+ def remove_images(method, value)
29
+ handle_iteration(image_handler.send(method, value)) do |item|
30
+ image_handler.expire item
31
+ image_handler.delete item
32
+ end
33
+ end
34
+
35
+ private
36
+
37
+ def handle_iteration(items)
38
+ raise Cloudkeeper::One::Errors::ArgumentError, 'Iteration error handler was called without a block!' unless block_given?
39
+
40
+ error = nil
41
+ items.each do |item|
42
+ begin
43
+ yield item
44
+ rescue Cloudkeeper::One::Errors::StandardError => ex
45
+ error ||= Cloudkeeper::One::Errors::MultiError.new
46
+ error << ex
47
+ logger.error ex.message
48
+ next
49
+ end
50
+ end
51
+
52
+ raise error if error
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,34 @@
1
+ module Cloudkeeper
2
+ module One
3
+ module ApplianceActions
4
+ module Update
5
+ include Utils::TemplatePreparation
6
+
7
+ def update_appliance_metadata(proto_appliance)
8
+ raise Cloudkeeper::One::Errors::ArgumentError, 'appliance cannot be nil' unless proto_appliance
9
+
10
+ templates = template_handler.find_by_appliance_id proto_appliance.identifier
11
+ templates.each do |template|
12
+ image = image_handler.find_by_name template.name
13
+ raise Cloudkeeper::One::Errors::Actions::UpdateError, "Missing coresponding image for template #{template.id.inspect}"\
14
+ unless image
15
+ update_image image, proto_appliance
16
+ update_template template, image, proto_appliance
17
+ end
18
+ end
19
+
20
+ def update_image(image, proto_appliance)
21
+ logger.debug "Updating image metadata for appliance #{proto_appliance.identifier.inspect}"
22
+ image_template = prepare_template 'image.erb', appliance: proto_appliance, name: image.name
23
+ image_handler.update image, image_template
24
+ end
25
+
26
+ def update_template(template, image, proto_appliance)
27
+ logger.debug "Updating template metadata for appliance #{proto_appliance.identifier.inspect}"
28
+ template_template = prepare_template 'template.erb', appliance: proto_appliance, name: template.name, image_id: image.id
29
+ template_handler.update template, template_template
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end