├── .gitignore ├── Gemfile ├── LICENSE ├── README.md ├── Rakefile ├── example_box ├── README.md ├── Vagrantfile ├── dummy.box └── metadata.json ├── lib ├── vagrant-ovirt3.rb └── vagrant-ovirt3 │ ├── action.rb │ ├── action │ ├── connect_ovirt.rb │ ├── create_network_interfaces.rb │ ├── create_vm.rb │ ├── destroy_vm.rb │ ├── halt_vm.rb │ ├── is_created.rb │ ├── is_running.rb │ ├── message_already_created.rb │ ├── message_already_up.rb │ ├── message_not_created.rb │ ├── message_not_suspended.rb │ ├── message_not_up.rb │ ├── message_saving_state.rb │ ├── read_ssh_info.rb │ ├── read_state.rb │ ├── resize_disk.rb │ ├── set_name_of_domain.rb │ ├── start_vm.rb │ ├── suspend_vm.rb │ ├── sync_folders.rb │ ├── wait_till_down.rb │ └── wait_till_up.rb │ ├── cap │ └── nic_mac_addresses.rb │ ├── config.rb │ ├── errors.rb │ ├── plugin.rb │ ├── provider.rb │ ├── util.rb │ ├── util │ ├── collection.rb │ └── timer.rb │ └── version.rb ├── locales └── en.yml ├── tools └── prepare_redhat_for_box.sh └── vagrant-ovirt3.gemspec /.gitignore: -------------------------------------------------------------------------------- 1 | *.gem 2 | .bundle 3 | Gemfile.lock 4 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | group :development do 4 | gem 'vagrant', :git => 'git://github.com/mitchellh/vagrant.git' 5 | end 6 | 7 | group :plugins do 8 | gem 'vagrant-ovirt3', :path => '.' 9 | end 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 Marcus Young 2 | 3 | MIT License 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | "Software"), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Vagrant oVirt/RHEV v3 Provider 2 | [![Gem Version](https://badge.fury.io/rb/vagrant-ovirt3.svg)](http://badge.fury.io/rb/vagrant-ovirt3) 3 | [![vagrant-ovirt3 API Documentation](https://www.omniref.com/ruby/gems/vagrant-ovirt3.png)](https://www.omniref.com/ruby/gems/vagrant-ovirt3) 4 | 5 | This is a [Vagrant](http://www.vagrantup.com) 1.1+ plugin that adds an 6 | [oVirt v3](http://ovirt.org) and 7 | [rhev v3](http://www.redhat.com/products/virtualization/) provider to Vagrant, 8 | allowing Vagrant to control and provision machines in oVirt and RHEV. 9 | 10 | In this document, both oVirt and RHEV names are used interchangeably and 11 | represent the same platform on top of which this provider should work. 12 | 13 | ## Installation 14 | 15 | ``` 16 | $ vagrant plugin uninstall vagrant-ovirt 17 | $ vagrant plugin install vagrant-ovirt3 18 | $ vagrant up --provider=ovirt3 19 | ``` 20 | 21 | ## Vagrant Project Preparation 22 | 23 | Create a Vagrantfile that looks like the following, filling in 24 | your information where necessary. 25 | 26 | ```ruby 27 | Vagrant.configure('2') do |config| 28 | config.vm.box = 'ovirt' 29 | config.vm.box_url = 'https://github.com/myoung34/vagrant-ovirt3/blob/master/example_box/dummy.box?raw=true' 30 | 31 | config.vm.network :private_network, 32 | :ip => '192.168.56.100', :nictype => 'virtio', :netmask => '255.255.255.0', #normal network configuration 33 | :ovirt__ip => '10.101.55.72', :ovirt__network_name => 'ovirtmgmt', :ovirt__gateway => '10.101.55.1' # oVirt specific information, overwrites previous on oVirt provider 34 | 35 | config.vm.provider :ovirt3 do |ovirt| 36 | ovirt.template = 'template' 37 | ovirt.cpus = 1 38 | ovirt.memory = 1024 39 | ovirt.console = 'vnc' #could also be 'spice' 40 | ovirt.url = 'https://youroVirtmaster:443' 41 | ovirt.username = 'username' 42 | ovirt.password = 'password' 43 | ovirt.datacenter = 'datacenter' 44 | ovirt.quota = "e92124b9-22f4-4cef-bcd6-b9ae22155dcd" 45 | ovirt.ca_no_verify = true 46 | ovirt.memory_guaranteed = 2048 # Supported by oVirt 3.6 and above only 47 | ovirt.connect_timeout = 30 48 | end 49 | end 50 | ``` 51 | 52 | ### RHEV/oVirt Configuration Options 53 | 54 | This provider exposes quite a few provider-specific configuration options: 55 | 56 | * `url` - URL to management interface. 57 | * `username` - Username to access oVirt. 58 | * `password` - Password to access oVirt. 59 | * `datacenter` - oVirt datacenter name, where machines will be created. 60 | * `cluster` - oVirt cluster name. Defaults to first cluster found. 61 | * `filtered_api` - Set to `true` if oVirt user does not have admin priviliges. 62 | * `ca_no_verify` - Set to `true` to not verify TLS certificates. 63 | * `ca_cert_store` - Certificate authority store to use for verification (this 64 | option will be replaced with `ca_cert` in a future version). 65 | * `ca_cert_file` - Like `ca_cert_store`, but provides a file containing a single 66 | certificate. 67 | * `quota` - The ID of the quota to use. This can be retrieved via the REST API 68 | * `memory_guaranteed` - The amount of memory guaranteed to the VM. *Supported by oVirt 3.6 and above only* 69 | * `connect_timeout` - The amount of time to wait until the VM changes state 70 | 71 | ### Domain Specific Options 72 | 73 | * `memory` - Amount of memory in MBytes. Defaults to 512 if not set. 74 | * `cpus` - Number of virtual cpus. Defaults to 1 if not set. 75 | * `template` - Name of template from which new VM should be created. 76 | * `template_version` - If a template has sub-versions, specify a sub-version 77 | number or name. 78 | * `console` - Console type to use. Can be 'vnc' or 'spice'. Default is 'spice' 79 | * `disk_size` - If set, the first volume of the VM will automatically be resized 80 | to the specified value. disk_size is in GB 81 | * `user_data` - If given, user data is made available to the VM via a virtual 82 | floppy disk. This data is used to configure VMs via cloud-init. The value for 83 | `user_data` should generally be a string in [cloud-config format][]. 84 | 85 | [cloud-config format]: https://cloudinit.readthedocs.org/en/latest/topics/examples.html 86 | 87 | Specific domain settings can be set for each domain separately in multi-VM 88 | environment. Example below shows a part of Vagrantfile, where specific options 89 | are set for dbserver domain. 90 | 91 | ```ruby 92 | Vagrant.configure("2") do |config| 93 | config.vm.define :dbserver do |dbserver| 94 | dbserver.vm.box = "ovirt" 95 | dbserver.vm.provider :ovirt3 do |vm| 96 | vm.memory = 2048 97 | vm.cpus = 2 98 | vm.template = "centos63-vagrant-base" 99 | end 100 | end 101 | 102 | # ... 103 | ``` 104 | 105 | ## Multiple provider Vagrantfile with Provisioners Example 106 | 107 | This example allows you to spin up a box under virtualbox using `$ vagrant up` as well as a VM under oVirt using a template with `$ vagrant up --provider=ovirt` 108 | Note, the network information will differ between the two. Under virtualbox, it should come up with an IP of `192.168.56.100`. Under oVirt it should come up as `10.101.55.72` if successful. 109 | 110 | ```ruby 111 | Vagrant.configure('2') do |config| 112 | config.vm.box = 'mybox' 113 | 114 | config.vm.network :private_network, 115 | :ip => '192.168.56.100', :nictype => 'virtio', :netmask => '255.255.255.0' #normal network configuration 116 | :ovirt__ip => '10.101.55.72', :ovirt__network_name => 'ovirtmgmt', :ovirt__gateway => '10.101.55.1', # oVirt specific information, overwrites previous on oVirt provider 117 | 118 | config.vm.provider :virtualbox do |vb| 119 | vb.customize [ 120 | # Key Value 121 | 'modifyvm', :id, 122 | '--cpuexecutioncap', '90', 123 | '--memory', '1376', 124 | '--nictype2', 'virtio', 125 | ] 126 | end 127 | 128 | 129 | config.vm.provider :ovirt3 do |ovirt| 130 | ovirt.template = 'template' 131 | ovirt.cpus = 1 132 | ovirt.memory = 1024 133 | ovirt.console = 'vnc' #could also be 'spice' 134 | ovirt.url = 'https://youroVirtmaster:443' 135 | ovirt.username = 'username' 136 | ovirt.password = 'password' 137 | ovirt.datacenter = 'datacenter' 138 | end 139 | 140 | config.vm.provision 'shell' do |shell| 141 | shell.inline = 'uname -a > /var/log/something.log 2>&1' 142 | end 143 | 144 | config.vm.provision :puppet do |puppet| 145 | puppet.options = [ 146 | "--environment development", 147 | '--hiera_config=/etc/puppet/hiera/hiera.yaml', 148 | ] 149 | puppet.manifests_path = './manifests' 150 | puppet.manifest_file = 'default.pp' 151 | end 152 | ``` 153 | 154 | ### Parallel Support 155 | 156 | By default VMs will be created and provisioned in parallel. If this causes 157 | resource issues or you want VMs to be created in series use --no-parallel 158 | 159 | ``` 160 | $ vagrant up 161 | $ vagrant up --no-parallel 162 | ``` 163 | 164 | ### How Project Is Created 165 | 166 | Vagrant goes through steps below when creating new project: 167 | 168 | 1. Connect to oVirt via REST API on every REST query. 169 | 2. Create new oVirt machine from template with additional network interfaces. 170 | 3. Start oVirt machine. 171 | 4. Check for IP address of VM using the REST API. 172 | 5. Wait till SSH is available. 173 | 6. Sync folders via `rsync` and run Vagrant provisioner on new domain if 174 | setup in Vagrantfile. 175 | 176 | ## Network Interfaces 177 | 178 | Networking features in the form of `config.vm.network` support private networks 179 | concept. No public network or port forwarding are supported in current version 180 | of provider. 181 | 182 | An examples of network interface definitions: 183 | 184 | ```ruby 185 | config.vm.define :test_vm1 do |test_vm1| 186 | test_vm1.vm.network :private_network, 187 | :ip => "10.20.30.40", 188 | :netmask => "255.255.255.0", 189 | :ovirt__network_name => "ovirt_networkname" 190 | end 191 | ``` 192 | 193 | In example below, one additional network interface is created for VM test_vm1. 194 | Interface is connected to `ovirt_networkname` network and configured to ip 195 | address `10.20.30.40/24`. If you omit ip address, interface will be configured 196 | dynamically via dhcp. 197 | 198 | ## Box Format 199 | 200 | Every provider in Vagrant must introduce a custom box format. This provider 201 | introduces oVirt boxes. You can view an example box in the 202 | [example_box](https://github.com/myoung34/vagrant-ovirt3/tree/master/example_box) 203 | directory. That directory also contains instructions on how to build a box. 204 | 205 | The box is a tarball containing: 206 | 207 | * `metadata.json` file describing box image (just a provider name). 208 | * `Vagrantfile` that does default settings for the provider-specific configuration for this provider. 209 | 210 | ## Contributing 211 | 212 | 1. Fork it 213 | 2. Create your feature branch (`git checkout -b my-new-feature`) 214 | 3. Commit your changes (`git commit -am 'Add some feature'`) 215 | 4. Push to the branch (`git push origin my-new-feature`) 216 | 5. Create new Pull Request 217 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env rake 2 | 3 | #require 'rubygems' 4 | #require 'bundler/setup' 5 | require 'bundler/gem_tasks' 6 | Bundler::GemHelper.install_tasks 7 | 8 | -------------------------------------------------------------------------------- /example_box/README.md: -------------------------------------------------------------------------------- 1 | # Vagrant oVirt3 Example Box 2 | 3 | Vagrant providers each require a custom provider-specific box format. 4 | This folder shows the example contents of a box for the `ovirt3` provider. 5 | To turn this into a box: 6 | 7 | ``` 8 | $ tar cvzf dummy.box ./metadata.json ./Vagrantfile 9 | ``` 10 | 11 | This box works by using Vagrant's built-in Vagrantfile merging to setup 12 | defaults for oVirt. These defaults can easily be overwritten by higher-level 13 | Vagrantfiles (such as project root Vagrantfiles). 14 | -------------------------------------------------------------------------------- /example_box/Vagrantfile: -------------------------------------------------------------------------------- 1 | # -*- mode: ruby -*- 2 | # vi: set ft=ruby : 3 | 4 | Vagrant.configure("2") do |config| 5 | config.vm.box = 'ovirt3' 6 | config.vm.box_url = 'https://github.com/myoung34/vagrant-ovirt3/blob/master/example_box/dummy.box?raw=true' 7 | 8 | config.vm.provider :ovirt3 do |ovirt| 9 | ovirt.url = "https://ovirt.example.com:443" 10 | ovirt.username = "username" 11 | ovirt.password = "secret" 12 | ovirt.datacenter = "Datacenter name" 13 | ovirt.template = "Template name" 14 | ovirt.quota = "e92124b9-22f4-4cef-bcd6-b9ae22155dcd" 15 | ovirt.cpus = 1 16 | ovirt.memory = 512 17 | ovirt.ca_no_verify = true 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /example_box/dummy.box: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myoung34/vagrant-ovirt3/4f9cfe8f89b243a0c2070161377b458aab5dc42d/example_box/dummy.box -------------------------------------------------------------------------------- /example_box/metadata.json: -------------------------------------------------------------------------------- 1 | { 2 | "provider": "ovirt3" 3 | } 4 | 5 | -------------------------------------------------------------------------------- /lib/vagrant-ovirt3.rb: -------------------------------------------------------------------------------- 1 | require 'pathname' 2 | require 'vagrant-ovirt3/plugin' 3 | 4 | module VagrantPlugins 5 | module OVirtProvider 6 | lib_path = Pathname.new(File.expand_path("../vagrant-ovirt3", __FILE__)) 7 | autoload :Action, lib_path.join("action") 8 | autoload :Errors, lib_path.join("errors") 9 | autoload :Util, lib_path.join("util") 10 | 11 | @@ovirt_connection = nil 12 | @@ovirt_client = nil 13 | def self.ovirt_connection 14 | @@ovirt_connection 15 | end 16 | 17 | def self.ovirt_connection=(conn) 18 | @@ovirt_connection = conn 19 | end 20 | 21 | def self.ovirt_client 22 | @@ovirt_client 23 | end 24 | 25 | def self.ovirt_client=(conn) 26 | @@ovirt_client = conn 27 | end 28 | 29 | 30 | def self.source_root 31 | @source_root ||= Pathname.new(File.expand_path("../../", __FILE__)) 32 | end 33 | end 34 | end 35 | -------------------------------------------------------------------------------- /lib/vagrant-ovirt3/action.rb: -------------------------------------------------------------------------------- 1 | require 'vagrant/action/builder' 2 | 3 | module VagrantPlugins 4 | module OVirtProvider 5 | module Action 6 | # Include the built-in modules so we can use them as top-level things. 7 | include Vagrant::Action::Builtin 8 | 9 | # This action is called to bring the box up from nothing. 10 | def self.action_up 11 | Vagrant::Action::Builder.new.tap do |b| 12 | b.use ConfigValidate 13 | b.use ConnectOVirt 14 | b.use Call, ReadState do |env, b2| 15 | if env[:machine_state_id] == :up 16 | b2.use SyncFolders 17 | b2.use MessageAlreadyUp 18 | next 19 | end 20 | 21 | if env[:machine_state_id] == :saving_state 22 | b2.use MessageSavingState 23 | next 24 | end 25 | 26 | if env[:machine_state_id] == :not_created 27 | b2.use SetNameOfDomain 28 | b2.use CreateVM 29 | b2.use ResizeDisk 30 | 31 | b2.use Provision 32 | b2.use CreateNetworkInterfaces 33 | 34 | b2.use SetHostname 35 | end 36 | 37 | b2.use StartVM 38 | b2.use WaitTillUp 39 | b2.use SyncFolders 40 | end 41 | end 42 | end 43 | 44 | def self.action_start 45 | with_ovirt do |env, b| 46 | if env[:machine_state_id] == :down 47 | b.use StartVM 48 | b.use WaitTillUp 49 | b.use SyncFolders 50 | end 51 | end 52 | end 53 | 54 | def self.action_halt 55 | with_ovirt do |env, b| 56 | if env[:machine_state_id] != :up 57 | b.use MessageNotUp 58 | next 59 | end 60 | b.use HaltVM 61 | end 62 | end 63 | 64 | def self.action_suspend 65 | with_ovirt do |env, b| 66 | if env[:machine_state_id] != :up 67 | b.use MessageNotUp 68 | next 69 | end 70 | b.use SuspendVM 71 | end 72 | end 73 | 74 | def self.action_resume 75 | with_ovirt do |env, b| 76 | if env[:machine_state_id] == :saving_state 77 | b.use MessageSavingState 78 | next 79 | end 80 | if env[:machine_state_id] != :suspended 81 | b.use MessageNotSuspended 82 | next 83 | end 84 | b.use StartVM 85 | b.use WaitTillUp 86 | b.use SyncFolders 87 | end 88 | end 89 | 90 | # This is the action that is primarily responsible for completely 91 | # freeing the resources of the underlying virtual machine. 92 | def self.action_destroy 93 | Vagrant::Action::Builder.new.tap do |b| 94 | b.use ConfigValidate 95 | b.use Call, IsCreated do |env, b2| 96 | if !env[:result] 97 | b2.use MessageNotCreated 98 | next 99 | end 100 | 101 | b2.use ConnectOVirt 102 | b2.use ProvisionerCleanup, :before if defined?(ProvisionerCleanup) 103 | b2.use HaltVM 104 | b2.use WaitTillDown 105 | b2.use DestroyVM 106 | end 107 | end 108 | end 109 | 110 | # This action is called to read the state of the machine. The resulting 111 | # state is expected to be put into the `:machine_state_id` key. 112 | def self.action_read_state 113 | Vagrant::Action::Builder.new.tap do |b| 114 | b.use ConfigValidate 115 | b.use ConnectOVirt 116 | b.use ReadState 117 | end 118 | end 119 | 120 | # This action is called to read the SSH info of the machine. The 121 | # resulting state is expected to be put into the `:machine_ssh_info` 122 | # key. 123 | def self.action_read_ssh_info 124 | Vagrant::Action::Builder.new.tap do |b| 125 | b.use ConfigValidate 126 | b.use ConnectOVirt 127 | b.use ReadSSHInfo 128 | end 129 | end 130 | 131 | def self.action_ssh 132 | Vagrant::Action::Builder.new.tap do |b| 133 | b.use ConfigValidate 134 | b.use ConnectOVirt 135 | b.use Call, ReadState do |env, b2| 136 | if env[:machine_state_id] == :not_created 137 | b2.use MessageNotCreated 138 | next 139 | end 140 | if env[:machine_state_id] != :up 141 | b2.use MessageNotUp 142 | next 143 | end 144 | b2.use SSHExec 145 | end 146 | end 147 | end 148 | 149 | def self.action_ssh_run 150 | Vagrant::Action::Builder.new.tap do |b| 151 | b.use ConfigValidate 152 | b.use ConnectOVirt 153 | b.use Call, ReadState do |env, b2| 154 | if env[:machine_state_id] == :not_created 155 | b2.use MessageNotCreated 156 | next 157 | end 158 | if env[:machine_state_id] != :up 159 | b2.use MessageNotUp 160 | next 161 | end 162 | b2.use SSHRun 163 | end 164 | end 165 | end 166 | 167 | def self.action_provision 168 | Vagrant::Action::Builder.new.tap do |b| 169 | b.use ConfigValidate 170 | b.use Call, IsCreated do |env, b2| 171 | if !env[:result] 172 | b2.use MessageNotCreated 173 | next 174 | end 175 | b2.use Provision 176 | b2.use SyncFolders 177 | end 178 | end 179 | end 180 | 181 | # This is the action implements the reload command 182 | # It uses the halt and start actions 183 | def self.action_reload 184 | Vagrant::Action::Builder.new.tap do |b| 185 | b.use Call, IsCreated do |env, b2| 186 | if !env[:result] 187 | b2.use MessageNotCreated 188 | next 189 | end 190 | b2.use Call, IsRunning do |env2, b3| 191 | # if vm is running keep going 192 | if env2[:result] 193 | b3.use ConfigValidate 194 | b3.use action_halt 195 | b3.use action_start 196 | end 197 | end 198 | end 199 | end 200 | end 201 | 202 | action_root = Pathname.new(File.expand_path("../action", __FILE__)) 203 | autoload :ConnectOVirt, action_root.join("connect_ovirt") 204 | autoload :IsCreated, action_root.join("is_created") 205 | autoload :IsRunning, action_root.join("is_running") 206 | autoload :SetNameOfDomain, action_root.join("set_name_of_domain") 207 | autoload :CreateVM, action_root.join("create_vm") 208 | autoload :CreateNetworkInterfaces, action_root.join("create_network_interfaces") 209 | autoload :ResizeDisk, action_root.join("resize_disk") 210 | autoload :StartVM, action_root.join("start_vm") 211 | autoload :MessageNotCreated, action_root.join("message_not_created") 212 | autoload :HaltVM, action_root.join("halt_vm") 213 | autoload :SuspendVM, action_root.join("suspend_vm") 214 | autoload :DestroyVM, action_root.join("destroy_vm") 215 | autoload :ReadState, action_root.join("read_state") 216 | autoload :ReadSSHInfo, action_root.join("read_ssh_info") 217 | autoload :WaitTillUp, action_root.join("wait_till_up") 218 | autoload :WaitTillDown, action_root.join("wait_till_down") 219 | autoload :SyncFolders, action_root.join("sync_folders") 220 | autoload :MessageAlreadyCreated, action_root.join("message_already_created") 221 | autoload :MessageAlreadyUp, action_root.join("message_already_up") 222 | autoload :MessageNotUp, action_root.join("message_not_up") 223 | autoload :MessageSavingState, action_root.join("message_saving_state") 224 | autoload :MessageNotSuspended, action_root.join("message_not_suspended") 225 | 226 | autoload :ProvisionerCleanup, 'vagrant/action/builtin/provisioner_cleanup' 227 | 228 | private 229 | def self.with_ovirt 230 | Vagrant::Action::Builder.new.tap do |b| 231 | b.use ConfigValidate 232 | b.use ConnectOVirt 233 | b.use Call, ReadState do |env, b2| 234 | if !env[:machine_state_id] == :not_created 235 | b2.use MessageNotCreated 236 | next 237 | end 238 | yield env, b2 239 | end 240 | end 241 | end 242 | end 243 | end 244 | end 245 | 246 | -------------------------------------------------------------------------------- /lib/vagrant-ovirt3/action/connect_ovirt.rb: -------------------------------------------------------------------------------- 1 | require 'fog' 2 | require 'log4r' 3 | require 'pp' 4 | require 'rbovirt' 5 | 6 | module VagrantPlugins 7 | module OVirtProvider 8 | module Action 9 | class ConnectOVirt 10 | def initialize(app, env) 11 | @logger = Log4r::Logger.new("vagrant_ovirt3::action::connect_ovirt") 12 | @app = app 13 | end 14 | 15 | def call(env) 16 | 17 | # We need both, fog and rbovirt client. Sometimes fog doesn't 18 | # support some operations like managing quotas, or working with 19 | # networks. For this rbovirt client is used. 20 | env[:ovirt_client] = OVirtProvider.ovirt_client if \ 21 | OVirtProvider.ovirt_client != nil 22 | 23 | if OVirtProvider.ovirt_connection != nil 24 | env[:ovirt_compute] = OVirtProvider.ovirt_connection 25 | return @app.call(env) 26 | end 27 | 28 | # Get config options for ovirt provider. 29 | config = env[:machine].provider_config 30 | 31 | conn_attr = {} 32 | conn_attr[:provider] = 'ovirt' 33 | conn_attr[:ovirt_url] = "#{config.url}/api" 34 | conn_attr[:ovirt_username] = config.username if config.username 35 | conn_attr[:ovirt_password] = config.password if config.password 36 | conn_attr[:ovirt_ca_no_verify] = config.ca_no_verify if config.ca_no_verify 37 | conn_attr[:ovirt_ca_cert_store] = config.ca_cert_store if config.ca_cert_store 38 | conn_attr[:ovirt_ca_cert_file] = config.ca_cert_file if config.ca_cert_file 39 | conn_attr[:ovirt_filtered_api] = config.filtered_api if config.filtered_api 40 | 41 | # We need datacenter id in fog connection initialization. But it's 42 | # much simpler to use datacenter name in Vagrantfile. So get 43 | # datacenter id here from rbovirt client before connecting to fog. 44 | env[:ovirt_client] = ovirt_connect(conn_attr) 45 | begin 46 | datacenter = OVirtProvider::Util::Collection.find_matching( 47 | env[:ovirt_client].datacenters, config.datacenter) 48 | rescue OVIRT::OvirtException => e 49 | raise Errors::FogOVirtConnectionError, 50 | :error_message => e.message 51 | end 52 | 53 | raise Errors::NoDatacenterError if datacenter == nil 54 | conn_attr[:ovirt_datacenter] = datacenter.id 55 | 56 | # Reconnect and prepar rbovirt client with datacenter set from 57 | # configuration. 58 | env[:ovirt_client] = ovirt_connect(conn_attr) 59 | OVirtProvider.ovirt_client = env[:ovirt_client] 60 | 61 | # Establish fog connection now. 62 | @logger.info("Connecting to oVirt (#{config.url}) ...") 63 | begin 64 | env[:ovirt_compute] = Fog::Compute.new(conn_attr) 65 | rescue OVIRT::OvirtException => e 66 | raise Errors::FogOVirtConnectionError, 67 | :error_message => e.message 68 | end 69 | 70 | OVirtProvider.ovirt_connection = env[:ovirt_compute] 71 | 72 | begin 73 | @app.call(env) 74 | rescue OVIRT::OvirtException => e 75 | raise Errors::VMNotFoundError if e.message =~ /^404/ 76 | end 77 | 78 | end 79 | 80 | private 81 | 82 | def ovirt_connect(credentials) 83 | OVIRT::Client.new( 84 | credentials[:ovirt_username], 85 | credentials[:ovirt_password], 86 | credentials[:ovirt_url], 87 | { :datacenter_id => credentials[:ovirt_datacenter], 88 | :ca_no_verify => credentials[:ovirt_ca_no_verify], 89 | :ca_cert_store => credentials[:ovirt_ca_cert_store], 90 | :ca_cert_file => credentials[:ovirt_ca_cert_file], 91 | :filtered_api => credentials[:ovirt_filtered_api] 92 | } 93 | ) 94 | end 95 | end 96 | end 97 | end 98 | end 99 | 100 | -------------------------------------------------------------------------------- /lib/vagrant-ovirt3/action/create_network_interfaces.rb: -------------------------------------------------------------------------------- 1 | require 'log4r' 2 | require 'vagrant/util/scoped_hash_override' 3 | 4 | module VagrantPlugins 5 | module OVirtProvider 6 | module Action 7 | # Create network interfaces for machine, before VM is running. 8 | class CreateNetworkInterfaces 9 | include Vagrant::Util::ScopedHashOverride 10 | 11 | def initialize(app, env) 12 | @logger = Log4r::Logger.new("vagrant_ovirt3::action::create_network_interfaces") 13 | @app = app 14 | end 15 | 16 | def call(env) 17 | # Get machine first. 18 | begin 19 | machine = OVirtProvider::Util::Collection.find_matching( 20 | env[:ovirt_compute].servers.all, env[:machine].id.to_s) 21 | rescue => e 22 | raise Errors::NoVMError, 23 | :vm_name => env[:machine].id.to_s 24 | end 25 | 26 | # Setup list of interfaces before creating them 27 | adapters = [] 28 | 29 | # First interface is for provisioning, so this slot is not usable. 30 | # This interface should be available already from template. 31 | 32 | env[:machine].config.vm.networks.each do |type, options| 33 | # We support private and public networks only. They mean both the 34 | # same right now. 35 | next if type != :private_network and type != :public_network 36 | 37 | # Get options for this interface. Options can be specified in 38 | # Vagrantfile in short format (:ip => ...), or provider format 39 | # (:ovirt__network_name => ...). 40 | options = scoped_hash_override(options, :ovirt) 41 | options = { 42 | :netmask => '255.255.255.0', 43 | :network_name => 'rhevm', 44 | :interface_type => 'virtio' 45 | }.merge(options) 46 | 47 | if options[:adapter] 48 | if adapters[options[:adapter]] 49 | raise Errors::InterfaceSlotNotAvailable 50 | end 51 | 52 | free_slot = options[:adapter].to_i 53 | else 54 | free_slot = find_empty(adapters, start=1) 55 | raise Errors::InterfaceSlotNotAvailable if free_slot == nil 56 | end 57 | 58 | adapters[free_slot] = options 59 | end 60 | 61 | # Create each interface as new domain device 62 | adapters.each_with_index do |opts, slot_number| 63 | next if slot_number == 0 or opts.nil? 64 | iface_number = slot_number + 1 65 | 66 | # Get network id 67 | network = OVirtProvider::Util::Collection.find_matching( 68 | env[:ovirt_client].networks(:cluster_id => env[:ovirt_cluster].id), 69 | opts[:network_name]) 70 | if network == nil 71 | raise Errors::NoNetworkError, 72 | :network_name => opts[:network_name] 73 | end 74 | 75 | @logger.info("Creating network interface nic#{iface_number}") 76 | begin 77 | machine.add_interface( 78 | :name => "nic#{iface_number}", 79 | :network => network.id, 80 | :interface => opts[:interface_type], 81 | ) 82 | rescue => e 83 | raise Errors::AddInterfaceError, 84 | :error_message => e.message 85 | end 86 | end 87 | 88 | # Continue the middleware chain. 89 | @app.call(env) 90 | 91 | # Configure interfaces that user requested. Machine should be up and 92 | # running now. 93 | networks_to_configure = [] 94 | 95 | adapters.each_with_index do |opts, slot_number| 96 | # Skip configuring first interface. It's used for provisioning and 97 | # it has to be available during provisioning - ifdown command is 98 | # not acceptable here. 99 | next if slot_number == 0 100 | 101 | network = { 102 | :interface => slot_number, 103 | #:mac => ..., 104 | } 105 | 106 | if opts[:ip] 107 | network = { 108 | :type => :static, 109 | :ip => opts[:ip], 110 | :netmask => opts[:netmask], 111 | :gateway => opts[:gateway], 112 | }.merge(network) 113 | else 114 | network[:type] = :dhcp 115 | end 116 | 117 | networks_to_configure << network 118 | end 119 | 120 | env[:ui].info I18n.t("vagrant.actions.vm.network.configuring") 121 | env[:machine].guest.capability( 122 | :configure_networks, networks_to_configure) 123 | end 124 | 125 | private 126 | 127 | def find_empty(array, start=0, stop=8) 128 | for i in start..stop 129 | return i if !array[i] 130 | end 131 | return nil 132 | end 133 | end 134 | end 135 | end 136 | end 137 | 138 | -------------------------------------------------------------------------------- /lib/vagrant-ovirt3/action/create_vm.rb: -------------------------------------------------------------------------------- 1 | require 'log4r' 2 | require 'vagrant/util/retryable' 3 | 4 | module VagrantPlugins 5 | module OVirtProvider 6 | module Action 7 | class CreateVM 8 | include Vagrant::Util::Retryable 9 | 10 | def initialize(app, env) 11 | @logger = Log4r::Logger.new("vagrant_ovirt3::action::create_vm") 12 | @app = app 13 | end 14 | 15 | def call(env) 16 | # Get config. 17 | config = env[:machine].provider_config 18 | 19 | # Gather some info about domain 20 | name = (config.name.nil? ? env[:domain_name] : config.name)[0,15] 21 | console = config.console 22 | cpus = config.cpus 23 | memory_guaranteed_size = config.memory_guaranteed ? config.memory_guaranteed*1024 : nil 24 | quota = config.quota 25 | memory_size = config.memory*1024 26 | connect_timeout = config.connect_timeout 27 | user_data = config.user_data ? 28 | Base64::encode64(config.user_data) : 29 | nil 30 | 31 | # Get cluster 32 | if config.cluster == nil 33 | cluster = env[:ovirt_compute].clusters.first 34 | else 35 | cluster = OVirtProvider::Util::Collection.find_matching( 36 | env[:ovirt_compute].clusters.all, config.cluster) 37 | end 38 | raise Errors::NoClusterError if cluster == nil 39 | # TODO fill env also with other ovirtoptions. 40 | env[:ovirt_cluster] = cluster 41 | 42 | # Get template 43 | template = env[:ovirt_compute].templates.all.find_all { |t| 44 | t.id == config.template or t.name == config.template 45 | } 46 | .sort_by { |t| t.raw.version.version_number.to_i }.reverse 47 | .find { |t| 48 | v = t.raw.version 49 | cv = config.template_version 50 | cv.nil? or (cv.to_i == v.version_number.to_i or cv == v.version_name) 51 | } 52 | if template == nil 53 | raise Errors::NoTemplateError, 54 | :template_name => config.template 55 | end 56 | ver = template.raw.version 57 | if !ver.version_name.nil? and !ver.version_name.empty? 58 | version_string = "#{ver.version_name} (#{ver.version_number.to_i})" 59 | else 60 | version_string = "#{ver.version_number.to_i}" 61 | end 62 | 63 | # Output the settings we're going to use to the user 64 | env[:ui].info(I18n.t("vagrant_ovirt3.creating_vm")) 65 | env[:ui].info(" -- Name: #{name}") 66 | env[:ui].info(" -- Cpus: #{cpus}") 67 | env[:ui].info(" -- Memory: #{memory_size/1024}M") 68 | env[:ui].info(" -- Template: #{template.name}") 69 | env[:ui].info(" -- Version: #{version_string}") 70 | env[:ui].info(" -- Datacenter: #{config.datacenter}") 71 | env[:ui].info(" -- Cluster: #{cluster.name}") 72 | env[:ui].info(" -- Console: #{console}") 73 | if memory_guaranteed_size 74 | env[:ui].info(" -- Memory Guaranteed: #{memory_guaranteed_size/1024}M") 75 | end 76 | if quota 77 | env[:ui].info(" -- Quota: #{quota}") 78 | end 79 | if config.disk_size 80 | env[:ui].info(" -- Disk size: #{config.disk_size}G") 81 | end 82 | if config.user_data 83 | env[:ui].info(" -- User data:\n#{config.user_data}") 84 | end 85 | 86 | # Create oVirt VM. 87 | attr = { 88 | :name => name, 89 | :cores => cpus, 90 | :memory => memory_size*1024, 91 | :cluster => cluster.id, 92 | :template => template.id, 93 | :display => {:type => console }, 94 | :user_data => user_data, 95 | :quota => quota, 96 | :memory_guaranteed => memory_guaranteed_size, 97 | } 98 | 99 | begin 100 | server = env[:ovirt_compute].servers.create(attr) 101 | rescue OVIRT::OvirtException => e 102 | raise Errors::FogCreateServerError, 103 | :error_message => e.message 104 | end 105 | 106 | # Immediately save the ID since it is created at this point. 107 | env[:machine].id = server.id 108 | 109 | # Wait till all volumes are ready. 110 | env[:ui].info(I18n.t("vagrant_ovirt3.wait_for_ready_vm")) 111 | for i in 0..connect_timeout 112 | ready = true 113 | server = env[:ovirt_compute].servers.get(env[:machine].id.to_s) 114 | server.volumes.each do |volume| 115 | if volume.status != 'ok' 116 | ready = false 117 | break 118 | end 119 | end 120 | if env[:machine].state.id != :down 121 | ready = false 122 | end 123 | break if ready 124 | sleep 2 125 | end 126 | 127 | if not ready 128 | raise Errors::WaitForReadyVmTimeout 129 | end 130 | 131 | @app.call(env) 132 | end 133 | 134 | def recover(env) 135 | return if env["vagrant.error"].is_a?(Vagrant::Errors::VagrantError) 136 | 137 | # Undo the import 138 | env[:ui].info(I18n.t("vagrant_ovirt3.error_recovering")) 139 | destroy_env = env.dup 140 | destroy_env.delete(:interrupted) 141 | destroy_env[:config_validate] = false 142 | destroy_env[:force_confirm_destroy] = true 143 | env[:action_runner].run(Action.action_destroy, destroy_env) 144 | end 145 | end 146 | end 147 | end 148 | end 149 | -------------------------------------------------------------------------------- /lib/vagrant-ovirt3/action/destroy_vm.rb: -------------------------------------------------------------------------------- 1 | require 'log4r' 2 | 3 | module VagrantPlugins 4 | module OVirtProvider 5 | module Action 6 | class DestroyVM 7 | def initialize(app, env) 8 | @logger = Log4r::Logger.new("vagrant_ovirt3::action::destroy_vm") 9 | @app = app 10 | end 11 | 12 | def call(env) 13 | # Destroy the server, remove the tracking ID 14 | env[:ui].info(I18n.t("vagrant_ovirt3.destroy_vm")) 15 | 16 | machine = env[:ovirt_compute].servers.get(env[:machine].id.to_s) 17 | machine.destroy 18 | env[:machine].id = nil 19 | 20 | @app.call(env) 21 | end 22 | end 23 | end 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /lib/vagrant-ovirt3/action/halt_vm.rb: -------------------------------------------------------------------------------- 1 | require 'log4r' 2 | 3 | module VagrantPlugins 4 | module OVirtProvider 5 | module Action 6 | class HaltVM 7 | def initialize(app, env) 8 | @logger = Log4r::Logger.new("vagrant_ovirt3::action::halt_vm") 9 | @app = app 10 | end 11 | 12 | def call(env) 13 | env[:ui].info(I18n.t("vagrant_ovirt3.halt_vm")) 14 | 15 | machine = env[:ovirt_compute].servers.get(env[:machine].id.to_s) 16 | machine.stop 17 | 18 | @app.call(env) 19 | end 20 | end 21 | end 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /lib/vagrant-ovirt3/action/is_created.rb: -------------------------------------------------------------------------------- 1 | module VagrantPlugins 2 | module OVirtProvider 3 | module Action 4 | # This can be used with "Call" built-in to check if the machine 5 | # is created and branch in the middleware. 6 | class IsCreated 7 | def initialize(app, env) 8 | @app = app 9 | end 10 | 11 | def call(env) 12 | env[:result] = env[:machine].state.id != :not_created 13 | @app.call(env) 14 | end 15 | end 16 | end 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /lib/vagrant-ovirt3/action/is_running.rb: -------------------------------------------------------------------------------- 1 | module VagrantPlugins 2 | module OVirtProvider 3 | module Action 4 | # This can be used with "Call" built-in to check if the machine 5 | # is created and branch in the middleware. 6 | class IsRunning 7 | def initialize(app, env) 8 | @app = app 9 | end 10 | 11 | def call(env) 12 | env[:result] = env[:machine].state.id == :up 13 | @app.call(env) 14 | end 15 | end 16 | end 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /lib/vagrant-ovirt3/action/message_already_created.rb: -------------------------------------------------------------------------------- 1 | module VagrantPlugins 2 | module OVirtProvider 3 | module Action 4 | class MessageAlreadyCreated 5 | def initialize(app, env) 6 | @app = app 7 | end 8 | 9 | def call(env) 10 | env[:ui].info(I18n.t("vagrant_ovirt3.already_created")) 11 | @app.call(env) 12 | end 13 | end 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /lib/vagrant-ovirt3/action/message_already_up.rb: -------------------------------------------------------------------------------- 1 | module VagrantPlugins 2 | module OVirtProvider 3 | module Action 4 | class MessageAlreadyUp 5 | def initialize(app, env) 6 | @app = app 7 | end 8 | 9 | def call(env) 10 | env[:ui].info(I18n.t("vagrant_ovirt3.already_up")) 11 | @app.call(env) 12 | end 13 | end 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /lib/vagrant-ovirt3/action/message_not_created.rb: -------------------------------------------------------------------------------- 1 | module VagrantPlugins 2 | module OVirtProvider 3 | module Action 4 | class MessageNotCreated 5 | def initialize(app, env) 6 | @app = app 7 | end 8 | 9 | def call(env) 10 | env[:ui].info(I18n.t("vagrant_ovirt3.not_created")) 11 | @app.call(env) 12 | end 13 | end 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /lib/vagrant-ovirt3/action/message_not_suspended.rb: -------------------------------------------------------------------------------- 1 | module VagrantPlugins 2 | module OVirtProvider 3 | module Action 4 | class MessageNotSuspended 5 | def initialize(app, env) 6 | @app = app 7 | end 8 | 9 | def call(env) 10 | env[:ui].info(I18n.t("vagrant_ovirt3.not_suspended")) 11 | @app.call(env) 12 | end 13 | end 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /lib/vagrant-ovirt3/action/message_not_up.rb: -------------------------------------------------------------------------------- 1 | module VagrantPlugins 2 | module OVirtProvider 3 | module Action 4 | class MessageNotUp 5 | def initialize(app, env) 6 | @app = app 7 | end 8 | 9 | def call(env) 10 | env[:ui].info(I18n.t("vagrant_ovirt3.not_up")) 11 | @app.call(env) 12 | end 13 | end 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /lib/vagrant-ovirt3/action/message_saving_state.rb: -------------------------------------------------------------------------------- 1 | module VagrantPlugins 2 | module OVirtProvider 3 | module Action 4 | class MessageSavingState 5 | def initialize(app, env) 6 | @app = app 7 | end 8 | 9 | def call(env) 10 | env[:ui].info(I18n.t("vagrant_ovirt3.saving_state")) 11 | @app.call(env) 12 | end 13 | end 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /lib/vagrant-ovirt3/action/read_ssh_info.rb: -------------------------------------------------------------------------------- 1 | require "log4r" 2 | 3 | module VagrantPlugins 4 | module OVirtProvider 5 | module Action 6 | # This action reads the SSH info for the machine and puts it into the 7 | # `:machine_ssh_info` key in the environment. 8 | class ReadSSHInfo 9 | def initialize(app, env) 10 | @app = app 11 | @logger = Log4r::Logger.new("vagrant_ovirt3::action::read_ssh_info") 12 | end 13 | 14 | def call(env) 15 | env[:machine_ssh_info] = read_ssh_info( 16 | env[:ovirt_compute], env[:machine]) 17 | 18 | @app.call(env) 19 | end 20 | 21 | def read_ssh_info(ovirt, machine) 22 | return nil if machine.id.nil? 23 | 24 | # Get config. 25 | config = machine.provider_config 26 | 27 | # Find the machine 28 | server = ovirt.servers.get(machine.id.to_s) 29 | 30 | if server.nil? 31 | # The machine can't be found 32 | @logger.info("Machine couldn't be found, assuming it got destroyed.") 33 | machine.id = nil 34 | return nil 35 | end 36 | 37 | ip_address = server.ips.first 38 | if ip_address == nil or ip_address == '' 39 | raise Errors::NoIpAddressError 40 | end 41 | 42 | # Return the info 43 | # TODO: Some info should be configurable in Vagrantfile 44 | return { 45 | :host => ip_address, 46 | :port => machine.config.ssh.guest_port, 47 | :username => machine.config.ssh.username, 48 | :private_key_path => machine.config.ssh.private_key_path, 49 | :forward_agent => machine.config.ssh.forward_agent, 50 | :forward_x11 => machine.config.ssh.forward_x11, 51 | } 52 | end 53 | end 54 | end 55 | end 56 | end 57 | -------------------------------------------------------------------------------- /lib/vagrant-ovirt3/action/read_state.rb: -------------------------------------------------------------------------------- 1 | require "log4r" 2 | 3 | module VagrantPlugins 4 | module OVirtProvider 5 | module Action 6 | # This action reads the state of the machine and puts it in the 7 | # `:machine_state_id` key in the environment. 8 | class ReadState 9 | def initialize(app, env) 10 | @app = app 11 | @logger = Log4r::Logger.new("vagrant_ovirt3::action::read_state") 12 | end 13 | 14 | def call(env) 15 | env[:machine_state_id] = read_state(env[:ovirt_compute], env[:machine]) 16 | @app.call(env) 17 | end 18 | 19 | # Possible states include (but may not be limited to): 20 | # :not_created, :up, :down, :saving_state, :suspended 21 | def read_state(ovirt, machine) 22 | return :not_created if machine.id.nil? 23 | 24 | # Find the machine 25 | server = ovirt.servers.get(machine.id) 26 | if server.nil? 27 | machine.id = nil 28 | return :not_created 29 | end 30 | 31 | # Return the state 32 | return server.status.to_sym 33 | end 34 | end 35 | end 36 | end 37 | end 38 | -------------------------------------------------------------------------------- /lib/vagrant-ovirt3/action/resize_disk.rb: -------------------------------------------------------------------------------- 1 | require 'log4r' 2 | require 'vagrant/util/scoped_hash_override' 3 | 4 | module VagrantPlugins 5 | module OVirtProvider 6 | module Action 7 | # Resize the disk if necessary, before VM is running. 8 | class ResizeDisk 9 | include Vagrant::Util::ScopedHashOverride 10 | 11 | def initialize(app, env) 12 | @logger = Log4r::Logger.new("vagrant_ovirt::action::resize_disk") 13 | @app = app 14 | end 15 | 16 | def call(env) 17 | # Is it necessary to resize the disk? 18 | config = env[:machine].provider_config 19 | connect_timeout = config.connect_timeout 20 | if config.disk_size.nil? 21 | # Nothing to do 22 | @app.call(env) 23 | return 24 | end 25 | 26 | # Get machine first. 27 | begin 28 | machine = OVirtProvider::Util::Collection.find_matching( 29 | env[:ovirt_compute].servers.all, env[:machine].id.to_s) 30 | rescue => e 31 | raise Errors::NoVMError, 32 | :vm_name => env[:machine].id.to_s 33 | end 34 | 35 | # Extend disk size if necessary 36 | begin 37 | machine.update_volume( 38 | :id => machine.volumes.first.id, 39 | :size => config.disk_size*1024*1024*1024, 40 | ) 41 | rescue => e 42 | raise Errors::UpdateVolumeError, 43 | :error_message => e.message 44 | end 45 | 46 | # Wait till all volumes are ready. 47 | env[:ui].info(I18n.t("vagrant_ovirt3.wait_for_ready_volume")) 48 | for i in 0..connect_timeout 49 | ready = true 50 | machine = env[:ovirt_compute].servers.get(env[:machine].id.to_s) 51 | machine.volumes.each do |volume| 52 | if volume.status != 'ok' 53 | ready = false 54 | break 55 | end 56 | end 57 | break if ready 58 | sleep 2 59 | end 60 | 61 | if not ready 62 | raise Errors::WaitForReadyResizedVolumeTimeout 63 | end 64 | 65 | @app.call(env) 66 | end 67 | 68 | end 69 | end 70 | end 71 | end 72 | 73 | -------------------------------------------------------------------------------- /lib/vagrant-ovirt3/action/set_name_of_domain.rb: -------------------------------------------------------------------------------- 1 | module VagrantPlugins 2 | module OVirtProvider 3 | module Action 4 | 5 | # Setup name for domain and domain volumes. 6 | class SetNameOfDomain 7 | @@MAX_NAME_LENGTH = 64 8 | def initialize(app, env) 9 | @app = app 10 | end 11 | 12 | def call(env) 13 | dir_name = env[:root_path].basename.to_s.dup.gsub(/[^-a-z0-9_]/i, "") 14 | timestamp = "_#{Time.now.to_f}" 15 | max_dir_name_length = dir_name.length-[(dir_name + timestamp).length-(@@MAX_NAME_LENGTH-1), 0].max 16 | env[:domain_name] = dir_name[0..max_dir_name_length] << timestamp 17 | 18 | # Check if the domain name is not already taken 19 | domain = OVirtProvider::Util::Collection.find_matching( 20 | env[:ovirt_compute].servers.all, env[:domain_name]) 21 | if domain != nil 22 | raise Vagrant::Errors::DomainNameExists, 23 | :domain_name => env[:domain_name] 24 | end 25 | 26 | @app.call(env) 27 | end 28 | end 29 | 30 | end 31 | end 32 | end 33 | 34 | -------------------------------------------------------------------------------- /lib/vagrant-ovirt3/action/start_vm.rb: -------------------------------------------------------------------------------- 1 | require 'log4r' 2 | 3 | module VagrantPlugins 4 | module OVirtProvider 5 | module Action 6 | 7 | # Just start the VM. 8 | class StartVM 9 | 10 | def initialize(app, env) 11 | @logger = Log4r::Logger.new("vagrant_ovirt::action::start_vm") 12 | @app = app 13 | end 14 | 15 | def call(env) 16 | config = env[:machine].provider_config 17 | connect_timeout = config.connect_timeout 18 | env[:ui].info(I18n.t("vagrant_ovirt3.starting_vm")) 19 | 20 | for i in 0..connect_timeout 21 | ready = true 22 | 23 | machine = env[:ovirt_compute].servers.get(env[:machine].id.to_s) 24 | 25 | if env[:machine].state.id == :image_locked 26 | ready = false 27 | end 28 | 29 | if machine == nil 30 | raise Errors::NoVMError, 31 | :vm_name => env[:machine].id.to_s 32 | end 33 | 34 | break if ready 35 | sleep 2 36 | end 37 | 38 | if not ready 39 | raise Errors::WaitForReadyVmTimeout 40 | end 41 | 42 | # Start VM. 43 | begin 44 | machine.start 45 | rescue OVIRT::OvirtException => e 46 | raise Errors::StartVMError, 47 | :error_message => e.message 48 | end 49 | 50 | @app.call(env) 51 | end 52 | end 53 | end 54 | end 55 | end 56 | -------------------------------------------------------------------------------- /lib/vagrant-ovirt3/action/suspend_vm.rb: -------------------------------------------------------------------------------- 1 | require 'log4r' 2 | 3 | module VagrantPlugins 4 | module OVirtProvider 5 | module Action 6 | class SuspendVM 7 | def initialize(app, env) 8 | @logger = Log4r::Logger.new("vagrant_ovirt3::action::suspend_vm") 9 | @app = app 10 | end 11 | 12 | def call(env) 13 | env[:ui].info(I18n.t("vagrant_ovirt3.suspend_vm")) 14 | 15 | machine = env[:ovirt_compute].servers.get(env[:machine].id.to_s) 16 | machine.suspend 17 | 18 | @app.call(env) 19 | end 20 | end 21 | end 22 | end 23 | end 24 | 25 | -------------------------------------------------------------------------------- /lib/vagrant-ovirt3/action/sync_folders.rb: -------------------------------------------------------------------------------- 1 | require "log4r" 2 | require "vagrant/util/subprocess" 3 | 4 | module VagrantPlugins 5 | module OVirtProvider 6 | module Action 7 | # This middleware uses `rsync` to sync the folders over to the 8 | # oVirt VM. 9 | class SyncFolders 10 | def initialize(app, env) 11 | @app = app 12 | @logger = Log4r::Logger.new("vagrant_ovirt::action::sync_folders") 13 | end 14 | 15 | def call(env) 16 | @app.call(env) 17 | 18 | ssh_info = env[:machine].ssh_info 19 | 20 | env[:machine].config.vm.synced_folders.each do |id, data| 21 | next if data[:disabled] 22 | hostpath = File.expand_path(data[:hostpath], env[:root_path]) 23 | guestpath = data[:guestpath] 24 | 25 | # Make sure there is a trailing slash on the host path to 26 | # avoid creating an additional directory with rsync 27 | hostpath = "#{hostpath}/" if hostpath !~ /\/$/ 28 | 29 | # on windows rsync.exe requires cygdrive-style paths. 30 | # assumes: /c/... 31 | # Should be msysgit and cygwin compatible if /etc/fstab in cygwin contains: 32 | # none / cygdrive binary,posix=0,user 0 0 33 | if Vagrant::Util::Platform.windows? 34 | hostpath = hostpath.gsub(/^(\w):/) { "/#{$1}" } 35 | end 36 | 37 | env[:ui].info(I18n.t("vagrant_ovirt3.rsync_folder", 38 | :hostpath => hostpath, 39 | :guestpath => guestpath)) 40 | 41 | # Create the guest path 42 | env[:machine].communicate.sudo("mkdir -p '#{guestpath}'") 43 | env[:machine].communicate.sudo("chown #{ssh_info[:username]} '#{guestpath}'") 44 | 45 | # Rsync over to the guest path using the SSH info 46 | command = [ 47 | "rsync", "--verbose", "--archive", "-z", "--owner", "--perms", 48 | "--exclude", ".vagrant/", 49 | "-e", "ssh -p #{ssh_info[:port]} -o StrictHostKeyChecking=no -i '#{ssh_info[:private_key_path][0]}'", 50 | hostpath, 51 | "#{ssh_info[:username]}@#{ssh_info[:host]}:#{guestpath}"] 52 | 53 | r = Vagrant::Util::Subprocess.execute(*command) 54 | if r.exit_code != 0 55 | raise Errors::RsyncError, 56 | :guestpath => guestpath, 57 | :hostpath => hostpath, 58 | :stderr => r.stderr 59 | end 60 | end 61 | end 62 | end 63 | end 64 | end 65 | end 66 | 67 | -------------------------------------------------------------------------------- /lib/vagrant-ovirt3/action/wait_till_down.rb: -------------------------------------------------------------------------------- 1 | require 'log4r' 2 | require 'vagrant-ovirt3/util/timer' 3 | require 'vagrant/util/retryable' 4 | 5 | module VagrantPlugins 6 | module OVirtProvider 7 | module Action 8 | 9 | # Wait till VM is stopped 10 | class WaitTillDown 11 | include Vagrant::Util::Retryable 12 | 13 | def initialize(app, env) 14 | @logger = Log4r::Logger.new("vagrant_ovirt3::action::wait_till_down") 15 | @app = app 16 | end 17 | 18 | def call(env) 19 | config = env[:machine].provider_config 20 | connect_timeout = config.connect_timeout 21 | 22 | env[:ui].info(I18n.t("vagrant_ovirt3.wait_till_down")) 23 | for i in 0..connect_timeout 24 | ready = true 25 | server = env[:ovirt_compute].servers.get(env[:machine].id.to_s) 26 | if env[:machine].state.id != :down 27 | ready = false 28 | end 29 | break if ready 30 | sleep 2 31 | end 32 | 33 | if not ready 34 | raise Errors::WaitForShutdownVmTimeout 35 | end 36 | 37 | 38 | @app.call(env) 39 | end 40 | 41 | end 42 | end 43 | end 44 | end 45 | 46 | -------------------------------------------------------------------------------- /lib/vagrant-ovirt3/action/wait_till_up.rb: -------------------------------------------------------------------------------- 1 | require 'log4r' 2 | require 'vagrant-ovirt3/util/timer' 3 | require 'vagrant/util/retryable' 4 | 5 | module VagrantPlugins 6 | module OVirtProvider 7 | module Action 8 | 9 | # Wait till VM is started, till it obtains an IP address and is 10 | # accessible via ssh. 11 | class WaitTillUp 12 | include Vagrant::Util::Retryable 13 | 14 | def initialize(app, env) 15 | @logger = Log4r::Logger.new("vagrant_ovirt3::action::wait_till_up") 16 | @app = app 17 | end 18 | 19 | def call(env) 20 | # Initialize metrics if they haven't been 21 | env[:metrics] ||= {} 22 | 23 | # Get config. 24 | config = env[:machine].provider_config 25 | 26 | # Wait for VM to obtain an ip address. 27 | env[:ip_address] = nil 28 | env[:metrics]["instance_ip_time"] = Util::Timer.time do 29 | env[:ui].info(I18n.t("vagrant_ovirt3.waiting_for_ip")) 30 | #retryable(:on => Fog::Errors::TimeoutError, :tries => 300) do 31 | for i in 1..300 32 | # If we're interrupted don't worry about waiting 33 | next if env[:interrupted] 34 | 35 | # Get VM. 36 | server = env[:ovirt_compute].servers.get(env[:machine].id.to_s) 37 | if server == nil 38 | raise NoVMError, :vm_name => '' 39 | end 40 | 41 | env[:ip_address] = server.ips.first 42 | @logger.debug("Got output #{env[:ip_address]}") 43 | break if env[:ip_address] =~ /[0-9\.]+/ 44 | sleep 2 45 | end 46 | #end 47 | end 48 | terminate(env) if env[:interrupted] 49 | @logger.info("Got IP address #{env[:ip_address]}") 50 | @logger.info("Time for getting IP: #{env[:metrics]["instance_ip_time"]}") 51 | 52 | # Machine has ip address assigned, now wait till we are able to 53 | # connect via ssh. 54 | env[:metrics]["instance_ssh_time"] = Util::Timer.time do 55 | env[:ui].info(I18n.t("vagrant_ovirt3.waiting_for_ssh")) 56 | retryable(:on => Fog::Errors::TimeoutError, :tries => 60) do 57 | # If we're interrupted don't worry about waiting 58 | next if env[:interrupted] 59 | 60 | # Wait till we are able to connect via ssh. 61 | next if env[:machine].communicate.ready? 62 | sleep 2 63 | end 64 | end 65 | terminate(env) if env[:interrupted] 66 | @logger.info("Time for SSH ready: #{env[:metrics]["instance_ssh_time"]}") 67 | 68 | # Booted and ready for use. 69 | env[:ui].info(I18n.t("vagrant_ovirt3.ready")) 70 | 71 | @app.call(env) 72 | end 73 | 74 | def recover(env) 75 | return if env["vagrant.error"].is_a?(Vagrant::Errors::VagrantError) 76 | 77 | if env[:machine].provider.state.id != :not_created 78 | # Undo the import 79 | terminate(env) 80 | end 81 | end 82 | 83 | def terminate(env) 84 | destroy_env = env.dup 85 | destroy_env.delete(:interrupted) 86 | destroy_env[:config_validate] = false 87 | destroy_env[:force_confirm_destroy] = true 88 | env[:action_runner].run(Action.action_destroy, destroy_env) 89 | end 90 | end 91 | end 92 | end 93 | end 94 | 95 | -------------------------------------------------------------------------------- /lib/vagrant-ovirt3/cap/nic_mac_addresses.rb: -------------------------------------------------------------------------------- 1 | # vim: ai ts=2 sts=2 et sw=2 ft=ruby 2 | module VagrantPlugins 3 | module OVirtProvider 4 | module Cap 5 | module NicMacAddresses 6 | def self.nic_mac_addresses(machine) 7 | ovirt = OVirtProvider.ovirt_connection 8 | interfaces = ovirt.list_vm_interfaces(machine.id.to_s) 9 | Hash[interfaces.map{ |i| [i[:name], i[:mac]] }] 10 | end 11 | end 12 | end 13 | end 14 | end 15 | 16 | -------------------------------------------------------------------------------- /lib/vagrant-ovirt3/config.rb: -------------------------------------------------------------------------------- 1 | require 'vagrant' 2 | 3 | module VagrantPlugins 4 | module OVirtProvider 5 | class Config < Vagrant.plugin('2', :config) 6 | 7 | attr_accessor :url 8 | attr_accessor :username 9 | attr_accessor :password 10 | attr_accessor :datacenter 11 | attr_accessor :cluster 12 | attr_accessor :filtered_api 13 | 14 | attr_accessor :connect_timeout 15 | 16 | # Domain specific settings used while creating new machine. 17 | attr_accessor :memory 18 | attr_accessor :memory_guaranteed 19 | attr_accessor :cpus 20 | attr_accessor :template 21 | attr_accessor :template_version 22 | attr_accessor :console 23 | attr_accessor :disk_size 24 | attr_accessor :user_data 25 | attr_accessor :name 26 | attr_accessor :quota 27 | 28 | # TODO: change 'ca_cert_store' to 'ca_cert' once rbovirt PR #55 merges. 29 | attr_accessor :ca_no_verify 30 | attr_accessor :ca_cert_store 31 | attr_accessor :ca_cert_file 32 | 33 | def initialize 34 | @url = UNSET_VALUE 35 | @username = UNSET_VALUE 36 | @password = UNSET_VALUE 37 | @datacenter = UNSET_VALUE 38 | @cluster = UNSET_VALUE 39 | @filtered_api = UNSET_VALUE 40 | 41 | @connect_timeout = UNSET_VALUE 42 | 43 | # Domain specific settings. 44 | @memory = UNSET_VALUE 45 | @memory_guaranteed = UNSET_VALUE 46 | @cpus = UNSET_VALUE 47 | @quota = UNSET_VALUE 48 | @template = UNSET_VALUE 49 | @template_version = UNSET_VALUE 50 | @console = UNSET_VALUE 51 | @disk_size = UNSET_VALUE 52 | @user_data = UNSET_VALUE 53 | @name = UNSET_VALUE 54 | 55 | @ca_no_verify = UNSET_VALUE 56 | @ca_cert_store = UNSET_VALUE 57 | @ca_cert_file = UNSET_VALUE 58 | end 59 | 60 | def finalize! 61 | @url = nil if @url == UNSET_VALUE 62 | @username = nil if @username == UNSET_VALUE 63 | @password = nil if @password == UNSET_VALUE 64 | @datacenter = nil if @datacenter == UNSET_VALUE 65 | @cluster = nil if @cluster == UNSET_VALUE 66 | @filtered_api = false if @filtered_api == UNSET_VALUE 67 | @connect_timeout = 10 if @connect_timeout == UNSET_VALUE 68 | 69 | # Domain specific settings. 70 | @memory = 512 if @memory == UNSET_VALUE 71 | @memory_guaranteed = nil if @memory_guaranteed == UNSET_VALUE 72 | @cpus = 1 if @cpus == UNSET_VALUE 73 | @quota = nil if @quota == UNSET_VALUE 74 | @template = 'Blank' if @template == UNSET_VALUE 75 | @template_version = nil if @template_version == UNSET_VALUE 76 | @console = 'spice' if @console == UNSET_VALUE 77 | @disk_size = nil if @disk_size == UNSET_VALUE 78 | @user_data = nil if @user_data == UNSET_VALUE 79 | @name = nil if @name == UNSET_VALUE 80 | 81 | @ca_no_verify = false if @ca_no_verify == UNSET_VALUE 82 | @ca_cert_store = nil if @ca_cert_store == UNSET_VALUE 83 | @ca_cert_file = nil if @ca_cert_file == UNSET_VALUE 84 | end 85 | 86 | def validate(machine) 87 | valid_console_types = ['vnc', 'spice'] 88 | raise Errors::InvalidConsoleType, 89 | :console => @console unless valid_console_types.include? @console 90 | end 91 | end 92 | end 93 | end 94 | 95 | -------------------------------------------------------------------------------- /lib/vagrant-ovirt3/errors.rb: -------------------------------------------------------------------------------- 1 | require 'vagrant' 2 | 3 | module VagrantPlugins 4 | module OVirtProvider 5 | module Errors 6 | class VagrantOVirtError < Vagrant::Errors::VagrantError 7 | error_namespace("vagrant_ovirt3.errors") 8 | end 9 | 10 | class InvalidConsoleType < VagrantOVirtError 11 | error_key(:console_error) 12 | end 13 | 14 | class RsyncError < VagrantOVirtError 15 | error_key(:rsync_error) 16 | end 17 | 18 | class FogOVirtConnectionError < VagrantOVirtError 19 | error_key(:fog_ovirt_connection_error) 20 | end 21 | 22 | class NoDatacenterError < VagrantOVirtError 23 | error_key(:no_datacenter_error) 24 | end 25 | 26 | class NoClusterError < VagrantOVirtError 27 | error_key(:no_cluster_error) 28 | end 29 | 30 | class NoTemplateError < VagrantOVirtError 31 | error_key(:no_template_error) 32 | end 33 | 34 | class NoQuotaError < VagrantOVirtError 35 | error_key(:no_template_error) 36 | end 37 | 38 | class FogCreateServerError < VagrantOVirtError 39 | error_key(:fog_create_server_error) 40 | end 41 | 42 | class InterfaceSlotNotAvailable < VagrantOVirtError 43 | error_key(:interface_slot_not_available) 44 | end 45 | 46 | class AddInterfaceError < VagrantOVirtError 47 | error_key(:add_interface_error) 48 | end 49 | 50 | class NoVMError < VagrantOVirtError 51 | error_key(:no_vm_error) 52 | end 53 | 54 | class VMNotFoundError < VagrantOVirtError 55 | error_key(:vm_not_found_error) 56 | end 57 | 58 | class StartVMError < VagrantOVirtError 59 | error_key(:start_vm_error) 60 | end 61 | 62 | class WaitForReadyVmTimeout < VagrantOVirtError 63 | error_key(:wait_for_ready_vm_timeout) 64 | end 65 | 66 | class WaitForShutdownVmTimeout < VagrantOVirtError 67 | error_key(:wait_for_shutdown_vm_timeout) 68 | end 69 | 70 | class NoIpAddressError < VagrantOVirtError 71 | error_key(:no_ip_address_error) 72 | end 73 | 74 | class NoNetworkError < VagrantOVirtError 75 | error_key(:no_network_error) 76 | end 77 | 78 | class UpdateVolumeError < VagrantOVirtError 79 | error_key(:update_volume_error) 80 | end 81 | 82 | class WaitForReadyResizedVolumeTimeout < VagrantOVirtError 83 | error_key(:wait_for_ready_resized_volume_timeout) 84 | end 85 | end 86 | end 87 | end 88 | 89 | -------------------------------------------------------------------------------- /lib/vagrant-ovirt3/plugin.rb: -------------------------------------------------------------------------------- 1 | # vim: ai ts=2 sts=2 et sw=2 ft=ruby 2 | begin 3 | require 'vagrant' 4 | rescue LoadError 5 | raise "The Vagrant oVirt v3 plugin must be run within Vagrant." 6 | end 7 | 8 | 9 | # This is a sanity check to make sure no one is attempting to install 10 | # this into an early Vagrant version. 11 | if Vagrant::VERSION < '1.1.0' 12 | raise "The Vagrant oVirt v3 plugin is only compatible with Vagrant 1.1+" 13 | end 14 | 15 | module VagrantPlugins 16 | module OVirtProvider 17 | class Plugin < Vagrant.plugin('2') 18 | name "ovirt3" 19 | description <<-DESC 20 | Vagrant plugin to manage oVirt v3 machines. 21 | DESC 22 | 23 | config("ovirt3", :provider) do 24 | require_relative "config" 25 | Config 26 | end 27 | 28 | provider("ovirt3", parallel: true) do 29 | # Setup logging and i18n 30 | setup_logging 31 | setup_i18n 32 | 33 | require_relative "provider" 34 | Provider 35 | end 36 | 37 | provider_capability("ovirt3", :nic_mac_addresses) do 38 | require_relative "cap/nic_mac_addresses" 39 | Cap::NicMacAddresses 40 | end 41 | 42 | # This initializes the internationalization strings. 43 | def self.setup_i18n 44 | I18n.load_path << File.expand_path("locales/en.yml", 45 | OVirtProvider.source_root) 46 | I18n.reload! 47 | end 48 | 49 | # This sets up our log level to be whatever VAGRANT_LOG is. 50 | def self.setup_logging 51 | require "log4r" 52 | 53 | level = nil 54 | begin 55 | level = Log4r.const_get(ENV["VAGRANT_LOG"].upcase) 56 | rescue NameError 57 | # This means that the logging constant wasn't found, 58 | # which is fine. We just keep `level` as `nil`. But 59 | # we tell the user. 60 | level = nil 61 | end 62 | 63 | # Some constants, such as "true" resolve to booleans, so the 64 | # above error checking doesn't catch it. This will check to make 65 | # sure that the log level is an integer, as Log4r requires. 66 | level = nil if !level.is_a?(Integer) 67 | 68 | # Set the logging level on all "vagrant" namespaced 69 | # logs as long as we have a valid level. 70 | if level 71 | logger = Log4r::Logger.new("vagrant_ovirt3") 72 | logger.outputters = Log4r::Outputter.stderr 73 | logger.level = level 74 | logger = nil 75 | end 76 | end 77 | end 78 | end 79 | end 80 | 81 | -------------------------------------------------------------------------------- /lib/vagrant-ovirt3/provider.rb: -------------------------------------------------------------------------------- 1 | require 'vagrant' 2 | 3 | module VagrantPlugins 4 | module OVirtProvider 5 | 6 | # This is the base class for a provider for the V2 API. A provider 7 | # is responsible for creating compute resources to match the 8 | # needs of a Vagrant-configured system. 9 | class Provider < Vagrant.plugin('2', :provider) 10 | def initialize(machine) 11 | @machine = machine 12 | end 13 | 14 | # This should return an action callable for the given name. 15 | def action(name) 16 | # Attempt to get the action method from the Action class if it 17 | # exists, otherwise return nil to show that we don't support the 18 | # given action. 19 | action_method = "action_#{name}" 20 | return Action.send(action_method) if Action.respond_to?(action_method) 21 | nil 22 | end 23 | 24 | # This method is called if the underying machine ID changes. Providers 25 | # can use this method to load in new data for the actual backing 26 | # machine or to realize that the machine is now gone (the ID can 27 | # become `nil`). 28 | def machine_id_changed 29 | end 30 | 31 | # This should return a hash of information that explains how to 32 | # SSH into the machine. If the machine is not at a point where 33 | # SSH is even possible, then `nil` should be returned. 34 | def ssh_info 35 | # Run a custom action called "read_ssh_info" which does what it says 36 | # and puts the resulting SSH info into the `:machine_ssh_info` key in 37 | # the environment. 38 | # 39 | # Ssh info has following format.. 40 | # 41 | #{ 42 | # :host => "1.2.3.4", 43 | # :port => "22", 44 | # :username => "mitchellh", 45 | # :private_key_path => "/path/to/my/key" 46 | #} 47 | env = @machine.action("read_ssh_info") 48 | env[:machine_ssh_info] 49 | end 50 | 51 | # This should return the state of the machine within this provider. 52 | # The state must be an instance of {MachineState}. 53 | def state 54 | # Run a custom action we define called "read_state" which does 55 | # what it says. It puts the state in the `:machine_state_id` 56 | # key in the environment. 57 | env = @machine.action("read_state") 58 | 59 | state_id = env[:machine_state_id] 60 | 61 | # Get the short and long description 62 | short = I18n.t("vagrant_ovirt3.states.short_#{state_id}") 63 | long = I18n.t("vagrant_ovirt3.states.long_#{state_id}") 64 | 65 | # Return the MachineState object 66 | Vagrant::MachineState.new(state_id, short, long) 67 | end 68 | 69 | def to_s 70 | id = @machine.id.nil? ? "new" : @machine.id 71 | "oVirt (#{id})" 72 | end 73 | end 74 | end 75 | end 76 | 77 | -------------------------------------------------------------------------------- /lib/vagrant-ovirt3/util.rb: -------------------------------------------------------------------------------- 1 | module VagrantPlugins 2 | module OVirtProvider 3 | module Util 4 | autoload :Collection, 'vagrant-ovirt3/util/collection' 5 | autoload :Timer, 'vagrant-ovirt3/util/timer' 6 | end 7 | end 8 | end 9 | 10 | -------------------------------------------------------------------------------- /lib/vagrant-ovirt3/util/collection.rb: -------------------------------------------------------------------------------- 1 | module VagrantPlugins 2 | module OVirtProvider 3 | module Util 4 | module Collection 5 | # This method finds a matching _thing_ in a collection of 6 | # _things_. This works matching if the ID or NAME equals to 7 | # `name`. Or, if `name` is a regexp, a partial match is chosen 8 | # as well. 9 | def self.find_matching(collection, name) 10 | collection.each do |single| 11 | return single if single.name == name 12 | return single if single.id == name 13 | end 14 | 15 | nil 16 | end 17 | end 18 | end 19 | end 20 | end 21 | 22 | -------------------------------------------------------------------------------- /lib/vagrant-ovirt3/util/timer.rb: -------------------------------------------------------------------------------- 1 | module VagrantPlugins 2 | module OVirtProvider 3 | module Util 4 | class Timer 5 | # A basic utility method that times the execution of the given 6 | # block and returns it. 7 | def self.time 8 | start_time = Time.now.to_f 9 | yield 10 | end_time = Time.now.to_f 11 | 12 | end_time - start_time 13 | end 14 | end 15 | end 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /lib/vagrant-ovirt3/version.rb: -------------------------------------------------------------------------------- 1 | module VagrantPlugins 2 | module OVirtProvider 3 | VERSION = '1.9.3' 4 | end 5 | end 6 | 7 | -------------------------------------------------------------------------------- /locales/en.yml: -------------------------------------------------------------------------------- 1 | en: 2 | vagrant_ovirt3: 3 | creating_vm: |- 4 | Creating VM with the following settings... 5 | destroy_vm: |- 6 | Removing VM... 7 | not_created: |- 8 | VM is not created. Please run `vagrant up` first. 9 | not_up: |- 10 | VM is not running. Please run `vagrant up` first. 11 | starting_vm: |- 12 | Starting VM. 13 | suspend_vm: |- 14 | Suspending VM... 15 | halt_vm: |- 16 | Halting VM... 17 | error_recovering: |- 18 | An error occured. Recovering.. 19 | wait_till_down: |- 20 | Waiting for VM to shutdown... 21 | waiting_for_ip: |- 22 | Waiting for VM to get an IP address... 23 | waiting_for_ssh: |- 24 | Waiting for SSH to become available... 25 | rsync_folder: |- 26 | Rsyncing folder: %{hostpath} => %{guestpath} 27 | wait_for_ready_vm: |- 28 | Waiting for VM to become "ready" to start... 29 | already_created: |- 30 | VM is already created. 31 | already_up: |- 32 | VM is already up. 33 | ready: |- 34 | Machine is booted and ready for use! 35 | wait_for_ready_volume: |- 36 | Waiting for VM volume to become "ready" to start... 37 | saving_state: |- 38 | VM is busy saving state. Please wait and try again. 39 | not_suspended: |- 40 | VM is not in a suspended state. 41 | 42 | errors: 43 | fog_ovirt_connection_error: |- 44 | Error while connecting to oVirt: %{error_message} 45 | console_error: |- 46 | Invalid console type specified. 47 | no_datacenter_error: |- 48 | No usable datacenter found! Please check if datacenter specified in 49 | configuration is avaliable. 50 | no_cluster_error: |- 51 | No usable cluster found! Please check if cluster specified in 52 | configuration is avaliable. 53 | no_quota_error: |- 54 | No usable quota found! Please check if quota specified in 55 | configuration is avaliable. 56 | no_template_error: |- 57 | No template %{template_name} found! 58 | fog_create_server_error: |- 59 | Error while creating domain: %{error_message} 60 | interface_slot_not_available: |- 61 | Interface adapter number is already in use. Please specify other adapter 62 | number. 63 | add_interface_error: |- 64 | Error while adding new interface to VM. %{error_message} 65 | no_vm_error: |- 66 | No VM %{vm_name} found. 67 | vm_not_found_error: |- 68 | No matching VM found on oVirt server. 69 | no_network_error: |- 70 | No network %{network_name} found. 71 | start_vm_error: |- 72 | Unable to start VM: %{error_message} 73 | wait_for_ready_vm_timeout: |- 74 | Timeout occurred while waiting for VM to become ready to start 75 | no_ip_address_error: |- 76 | No IP address found. 77 | rsync_error: |- 78 | There was an error when attemping to rsync a share folder. 79 | Please inspect the error message below for more info. 80 | 81 | Host path: %{hostpath} 82 | Guest path: %{guestpath} 83 | Error: %{stderr} 84 | update_volume_error: |- 85 | Error while updating volume. %{error_message} 86 | wait_for_ready_resized_volume_timeout: |- 87 | Timeout occurred while waiting for resized volume to become ready 88 | wait_for_shutdown_vm_timeout: |- 89 | Timeout occurred while waiting for VM to shutdown 90 | 91 | states: 92 | short_paused: |- 93 | pause 94 | short_shutoff: |- 95 | shutoff 96 | long_shutoff: |- 97 | The oVirt machine is not running. Run `vagrant up` to start it. 98 | short_down: |- 99 | shutoff 100 | long_down: |- 101 | The oVirt machine is not running. Run `vagrant up` to start it. 102 | short_not_created: |- 103 | not created 104 | long_not_created: |- 105 | The oVirt domain is not created. Run `vagrant up` to create it. 106 | short_running: |- 107 | running 108 | long_running: |- 109 | The oVirt domain is running. To stop this machine, you can run 110 | `vagrant halt`. To destroy the machine, you can run `vagrant destroy`. 111 | short_up: |- 112 | running 113 | long_up: |- 114 | The oVirt domain is running. To stop this machine, you can run 115 | `vagrant halt`. To destroy the machine, you can run `vagrant destroy`. 116 | -------------------------------------------------------------------------------- /tools/prepare_redhat_for_box.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash +x 2 | 3 | # This script should help to prepare RedHat and RedHat like OS (CentOS, 4 | # Scientific Linux, ...) for Vagrant usage. 5 | 6 | # To create new box image, just install minimal base system in VM. Then upload 7 | # this script to the VM and run it. After script has finished, halt the machine 8 | # and then create an oVirt template, which will be used for creating new 9 | # vagrant machines. 10 | 11 | 12 | # We need a hostname. 13 | if [ $# -ne 1 ]; then 14 | echo "Usage: $0 " 15 | echo "Hostname should be in format vagrant-[os-name], e.g. vagrant-redhat63." 16 | exit 1 17 | fi 18 | 19 | 20 | # On which version of RedHet are we running? 21 | RHEL_MAJOR_VERSION=$(sed 's/.*release \([0-9]\)\..*/\1/' /etc/redhat-release) 22 | if [ $? -ne 0 ]; then 23 | echo "Is this a RedHat distro?" 24 | exit 1 25 | fi 26 | echo "* Found RedHat ${RHEL_MAJOR_VERSION} version." 27 | 28 | 29 | # Setup hostname vagrant-something. 30 | FQDN="$1.vagrantup.com" 31 | if grep '^HOSTNAME=' /etc/sysconfig/network > /dev/null; then 32 | sed -i 's/HOSTNAME=\(.*\)/HOSTNAME='${FQDN}'/' /etc/sysconfig/network 33 | else 34 | echo "HOSTNAME=${FQDN}" >> /etc/sysconfig/network 35 | fi 36 | 37 | 38 | # Enable EPEL and Puppet repositories. 39 | if [[ $RHEL_MAJOR_VERSION -eq 5 ]]; then 40 | yum install -y \ 41 | http://ftp.astral.ro/mirrors/fedora/pub/epel/5/x86_64/epel-release-5-4.noarch.rpm \ 42 | https://yum.puppetlabs.com/puppetlabs-release-el-5.noarch.rpm 43 | elif [[ $RHEL_MAJOR_VERSION -eq 6 ]]; then 44 | yum install -y \ 45 | http://ftp.astral.ro/mirrors/fedora/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm \ 46 | https://yum.puppetlabs.com/puppetlabs-release-el-6.noarch.rpm 47 | elif [[ $RHEL_MAJOR_VERSION -eq 7 ]]; then 48 | yum install -y \ 49 | http://ftp.astral.ro/mirrors/fedora/pub/epel/7/x86_64/e/epel-release-7-5.noarch.rpm \ 50 | https://yum.puppetlabs.com/puppetlabs-release-el-7.noarch.rpm 51 | else 52 | echo "Is this a valid major release?" 53 | exit 1 54 | fi 55 | 56 | # Install some required software. 57 | yum -y install openssh-server openssh-clients sudo curl \ 58 | ruby ruby-devel make gcc rubygems rsync puppet ovirt-guest-agent 59 | chkconfig sshd on 60 | 61 | # Users, groups, passwords and sudoers. 62 | grep 'vagrant' /etc/passwd > /dev/null 63 | if [ $? -ne 0 ]; then 64 | echo '* Creating user vagrant.' 65 | useradd vagrant 66 | echo 'vagrant' | passwd --stdin vagrant 67 | fi 68 | grep '^admin:' /etc/group > /dev/null || groupadd admin 69 | usermod -G admin vagrant 70 | 71 | echo 'Defaults env_keep += "SSH_AUTH_SOCK"' >> /etc/sudoers 72 | echo '%admin ALL=NOPASSWD: ALL' >> /etc/sudoers 73 | sed -i 's/Defaults\s*requiretty/Defaults !requiretty/' /etc/sudoers 74 | 75 | 76 | # SSH setup 77 | # Add Vagrant ssh key for root accout. 78 | sed -i 's/.*UseDNS.*/UseDNS no/' /etc/ssh/sshd_config 79 | 80 | vagrant_home=/home/vagrant 81 | [ -d $vagrant_home/.ssh ] || mkdir $vagrant_home/.ssh 82 | chmod 700 $vagrant_home/.ssh 83 | curl -k -L --silent https://raw.githubusercontent.com/mitchellh/vagrant/master/keys/vagrant.pub > $vagrant_home/.ssh/authorized_keys 84 | chmod 600 $vagrant_home/.ssh/authorized_keys 85 | chown -R vagrant:vagrant $vagrant_home/.ssh 86 | 87 | 88 | # Disable firewall and switch SELinux to permissive mode. 89 | chkconfig iptables off 90 | chkconfig ip6tables off 91 | sed -i 's/SELINUX=enforcing/SELINUX=permissive/' /etc/sysconfig/selinux 92 | [ -f /etc/selinux/config ] && sed -i 's/SELINUX=enforcing/SELINUX=permissive/' /etc/selinux/config 93 | 94 | 95 | # Networking setup.. 96 | 97 | # Problem situation: Two interfaces are connected to same network. One interface 98 | # wants to renew DHCP lease and asks server for address. DHCPACK message from 99 | # server arrives, client moves to BOUND state. The client performs a check on 100 | # the suggested address to ensure that the address is not already in use. On 101 | # arping for specified IP address, other interface replies and that's why 102 | # dhclient-script replies with DHCPDECLINE message. (See RFC2131, 4.4.1.). 103 | # Solution: Set sysctl to reply only if the target IP address is local address 104 | # configured on the incoming interface. (See kernel documentation 105 | # Documentation/networking/ip-sysctl.txt) 106 | set_sysctl() 107 | { 108 | grep $1 /etc/sysctl.conf > /dev/null 109 | [ $? -eq 0 ] && sed -i '/'$1'/d' /etc/sysctl.conf 110 | echo "$1 = $2" >> /etc/sysctl.conf 111 | } 112 | set_sysctl 'net.ipv4.conf.all.arp_ignore' 1 113 | set_sysctl 'net.ipv4.conf.all.arp_announce' 2 114 | set_sysctl 'net.ipv4.conf.all.rp_filter' 3 115 | 116 | # Don't fix ethX names to hw address. 117 | rm -f /etc/udev/rules.d/*persistent-net.rules 118 | rm -f /etc/udev/rules.d/*-net.rules 119 | rm -fr /var/lib/dhclient/* 120 | 121 | # Interface eth0 should always get IP address via dhcp. 122 | cat > /etc/sysconfig/network-scripts/ifcfg-eth0 << EOF 123 | DEVICE="eth0" 124 | BOOTPROTO="dhcp" 125 | ONBOOT="yes" 126 | NM_CONTROLLED="no" 127 | EOF 128 | 129 | 130 | # Do some cleanup.. 131 | rm -f ~root/.bash_history 132 | yum clean all 133 | -------------------------------------------------------------------------------- /vagrant-ovirt3.gemspec: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | require File.expand_path('../lib/vagrant-ovirt3/version', __FILE__) 3 | 4 | Gem::Specification.new do |gem| 5 | gem.authors = ["Marcus Young"] 6 | gem.email = ["myoung34@my.apsu.edu"] 7 | gem.description = %q{Vagrant provider for oVirt and RHEV v3} 8 | gem.summary = %q{This vagrant plugin provides the ability to create, control, and destroy virtual machines under oVirt/RHEV} 9 | gem.homepage = "https://github.com/myoung34/vagrant-ovirt3" 10 | gem.licenses = ['MIT'] 11 | 12 | gem.files = `git ls-files`.split($\) 13 | gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) } 14 | gem.test_files = gem.files.grep(%r{^(test|spec|features)/}) 15 | gem.name = "vagrant-ovirt3" 16 | gem.require_paths = ["lib"] 17 | gem.version = VagrantPlugins::OVirtProvider::VERSION 18 | 19 | gem.add_runtime_dependency "fog", "~> 1.27" 20 | gem.add_runtime_dependency 'rbovirt', '~> 0.0', '= 0.0.32' 21 | 22 | gem.add_development_dependency 'rake', '~> 0' 23 | end 24 | 25 | --------------------------------------------------------------------------------