cloudkeeper-one 1.0.0

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