cloudkeeper-one 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +11 -0
- data/.gitmodules +3 -0
- data/.rspec +2 -0
- data/.rubocop.yml +48 -0
- data/.travis.yml +22 -0
- data/CODE_OF_CONDUCT.md +49 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +17 -0
- data/README.md +98 -0
- data/Rakefile +17 -0
- data/bin/cloudkeeper-one +5 -0
- data/cloudkeeper-one.gemspec +44 -0
- data/config/cloudkeeper-one.yml +23 -0
- data/config/templates/image.erb +20 -0
- data/config/templates/template.erb +19 -0
- data/lib/cloudkeeper/one/appliance_actions/list.rb +68 -0
- data/lib/cloudkeeper/one/appliance_actions/registration.rb +73 -0
- data/lib/cloudkeeper/one/appliance_actions/removal.rb +57 -0
- data/lib/cloudkeeper/one/appliance_actions/update.rb +34 -0
- data/lib/cloudkeeper/one/appliance_actions/utils/image_download.rb +43 -0
- data/lib/cloudkeeper/one/appliance_actions/utils/template_preparation.rb +36 -0
- data/lib/cloudkeeper/one/appliance_actions/utils/templates/attributes.erb +23 -0
- data/lib/cloudkeeper/one/appliance_actions/utils.rb +10 -0
- data/lib/cloudkeeper/one/appliance_actions.rb +11 -0
- data/lib/cloudkeeper/one/cli.rb +185 -0
- data/lib/cloudkeeper/one/core_connector.rb +106 -0
- data/lib/cloudkeeper/one/errors/actions/action_error.rb +9 -0
- data/lib/cloudkeeper/one/errors/actions/listing_error.rb +9 -0
- data/lib/cloudkeeper/one/errors/actions/registration_error.rb +9 -0
- data/lib/cloudkeeper/one/errors/actions/update_error.rb +9 -0
- data/lib/cloudkeeper/one/errors/actions.rb +12 -0
- data/lib/cloudkeeper/one/errors/argument_error.rb +7 -0
- data/lib/cloudkeeper/one/errors/invalid_configuration_error.rb +7 -0
- data/lib/cloudkeeper/one/errors/multi_error.rb +25 -0
- data/lib/cloudkeeper/one/errors/network_connection_error.rb +7 -0
- data/lib/cloudkeeper/one/errors/opennebula/api_call_timeout_error.rb +9 -0
- data/lib/cloudkeeper/one/errors/opennebula/authentication_error.rb +9 -0
- data/lib/cloudkeeper/one/errors/opennebula/missing_pool_error.rb +9 -0
- data/lib/cloudkeeper/one/errors/opennebula/opennebula_error.rb +9 -0
- data/lib/cloudkeeper/one/errors/opennebula/resource_not_found_error.rb +9 -0
- data/lib/cloudkeeper/one/errors/opennebula/resource_retrieval_error.rb +9 -0
- data/lib/cloudkeeper/one/errors/opennebula/resource_state_error.rb +9 -0
- data/lib/cloudkeeper/one/errors/opennebula/stub_error.rb +9 -0
- data/lib/cloudkeeper/one/errors/opennebula/user_not_authorized_error.rb +9 -0
- data/lib/cloudkeeper/one/errors/opennebula.rb +17 -0
- data/lib/cloudkeeper/one/errors/standard_error.rb +7 -0
- data/lib/cloudkeeper/one/errors.rb +14 -0
- data/lib/cloudkeeper/one/opennebula/appliance_handler.rb +91 -0
- data/lib/cloudkeeper/one/opennebula/datastore_handler.rb +16 -0
- data/lib/cloudkeeper/one/opennebula/group_handler.rb +12 -0
- data/lib/cloudkeeper/one/opennebula/handler.rb +59 -0
- data/lib/cloudkeeper/one/opennebula/helper.rb +27 -0
- data/lib/cloudkeeper/one/opennebula/image_handler.rb +133 -0
- data/lib/cloudkeeper/one/opennebula/tags.rb +34 -0
- data/lib/cloudkeeper/one/opennebula/template_handler.rb +24 -0
- data/lib/cloudkeeper/one/opennebula.rb +14 -0
- data/lib/cloudkeeper/one/settings.rb +21 -0
- data/lib/cloudkeeper/one/version.rb +5 -0
- data/lib/cloudkeeper/one.rb +19 -0
- data/lib/cloudkeeper_grpc.rb +5 -0
- 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
data/.gitmodules
ADDED
data/.rspec
ADDED
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'
|
data/CODE_OF_CONDUCT.md
ADDED
@@ -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
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
|
data/bin/cloudkeeper-one
ADDED
@@ -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
|