dopv 0.11.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +23 -0
  3. data/.rspec +2 -0
  4. data/ChangeLog.md +456 -0
  5. data/Gemfile +6 -0
  6. data/Gemfile.lock +260 -0
  7. data/Guardfile +22 -0
  8. data/LICENSE.txt +177 -0
  9. data/README.md +214 -0
  10. data/Rakefile +6 -0
  11. data/bin/dopv +4 -0
  12. data/dopv.gemspec +52 -0
  13. data/lib/dopv.rb +166 -0
  14. data/lib/dopv/cli.rb +54 -0
  15. data/lib/dopv/cli/command_add.rb +37 -0
  16. data/lib/dopv/cli/command_export.rb +26 -0
  17. data/lib/dopv/cli/command_import.rb +32 -0
  18. data/lib/dopv/cli/command_list.rb +18 -0
  19. data/lib/dopv/cli/command_remove.rb +29 -0
  20. data/lib/dopv/cli/command_run.rb +38 -0
  21. data/lib/dopv/cli/command_update.rb +35 -0
  22. data/lib/dopv/cli/command_validate.rb +30 -0
  23. data/lib/dopv/infrastructure.rb +40 -0
  24. data/lib/dopv/infrastructure/providers/baremetal.rb +12 -0
  25. data/lib/dopv/infrastructure/providers/base.rb +422 -0
  26. data/lib/dopv/infrastructure/providers/openstack.rb +308 -0
  27. data/lib/dopv/infrastructure/providers/ovirt.rb +228 -0
  28. data/lib/dopv/infrastructure/providers/vsphere.rb +322 -0
  29. data/lib/dopv/log.rb +14 -0
  30. data/lib/dopv/persistent_disk.rb +128 -0
  31. data/lib/dopv/plan.rb +17 -0
  32. data/lib/dopv/state_store.rb +87 -0
  33. data/lib/dopv/version.rb +3 -0
  34. data/spec/data/hooks/test_hook_script_1 +9 -0
  35. data/spec/data/hooks/test_hook_script_2 +10 -0
  36. data/spec/data/plans/test-plan-1.yaml +140 -0
  37. data/spec/spec_helper.rb +112 -0
  38. data/spec/unit/dopv/dopv_spec.rb +7 -0
  39. data/spec/unit/dopv/persistent_disk_spec.rb +38 -0
  40. data/spec/unit/dopv/plan_spec.rb +34 -0
  41. data/spec/unit/dopv/version_spec.rb +17 -0
  42. metadata +401 -0
@@ -0,0 +1,17 @@
1
+ require 'forwardable'
2
+ require 'yaml'
3
+ require 'dop_common'
4
+
5
+ module Dopv
6
+ class Plan
7
+ extend Forwardable
8
+
9
+ attr_reader :plan_parser
10
+
11
+ def_delegators :@plan_parser, :name, :nodes, :max_in_flight, :valid?
12
+
13
+ def initialize(plan_parser)
14
+ @plan_parser = plan_parser
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,87 @@
1
+ #
2
+ # This is the DOPv disk state store
3
+ #
4
+ module Dopv
5
+ class StateStore
6
+
7
+ def initialize(plan_name, plan_store)
8
+ @plan_store = plan_store
9
+ @plan_name = plan_name
10
+ @state_store = @plan_store.state_store(plan_name, 'dopv')
11
+ end
12
+
13
+ def update(options = {})
14
+ if options[:clear]
15
+ clear(options)
16
+ elsif options[:ignore]
17
+ ignore(options)
18
+ else
19
+ update_state(options)
20
+ end
21
+ rescue DopCommon::UnknownVersionError => e
22
+ Dopv.log.warn("The state had an unknown plan version #{e.message}")
23
+ Dopv.log.warn("Bumping state to most recent version")
24
+ ignore(options)
25
+ rescue => e
26
+ Dopv.log.error("An error occured during update: #{e.message}")
27
+ Dopv.log.error("Please update with the 'clear' or 'ignore' option")
28
+ end
29
+
30
+ def export
31
+ @state_store.transaction(true) do
32
+ @state_store[:data_volumes] || {}
33
+ end
34
+ end
35
+
36
+ def import(data_volumes)
37
+ @state_store.transaction do
38
+ @state_store[:data_volumes] = data_volumes
39
+ end
40
+ end
41
+
42
+ def method_missing(m, *args, &block)
43
+ @state_store.send(m, *args, &block)
44
+ end
45
+
46
+ private
47
+
48
+ def clear(options)
49
+ @state_store.transaction do
50
+ Dopv.log.debug("Clearing the disk state for plan #{@plan_name}")
51
+ ver = @plan_store.show_versions(@plan_name).last
52
+ @state_store[:data_volumes] = {}
53
+ @state_store[:version] = ver
54
+ end
55
+ end
56
+
57
+ def ignore(options)
58
+ @state_store.transaction do
59
+ ver = @plan_store.show_versions(@plan_name).last
60
+ Dopv.log.debug("Ignoring update and setting disk state version of plan #{@plan_name} to #{ver}")
61
+ @state_store[:version] = ver
62
+ end
63
+ end
64
+
65
+ def update_state(options)
66
+ @state_store.update do |plan_diff|
67
+ Dopv.log.debug("Updating disk state for plan #{@plan_name}. This is the diff:")
68
+ Dopv.log.debug(plan_diff.to_s)
69
+ #TODO: Add update logic for plan updates here
70
+ end
71
+ end
72
+
73
+ end
74
+
75
+ class StateStoreObserver
76
+
77
+ def initialize(plan, state_store)
78
+ @plan = plan
79
+ @state_store = state_store
80
+ end
81
+
82
+ def update(notify_only = false)
83
+ @state_store.persist_state(@plan)
84
+ end
85
+
86
+ end
87
+ end
@@ -0,0 +1,3 @@
1
+ module Dopv
2
+ VERSION = '0.11.0'
3
+ end
@@ -0,0 +1,9 @@
1
+ #!/bin/bash
2
+
3
+ echo "This is a testing hook #1"
4
+ echo "Nodename: ${1}"
5
+ echo "Change flag: ${2}"
6
+
7
+ env
8
+
9
+ exit 0
@@ -0,0 +1,10 @@
1
+ #!/bin/bash
2
+
3
+ echo "This is a testing hook #2"
4
+ echo "Nodename: ${1}"
5
+ echo "Change flag: ${2}"
6
+
7
+ env
8
+
9
+ echo "Trying to list a non-existent directory"
10
+ ls -la /non-existent
@@ -0,0 +1,140 @@
1
+ name: test-1
2
+ max_in_flight: 5
3
+
4
+ credentials:
5
+ api_login_ovirt:
6
+ type: username_password
7
+ username: foo@bar
8
+ password: foobar
9
+ deployment_login:
10
+ type: username_password
11
+ username: root
12
+ password: baz
13
+
14
+ infrastructures:
15
+ test-1:
16
+ type: ovirt
17
+ endpoint: https://foo.bar.baz/api
18
+ credentials: api_login_ovirt
19
+ networks:
20
+ net-1:
21
+ ip_pool:
22
+ from: 192.168.0.10
23
+ to: 192.168.0.245
24
+ ip_netmask: 255.255.255.0
25
+ ip_defgw: 192.168.0.254
26
+ net-2:
27
+ ip_pool:
28
+ from: 192.168.1.10
29
+ to: 192.168.1.245
30
+ ip_netmask: 255.255.255.0
31
+ ip_defgw: 192.168.1.254
32
+ affinity_groups:
33
+ test-1:
34
+ positive: true
35
+ enforce: false
36
+ cluster: test-1
37
+
38
+ hooks:
39
+ pre_create_vm:
40
+ - spec/data/hooks/test_hook_script_1
41
+ - spec/data/hooks/test_hook_script_2
42
+ post_create_vm:
43
+ - spec/data/hooks/test_hook_script_1
44
+ - spec/data/hooks/test_hook_script_2
45
+ pre_destroy_vm:
46
+ - spec/data/hooks/test_hook_script_1
47
+ - spec/data/hooks/test_hook_script_2
48
+ post_destroy_vm:
49
+ - spec/data/hooks/test_hook_script_1
50
+ - spec/data/hooks/test_hook_script_2
51
+
52
+ nodes:
53
+ test-1.foo.bar.baz:
54
+ infrastructure: test-1
55
+ infrastructure_properties:
56
+ datacenter: test-1
57
+ cluster: test-1
58
+ keep_ha: false
59
+ affinity_groups:
60
+ - test-1
61
+ full_clone: false
62
+ image: img-1
63
+ interfaces:
64
+ eth0:
65
+ network: net-1
66
+ ip: 192.168.0.11
67
+ eth1:
68
+ network: net-2
69
+ ip: dhcp
70
+ set_gateway: false
71
+ disks:
72
+ disk-1:
73
+ pool: test-1
74
+ size: 1G
75
+ disk-2:
76
+ pool: test-2
77
+ size: 2G
78
+ thin: false
79
+ dns:
80
+ name_servers:
81
+ - 192.168.1.254
82
+ search_domains:
83
+ - foo.bar.baz
84
+ cores: 3
85
+ memory: 6G
86
+ credentials:
87
+ - deployment_login
88
+ test-2.foo.bar.baz:
89
+ infrastructure: test-1
90
+ infrastructure_properties:
91
+ datacenter: test-1
92
+ cluster: test-1
93
+ keep_ha: false
94
+ affinity_groups:
95
+ - test-1
96
+ full_clone: false
97
+ image: img-2
98
+ interfaces:
99
+ eth0:
100
+ network: net-1
101
+ ip: 192.168.0.12
102
+ disks:
103
+ disk-1:
104
+ pool: test-3
105
+ size: 1G
106
+ dns:
107
+ name_servers:
108
+ - 192.168.1.254
109
+ search_domains:
110
+ - foo.bar.baz
111
+ flavor: small
112
+ credentials:
113
+ - deployment_login
114
+
115
+ steps:
116
+ default:
117
+ - name: '0 - 1: ALL: Configure ssh login credentials'
118
+ nodes: all
119
+ max_in_flight: -1
120
+ set_plugin_defaults:
121
+ - plugins: "/^ssh/"
122
+ :credentials: deployment_login
123
+ command:
124
+ plugin: dummy
125
+ - name: '0 - 2: ALL: Make sure we can login to all nodes'
126
+ nodes: all
127
+ max_in_flight: -1
128
+ command:
129
+ plugin: ssh/wait_for_login
130
+ plugin_timeout: 600
131
+ - name: '0 - 3: ALL: Disable puppet to prevent automatic runs'
132
+ nodes: all
133
+ max_in_flight: -1
134
+ command:
135
+ plugin: ssh/custom
136
+ exec: |
137
+ echo "Dopi was here" > /tmp/dopi.txt
138
+ verify_commands:
139
+ - plugin: ssh/file_exists
140
+ file: "/tmp/dopi.txt"
@@ -0,0 +1,112 @@
1
+ require 'simplecov'
2
+ SimpleCov.start do
3
+ add_filter '/spec/'
4
+ add_filter '/.bundle/'
5
+ add_filter '/vendor/'
6
+ end
7
+
8
+ require 'dopv'
9
+
10
+ # This file was generated by the `rspec --init` command. Conventionally, all
11
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
12
+ # The generated `.rspec` file contains `--require spec_helper` which will cause
13
+ # this file to always be loaded, without a need to explicitly require it in any
14
+ # files.
15
+ #
16
+ # Given that it is always loaded, you are encouraged to keep this file as
17
+ # light-weight as possible. Requiring heavyweight dependencies from this file
18
+ # will add to the boot time of your test suite on EVERY test run, even for an
19
+ # individual file that may not need all of that loaded. Instead, consider making
20
+ # a separate helper file that requires the additional dependencies and performs
21
+ # the additional setup, and require it from the spec files that actually need
22
+ # it.
23
+ #
24
+ # The `.rspec` file also contains a few flags that are not defaults but that
25
+ # users commonly want.
26
+ #
27
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
28
+ RSpec.configure do |config|
29
+ # rspec-expectations config goes here. You can use an alternate
30
+ # assertion/expectation library such as wrong or the stdlib/minitest
31
+ # assertions if you prefer.
32
+ config.expect_with :rspec do |expectations|
33
+ # This option will default to `true` in RSpec 4. It makes the `description`
34
+ # and `failure_message` of custom matchers include text for helper methods
35
+ # defined using `chain`, e.g.:
36
+ # be_bigger_than(2).and_smaller_than(4).description
37
+ # # => "be bigger than 2 and smaller than 4"
38
+ # ...rather than:
39
+ # # => "be bigger than 2"
40
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
41
+ end
42
+
43
+ # rspec-mocks config goes here. You can use an alternate test double
44
+ # library (such as bogus or mocha) by changing the `mock_with` option here.
45
+ config.mock_with :rspec do |mocks|
46
+ # Prevents you from mocking or stubbing a method that does not exist on
47
+ # a real object. This is generally recommended, and will default to
48
+ # `true` in RSpec 4.
49
+ mocks.verify_partial_doubles = true
50
+ end
51
+
52
+ # This option will default to `:apply_to_host_groups` in RSpec 4 (and will
53
+ # have no way to turn it off -- the option exists only for backwards
54
+ # compatibility in RSpec 3). It causes shared context metadata to be
55
+ # inherited by the metadata hash of host groups and examples, rather than
56
+ # triggering implicit auto-inclusion in groups with matching metadata.
57
+ config.shared_context_metadata_behavior = :apply_to_host_groups
58
+
59
+ # The settings below are suggested to provide a good initial experience
60
+ # with RSpec, but feel free to customize to your heart's content.
61
+ =begin
62
+ # This allows you to limit a spec run to individual examples or groups
63
+ # you care about by tagging them with `:focus` metadata. When nothing
64
+ # is tagged with `:focus`, all examples get run. RSpec also provides
65
+ # aliases for `it`, `describe`, and `context` that include `:focus`
66
+ # metadata: `fit`, `fdescribe` and `fcontext`, respectively.
67
+ config.filter_run_when_matching :focus
68
+
69
+ # Allows RSpec to persist some state between runs in order to support
70
+ # the `--only-failures` and `--next-failure` CLI options. We recommend
71
+ # you configure your source control system to ignore this file.
72
+ config.example_status_persistence_file_path = "spec/examples.txt"
73
+
74
+ # Limits the available syntax to the non-monkey patched syntax that is
75
+ # recommended. For more details, see:
76
+ # - http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/
77
+ # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
78
+ # - http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/#zero-monkey-patching-mode
79
+ config.disable_monkey_patching!
80
+
81
+ # This setting enables warnings. It's recommended, but in some cases may
82
+ # be too noisy due to issues in dependencies.
83
+ config.warnings = true
84
+
85
+ # Many RSpec users commonly either run the entire suite or an individual
86
+ # file, and it's useful to allow more verbose output when running an
87
+ # individual spec file.
88
+ if config.files_to_run.one?
89
+ # Use the documentation formatter for detailed output,
90
+ # unless a formatter has already been configured
91
+ # (e.g. via a command-line flag).
92
+ config.default_formatter = 'doc'
93
+ end
94
+
95
+ # Print the 10 slowest examples and example groups at the
96
+ # end of the spec run, to help surface which specs are running
97
+ # particularly slow.
98
+ config.profile_examples = 10
99
+
100
+ # Run specs in random order to surface order dependencies. If you find an
101
+ # order dependency and want to debug it, you can fix the order by providing
102
+ # the seed, which is printed after each run.
103
+ # --seed 1234
104
+ config.order = :random
105
+
106
+ # Seed global randomization in this process using the `--seed` CLI option.
107
+ # Setting this allows you to use `--seed` to deterministically reproduce
108
+ # test failures related to randomization by passing the same `--seed` value
109
+ # as the one that triggered the failure.
110
+ Kernel.srand config.seed
111
+ =end
112
+ end
@@ -0,0 +1,7 @@
1
+ require 'spec_helper'
2
+
3
+ describe Dopv do
4
+ it 'should be a module' do
5
+ expect(Dopv).to be_kind_of(Module)
6
+ end
7
+ end
@@ -0,0 +1,38 @@
1
+ require 'spec_helper'
2
+ require 'securerandom'
3
+
4
+ describe Dopv::PersistentDisk::Entry do
5
+ before(:each) do
6
+ @disk_valid = {
7
+ :name => 'disk-1',
8
+ :id => SecureRandom.uuid,
9
+ :pool => 'pool-1',
10
+ :node => 'foo.bar.baz',
11
+ :size => 1024*1024*1024
12
+ }
13
+ @entry = Dopv::PersistentDisk::Entry.new(@disk_valid)
14
+ end
15
+
16
+ describe '#new' do
17
+ it 'creates a new entry object from proper input' do
18
+ expect(@entry).to be_an_instance_of(Dopv::PersistentDisk::Entry)
19
+ end
20
+
21
+ it 'will raise an exception if input is incorrect' do
22
+ expect { Dopv::PersistentDisk::Entry.new({}) }.to \
23
+ raise_error(Dopv::PersistentDisk::PersistentDiskError)
24
+ end
25
+ end
26
+
27
+ %w(name id pool size node).each do |accessor|
28
+ describe "##{accessor}" do
29
+ it "responds to #{accessor}" do
30
+ expect(@entry.respond_to?(:"#{accessor}")).to be true
31
+ end
32
+
33
+ it "returns entry's #{accessor}" do
34
+ expect(@entry.send(:"#{accessor}")).to eq @disk_valid[:"#{accessor}"]
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,34 @@
1
+ require 'spec_helper'
2
+ require 'yaml'
3
+
4
+ describe Dopv::Plan do
5
+ before(:each) do
6
+ plan_file = 'spec/data/plans/test-plan-1.yaml'
7
+ plan_parser = DopCommon::Plan.new(YAML.load_file(plan_file))
8
+ @plan = Dopv::Plan.new(plan_parser)
9
+ end
10
+
11
+ describe '#new' do
12
+ it 'should create a plan object' do
13
+ expect(@plan).to be_a Dopv::Plan
14
+ end
15
+ end
16
+
17
+ describe '#name' do
18
+ it 'is called test-1' do
19
+ expect(@plan.name).to eq 'test-1'
20
+ end
21
+ end
22
+
23
+ describe '#nodes' do
24
+ it 'creates two nodes' do
25
+ expect(@plan.nodes.length).to eq 2
26
+ end
27
+ end
28
+
29
+ describe '#valid?' do
30
+ it 'is a valid plan' do
31
+ expect(@plan.valid?).to eq true
32
+ end
33
+ end
34
+ end