cloudkeeper 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 +12 -0
- data/.gitmodules +3 -0
- data/.rspec +2 -0
- data/.rubocop.yml +61 -0
- data/.travis.yml +21 -0
- data/CODE_OF_CONDUCT.md +49 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +17 -0
- data/README.md +122 -0
- data/Rakefile +17 -0
- data/bin/cloudkeeper +5 -0
- data/cloudkeeper.gemspec +45 -0
- data/config/cloudkeeper.yml +27 -0
- data/lib/cloudkeeper.rb +16 -0
- data/lib/cloudkeeper/backend_connector.rb +123 -0
- data/lib/cloudkeeper/cli.rb +174 -0
- data/lib/cloudkeeper/command_executioner.rb +22 -0
- data/lib/cloudkeeper/entities.rb +11 -0
- data/lib/cloudkeeper/entities/appliance.rb +84 -0
- data/lib/cloudkeeper/entities/conversions.rb +48 -0
- data/lib/cloudkeeper/entities/convertables.rb +8 -0
- data/lib/cloudkeeper/entities/convertables/convertable.rb +63 -0
- data/lib/cloudkeeper/entities/convertables/ova.rb +54 -0
- data/lib/cloudkeeper/entities/image.rb +40 -0
- data/lib/cloudkeeper/entities/image_file.rb +23 -0
- data/lib/cloudkeeper/entities/image_formats.rb +7 -0
- data/lib/cloudkeeper/entities/image_formats/ova.rb +41 -0
- data/lib/cloudkeeper/entities/image_list.rb +84 -0
- data/lib/cloudkeeper/errors.rb +20 -0
- data/lib/cloudkeeper/errors/appliance.rb +7 -0
- data/lib/cloudkeeper/errors/appliance/propagation_error.rb +7 -0
- data/lib/cloudkeeper/errors/argument_error.rb +5 -0
- data/lib/cloudkeeper/errors/backend_error.rb +5 -0
- data/lib/cloudkeeper/errors/command_execution_error.rb +5 -0
- data/lib/cloudkeeper/errors/convertables.rb +7 -0
- data/lib/cloudkeeper/errors/convertables/convertability_error.rb +7 -0
- data/lib/cloudkeeper/errors/image.rb +9 -0
- data/lib/cloudkeeper/errors/image/conversion_error.rb +7 -0
- data/lib/cloudkeeper/errors/image/download_error.rb +7 -0
- data/lib/cloudkeeper/errors/image/format.rb +12 -0
- data/lib/cloudkeeper/errors/image/format/no_format_recognized_error.rb +9 -0
- data/lib/cloudkeeper/errors/image/format/no_required_format_available_error.rb +9 -0
- data/lib/cloudkeeper/errors/image/format/ova.rb +12 -0
- data/lib/cloudkeeper/errors/image/format/ova/invalid_archive_error.rb +11 -0
- data/lib/cloudkeeper/errors/image/format/ova/ova_format_error.rb +11 -0
- data/lib/cloudkeeper/errors/image/format/recognition_error.rb +9 -0
- data/lib/cloudkeeper/errors/image_list.rb +9 -0
- data/lib/cloudkeeper/errors/image_list/download_error.rb +7 -0
- data/lib/cloudkeeper/errors/image_list/retrieval_error.rb +7 -0
- data/lib/cloudkeeper/errors/image_list/verification_error.rb +7 -0
- data/lib/cloudkeeper/errors/invalid_configuration_error.rb +5 -0
- data/lib/cloudkeeper/errors/invalid_url_error.rb +5 -0
- data/lib/cloudkeeper/errors/network_connection_error.rb +5 -0
- data/lib/cloudkeeper/errors/nginx_error.rb +5 -0
- data/lib/cloudkeeper/errors/no_such_file_error.rb +5 -0
- data/lib/cloudkeeper/errors/not_implemented_error.rb +5 -0
- data/lib/cloudkeeper/errors/parsing.rb +10 -0
- data/lib/cloudkeeper/errors/parsing/invalid_appliance_hash_error.rb +7 -0
- data/lib/cloudkeeper/errors/parsing/invalid_image_hash_error.rb +7 -0
- data/lib/cloudkeeper/errors/parsing/invalid_image_list_hash_error.rb +7 -0
- data/lib/cloudkeeper/errors/parsing/parsing_error.rb +7 -0
- data/lib/cloudkeeper/errors/permission_denied_error.rb +5 -0
- data/lib/cloudkeeper/errors/standard_error.rb +5 -0
- data/lib/cloudkeeper/managers.rb +7 -0
- data/lib/cloudkeeper/managers/appliance_manager.rb +152 -0
- data/lib/cloudkeeper/managers/image_list_manager.rb +88 -0
- data/lib/cloudkeeper/managers/image_manager.rb +82 -0
- data/lib/cloudkeeper/nginx.rb +5 -0
- data/lib/cloudkeeper/nginx/http_server.rb +113 -0
- data/lib/cloudkeeper/nginx/templates/nginx.conf.erb +32 -0
- data/lib/cloudkeeper/settings.rb +19 -0
- data/lib/cloudkeeper/utils.rb +7 -0
- data/lib/cloudkeeper/utils/checksum.rb +9 -0
- data/lib/cloudkeeper/utils/hash.rb +9 -0
- data/lib/cloudkeeper/utils/url.rb +11 -0
- data/lib/cloudkeeper/version.rb +3 -0
- data/lib/cloudkeeper_grpc.rb +5 -0
- metadata +416 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: e3b7552e766ed9dff94b3c02ead5b2d7457146d7
|
4
|
+
data.tar.gz: 9fc5d03ddd65bd5502b9bbf7cfa716c5e5f17306
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 0a9273fe7503544dd2ed1749d577fbf49a8db35a7b6a9dc4f71230109000bf7e302d9b5c8050a955515b105af0dbcb48fc23a8923b06f3f4f9631cce3a020cae
|
7
|
+
data.tar.gz: 69ee71cc79f047eeb8efb5a80c512285feca404c2047c178d00d563fc57aab294ba7db8873ece88cf038e966167f466ce295e783d366750801bf7e719ac56eb1
|
data/.gitignore
ADDED
data/.gitmodules
ADDED
data/.rspec
ADDED
data/.rubocop.yml
ADDED
@@ -0,0 +1,61 @@
|
|
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
|
+
|
12
|
+
Style/Documentation:
|
13
|
+
Enabled: false
|
14
|
+
|
15
|
+
Metrics/MethodLength:
|
16
|
+
Max: 15
|
17
|
+
Exclude:
|
18
|
+
- 'lib/cloudkeeper/entities/appliance.rb'
|
19
|
+
- 'lib/cloudkeeper/nginx/http_server.rb'
|
20
|
+
|
21
|
+
Metrics/AbcSize:
|
22
|
+
Max: 20
|
23
|
+
Exclude:
|
24
|
+
- 'lib/cloudkeeper/entities/conversions.rb'
|
25
|
+
|
26
|
+
Metrics/ClassLength:
|
27
|
+
Max: 120
|
28
|
+
Exclude:
|
29
|
+
- 'lib/cloudkeeper/cli.rb'
|
30
|
+
|
31
|
+
RSpec/MultipleExpectations:
|
32
|
+
Enabled: false
|
33
|
+
|
34
|
+
RSpec/ExampleLength:
|
35
|
+
Enabled: false
|
36
|
+
|
37
|
+
RSpec/NestedGroups:
|
38
|
+
Max: 3
|
39
|
+
|
40
|
+
RSpec/NestedGroups:
|
41
|
+
Max: 4
|
42
|
+
Include:
|
43
|
+
- 'spec/cloudkeeper/backend_connector_spec.rb'
|
44
|
+
|
45
|
+
RSpec/SubjectStub:
|
46
|
+
Exclude:
|
47
|
+
- 'spec/cloudkeeper/backend_connector_spec.rb'
|
48
|
+
|
49
|
+
Metrics/ParameterLists:
|
50
|
+
Exclude:
|
51
|
+
- 'lib/cloudkeeper/entities/*.rb'
|
52
|
+
|
53
|
+
Metrics/BlockLength:
|
54
|
+
Exclude:
|
55
|
+
- 'Rakefile'
|
56
|
+
- '**/*.rake'
|
57
|
+
- 'spec/**/*.rb'
|
58
|
+
- '*.gemspec'
|
59
|
+
- 'lib/cloudkeeper/entities/appliance.rb'
|
60
|
+
- 'lib/cloudkeeper/entities/image_list.rb'
|
61
|
+
- 'lib/cloudkeeper/grpc/*'
|
data/.travis.yml
ADDED
@@ -0,0 +1,21 @@
|
|
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
|
+
fast_finish: true
|
14
|
+
|
15
|
+
branches:
|
16
|
+
only:
|
17
|
+
- master
|
18
|
+
|
19
|
+
before_install: 'gem install bundler -v 1.13.0'
|
20
|
+
|
21
|
+
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,122 @@
|
|
1
|
+
# cloudkeeper
|
2
|
+
cloudkeeper is an AppDB <-> cloud synchronization utility
|
3
|
+
|
4
|
+
[![Build Status](https://secure.travis-ci.org/the-cloudkeeper-project/cloudkeeper.png)](http://travis-ci.org/the-cloudkeeper-project/cloudkeeper)
|
5
|
+
[![Dependency Status](https://gemnasium.com/the-cloudkeeper-project/cloudkeeper.png)](https://gemnasium.com/the-cloudkeeper-project/cloudkeeper)
|
6
|
+
[![Gem Version](https://fury-badge.herokuapp.com/rb/cloudkeeper.png)](https://badge.fury.io/rb/cloudkeeper)
|
7
|
+
[![Code Climate](https://codeclimate.com/github/the-cloudkeeper-project/cloudkeeper.png)](https://codeclimate.com/github/the-cloudkeeper-project/cloudkeeper)
|
8
|
+
|
9
|
+
## What does cloudkeeper do?
|
10
|
+
cloudkeeper is able to read image lists provided by EGI AppDB, parse their content and decide what cloud appliances should be added, updated or removed from managed cloud. During the addition and update cloudkeeper is able to download an appliance's image and convert it to the format supported by the managed cloud.
|
11
|
+
|
12
|
+
Currently supported image formats are:
|
13
|
+
* QCOW2
|
14
|
+
* RAW
|
15
|
+
* VMDK
|
16
|
+
* OVA
|
17
|
+
|
18
|
+
## How does cloudkeeper work?
|
19
|
+
cloudkeeper communicates with cloud specific components via [gRPC](http://www.grpc.io/) communication framework to manage individual clouds.
|
20
|
+
|
21
|
+
Currently supported clouds:
|
22
|
+
* [OpenNebula](https://opennebula.org/) - component [cloudkeeper-one](https://github.com/the-cloudkeeper-project/cloudkeeper-one)
|
23
|
+
* [OpenStack](https://www.openstack.org/) - component [cloudkeeper-os](https://github.com/the-cloudkeeper-project/cloudkeeper-os) (under development)
|
24
|
+
|
25
|
+
## Requirements
|
26
|
+
* Ruby >= 2.2.0
|
27
|
+
* Rubygems
|
28
|
+
* qemu-img (image conversion utility)
|
29
|
+
* NGINX (optional)
|
30
|
+
|
31
|
+
## Installation
|
32
|
+
|
33
|
+
### From RubyGems.org
|
34
|
+
To install the most recent stable version
|
35
|
+
```bash
|
36
|
+
gem install cloudkeeper
|
37
|
+
```
|
38
|
+
|
39
|
+
### From source (dev)
|
40
|
+
**Installation from source should never be your first choice! Especially, if you are not
|
41
|
+
familiar with RVM, Bundler, Rake and other dev tools for Ruby!**
|
42
|
+
|
43
|
+
**However, if you wish to contribute to our project, this is the right way to start.**
|
44
|
+
|
45
|
+
To build and install the bleeding edge version from master
|
46
|
+
|
47
|
+
```bash
|
48
|
+
git clone git://github.com/the-cloudkeeper-project/cloudkeeper.git
|
49
|
+
cd cloudkeeper
|
50
|
+
gem install bundler
|
51
|
+
bundle install
|
52
|
+
bundle exec rake spec
|
53
|
+
```
|
54
|
+
|
55
|
+
## Configuration
|
56
|
+
### Create a configuration file for cloudkeeper
|
57
|
+
Configuration file can be read by cloudkeeper from these
|
58
|
+
three locations:
|
59
|
+
|
60
|
+
* `~/.cloudkeeper/cloudkeeper.yml`
|
61
|
+
* `/etc/cloudkeeper/cloudkeeper.yml`
|
62
|
+
* `PATH_TO_GEM_DIR/config/cloudkeeper.yml`
|
63
|
+
|
64
|
+
The default configuration file can be found at the last location
|
65
|
+
`PATH_TO_GEM_DIR/config/cloudkeeper.yml`.
|
66
|
+
|
67
|
+
## Usage
|
68
|
+
cloudkeeper is run with executable `cloudkeeper`. For further assistance run `cloudkeeper help sync`:
|
69
|
+
```bash
|
70
|
+
$ cloudkeeper help sync
|
71
|
+
|
72
|
+
Usage:
|
73
|
+
cloudkeeper sync --backend-endpoint=BACKEND-ENDPOINT --formats=one two three --image-dir=IMAGE-DIR --image-lists=one two three --qemu-img-binary=QEMU-IMG-BINARY
|
74
|
+
|
75
|
+
Options:
|
76
|
+
--image-lists=one two three # List of image lists to sync against
|
77
|
+
[--ca-dir=CA-DIR] # CA directory
|
78
|
+
# Default: /etc/grid-security/certificates/
|
79
|
+
[--authentication], [--no-authentication] # Client <-> server authentication
|
80
|
+
[--certificate=CERTIFICATE] # Core's host certificate
|
81
|
+
# Default: /etc/grid-security/hostcert.pem
|
82
|
+
[--key=KEY] # Core's host key
|
83
|
+
# Default: /etc/grid-security/hostkey.pem
|
84
|
+
--image-dir=IMAGE-DIR # Directory to store images to
|
85
|
+
# Default: /var/spool/cloudkeeper/images/
|
86
|
+
--qemu-img-binary=QEMU-IMG-BINARY # Path to qemu-img binary (image conversion)
|
87
|
+
# Default: /usr/bin/qemu-img
|
88
|
+
[--nginx-binary=NGINX-BINARY] # Path to nginx binary (HTTP server)
|
89
|
+
# Default: /usr/bin/nginx
|
90
|
+
[--remote-mode], [--no-remote-mode] # Remote mode starts HTTP server (NGINX) and serves images to backend via HTTP
|
91
|
+
[--nginx-error-log-file=NGINX-ERROR-LOG-FILE] # NGINX error log file
|
92
|
+
# Default: /var/log/cloudkeeper/nginx-error.log
|
93
|
+
[--nginx-access-log-file=NGINX-ACCESS-LOG-FILE] # NGINX access log file
|
94
|
+
# Default: /var/log/cloudkeeper/nginx-access.log
|
95
|
+
[--nginx-pid-file=NGINX-PID-FILE] # NGINX pid file
|
96
|
+
# Default: /var/run/cloudkeeper/nginx.pid
|
97
|
+
[--nginx-ip-address=NGINX-IP-ADDRESS] # IP address NGINX can listen on
|
98
|
+
# Default: 127.0.0.1
|
99
|
+
[--nginx-min-port=N] # Minimal port NGINX can listen on
|
100
|
+
# Default: 7300
|
101
|
+
[--nginx-max-port=N] # Maximal port NGINX can listen on
|
102
|
+
# Default: 7400
|
103
|
+
--backend-endpoint=BACKEND-ENDPOINT # Backend's gRPC endpoint
|
104
|
+
# Default: 127.0.0.1:50051
|
105
|
+
[--backend-certificate=BACKEND-CERTIFICATE] # Backend's certificate
|
106
|
+
# Default: /etc/grid-security/backendcert.pem
|
107
|
+
--formats=one two three # List of acceptable formats images can be converted to
|
108
|
+
# Default: ["qcow2"]
|
109
|
+
--logging-level=LOGGING-LEVEL
|
110
|
+
# Default: ERROR
|
111
|
+
# Possible values: DEBUG, INFO, WARN, ERROR, FATAL, UNKNOWN
|
112
|
+
[--logging-file=LOGGING-FILE] # File to write logs to
|
113
|
+
# Default: /var/log/cloudkeeper/cloudkeeper.log
|
114
|
+
[--debug], [--no-debug] # Runs cloudkeeper in debug mode
|
115
|
+
```
|
116
|
+
|
117
|
+
## Contributing
|
118
|
+
1. Fork it ( https://github.com/the-cloudkeeper-project/cloudkeeper/fork )
|
119
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
120
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
121
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
122
|
+
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
ADDED
data/cloudkeeper.gemspec
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'cloudkeeper/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'cloudkeeper'
|
8
|
+
spec.version = Cloudkeeper::VERSION
|
9
|
+
spec.authors = ['Michal Kimle']
|
10
|
+
spec.email = ['kimle.michal@gmail.com']
|
11
|
+
|
12
|
+
spec.summary = 'Synchronize cloud appliances between AppDB and cloud platforms'
|
13
|
+
spec.description = 'Synchronize cloud appliances between AppDB and cloud platforms'
|
14
|
+
spec.homepage = 'https://github.com/Misenko/cloudkeeper'
|
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.13'
|
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 'vcr', '~> 3.0'
|
30
|
+
spec.add_development_dependency 'webmock', '~> 2.1'
|
31
|
+
spec.add_development_dependency 'diffy', '~> 3.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 'mixlib-shellout', '~> 2.2'
|
37
|
+
spec.add_runtime_dependency 'grpc', '~> 1.0'
|
38
|
+
spec.add_runtime_dependency 'settingslogic', '~> 2.0'
|
39
|
+
spec.add_runtime_dependency 'zaru', '~> 0.1'
|
40
|
+
spec.add_runtime_dependency 'activesupport', '~> 4.0'
|
41
|
+
spec.add_runtime_dependency 'tilt', '~> 2.0'
|
42
|
+
spec.add_runtime_dependency 'faraday', '~> 0.11'
|
43
|
+
|
44
|
+
spec.required_ruby_version = '>= 2.2.0'
|
45
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
cloudkeeper:
|
2
|
+
image-lists: # List of image lists to sync against
|
3
|
+
ca-dir: /etc/grid-security/certificates/ # CA directory
|
4
|
+
authentication: false # core (client) <-> backend (server) authentication (certificate, key and backend-certificate options)
|
5
|
+
certificate: /etc/grid-security/hostcert.pem # Core's host certificate
|
6
|
+
key: /etc/grid-security/hostkey.pem # Core's host key
|
7
|
+
image-dir: /var/spool/cloudkeeper/images/ # Directory to store images to
|
8
|
+
binaries:
|
9
|
+
qemu-img: /usr/bin/qemu-img # qemu-img binary (image conversion) location
|
10
|
+
nginx: /usr/bin/nginx # nginx binary (HTTP server) location
|
11
|
+
remote-mode: false # Remote mode starts HTTP server (NGINX) and serves images to backend via HTTP
|
12
|
+
nginx:
|
13
|
+
error-log-file: /var/log/cloudkeeper/nginx-error.log # File for NGINX error log
|
14
|
+
access-log-file: /var/log/cloudkeeper/nginx-access.log # File for NGINX access log
|
15
|
+
pid-file: /var/run/cloudkeeper/nginx.pid # NGINX pid file
|
16
|
+
ip-address: 127.0.0.1 # IP address NGINX can listen on
|
17
|
+
min-port: 7300 # Minimal port NGINX can listen on
|
18
|
+
max-port: 7400 # Maximal port NGINX can listen on
|
19
|
+
backend:
|
20
|
+
endpoint: 127.0.0.1:50051 # Backend's gRPC endpoint
|
21
|
+
certificate: /etc/grid-security/backendcert.pem # Backend's certificate
|
22
|
+
formats: # List of acceptable formats images can be converted to
|
23
|
+
- qcow2
|
24
|
+
logging:
|
25
|
+
level: ERROR # Logging level
|
26
|
+
file: /var/log/cloudkeeper/cloudkeeper.log # File to write log to. To turn off file logging leave this field empty.
|
27
|
+
debug: false # Debug mode
|
data/lib/cloudkeeper.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'active_support/all'
|
2
|
+
require 'mixlib/shellout'
|
3
|
+
|
4
|
+
module Cloudkeeper
|
5
|
+
autoload :Settings, 'cloudkeeper/settings'
|
6
|
+
autoload :CLI, 'cloudkeeper/cli'
|
7
|
+
autoload :Utils, 'cloudkeeper/utils'
|
8
|
+
autoload :Nginx, 'cloudkeeper/nginx'
|
9
|
+
autoload :CommandExecutioner, 'cloudkeeper/command_executioner'
|
10
|
+
autoload :Entities, 'cloudkeeper/entities'
|
11
|
+
autoload :Managers, 'cloudkeeper/managers'
|
12
|
+
autoload :BackendConnector, 'cloudkeeper/backend_connector'
|
13
|
+
autoload :Errors, 'cloudkeeper/errors'
|
14
|
+
end
|
15
|
+
|
16
|
+
require 'cloudkeeper/version'
|
@@ -0,0 +1,123 @@
|
|
1
|
+
module Cloudkeeper
|
2
|
+
class BackendConnector
|
3
|
+
include Cloudkeeper::Entities::Conversions
|
4
|
+
|
5
|
+
attr_reader :grpc_client, :nginx
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@grpc_client = CloudkeeperGrpc::Communicator::Stub.new(Cloudkeeper::Settings[:'backend-endpoint'], credentials)
|
9
|
+
@nginx = Cloudkeeper::Nginx::HttpServer.new
|
10
|
+
end
|
11
|
+
|
12
|
+
def pre_action
|
13
|
+
logger.debug "'pre_action' gRPC method call"
|
14
|
+
handle_errors grpc_client.pre_action(Google::Protobuf::Empty.new, return_op: true), raise_exception: true
|
15
|
+
end
|
16
|
+
|
17
|
+
def post_action
|
18
|
+
logger.debug "'post_action' gRPC method call"
|
19
|
+
handle_errors grpc_client.post_action(Google::Protobuf::Empty.new, return_op: true)
|
20
|
+
end
|
21
|
+
|
22
|
+
def add_appliance(appliance)
|
23
|
+
logger.debug "'add_appliance' gRPC method call"
|
24
|
+
manage_appliance appliance, :add_appliance
|
25
|
+
end
|
26
|
+
|
27
|
+
def update_appliance(appliance)
|
28
|
+
logger.debug "'update_appliance' gRPC method call"
|
29
|
+
manage_appliance appliance, :update_appliance
|
30
|
+
end
|
31
|
+
|
32
|
+
def remove_appliance(appliance)
|
33
|
+
logger.debug "'remove_appliance' gRPC method call"
|
34
|
+
manage_appliance appliance, :remove_appliance
|
35
|
+
end
|
36
|
+
|
37
|
+
def remove_image_list(image_list_identifier)
|
38
|
+
logger.debug "'remove_image_list' gRPC method call"
|
39
|
+
handle_errors grpc_client.remove_image_list(
|
40
|
+
CloudkeeperGrpc::ImageListIdentifier.new(image_list_identifier: image_list_identifier),
|
41
|
+
return_op: true
|
42
|
+
)
|
43
|
+
end
|
44
|
+
|
45
|
+
def image_lists
|
46
|
+
logger.debug "'image_lists' gRPC method call"
|
47
|
+
handle_errors(grpc_client.image_lists(Google::Protobuf::Empty.new, return_op: true)) do |response|
|
48
|
+
response.map(&:image_list_identifier)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def appliances(image_list_identifier)
|
53
|
+
logger.debug "'appliances' gRPC method call"
|
54
|
+
handle_errors(
|
55
|
+
grpc_client.appliances(
|
56
|
+
CloudkeeperGrpc::ImageListIdentifier.new(image_list_identifier: image_list_identifier),
|
57
|
+
return_op: true
|
58
|
+
)
|
59
|
+
) do |response|
|
60
|
+
response.inject({}) do |acc, elem|
|
61
|
+
image = convert_image_proto(elem.image)
|
62
|
+
appliance = convert_appliance_proto elem, image
|
63
|
+
acc.merge appliance.identifier => appliance
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
private
|
69
|
+
|
70
|
+
def credentials
|
71
|
+
return :this_channel_is_insecure unless Cloudkeeper::Settings[:authentication]
|
72
|
+
|
73
|
+
GRPC::Core::ChannelCredentials.new(
|
74
|
+
File.read(Cloudkeeper::Settings[:'backend-certificate']),
|
75
|
+
File.read(Cloudkeeper::Settings[:key]),
|
76
|
+
File.read(Cloudkeeper::Settings[:certificate])
|
77
|
+
)
|
78
|
+
end
|
79
|
+
|
80
|
+
def handle_errors(operation, raise_exception: false)
|
81
|
+
return_value = operation.execute
|
82
|
+
return_value = yield(return_value) if block_given?
|
83
|
+
check_status operation.trailing_metadata, raise_exception: raise_exception
|
84
|
+
|
85
|
+
return_value
|
86
|
+
end
|
87
|
+
|
88
|
+
def check_status(metadata, raise_exception: false)
|
89
|
+
return if metadata[CloudkeeperGrpc::Constants::KEY_STATUS] == CloudkeeperGrpc::Constants::STATUS_SUCCESS
|
90
|
+
|
91
|
+
message = "#{metadata[CloudkeeperGrpc::Constants::KEY_STATUS]}: #{metadata[CloudkeeperGrpc::Constants::KEY_MESSAGE]}"
|
92
|
+
logger.error "Backend error: #{message}"
|
93
|
+
raise Cloudkeeper::Errors::BackendError, message if raise_exception
|
94
|
+
end
|
95
|
+
|
96
|
+
def set_remote_data(image_proto, access_data)
|
97
|
+
image_proto.mode = :REMOTE
|
98
|
+
image_proto.location = access_data[:url]
|
99
|
+
image_proto.username = access_data[:username]
|
100
|
+
image_proto.password = access_data[:password]
|
101
|
+
end
|
102
|
+
|
103
|
+
def prepare_image_proto(image)
|
104
|
+
image ? convert_image(image) : nil
|
105
|
+
end
|
106
|
+
|
107
|
+
def manage_appliance(appliance, call)
|
108
|
+
image = appliance.image
|
109
|
+
image_proto = prepare_image_proto image
|
110
|
+
|
111
|
+
if Cloudkeeper::Settings[:'remote-mode'] && image
|
112
|
+
nginx.start image_proto.location
|
113
|
+
set_remote_data image_proto, nginx.access_data
|
114
|
+
end
|
115
|
+
|
116
|
+
handle_errors grpc_client.send(call, convert_appliance(appliance, image_proto), return_op: true)
|
117
|
+
|
118
|
+
nginx.stop if Cloudkeeper::Settings[:'remote-mode'] && image
|
119
|
+
rescue Cloudkeeper::Errors::NginxError, Cloudkeeper::Errors::Image::Format::NoRequiredFormatAvailableError => ex
|
120
|
+
raise Cloudkeeper::Errors::Appliance::PropagationError, ex
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|