├── onedeploy ├── oneping ├── onessh-copy-id ├── oneinstantiate ├── onereport ├── oneuser-sshkey ├── onevnc ├── onevcenterirb ├── oneirb ├── oneconf ├── onelog ├── bootstrap └── example.yaml ├── dev-tools └── onedepkidnap ├── onepush ├── bash_completion.d └── one ├── onessh ├── oneip ├── onecast ├── onefind ├── ansible_inventory.rb ├── README.md ├── LICENSE ├── onebootstrap-4.14 └── onebootstrap /onedeploy: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | onevm deploy `onetemplate instantiate $1|awk '{print $NF}'` `onehost list|sed 1d|awk '{if($NF=="on"){print $1}}'|head -n1` 3 | -------------------------------------------------------------------------------- /oneping: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | VM=$1 4 | shift 5 | 6 | IP=$(onevm show $VM -x|grep ''|grep -o '[0-9.]\+'|head -n1) 7 | 8 | ping "$IP" 9 | 10 | 11 | -------------------------------------------------------------------------------- /onessh-copy-id: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | VM=$1 4 | USER=$2 5 | [ -n "$USER" ] && USER="$USER@" 6 | 7 | IP=$(onevm show $VM|grep IP=|grep -Eo '[0-9.]+'|head -n 1) 8 | 9 | 10 | ssh-copy-id "${USER}${IP}" 11 | 12 | 13 | -------------------------------------------------------------------------------- /oneinstantiate: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | function getattr { 4 | echo "$INFO"|grep -E "^$1\b"|awk '{print $3}' 5 | } 6 | 7 | INFO=$(onetemplate show $1) 8 | 9 | ID=`getattr ID` 10 | NAME=`getattr NAME` 11 | 12 | echo onetemplate instantiate $ID --name $NAME 13 | onetemplate instantiate $ID --name $NAME 14 | -------------------------------------------------------------------------------- /onereport: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | require 'rexml/document' 4 | require 'pp' 5 | 6 | vmpool_x = `onevm list -x` 7 | vmpool = REXML::Document.new(vmpool_x).root 8 | 9 | first = true 10 | 11 | vmpool.elements.each("VM") do |vm| 12 | puts unless first 13 | first = false if first 14 | 15 | puts "VM: " + vm.elements["ID"].text 16 | puts "NAME: " + vm.elements["NAME"].text 17 | hostname = vm.elements["HISTORY_RECORDS/HISTORY/HOSTNAME"].text rescue nil 18 | puts "HOSTNAME: " + hostname if hostname 19 | 20 | vm.elements.each("TEMPLATE/GRAPHICS") do |vnc| 21 | if vnc_port = vnc.elements["PORT"] 22 | puts "VNC PORT: " + vnc_port.text 23 | end 24 | end 25 | vm.elements.each("TEMPLATE/NIC") do |nic| 26 | if ip = nic.elements["IP"] 27 | puts "IP: " + ip.text 28 | end 29 | end 30 | end 31 | -------------------------------------------------------------------------------- /oneuser-sshkey: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby 2 | 3 | ONE_LOCATION=ENV["ONE_LOCATION"] 4 | 5 | if !ONE_LOCATION 6 | RUBY_LIB_LOCATION="/usr/lib/one/ruby" 7 | VAR_LOCATION = "/var/lib/one" 8 | LIB_LOCATION = "/usr/lib/one" 9 | ETC_LOCATION = "/etc/one" 10 | else 11 | RUBY_LIB_LOCATION=ONE_LOCATION+"/lib/ruby" 12 | VAR_LOCATION = ONE_LOCATION+"/var" 13 | LIB_LOCATION = ONE_LOCATION+"/lib" 14 | ETC_LOCATION = ONE_LOCATION + "/etc" 15 | end 16 | 17 | $: << RUBY_LIB_LOCATION 18 | $: << RUBY_LIB_LOCATION+"/cloud" 19 | $: << RUBY_LIB_LOCATION+"/cli" 20 | 21 | ################################################ 22 | # Required libraries 23 | ################################################ 24 | require 'opennebula' 25 | include OpenNebula 26 | 27 | require 'pp' 28 | 29 | client = Client.new 30 | 31 | file = ARGV[0] || "#{ENV['HOME']}/.ssh/id_rsa.pub" 32 | ssh_public_key = File.read(file).strip 33 | 34 | user = User.new_with_id(OpenNebula::User::SELF, client) 35 | rc = user.info 36 | if OpenNebula.is_error?(rc) 37 | STDERR.puts rc.message 38 | exit 1 39 | end 40 | 41 | rc = user.update(%Q{SSH_PUBLIC_KEY="#{ssh_public_key}"}, false) 42 | if OpenNebula.is_error?(rc) 43 | STDERR.puts rc.message 44 | exit 1 45 | end 46 | -------------------------------------------------------------------------------- /onevnc: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | require 'getoptlong' 4 | 5 | ONE_LOCATION=ENV["ONE_LOCATION"] 6 | 7 | if !ONE_LOCATION 8 | RUBY_LIB_LOCATION="/usr/lib/one/ruby" 9 | VAR_LOCATION = "/var/lib/one" 10 | LIB_LOCATION = "/usr/lib/one" 11 | ETC_LOCATION = "/etc/one" 12 | else 13 | RUBY_LIB_LOCATION=ONE_LOCATION+"/lib/ruby" 14 | VAR_LOCATION = ONE_LOCATION+"/var" 15 | LIB_LOCATION = ONE_LOCATION+"/lib" 16 | ETC_LOCATION = ONE_LOCATION + "/etc" 17 | end 18 | 19 | $: << RUBY_LIB_LOCATION 20 | 21 | require 'opennebula' 22 | include OpenNebula 23 | 24 | CLIENT = Client.new 25 | 26 | def get_id(name) 27 | pool = VirtualMachinePool.new(CLIENT, -1) 28 | rc = pool.info 29 | 30 | if OpenNebula.is_error?(rc) 31 | STDERR.puts rc.message 32 | exit 1 33 | end 34 | 35 | pool.each do |vm| 36 | if vm['NAME'] == name 37 | return vm['ID'] 38 | end 39 | end 40 | 41 | return nil 42 | end 43 | 44 | id = ARGV.shift 45 | 46 | if !id.match(/^\d+$/) 47 | vm_id = get_id(id) 48 | 49 | if vm_id.nil? 50 | STDERR.puts "VM '#{id}' not found" 51 | exit 1 52 | else 53 | id = vm_id 54 | end 55 | end 56 | 57 | vm = VirtualMachine.new_with_id(id, CLIENT) 58 | rc = vm.info 59 | if OpenNebula.is_error?(rc) 60 | STDERR.puts rc.message 61 | exit 1 62 | end 63 | 64 | host = vm['HISTORY_RECORDS/HISTORY[last()]/HOSTNAME'] 65 | port = vm['TEMPLATE/GRAPHICS/PORT'] 66 | 67 | vncviewer = ARGV.shift || 'vinagre' 68 | 69 | cmd = [vncviewer, "#{host}::#{port}"] 70 | 71 | puts cmd.join(" ") 72 | exec(*cmd) 73 | -------------------------------------------------------------------------------- /onevcenterirb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | ONE_LOCATION=ENV["ONE_LOCATION"] if !defined?(ONE_LOCATION) 4 | 5 | if !ONE_LOCATION 6 | RUBY_LIB_LOCATION="/usr/lib/one/ruby" if !defined?(RUBY_LIB_LOCATION) 7 | else 8 | RUBY_LIB_LOCATION=ONE_LOCATION+"/lib/ruby" if !defined?(RUBY_LIB_LOCATION) 9 | end 10 | 11 | $: << RUBY_LIB_LOCATION 12 | $: << File.dirname(__FILE__) 13 | 14 | require 'vcenter_driver' 15 | 16 | def vclient_host(id) 17 | vi_client = VCenterDriver::VIClient.new_from_host(id) 18 | end 19 | 20 | def vm(vmid) 21 | one_vm = VCenterDriver::VIHelper.one_item(OpenNebula::VirtualMachine, vmid) 22 | did = one_vm["DEPLOY_ID"] 23 | hid = one_vm.retrieve_xmlelements("HISTORY_RECORDS/HISTORY/HID").last.text.to_i 24 | VCenterDriver::VirtualMachine.new_one(vclient_host(hid), did, one_vm) 25 | end 26 | 27 | def ds(dsid) 28 | one_ds = VCenterDriver::VIHelper.one_item(OpenNebula::Datastore, dsid) 29 | ref = one_ds["TEMPLATE/VCENTER_DS_REF"] 30 | vc = one_ds["TEMPLATE/VCENTER_HOST"] 31 | 32 | pool = VCenterDriver::VIHelper.one_pool(OpenNebula::HostPool) 33 | hid =pool.retrieve_xmlelements("HOST[TEMPLATE/VCENTER_HOST = '#{vc}']").first["ID"] 34 | 35 | vi_client = vclient_host(hid) 36 | 37 | VCenterDriver::Datastore.new_from_ref(ref, vi_client) 38 | end 39 | 40 | def host(hid) 41 | vi_client = vclient_host(hid) 42 | one_h = VCenterDriver::VIHelper.one_item(OpenNebula::Host, hid) 43 | 44 | VCenterDriver::ClusterComputeResource.new_from_ref(one_h['TEMPLATE/VCENTER_CCR_REF'], vi_client) 45 | end 46 | 47 | version = ">= 0" 48 | gem 'pry', version 49 | load Gem.bin_path('pry', 'pry', version) 50 | -------------------------------------------------------------------------------- /oneirb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby 2 | 3 | ONE_LOCATION=ENV["ONE_LOCATION"] 4 | 5 | if !ONE_LOCATION 6 | RUBY_LIB_LOCATION="/usr/lib/one/ruby" 7 | VAR_LOCATION = "/var/lib/one" 8 | LIB_LOCATION = "/usr/lib/one" 9 | ETC_LOCATION = "/etc/one" 10 | else 11 | RUBY_LIB_LOCATION=ONE_LOCATION+"/lib/ruby" 12 | VAR_LOCATION = ONE_LOCATION+"/var" 13 | LIB_LOCATION = ONE_LOCATION+"/lib" 14 | ETC_LOCATION = ONE_LOCATION + "/etc" 15 | end 16 | 17 | $: << RUBY_LIB_LOCATION 18 | $: << RUBY_LIB_LOCATION+"/cloud" # For the Repository Manager 19 | $: << RUBY_LIB_LOCATION+"/cli" # For the Repository Manager 20 | $: << LIB_LOCATION+'/oneflow/lib' 21 | 22 | ################################################ 23 | # Required libraries 24 | ################################################ 25 | 26 | require 'base64' 27 | require 'csv' 28 | require 'date' 29 | require 'digest/md5' 30 | require 'erb' 31 | require 'fileutils' 32 | require 'json' 33 | require 'nokogiri' 34 | require 'openssl' 35 | require 'ox' 36 | require 'set' 37 | require 'socket' 38 | require 'sqlite3' 39 | require 'tempfile' 40 | require 'time' 41 | require 'uri' 42 | require 'yaml' 43 | require 'pp' 44 | 45 | require 'opennebula' 46 | require 'vcenter_driver' 47 | include OpenNebula 48 | 49 | 50 | @client = Client.new 51 | 52 | module OpenNebula 53 | class XMLElement 54 | def self.from_xml(s) 55 | m = s.match(/^<(\w+)>/) 56 | root_element = m[1] 57 | 58 | elem = XMLElement.new 59 | elem.initialize_xml(s, root_element) 60 | return elem 61 | end 62 | end 63 | end 64 | 65 | version = ">= 0" 66 | gem 'pry', version 67 | load Gem.bin_path('pry', 'pry', version) 68 | -------------------------------------------------------------------------------- /oneconf: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | # This script prepares oned.conf and sched.conf 4 | 5 | require "fileutils" 6 | 7 | # Taken from: http://jimeh.me/blog/2010/02/22/built-in-sudo-for-ruby-command-line-tools/ 8 | def sudome 9 | if ENV["USER"] != "root" 10 | exec("sudo #{ENV['_']} #{ARGV.join(' ')}") 11 | end 12 | end 13 | 14 | class String 15 | def uncomment(string) 16 | self.gsub!(string) do |m| 17 | m.split("\n").map{|e| e.gsub(/^([\t\s]*)#+/,'\1')}.join("\n") 18 | end 19 | end 20 | end 21 | 22 | if ONE_LOCATION = ENV['ONE_LOCATION'] 23 | oned_conf = ONE_LOCATION + '/etc/oned.conf' 24 | sched_conf = ONE_LOCATION + '/etc/sched.conf' 25 | else 26 | sudome() 27 | 28 | oned_conf = '/etc/one/oned.conf' 29 | sched_conf = '/etc/one/sched.conf' 30 | end 31 | 32 | now = Time.now.strftime('%Y%m%d%H%M%S').to_s 33 | 34 | FileUtils.cp(oned_conf, oned_conf + '.' + now) 35 | FileUtils.cp(sched_conf, sched_conf + '.' + now) 36 | 37 | # oned.conf 38 | 39 | conf = File.read(oned_conf) 40 | 41 | single_vals = { 42 | :manager_timer => 5, 43 | :monitoring_interval => 25 44 | } 45 | 46 | single_vals.each do |k,v| 47 | k = k.to_s.upcase 48 | v = v.to_s 49 | 50 | if conf.match(/^#{k}/) 51 | puts "replace #{k} = #{v}" 52 | conf.gsub!(/^#{k}.*$/,"#{k} = #{v}") 53 | else 54 | puts "add #{k} = #{v}" 55 | conf << "\n#{k} = #{v}" 56 | end 57 | end 58 | 59 | conf.uncomment('#TM_MAD = [ 60 | # name = "tm_ssh", 61 | # executable = "one_tm", 62 | # arguments = "tm_ssh/tm_ssh.conf" ]') 63 | conf.uncomment('#TM_MAD = [ 64 | # name = "tm_dummy", 65 | # executable = "one_tm", 66 | # arguments = "tm_dummy/tm_dummy.conf" ]') 67 | conf.uncomment('#IM_MAD = [ name="im_dummy", executable="one_im_dummy"]') 68 | conf.uncomment('#VM_MAD = [ name="vmm_dummy", executable="one_vmm_dummy", type="xml" ]') 69 | 70 | #File.open(oned_conf,'w'){|f| f.write(conf)} 71 | 72 | # sched.conf 73 | 74 | conf = File.read(sched_conf) 75 | 76 | conf.gsub!('SCHED_INTERVAL = 30','SCHED_INTERVAL = 5') 77 | File.open(sched_conf,'w'){|f| f.write(conf)} 78 | 79 | -------------------------------------------------------------------------------- /onelog: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ "$1" = "--tail" -o "$1" == "-f" ]; then 4 | shift 5 | PAGER="tail -f" 6 | else 7 | PAGER=${PAGER:-less} 8 | fi 9 | 10 | 11 | if [ -n "$ONE_LOCATION" ]; then 12 | if [ -n "$1" ]; then 13 | case "$1" in 14 | econe) 15 | $PAGER $ONE_LOCATION/var/econe-server.log 16 | ;; 17 | econe.error) 18 | $PAGER $ONE_LOCATION/var/econe-server.error 19 | ;; 20 | sunstone) 21 | $PAGER $ONE_LOCATION/var/sunstone.log 22 | ;; 23 | sunstone.error) 24 | $PAGER $ONE_LOCATION/var/sunstone.error 25 | ;; 26 | sched) 27 | $PAGER $ONE_LOCATION/var/sched.log 28 | ;; 29 | monitor) 30 | $PAGER $ONE_LOCATION/var/monitor.log 31 | ;; 32 | fireedge) 33 | $PAGER $ONE_LOCATION/var/fireedge.log 34 | ;; 35 | fireedgerr) 36 | $PAGER $ONE_LOCATION/var/fireedge.error 37 | ;; 38 | *) 39 | $PAGER $ONE_LOCATION/var/vms/$1/vm.log 40 | ;; 41 | esac 42 | else 43 | $PAGER $ONE_LOCATION/var/oned.log 44 | fi 45 | else 46 | if [ -n "$1" ]; then 47 | case "$1" in 48 | econe) 49 | $PAGER /var/log/one/econe-server.log 50 | ;; 51 | econe.error) 52 | $PAGER /var/log/one/econe-server.error 53 | ;; 54 | sunstone) 55 | $PAGER /var/log/one/sunstone.log 56 | ;; 57 | sunstone.error) 58 | $PAGER /var/log/one/sunstone.error 59 | ;; 60 | sched) 61 | $PAGER /var/log/one/sched.log 62 | ;; 63 | monitor) 64 | $PAGER /var/log/one/monitor.log 65 | ;; 66 | fireedge) 67 | $PAGER /var/log/one/fireedge.log 68 | ;; 69 | fireedgerr) 70 | $PAGER /var/log/one/fireedge.err 71 | ;; 72 | *) 73 | $PAGER /var/log/one/$1.log 74 | ;; 75 | esac 76 | else 77 | $PAGER /var/log/one/oned.log 78 | fi 79 | fi 80 | -------------------------------------------------------------------------------- /bootstrap/example.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | # Available actions: 4 | # 5 | # - create 6 | # - update 7 | # 8 | # Available types: 9 | # 10 | # - user 11 | # - host 12 | # - image 13 | # - net 14 | # - template 15 | # - datastore 16 | # 17 | # List of examples. Commented options indicate optional attributes and their 18 | # default values: 19 | # 20 | # ## Create a User 21 | # 22 | # - action: create 23 | # type: user 24 | # name: steven 25 | # password: JGns/js 26 | # # :driver: core 27 | # 28 | # ## Create a Host 29 | # 30 | # - action: create 31 | # type: host 32 | # name: localhost 33 | # im: kvm 34 | # vmm: kvm 35 | # vnm: dummy 36 | # # :cluster_id: 37 | # 38 | # ## Create an Image 39 | # 40 | # - action: create 41 | # type: image 42 | # ds_id: 1 43 | # template: 44 | # name: ttylinux 45 | # type: OS 46 | # path: http://opennebula-marketplace.s3.amazonaws.com/ttylinux.img 47 | # driver: raw 48 | # prefix: vd 49 | # 50 | # ## Create a Virtual Network 51 | # 52 | # - action: create 53 | # type: net 54 | # # :cluster_id: 55 | # template: 56 | # name: private 57 | # bridge: br0 58 | # dns: 10.3.4.1 59 | # model: virtio 60 | # ar: 61 | # - ip: 10.3.4.20 62 | # size: 235 63 | # type: IP4 64 | # 65 | # ## Create a Template 66 | # 67 | # - action: create 68 | # type: template 69 | # template: 70 | # name: ttylinux 71 | # cpu: 1 72 | # memory: 512 73 | # arch: x86_64 74 | # disk: 75 | # image: ttylinux 76 | # nic: 77 | # network: private 78 | # graphics: 79 | # type: vnc 80 | # listen: 0.0.0.0 81 | # context: 82 | # ssh_public_key: $USER[SSH_PUBLIC_KEY] 83 | # network: YES 84 | # 85 | # ## Update a user (or any other resource) by name 86 | # 87 | # - action: update 88 | # type: user 89 | # name: steven 90 | # # :append: true 91 | # template: 92 | # ssh_public_key: "the key..." 93 | # 94 | # ## Update a user (or any other resource) by ID 95 | # 96 | # - action: update 97 | # type: user 98 | # id: 23 99 | # # :append: true 100 | # template: 101 | # ssh_public_key: "the key..." 102 | # 103 | -------------------------------------------------------------------------------- /dev-tools/onedepkidnap: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby 2 | 3 | ONE_LOCATION = ENV['ONE_LOCATION'] 4 | 5 | if !ONE_LOCATION 6 | RUBY_LIB_LOCATION = '/usr/lib/one/ruby' 7 | VAR_LOCATION = '/var/lib/one' 8 | LIB_LOCATION = '/usr/lib/one' 9 | ETC_LOCATION = '/etc/one' 10 | else 11 | RUBY_LIB_LOCATION = ONE_LOCATION + '/lib/ruby' 12 | VAR_LOCATION = ONE_LOCATION + '/var' 13 | LIB_LOCATION = ONE_LOCATION + '/lib' 14 | ETC_LOCATION = ONE_LOCATION + '/etc' 15 | end 16 | 17 | VMM_VCENTER = VAR_LOCATION + '/remotes/vmm/vcenter' 18 | $LOAD_PATH << RUBY_LIB_LOCATION 19 | 20 | require 'fileutils' 21 | 22 | template_id = ARGV[0] 23 | 24 | # Add unindent 25 | class String 26 | 27 | def unindent(spaces = 4) 28 | gsub!(/^ {#{spaces}}/, '') 29 | end 30 | 31 | end 32 | 33 | HIJACK_CODE = <<-EOT.unindent(1) 34 | #!/bin/bash 35 | cat > /tmp/one_deploy_xmldrvaction 36 | exit -1 37 | EOT 38 | 39 | # backup vcenter deploy 40 | File.rename VMM_VCENTER + '/deploy', VMM_VCENTER + '/deploy.bk' 41 | 42 | # write hijack code 43 | File.open(VMM_VCENTER + '/deploy', 'w') {|file| file.write(HIJACK_CODE) } 44 | File.chmod(0o0755, VMM_VCENTER + '/deploy') 45 | 46 | begin 47 | # instantiate template 48 | vm_id = `onetemplate instantiate #{template_id}`.split(':')[1].strip 49 | raise if vm_id.to_i.to_s != vm_id 50 | 51 | loop do 52 | state = `onevm show #{vm_id}|grep ^LCM_STATE|cut -d':' -f 2` 53 | state.strip! if state 54 | puts "Waiting for VM #{vm_id} in state BOOT_FAILURE, got: " + state 55 | break if state == 'BOOT_FAILURE' 56 | 57 | sleep 1 58 | end 59 | rescue StandardError 60 | STDERR.puts 'Instantiate failed, rolling back changes in deploy script' 61 | FileUtils.mv(VMM_VCENTER + '/deploy.bk', VMM_VCENTER + '/deploy') 62 | exit(-1) 63 | end 64 | 65 | 66 | # inject pry code 67 | deployment_file = File.open(VMM_VCENTER + '/deploy', 'w') 68 | backup_deployment_file = File.new(VMM_VCENTER + '/deploy.bk') 69 | backup_deployment_file.each do |line| 70 | if line =~ /^drv_action.initialize_xml/ 71 | deployment_file << <<-EOT.unindent(10) 72 | drv_xml = `cat /tmp/one_deploy_xmldrvaction`.gsub('\\n','') 73 | drv_action.initialize_xml(Base64.decode64(drv_xml), 'VM') 74 | require 'pry-byebug' 75 | binding.pry 76 | EOT 77 | else 78 | deployment_file << line 79 | end 80 | end 81 | 82 | deployment_file.close 83 | backup_deployment_file.close 84 | 85 | puts 86 | puts 'Deploy kidnapped. Execute the following to debug the deploy:' 87 | puts " #{`onelog #{vm_id}|grep failed|grep deploy|tail -1`.split(':')[5].strip}" 88 | puts 89 | puts 'Remember to restore the deploy script afterwards:' 90 | puts " mv #{VMM_VCENTER + '/deploy.bk'} #{VMM_VCENTER + '/deploy'}" 91 | -------------------------------------------------------------------------------- /onepush: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby 2 | 3 | $LOAD_PATH << '/usr/lib/one/ruby/' 4 | Gem.paths = { 5 | 'GEM_PATH' => '/usr/share/one/gems-dist' 6 | } 7 | 8 | require 'base64' 9 | require 'json' 10 | require 'nokogiri' 11 | require 'opennebula' 12 | 13 | def get_vm_host(vm_id) 14 | c = OpenNebula::Client.new 15 | 16 | vm_pool = OpenNebula::VirtualMachinePool.new(c) 17 | rc = vm_pool.info_all! 18 | raise rc.message if OpenNebula.is_error?(rc) 19 | 20 | vm_pool.retrieve_xmlelements("VM[ID=#{vm_id}]/HISTORY_RECORDS/HISTORY[last()]/HOSTNAME")[0] \ 21 | || abort("Machine #{vm_id} does not exist or is not running") 22 | 23 | vm_pool.retrieve_xmlelements("VM[ID=#{vm_id}]/HISTORY_RECORDS/HISTORY[last()]/HOSTNAME")[0].text 24 | end 25 | 26 | def query_vm_agent(vm_id, query, host = 'localhost') 27 | cmd = "virsh -c 'qemu+ssh://#{host}/system' qemu-agent-command one-#{vm_id} '#{query.to_json}'" 28 | out = `#{cmd}` 29 | JSON.parse(out) 30 | end 31 | 32 | def guest_change_permissions(vm_id, remote_path, permissions) 33 | host = get_vm_host(vm_id) 34 | 35 | exec_chmod = { 'execute' => 'guest-exec', 36 | 'arguments' => { 37 | 'path' => '/bin/chmod', 38 | 'arg' => [permissions, remote_path] 39 | } 40 | } 41 | 42 | query_vm_agent(vm_id, exec_chmod, host) 43 | end 44 | 45 | def guest_file_write(vm_id, local_path, remote_path) 46 | host = get_vm_host(vm_id) 47 | openfile = { 'execute' => 'guest-file-open', 48 | 'arguments' => { 49 | 'path' => remote_path, 50 | 'mode' => 'w' 51 | } 52 | } 53 | 54 | handle = query_vm_agent(vm_id, openfile, host)['return'] 55 | 56 | abort("Couldn't open file #{remote_path} in the guest") unless handle >= 0 57 | 58 | writefile = { 'execute' => 'guest-file-write', 59 | 'arguments' => { 60 | 'handle' => handle, 61 | 'buf-b64' => Base64.encode64(File.open(local_path, 'rb').read) 62 | } 63 | } 64 | 65 | wstatus = query_vm_agent(vm_id, writefile, host)['return'] 66 | puts("#{wstatus['count']} bytes written from #{local_path} to VM #{vm_id} on #{remote_path}") 67 | 68 | closefile = { 'execute' => 'guest-file-close', 69 | 'arguments' => {'handle' => handle } 70 | } 71 | 72 | status = query_vm_agent(vm_id, closefile, host) 73 | end 74 | 75 | ARGV.length != 3 && abort("Usage: #{ARGV[0]} VM_ID SOURCE_FILE DESTINATION_FILE") 76 | 77 | VM_ID, SRC_FILE, DST_FILE = ARGV[0], ARGV[1], ARGV[2] 78 | 79 | VM_ID =~ %r{[0-9]+} || abort("#{VM_ID} is not a valid ID for a VM") 80 | File.exist?(SRC_FILE) || abort("File #{SRC_FILE} does not exist") 81 | DST_FILE =~ %r{^(\/[A-z0-9_-]+)+} || abort("Destination file #{DST_FILE} does not look like a valid path") 82 | 83 | SRC_PERMISSIONS = (format('%04o', File.stat(SRC_FILE).mode))[3..] 84 | 85 | 86 | guest_file_write(VM_ID, SRC_FILE, DST_FILE) 87 | guest_change_permissions(VM_ID, DST_FILE, SRC_PERMISSIONS) 88 | 89 | 90 | -------------------------------------------------------------------------------- /bash_completion.d/one: -------------------------------------------------------------------------------- 1 | _one_list() { 2 | local cmd filter 3 | one_cmd=$1 4 | if [ -n "$2" ]; then 5 | filter="-f $2" 6 | fi 7 | echo $($one_cmd $filter list|sed 1d|awk '{print $1}') 8 | return 0 9 | } 10 | 11 | _onevm() { 12 | local cur prev opts cmd 13 | COMPREPLY=() 14 | cur="${COMP_WORDS[COMP_CWORD]}" 15 | prev="${COMP_WORDS[COMP_CWORD-1]}" 16 | if [ "${#COMP_WORDS[@]}" -gt "2" ]; then 17 | pprev="${COMP_WORDS[COMP_CWORD-2]}" 18 | fi 19 | opts="create deploy shutdown livemigrate migrate hold release stop cancel suspend resume delete restart list show top history" 20 | cmd=onevm 21 | if [ $COMP_CWORD == 1 ] 22 | then 23 | COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) 24 | return 0 25 | elif [ $COMP_CWORD == 2 ] 26 | then 27 | case "$prev" in 28 | show|delete) 29 | vms=`_one_list $cmd` 30 | COMPREPLY=( $(compgen -W "${vms}" -- ${cur}) ) 31 | return 0 32 | ;; 33 | cancel|shutdown|suspend|stop) 34 | vms=`_one_list $cmd stat='runn'` 35 | COMPREPLY=( $(compgen -W "${vms}" -- ${cur}) ) 36 | return 0 37 | ;; 38 | create|submit) 39 | COMPREPLY=( $(compgen -A file -- ${cur}) ) 40 | return 0 41 | ;; 42 | migrate) 43 | vms=`_one_list $cmd stat='runn'` 44 | COMPREPLY=( $(compgen -W "${vms}" -- ${cur}) ) 45 | return 0 46 | ;; 47 | esac 48 | elif [ $COMP_CWORD == 3 ] 49 | then 50 | case "$pprev" in 51 | migrate) 52 | hosts=`onehost list -f STAT=on|sed 1d|awk '{print $2}'` 53 | COMPREPLY=( $(compgen -W "${hosts}" -- ${cur}) ) 54 | return 0 55 | ;; 56 | esac 57 | fi 58 | } 59 | 60 | complete -F _onevm onevm 61 | 62 | _onevnet() { 63 | local cur prev opts cmd 64 | COMPREPLY=() 65 | cur="${COMP_WORDS[COMP_CWORD]}" 66 | prev="${COMP_WORDS[COMP_CWORD-1]}" 67 | opts="create delete list show" 68 | cmd=onevnet 69 | if [ $COMP_CWORD == 1 ] 70 | then 71 | COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) 72 | return 0 73 | elif [ $COMP_CWORD == 2 ] 74 | then 75 | case "$prev" in 76 | create|submit) 77 | COMPREPLY=( $(compgen -A file -- ${cur}) ) 78 | return 0 79 | ;; 80 | delete|show) 81 | vnets=`_one_list $cmd` 82 | COMPREPLY=( $(compgen -W "${vnets}" -- ${cur}) ) 83 | return 0 84 | ;; 85 | esac 86 | fi 87 | 88 | } 89 | 90 | complete -F _onevnet onevnet 91 | 92 | _onehost() { 93 | local cur prev opts cmd 94 | COMPREPLY=() 95 | cur="${COMP_WORDS[COMP_CWORD]}" 96 | prev="${COMP_WORDS[COMP_CWORD-1]}" 97 | opts="create show delete list enable disable top" 98 | cmd=onehost 99 | if [ $COMP_CWORD == 1 ] 100 | then 101 | COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) 102 | return 0 103 | elif [ $COMP_CWORD == 2 ] 104 | then 105 | case "$prev" in 106 | create|submit) 107 | COMPREPLY=( $(compgen -A file -- ${cur}) ) 108 | return 0 109 | ;; 110 | delete|show) 111 | hosts=`_one_list $cmd` 112 | COMPREPLY=( $(compgen -W "${hosts}" -- ${cur}) ) 113 | return 0 114 | ;; 115 | enable) 116 | hosts=`_one_list $cmd stat='off'` 117 | COMPREPLY=( $(compgen -W "${hosts}" -- ${cur}) ) 118 | return 0 119 | ;; 120 | disable) 121 | hosts=`_one_list $cmd stat='on'` 122 | COMPREPLY=( $(compgen -W "${hosts}" -- ${cur}) ) 123 | return 0 124 | ;; 125 | esac 126 | fi 127 | 128 | } 129 | 130 | complete -F _onehost onehost 131 | -------------------------------------------------------------------------------- /onessh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | require 'getoptlong' 4 | 5 | ONE_LOCATION=ENV["ONE_LOCATION"] 6 | 7 | if !ONE_LOCATION 8 | RUBY_LIB_LOCATION="/usr/lib/one/ruby" 9 | VAR_LOCATION = "/var/lib/one" 10 | LIB_LOCATION = "/usr/lib/one" 11 | ETC_LOCATION = "/etc/one" 12 | else 13 | RUBY_LIB_LOCATION=ONE_LOCATION+"/lib/ruby" 14 | VAR_LOCATION = ONE_LOCATION+"/var" 15 | LIB_LOCATION = ONE_LOCATION+"/lib" 16 | ETC_LOCATION = ONE_LOCATION + "/etc" 17 | end 18 | 19 | $: << RUBY_LIB_LOCATION 20 | 21 | require 'opennebula' 22 | include OpenNebula 23 | 24 | CLIENT = Client.new 25 | 26 | def get_id(name) 27 | pool = VirtualMachinePool.new(CLIENT, -1) 28 | rc = pool.info 29 | 30 | if OpenNebula.is_error?(rc) 31 | STDERR.puts rc.message 32 | exit 1 33 | end 34 | 35 | pool.each do |vm| 36 | if vm['NAME'] == name 37 | return vm['ID'] 38 | end 39 | end 40 | 41 | return nil 42 | end 43 | 44 | opts = GetoptLong.new( 45 | [ '--ip', GetoptLong::NO_ARGUMENT ], 46 | [ '--name', GetoptLong::NO_ARGUMENT ], 47 | [ '--nic_id', GetoptLong::REQUIRED_ARGUMENT ], 48 | [ '--network_id', GetoptLong::REQUIRED_ARGUMENT ], 49 | [ '--network', GetoptLong::REQUIRED_ARGUMENT ], 50 | [ '--wait', GetoptLong::NO_ARGUMENT ], 51 | [ '--retries', GetoptLong::REQUIRED_ARGUMENT ], 52 | [ '--login', '-l', GetoptLong::REQUIRED_ARGUMENT ], 53 | [ '--interval', GetoptLong::REQUIRED_ARGUMENT ] 54 | ) 55 | 56 | ip = true 57 | name = false 58 | nic_id = nil 59 | network_id = nil 60 | network = nil 61 | wait = false 62 | retries = 100 63 | interval = 1 64 | login = "root" 65 | 66 | opts.each do |opt, arg| 67 | case opt 68 | when '--ip' 69 | ip = true 70 | when '--name' 71 | ip = false 72 | when '--nic_id' 73 | nic_id = arg 74 | when '--network_id' 75 | network_id = arg 76 | when '--network' 77 | network = arg 78 | when '--wait' 79 | wait = true 80 | when '--retries' 81 | retries = arg.to_i 82 | when '--login' 83 | login = arg 84 | when '--interval' 85 | interval = arg.to_i 86 | end 87 | end 88 | 89 | id = ARGV.shift 90 | 91 | if !id.match(/^\d+$/) 92 | vm_id = get_id(id) 93 | 94 | if vm_id.nil? 95 | STDERR.puts "VM '#{id}' not found" 96 | exit 1 97 | else 98 | id = vm_id 99 | end 100 | end 101 | 102 | vm = VirtualMachine.new_with_id(id, CLIENT) 103 | rc = vm.info 104 | if OpenNebula.is_error?(rc) 105 | STDERR.puts rc.message 106 | exit 1 107 | end 108 | 109 | xpath = "/VM/TEMPLATE/NIC" 110 | if nic_id 111 | ip = true 112 | xpath += "[NIC_ID='#{nic_id}']" 113 | elsif network_id 114 | ip = true 115 | xpath += "[NETWORK_ID='#{network_id}']" 116 | elsif network 117 | ip = true 118 | xpath += "[NETWORK='#{network}']" 119 | end 120 | 121 | hostname = nil 122 | 123 | if ip 124 | vm.each(xpath) do |nic| 125 | hostname = nic['IP'] 126 | break 127 | end 128 | else 129 | hostname = vm['NAME'] 130 | end 131 | 132 | if hostname.nil? 133 | STDERR.puts "IP for VM '#{vm['NAME']}' not found" 134 | exit 1 135 | end 136 | 137 | ssh_cmd = ['ssh', '-l', login, hostname] 138 | 139 | if wait 140 | wait_args = [ 141 | "-o", "PasswordAuthentication=no", 142 | "-o", "IdentitiesOnly=yes", 143 | "-o", "StrictHostKeyChecking=no", 144 | "-o", "UserKnownHostsFile=/dev/null", 145 | "-o", "LogLevel=quiet", 146 | "-o", "ConnectionAttempts=3", 147 | "-o", "ConnectTimeout=10", 148 | "-o", "ControlMaster=no", 149 | "-o", "ControlPath=no", 150 | "exit", "0" 151 | ] 152 | 153 | ssh_cmd += wait_args 154 | 155 | retries.times do 156 | if system(*ssh_cmd) 157 | exit 0 158 | end 159 | sleep interval 160 | end 161 | exit 1 162 | else 163 | ssh_cmd += ARGV 164 | exec(*ssh_cmd) 165 | end 166 | 167 | 168 | -------------------------------------------------------------------------------- /oneip: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ARG_IP="" 4 | ARG_NET="" 5 | NET_IDS=$(onevnet list | grep -v ID | awk '{print $1}') 6 | 7 | if [ $1 == "-c" ] || [ $1 == "--check" ] 8 | then 9 | if [[ $2 =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]] 10 | then 11 | ARG_IP=$2 12 | else 13 | echo "#############################################" 14 | echo " This ($2) is not valid IP format" 15 | echo "#############################################" 16 | exit 17 | fi 18 | fi 19 | if [ $1 == "-g" ] || [ $1 == "--get" ] 20 | then 21 | NET_EXISTS=false 22 | ARG_NET="$2" 23 | for i in "${NET_IDS[@]}" 24 | do 25 | if [[ $i == $ARG_NET ]] 26 | then 27 | NET_EXISTS=true 28 | fi 29 | done 30 | if [[ $NET_EXISTS == "true" ]] 31 | then 32 | echo "#############################################" 33 | echo " Net with this IP ($2) does not exists" 34 | echo "#############################################" 35 | exit 36 | fi 37 | fi 38 | 39 | 40 | 41 | ALL_IPS="" 42 | for NETS in $NET_IDS 43 | do 44 | NET_RANGES=$(onevnet show $NETS | grep "^IP" | awk '{print $2 "-" $3}') 45 | for RANGE in $NET_RANGES 46 | do 47 | RANGE_FIRST=$(echo $RANGE | awk -F \- '{print $1}') 48 | RANGE_LAST=$(echo $RANGE | awk -F \- '{print $2}') 49 | WILD_CARD=$(echo $RANGE_FIRST | awk -F \. '{print $1"."$2"."$3".%g" }') 50 | RANGE_START=$(echo $RANGE_FIRST | awk -F \. '{print $4}') 51 | RANGE_LAST=$(echo $RANGE_LAST | awk -F \. '{print $4}') 52 | SUBNET_IPS=$(seq -f "$WILD_CARD" $RANGE_START $RANGE_LAST) 53 | ALL_IPS="$ALL_IPS $SUBNET_IPS" 54 | done 55 | done 56 | 57 | case $1 in 58 | 59 | "-c" | "--check") 60 | IP_PINGED=false 61 | IP_RESERVED=false 62 | IP_USED=false 63 | IP_IS_IN_SUBNET_BUT_NOT_USED=false 64 | for NET in $NET_IDS 65 | do 66 | IP_IN_SUBNET=$(onevnet show $NET|grep -i " $2 ") 67 | if [ -z "$IP_IN_SUBNET" ] 68 | then 69 | if ping -c1 -w2 $2 >/dev/null 2>&1 70 | then 71 | IP_PINGED=true 72 | fi 73 | else 74 | if [[ ! -z "$IP_IN_SUBNET" ]] 75 | then 76 | VM_ID=$(echo $IP_IN_SUBNET | awk '{print $2}' | awk -F\: '{print $2}') 77 | fi 78 | if [ "$VM_ID" == "-1" ] 79 | then 80 | IP_RESERVED=true 81 | echo "#############################################" 82 | echo " This IP is reserved" 83 | echo "#############################################" 84 | else 85 | IP_USED=true 86 | VM_NAME=$(onevm show $VM_ID | grep ^NAME | awk '{print $3}') 87 | VM_HOST=$(onevm show $VM_ID | grep ^HOST | awk '{print $3}') 88 | echo "#############################################" 89 | echo " This IP is on VM" 90 | echo " VM : $VM_NAME" 91 | echo " Host : $VM_HOST" 92 | echo "#############################################" 93 | fi 94 | fi 95 | done 96 | if [ "$IP_PINGED" == "true" ] && [ "$IP_RESERVED" == "false" ] && [ "$IP_USED" == "false" ] 97 | then 98 | echo "#############################################" 99 | echo " This IP is not used by opennebula but it is pingable" 100 | echo "#############################################" 101 | fi 102 | if [ "$IP_PINGED" == "false" ] && [ "$IP_RESERVED" == "false" ] && [ "$IP_USED" == "false" ] 103 | then 104 | echo "#############################################" 105 | echo " IP is FREE" 106 | echo "#############################################" 107 | fi 108 | 109 | ;; 110 | 111 | "-g" | "--give") 112 | USED_IPS=$(onevnet show $NET_ID | grep -Eo '[0-9]+[.][0-9]+[.][0-9]+[.][0-9]+') 113 | FOUND_IP=false 114 | for IP in $SUBNET_IPS 115 | do 116 | for used_ip in $USED_IPS 117 | do 118 | if [ $IP == $used_ip ] 119 | then 120 | FOUND_IP=true 121 | break 122 | else 123 | FOUND_IP=false 124 | continue 125 | fi 126 | done 127 | if [ $FOUND_IP == "false" ] 128 | then 129 | if ping -c1 -w3 $IP >/dev/null 2>&1 130 | then 131 | continue 132 | else 133 | echo $IP is free 134 | exit 135 | fi 136 | fi 137 | done 138 | ;; 139 | 140 | *) 141 | echo 142 | echo "oneip --check 172.16.77.134" 143 | echo "oneip -c 172.16.77.134" 144 | echo "oneip --get [NET_ID]" 145 | echo "oneip -g [NET_ID]" 146 | ;; 147 | esac 148 | 149 | -------------------------------------------------------------------------------- /onecast: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | require 'getoptlong' 4 | require 'tempfile' 5 | require 'open-uri' 6 | 7 | HELP_TEXT=<] 10 | 11 | Options: 12 | -d, --data = Sets the value that goes into a template 13 | -c, --create [vm|vnet|image] Calls create command of onvm, onevnet 14 | or oneimage. If the object type is no 15 | specified then onevm is called 16 | -h, --help Prints this help text 17 | 18 | Template: 19 | Template variables have the form ${NAME}. The name of the variable is 20 | case sensitive and is translated to the value specified in the command 21 | line or the environment. It can also have a default value if the variable 22 | is not specified in the command line or not found in the environment this 23 | way ${NAME|default value}. 24 | EOT 25 | 26 | class OneCast 27 | attr_reader :vars, :error 28 | 29 | REG_VAR=/\$\{([^}|]+)(\|([^}]+))?\}/ 30 | 31 | def initialize(template, data) 32 | @vars=ENV.to_hash 33 | @error=nil 34 | @template=template.clone 35 | 36 | data.each do |text| 37 | parsed=parse_data_variable(text) 38 | raise "Bad formatted variable: '#{text}'" if !parsed 39 | @vars[parsed[0]]=parsed[1].gsub("\\n", "\n") 40 | end 41 | end 42 | 43 | def rewrite_template 44 | @error=nil 45 | 46 | @template.gsub(REG_VAR) do |var| 47 | match=REG_VAR.match(var) 48 | 49 | var_name=match[1] 50 | default_value=match[3] 51 | 52 | d=@vars[var_name] 53 | 54 | d||=default_value 55 | 56 | if !d 57 | @error||='' 58 | @error+="Variable '#{var_name}' not set. " 59 | end 60 | 61 | d 62 | end 63 | end 64 | 65 | private 66 | 67 | def parse_data_variable(text) 68 | m=(/^([^=]+)=["']?(.*)["']?/m).match(text) 69 | if m 70 | m[1,2] 71 | else 72 | nil 73 | end 74 | end 75 | 76 | end 77 | 78 | def print_help 79 | puts HELP_TEXT 80 | end 81 | 82 | opts = GetoptLong.new( 83 | [ '--help', '-h', GetoptLong::NO_ARGUMENT ], 84 | [ '--data', '-d', GetoptLong::REQUIRED_ARGUMENT ], 85 | [ '--create', '-c', GetoptLong::OPTIONAL_ARGUMENT], 86 | [ '--temp', '-t', GetoptLong::OPTIONAL_ARGUMENT] 87 | ) 88 | 89 | text_variables=Array.new 90 | create=false 91 | temp=false 92 | 93 | begin 94 | opts.each do |opt, arg| 95 | case opt 96 | when '--data' 97 | text_variables< e 119 | STDERR.puts e 120 | print_help 121 | exit(-1) 122 | end 123 | 124 | template_name=ARGV[0] 125 | 126 | if !template_name 127 | STDERR.puts "ERROR: Template file not provided.\n\n" 128 | print_help 129 | exit(-1) 130 | end 131 | 132 | begin 133 | file=open(template_name) 134 | template_text=file.read 135 | file.close 136 | rescue 137 | puts "Could not read template file '#{template_name}'." 138 | exit(-1) 139 | end 140 | 141 | begin 142 | onecast=OneCast.new(template_text, text_variables) 143 | rescue Exception => e 144 | puts e 145 | exit(-1) 146 | end 147 | 148 | final_template=onecast.rewrite_template 149 | errors=onecast.error 150 | 151 | 152 | STDERR.puts errors if errors 153 | 154 | if create 155 | temp=Tempfile.new "#{create}.one" 156 | temp.write final_template 157 | temp.close 158 | system "one#{create} create -v #{temp.path}" 159 | temp.unlink 160 | 161 | exit(0) 162 | end 163 | 164 | if temp 165 | tempf = `mktemp --tmpdir=/tmp --suffix=.one onecast.XXX`.strip 166 | File.open(tempf,'w'){|file| file.write final_template} 167 | puts tempf 168 | else 169 | puts final_template 170 | end 171 | -------------------------------------------------------------------------------- /onefind: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | # This script finds all elements that have an specific value in their template 4 | # To run it, simply execute: 5 | # ./find VALUE_TO_FIND PATH_TO_SEARCH 6 | # ./find YES TEMPLATE/ALLOW_ORPHANS 7 | # 8 | # How you should read the output? The script will output the following: 9 | # ELEMENT_NAME 10 | # ------------ 11 | # ID_1 12 | # ID_2 13 | # 14 | # If no elements are found, you will see a message like: `No elements found` 15 | # 16 | # WARNING: if you want to check all the elements in your cloud, run the script 17 | # under oneadmin (or oneadmin group) user 18 | 19 | ONE_LOCATION = ENV['ONE_LOCATION'] 20 | 21 | if !ONE_LOCATION 22 | RUBY_LIB_LOCATION = '/usr/lib/one/ruby' 23 | GEMS_LOCATION = '/usr/share/one/gems' 24 | else 25 | RUBY_LIB_LOCATION = ONE_LOCATION + '/lib/ruby' 26 | GEMS_LOCATION = ONE_LOCATION + '/share/gems' 27 | end 28 | 29 | if File.directory?(GEMS_LOCATION) 30 | $LOAD_PATH.reject! {|l| l =~ /vendor_ruby/ } 31 | require 'rubygems' 32 | Gem.use_paths(File.realpath(GEMS_LOCATION)) 33 | end 34 | 35 | $LOAD_PATH << RUBY_LIB_LOCATION 36 | 37 | require 'opennebula' 38 | 39 | ################################################################################ 40 | # FUNCTIONS 41 | ################################################################################ 42 | 43 | # Search inside path 44 | # 45 | # @param hash [Hash] Hash to seach in 46 | # @param path [String] Path to search on 47 | def dsearch(hash, path) 48 | path.delete_if {|s| s.nil? || s.empty? } 49 | 50 | path.each do |p| 51 | if hash.is_a? Hash 52 | if hash[p] 53 | hash = hash[p] 54 | else 55 | hash = nil 56 | break 57 | end 58 | else 59 | hash = nil 60 | break 61 | end 62 | end 63 | 64 | hash 65 | end 66 | 67 | # Execute main loop to find elements 68 | # 69 | # @param pools [Array] OpenNebula pools names 70 | # @param value [String] Value to find 71 | # @param path [Array] Path to search on 72 | # 73 | # @return [Hash] Hash with each element as key and found IDs as value 74 | def main(pools, value, path) 75 | # Get client object to make calls 76 | client = OpenNebula::Client.new 77 | ret = {} 78 | 79 | # Iterate over all pools 80 | pools.each do |p_class| 81 | pool = OpenNebula.const_get(p_class).new(client) 82 | rc = pool.info_all 83 | ids = [] 84 | 85 | if OpenNebula.is_error?(rc) 86 | STDERR.puts rc.message 87 | exit(-1) 88 | end 89 | 90 | # Iterate over each pool element 91 | pool.each do |elem| 92 | elem = elem.to_hash[pool.element_name] 93 | id = elem['ID'] 94 | elem = dsearch(elem, path) 95 | 96 | next unless elem == value 97 | 98 | ids << id 99 | end 100 | 101 | next if ids.empty? 102 | 103 | ret[pool.element_name] = ids 104 | end 105 | 106 | ret 107 | end 108 | 109 | ################################################################################ 110 | ################################################################################ 111 | 112 | if !ARGV[0] && !ARGV[1] 113 | STDERR.puts 'Value to find or path not provided!' 114 | STDERR.puts '`find.rb` ' 115 | exit(-1) 116 | end 117 | 118 | # Get path to find value 119 | path = ARGV[1].split('/') 120 | 121 | unless path.is_a? Array 122 | STDERR.puts 'Wrong path format! It should be A/B/C way' 123 | end 124 | 125 | ################################################################################ 126 | ################################################################################ 127 | 128 | # OpenNebula pools 129 | pools = OpenNebula.constants.select {|c| OpenNebula.const_get(c).is_a? Class } 130 | 131 | # Remove parent classes or pools that are accessed by other services like flow 132 | pools -= [:Pool, 133 | :DocumentPool, 134 | :ServicePool, 135 | :ServiceTemplatePool, 136 | :XMLPool, 137 | :OpenNebulaServicePool] 138 | 139 | pools.select! {|p| p =~ /Pool$/ } 140 | 141 | ret = main(pools, ARGV[0], path) 142 | 143 | if ret.empty? 144 | puts 'No elements found' 145 | else 146 | ret.each do |key, value| 147 | puts "#{key}S" 148 | (key.size + 1).times { print '-' } 149 | puts 150 | 151 | value.each {|id| puts id } 152 | 153 | puts unless key == ret.keys.last 154 | end 155 | end 156 | -------------------------------------------------------------------------------- /ansible_inventory.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby 2 | 3 | # This inventory extracts VM information from OpenNebula to be used by Ansible. 4 | 5 | # The following information is obtained: 6 | 7 | # * All the parameters in the Context and in the User Template 8 | # * Disk information: size, image_id and persistancy 9 | # * Network information: IP, MAC address, etc 10 | 11 | # Only VMs that meet any of these conditions are returned by the inventory 12 | 13 | # * It has a context variable called "ANSIBLE". The content of this variable is 14 | # the ansible group it will be placed into 15 | # * It has the "ansible" label 16 | # * It has a label under "ansible". Whatever the label is will be the ansible 17 | # group it will be placed into 18 | 19 | # If there is no DNS for the VM, you may use the User Template variable 20 | # "ANSIBLE_HOST" in order to specify what IP should this inventory report to 21 | # ansible: 22 | 23 | # * ANSIBLE_HOST is undefined: Ansible will use the VM name 24 | # * ANSIBLE_HOST=yes: Ansible will use the IP of the first interface 25 | # * ANSIBLE_HOST=eth0: Ansible will use the IP of the first interface 26 | # * ANSIBLE_HOST=eth1: Ansible will use the IP of the second interface 27 | # * ANSIBLE_HOST=ethN: Ansible will use the IP of the N-1 interface 28 | 29 | ONE_LOCATION=ENV["ONE_LOCATION"] 30 | 31 | if !ONE_LOCATION 32 | RUBY_LIB_LOCATION = "/usr/lib/one/ruby" 33 | VAR_LOCATION = "/var/lib/one" 34 | LIB_LOCATION = "/usr/lib/one" 35 | ETC_LOCATION = "/etc/one" 36 | else 37 | RUBY_LIB_LOCATION = ONE_LOCATION + "/lib/ruby" 38 | VAR_LOCATION = ONE_LOCATION + "/var" 39 | LIB_LOCATION = ONE_LOCATION + "/lib" 40 | ETC_LOCATION = ONE_LOCATION + "/etc" 41 | end 42 | 43 | $: << RUBY_LIB_LOCATION 44 | 45 | require 'opennebula' 46 | include OpenNebula 47 | 48 | require 'pp' 49 | require 'json' 50 | 51 | class Inventory 52 | attr_reader :inventory, :hostvars 53 | 54 | def initialize 55 | @inventory = {} 56 | @hostvars = {} 57 | 58 | mkgroup(:all) 59 | end 60 | 61 | def host(name, group = :all) 62 | mkgroup(group) 63 | @inventory[group][:hosts] << name 64 | end 65 | 66 | def groupvar(group, var, val) 67 | mkgroup(group) 68 | @inventory[group][:vars][var.downcase] = val 69 | end 70 | 71 | def hostvar(host, var, val) 72 | @hostvars[host] = {} if @hostvars[host].nil? 73 | @hostvars[host][var.downcase] = val 74 | end 75 | 76 | def to_json 77 | { 78 | "_meta" => { 79 | "hostvars" => @hostvars 80 | }, 81 | }.merge(@inventory).to_json 82 | end 83 | 84 | private 85 | 86 | def mkgroup(group) 87 | @inventory[group] = {} if @inventory[group].nil? 88 | @inventory[group][:hosts] = [] if @inventory[group][:hosts].nil? 89 | @inventory[group][:vars] = {} if @inventory[group][:vars].nil? 90 | end 91 | end 92 | 93 | client = Client.new 94 | 95 | vm_pool = VirtualMachinePool.new(client, -1) 96 | 97 | rc = vm_pool.info 98 | 99 | if OpenNebula.is_error?(rc) 100 | puts rc.message 101 | exit -1 102 | end 103 | 104 | inventory = Inventory.new 105 | vm_pool.each do |vm| 106 | # explizit info pull to gather all Context vairables 107 | vm.info 108 | # Require READY=YES if REPORT_READY=YES 109 | if vm["TEMPLATE/CONTEXT/REPORT_READY"] == "YES" && 110 | vm["TEMPLATE/CONTEXT/TOKEN"] == "YES" && 111 | vm["USER_TEMPLATE/READY"] != "YES" then 112 | 113 | next 114 | end 115 | 116 | labels = vm["USER_TEMPLATE/LABELS"].split(",").select do |e| 117 | e.match(/ansible(\/|$)/) 118 | end rescue nil 119 | 120 | ansible_role = vm["TEMPLATE/CONTEXT/ANSIBLE_ROLE"] rescue nil 121 | 122 | if (labels.nil? || labels.empty?) && (ansible_role.nil? || ansible_role.empty?) 123 | next 124 | end 125 | 126 | id = "one-#{vm['ID']}" 127 | name = vm["NAME"] 128 | 129 | vm.each('TEMPLATE/CONTEXT/*') do |e| 130 | var = e.name 131 | val = e.text 132 | 133 | next if %w(DISK_ID NETWORK TARGET).include?(var) 134 | 135 | inventory.hostvar(name, var, val) 136 | end 137 | 138 | vm.each('USER_TEMPLATE/*') do |e| 139 | var = e.name 140 | val = e.text 141 | 142 | next if %w(ANSIBLE_HOST).include?(var) 143 | 144 | inventory.hostvar(name, var, val) 145 | end 146 | 147 | i=0 148 | vm.each('TEMPLATE/DISK') do |disk| 149 | %w(image image_id size).each do |key| 150 | val = disk[key.upcase] 151 | 152 | if !val.nil? && !val.empty? 153 | inventory.hostvar(name, "disk_#{i}_#{key}", val) 154 | end 155 | end 156 | 157 | persistent = !(disk['CLONE'] == 'YES') 158 | inventory.hostvar(name, "disk_#{i}_persistent", persistent) 159 | 160 | i+=1 161 | end 162 | 163 | ansible_host = vm["USER_TEMPLATE/ANSIBLE_HOST"] 164 | ansible_host ||= vm["TEMPLATE/CONTEXT/ANSIBLE_HOST"] 165 | ansible_host ||= ENV['ANSIBLE_HOST'] 166 | 167 | if ansible_host 168 | var_ip = if ansible_host.match(/^eth\d+$/i) 169 | ansible_host.upcase + "_IP" 170 | else 171 | "ETH0_IP" 172 | end 173 | 174 | ip = vm["TEMPLATE/CONTEXT/#{var_ip}"] 175 | 176 | inventory.hostvar(name, "ansible_host", ip) if ip 177 | end 178 | 179 | labels.each do |label| 180 | _, group = label.split("/", 2) 181 | inventory.host(name, group.gsub("/", ",")) if group 182 | end if labels 183 | 184 | if ansible_role && !ansible_role.empty? 185 | inventory.host(name, ansible_role) 186 | end 187 | 188 | inventory.host(name) 189 | end 190 | 191 | puts inventory.to_json 192 | 193 | exit 0 194 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | OpenNebula CLI Tools 2 | ==================== 3 | 4 | This a collection of scripts useful for OpenNebula administrators. Their aim is 5 | to improve the user experience in the shell with simple, short and elegant 6 | scripts that use the power and simplicity of OpenNebula's CLI commands. 7 | 8 | Contributions, hacks, ideas, improvements are more than welcome! 9 | 10 | Commands 11 | -------- 12 | 13 | - [__onelog__](#onelog): Displays OpenNebula logs. 14 | - [__oneinstantiate__](#oneinstantiate): Instantiates template with a name. 15 | - [__onedeploy__](#onedeploy): Creates and deploys instantaneously a Virtual Machine. 16 | - [__onereport__](#onereport): Displays a summary of running VMs. 17 | - [__onessh__](#onessh): SSH's into a running VM. 18 | - [__onessh-copy-id__](#onessh-copy-id): Copies public key to a running VM. 19 | - [__onevnc__](#onevnc): Opens the VNC console of a running VM. 20 | - [__oneirb__](#oneirb): Opens an IRB session with all the OpenNebula libraries. 21 | - [__oneconf__](#oneconf): Modifies the default configuration files. 22 | - [__onebootstrap__](#onebootstrap): Creates initial OpenNebula resources. 23 | - [__onecast__](#onecast): OpenNebula templates with variables. 24 | - [__oneip__](#oneip): Returns state of IP (Used, Reserved, Free) and also get free IP to reserve. 25 | - [__oneping__](#oneping): Pings a VM. 26 | - [__onevcenterirb__](#onevcenterirb): Enters an irb environment with vCenter driver loaded. 27 | - [__onefind__](#onefind): Finds a value in object information. It accepts any path. 28 | - [__onepush__](#onepush): Copy a file on a VM with qemu guest agent running on it 29 | 30 | *Dev commands* 31 | 32 | - [__onedepkidnap__](#onedepkidnap): Kidnaps driver action to deploy and adds ruby pry 33 | 34 | 35 | onelog 36 | ------ 37 | 38 | If no argument is passed it displays `oned.log`. One of these arguments can be passed: 39 | 40 | - `econe`: econe-server.log 41 | - `econe.error`: econe-server.error 42 | - `occi`: occi-server.log 43 | - `occi.error`: occi-server.error 44 | - `sunstone`: sunstone-server.log 45 | - `sunstone.error`: sunstone-server.error 46 | - `ozones`: ozones-server.log 47 | - `ozones.error`: ozones-server.error 48 | - `VM_ID`: the vm.log is displayed 49 | 50 | Example: 51 | 52 | $ onelog 53 | [ opens oned.log in your $PAGER ] 54 | $ onelog 10 55 | [ opens the vm.log for VM 10 in your $PAGER ] 56 | 57 | oneinstantiate 58 | -------------- 59 | 60 | A wrapper for the `onetemplate instantiate` command. It instantiates a template 61 | using the name of the template as the Virtual Machine name: 62 | 63 | $ oneinstantiate 0 64 | onetemplate instantiate 0 -n ubuntu 65 | VM ID: 11 66 | 67 | 68 | onedeploy 69 | --------- 70 | 71 | Creates a Virtual Machine and deploys it instantaneously in the first available 72 | host it founds: 73 | 74 | $ onedeploy vm_template.one 75 | 76 | onereport 77 | --------- 78 | 79 | Displays a summary of running Virtual Machines: 80 | 81 | $ onereport 82 | VM: 9 83 | NAME: one-9 84 | HOSTNAME: localhost 85 | VNC PORT: 5909 86 | IP: 172.16.0.205 87 | IP: 172.16.1.1 88 | 89 | VM: 10 90 | NAME: ttylinux 91 | HOSTNAME: localhost 92 | 93 | onessh 94 | ------ 95 | 96 | SSH's into a running VM: 97 | 98 | $ onessh 9 -l root 99 | 100 | onessh-copy-id 101 | -------------- 102 | 103 | Copies the public key to a running VM identified by ID or by name. If a second 104 | parameter is passed to the script, it will be used as the username. 105 | 106 | # To the same username 107 | $ onessh-copy-id 9 108 | Warning: Permanently added 'localhost' (ECDSA) to the list of known hosts. 109 | user@192.168.1.10's password: 110 | 111 | # To a different username 112 | $ onessh-copy-id 9 root 113 | Warning: Permanently added 'localhost' (ECDSA) to the list of known hosts. 114 | root@192.168.1.10's password: 115 | 116 | onevnc 117 | ------ 118 | 119 | Opens the VNC console of a running VM: 120 | 121 | $ onevnc 9 122 | 123 | oneirb 124 | ------ 125 | 126 | Enters an irb environment with all the OpenNebula libraries loaded. The instance 127 | variable `@client` is available in the IRB shell. 128 | 129 | $ oneirb 130 | >> vm = VirtualMachine.new(VirtualMachine.build_xml('10'), @client); 131 | ?> vm.info; 132 | ?> vm['NAME'] 133 | => "ttylinux" 134 | 135 | onevcenterirb 136 | ------------- 137 | 138 | Enters an irb environment with vCenter driver loaded: 139 | 140 | $ onevcenterirb 141 | $ vm = vm(0) # get vcenterdriver machine with opennebula id: 0 142 | $ vm.one_item['ID'] 143 | => "0" 144 | $ vm.disk(0).managed? 145 | => false 146 | $ vm.disk(0).ds.class 147 | => RbVmomi::VIM::Datastore 148 | 149 | oneconf 150 | ------- 151 | 152 | This ruby script backs up and rewrites `oned.conf` and `sched.conf`, performing 153 | the following changes: 154 | 155 | #### oned.conf 156 | 157 | - `MANAGER_TIMER`: 5 seconds 158 | - `HOST_MONITORING_INTERVAL`: 10 seconds 159 | - `VM_POLLING_INTERVAL`: 10 seconds 160 | - Enables `TM_SSH` 161 | - Enables `TM_DUMMY` 162 | - Enables `IM_DUMMY` 163 | - Enables `VMM_DUMMY` 164 | 165 | #### sched.conf 166 | 167 | - `SCHED_INTERVAL`: 5 seconds 168 | 169 | onebootstrap 170 | ------------ 171 | 172 | This command should be executed only with a fresh OpenNebula installation. It 173 | will create some resources: 174 | 175 | * __host__: localhost with KVM configuration 176 | * __datastore__: a file-system based user datastore 177 | * __users__: Any users in the folder. If `default.user` exists, the following resources will be created inder his name. 178 | * __vnet__: a few IPs in the 172.16.0.0/24 network connected to bridge `br0` 179 | * __image__: an Ubuntu image (users will have to execute first 180 | `bootstrap/image/download_ubuntu.sh`) 181 | * __template__: an Ubuntu template ready to be instantiated 182 | 183 | By default the command will look in the `bootstrap/` directory. However, a 184 | different path may be provided as an argument. 185 | 186 | All of these resources can be customized by editing the files inside 187 | `bootstrap/`. Other resources can be added and they will also be created. 188 | 189 | 190 | The datastore where the images will be instantiated needs to have `DEFAULT = 191 | YES` inside the template. This is only necessary if more than one datastore is 192 | created. 193 | 194 | onecast 195 | ------- 196 | 197 | This tool that can rewrite parts of a VM template substituting the variables it 198 | contains by some values that the user provides. It also gets values from the 199 | environment if the values are not explicitly provided by the user and can also 200 | have a default value so they will be translated to something meaningful if not 201 | found by other methods. 202 | 203 | An example of a VM template meaningful to onecast can be this one: 204 | 205 | NAME = "${NAME}" 206 | CPU = ${CPU|1.0} 207 | VCPU = ${CPU|1} 208 | MEMORY = ${MEMORY|512} 209 | DISK = [ 210 | SOURCE = "${HOME}/images/vm.img", 211 | TARGET = sda 212 | ] 213 | 214 | In this example we can see that the placeholder for the variable values is 215 | specified with `${VARIABLE}`. The name of the variable is case sensitive and 216 | this will be translated to its value (user provided or from the environment) or 217 | left blank if not found. We have to be careful with variables not set or they 218 | will render the template unusable in some cases. To overcome this problem, and 219 | also to give some values that the user may not want to modify, default values 220 | can be provided alongside the variable name. Variable names with default values 221 | are specified with `${VARIABLE|default value}`. Doing so if the variable is not 222 | set by the user in the command line or found in the environment it will be 223 | substituted by the default value. 224 | 225 | It is also very useful to use environment variables to get some information 226 | specific to the user, in this example we suppose every user has a file called 227 | `images/vm.img` in their home directory so we use `$HOME` environment variable 228 | to point to it. 229 | 230 | To generate the final template we use the this command: 231 | 232 | $ onecast -d NAME="test vm" test.one 233 | NAME = "test vm" 234 | CPU = 1.0 235 | VCPU = 1 236 | MEMORY = 512 237 | DISK = [ 238 | SOURCE = "/home/oneuser/images/vm.img", 239 | TARGET = sda 240 | ] 241 | 242 | We have to specify the template file to the onecast script and we can also 243 | provide variables using _-d_ option. This option will have an argument in this 244 | form `NAME=value` that will be used to substitute any variable in the template 245 | with that name. More than one of those variables can be added in the command 246 | line. As another example to illustrate this we can also set the memory to 1Gb 247 | issuing this command: 248 | 249 | $ onecast -d NAME="test vm" -d MEMORY=1024 test.one 250 | NAME = "test vm" 251 | CPU = 1.0 252 | VCPU = 1 253 | MEMORY = 1024 254 | DISK = [ 255 | SOURCE = "/home/oneuser/images/vm.img", 256 | TARGET = sda 257 | ] 258 | 259 | The output of the command can then be redirected to a file and use it to create 260 | a new VM or use the parameter _-c_ so the VM is automatically sent to 261 | OpenNebula: 262 | 263 | $ onecast -d NAME="test vm" -d MEMORY=1024 test.one -c 264 | ID: 9 265 | 266 | oneping 267 | ------- 268 | 269 | Pings a VM: 270 | 271 | $ oneping 9 272 | 273 | onepush 274 | ------- 275 | 276 | Copy a file in a VM via qemu guest agent. 277 | Usage: `onepush VM_ID SRC_FILE DST_FILE` 278 | 279 | $ onepush 1234 hosts_for_vm_1234 /etc/hosts 280 | 281 | oneip 282 | ----- 283 | 284 | Returns the ip of a VM: 285 | 286 | $ oneip --check 172.16.77.134 287 | $ oneip -c 172.16.77.134 288 | $ oneip --get [NET_ID] 289 | $ oneip -g [NET_ID] 290 | 291 | Useful for things like: 292 | 293 | $ scp myfile root@`oneip 0`: 294 | 295 | onefind 296 | ------- 297 | 298 | Finds a value in object information: 299 | 300 | $ onefind gold TEMPLATE/OBJ_TYPE 301 | HOSTS 302 | ----- 303 | 2 304 | 305 | DATASTORES 306 | ---------- 307 | 0 308 | 309 | onedepkidnap 310 | ------------ 311 | 312 | Kidnaps deploy drv_action xml and writes it to /tmp/one_deploy_xmldrvaction. Add binding.pry to execute deploy action step by step. 313 | 314 | $ onedepkidnap 0 315 | Waiting for VM 26 in state BOOT_FAILURE, got: LCM_INIT 316 | Waiting for VM 26 in state BOOT_FAILURE, got: LCM_INIT 317 | Waiting for VM 26 in state BOOT_FAILURE, got: LCM_INIT 318 | Waiting for VM 26 in state BOOT_FAILURE, got: LCM_INIT 319 | Waiting for VM 26 in state BOOT_FAILURE, got: LCM_INIT 320 | Waiting for VM 26 in state BOOT_FAILURE, got: LCM_INIT 321 | Waiting for VM 26 in state BOOT_FAILURE, got: LCM_INIT 322 | Waiting for VM 26 in state BOOT_FAILURE, got: LCM_INIT 323 | Waiting for VM 26 in state BOOT_FAILURE, got: PROLOG 324 | Waiting for VM 26 in state BOOT_FAILURE, got: BOOT_FAILURE 325 | 326 | Deploy kidnapped. Execute the following to debug the deploy: 327 | /home/tinova/dev/one/master/var/remotes/vmm/vcenter/deploy '/home/tinova/dev/one/master/var/vms/26/deployment.0' 'Cluster' 26 Cluster 328 | 329 | Remember to restore the deploy script afterwards: 330 | mv /home/tinova/dev/one/master/var/remotes/vmm/vcenter/deploy.bk /home/tinova/dev/one/master/var/remotes/vmm/vcenter/deploy 331 | 332 | Author 333 | ====== 334 | 335 | Jaime Melis (http://github.com/jmelis) 336 | 337 | Maintainer 338 | ---------- 339 | 340 | Tino Vazquez (http://github/tinova) 341 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /onebootstrap-4.14: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | require "yaml" 4 | require "tempfile" 5 | require "erb" 6 | require "pp" 7 | 8 | begin 9 | require "colored" 10 | COLORED=true 11 | rescue Exception => e 12 | COLORED=false 13 | end 14 | 15 | DIR = File.dirname(File.realpath(__FILE__)) 16 | 17 | ################################################################################ 18 | # Load OpenNebula 19 | ################################################################################ 20 | 21 | ONE_LOCATION=ENV["ONE_LOCATION"] 22 | 23 | if !ONE_LOCATION 24 | RUBY_LIB_LOCATION = "/usr/lib/one/ruby" 25 | VAR_LOCATION = "/var/lib/one" 26 | LIB_LOCATION = "/usr/lib/one" 27 | ETC_LOCATION = "/etc/one" 28 | else 29 | RUBY_LIB_LOCATION = ONE_LOCATION + "/lib/ruby" 30 | VAR_LOCATION = ONE_LOCATION + "/var" 31 | LIB_LOCATION = ONE_LOCATION + "/lib" 32 | ETC_LOCATION = ONE_LOCATION + "/etc" 33 | end 34 | 35 | $: << RUBY_LIB_LOCATION 36 | 37 | require 'opennebula' 38 | include OpenNebula 39 | 40 | CLIENT = Client.new 41 | 42 | ################################################################################ 43 | # Read Configuration 44 | ################################################################################ 45 | 46 | yaml_file = ARGV[0] || File.join(DIR, "bootstrap", "default.yaml") 47 | 48 | begin 49 | conf = YAML.load_file(yaml_file) 50 | rescue 51 | STDERR.puts "'#{yaml_file}' is not a valid yaml file." 52 | exit 1 53 | end 54 | 55 | ################################################################################ 56 | # Helper 57 | ################################################################################ 58 | 59 | def error(e) 60 | m = if e.instance_of?(String) 61 | e 62 | else 63 | e.message 64 | end 65 | 66 | if COLORED 67 | STDERR.puts m.red 68 | else 69 | STDERR.puts m 70 | end 71 | 72 | exit 1 73 | end 74 | 75 | def log(e, level=nil) 76 | if COLORED 77 | m = case level 78 | when :ok 79 | e.green 80 | when :warn 81 | e.cyan 82 | when :info 83 | e.blue 84 | when :error 85 | e.red 86 | else 87 | e 88 | end 89 | else 90 | m = e 91 | end 92 | 93 | puts m 94 | end 95 | 96 | ############################################################################### 97 | # The TemplateParser Class parses a VM template file and builds a hash with 98 | # the info. It does not check syntax. 99 | ############################################################################### 100 | 101 | class TemplateParser 102 | ########################################################################## 103 | # Patterns to parse the template File 104 | ########################################################################## 105 | 106 | NAME_REG =/[\w\d_-]+/ 107 | VARIABLE_REG =/\s*(#{NAME_REG})\s*=\s*/ 108 | 109 | SIMPLE_VARIABLE_REG =/#{VARIABLE_REG}([^\[]+?)(#.*)?/ 110 | SINGLE_VARIABLE_REG =/^#{SIMPLE_VARIABLE_REG}$/ 111 | ARRAY_VARIABLE_REG =/^#{VARIABLE_REG}\[(.*?)\]/m 112 | 113 | ########################################################################## 114 | ########################################################################## 115 | 116 | def initialize(template_string) 117 | @conf=parse_conf(template_string) 118 | end 119 | 120 | def add_configuration_value(key,value) 121 | add_value(@conf,key,value) 122 | end 123 | 124 | def [](key) 125 | @conf[key.to_s.upcase] 126 | end 127 | 128 | def hash 129 | @conf 130 | end 131 | 132 | def self.template_like_str(attributes, indent=true) 133 | if indent 134 | ind_enter="\n" 135 | ind_tab=' ' 136 | else 137 | ind_enter='' 138 | ind_tab=' ' 139 | end 140 | 141 | str=attributes.collect do |key, value| 142 | if value 143 | str_line="" 144 | if value.class==Array 145 | 146 | value.each do |value2| 147 | str_line << key.to_s.upcase << "=[" << ind_enter 148 | if value2 && value2.class==Hash 149 | str_line << value2.collect do |key3, value3| 150 | str = ind_tab + key3.to_s.upcase + "=" 151 | str += "\"#{value3.to_s}\"" if value3 152 | str 153 | end.compact.join(",\n") 154 | end 155 | str_line << "\n]\n" 156 | end 157 | 158 | elsif value.class==Hash 159 | str_line << key.to_s.upcase << "=[" << ind_enter 160 | 161 | str_line << value.collect do |key3, value3| 162 | str = ind_tab + key3.to_s.upcase + "=" 163 | str += "\"#{value3.to_s}\"" if value3 164 | str 165 | end.compact.join(",\n") 166 | 167 | str_line << "\n]\n" 168 | 169 | else 170 | str_line< BSHost, 250 | "image" => BSImage, 251 | "template" => BSTemplate, 252 | "net" => BSNet, 253 | "datastore" => BSDatastore, 254 | "user" => BSUser 255 | } 256 | return resources[hash["type"]].new(hash) 257 | end 258 | 259 | def initialize(hash) 260 | @hash = hash 261 | end 262 | 263 | def to_s 264 | hash = "@type:#{@hash["type"]}" 265 | 266 | if (name = @hash["name"] || @hash["template"]["name"]) 267 | hash << "/@name:#{name}" 268 | end 269 | 270 | if (the_id = @hash["id"]) 271 | hash << "/@id:#{the_id}" 272 | end 273 | 274 | return hash 275 | end 276 | 277 | def do! 278 | log("* #{self}", :info) 279 | 280 | case action = @hash["action"].to_sym 281 | when :create 282 | if id.nil? 283 | create 284 | wait 285 | 286 | log("> Create", :ok) 287 | else 288 | log("> Skipping: resource exists", :warn) 289 | end 290 | when :update 291 | if !id.nil? 292 | update 293 | log("> Update", :ok) 294 | else 295 | log("> Skipping: does not exist", :warn) 296 | end 297 | else 298 | error("Unknown action: '#{action}'.") 299 | end 300 | end 301 | 302 | def update 303 | resource_class = self.class.class_variable_get(:@@resource_class) 304 | 305 | append = @hash["append"] || true 306 | 307 | r = resource_class.new_with_id(id, CLIENT) 308 | 309 | template = TemplateParser.template_like_str(@hash["template"]) 310 | 311 | rc = r.update(template, append) 312 | error(rc) if OpenNebula.is_error?(rc) 313 | end 314 | 315 | def id 316 | if (id = @hash["id"]) 317 | return id 318 | end 319 | 320 | name = @hash["name"] || @hash["template"]["name"] rescue nil 321 | if name.nil? 322 | error("Fields 'NAME' or 'ID' are required") 323 | return nil 324 | end 325 | 326 | pool_class = self.class.class_variable_get(:@@pool_class) 327 | 328 | pool = pool_class.new(CLIENT) 329 | rc = pool.info 330 | error(rc) if OpenNebula.is_error?(rc) 331 | 332 | pool.each do |e| 333 | return e["ID"] if e["NAME"] == name 334 | end 335 | 336 | return nil 337 | end 338 | 339 | def wait 340 | return true 341 | end 342 | 343 | def wait_states(states) 344 | RETRIES.times do 345 | rc = @resource.info 346 | error(rc) if OpenNebula.is_error?(rc) 347 | 348 | if [states].flatten.include?(@resource.state_str) 349 | return true 350 | end 351 | 352 | sleep INTERVAL 353 | end 354 | 355 | return false 356 | end 357 | end 358 | 359 | class BSHost < BS 360 | @@resource_class = Host 361 | @@pool_class = HostPool 362 | 363 | def create 364 | @resource = @@resource_class.new(@@resource_class.build_xml, CLIENT) 365 | 366 | args = [@hash["name"], 367 | @hash["im"], 368 | @hash["vmm"], 369 | @hash["vnm"]] 370 | 371 | if (cluster_id = @hash["cluster_id"]) 372 | args << cluster_id 373 | end 374 | 375 | rc = @resource.allocate(*args) 376 | 377 | error(rc) if OpenNebula.is_error?(rc) 378 | end 379 | 380 | def wait 381 | wait_states(["MONITORING_MONITORED", "MONITORED"]) 382 | end 383 | end 384 | 385 | class BSImage < BS 386 | @@resource_class = Image 387 | @@pool_class = ImagePool 388 | 389 | def create 390 | @resource = @@resource_class.new(@@resource_class.build_xml, CLIENT) 391 | 392 | template = TemplateParser.template_like_str(@hash["template"]) 393 | 394 | rc = @resource.allocate(template, @hash["ds_id"]) 395 | error(rc) if OpenNebula.is_error?(rc) 396 | end 397 | 398 | def wait 399 | RETRIES.times do 400 | rc = @resource.info 401 | error(rc) if OpenNebula.is_error?(rc) 402 | 403 | if @resource.state_str == "READY" 404 | return true 405 | end 406 | 407 | sleep INTERVAL 408 | end 409 | 410 | return false 411 | end 412 | end 413 | 414 | class BSNet < BS 415 | @@resource_class = VirtualNetwork 416 | @@pool_class = VirtualNetworkPool 417 | 418 | def create 419 | @resource = @@resource_class.new(@@resource_class.build_xml, CLIENT) 420 | 421 | template = TemplateParser.template_like_str(@hash["template"]) 422 | 423 | args = [template] 424 | 425 | if (cluster_id = @hash["cluster_id"] rescue nil) 426 | args << cluster_id 427 | end 428 | 429 | rc = @resource.allocate(*args) 430 | error(rc) if OpenNebula.is_error?(rc) 431 | end 432 | end 433 | 434 | class BSDatastore < BS 435 | @@resource_class = Datastore 436 | @@pool_class = DatastorePool 437 | 438 | def create 439 | @resource = @@resource_class.new(@@resource_class.build_xml, CLIENT) 440 | 441 | template = TemplateParser.template_like_str(@hash["template"]) 442 | 443 | args = [template] 444 | 445 | if (cluster_id = @hash["cluster_id"] rescue nil) 446 | args << cluster_id 447 | end 448 | 449 | rc = @resource.allocate(*args) 450 | error(rc) if OpenNebula.is_error?(rc) 451 | end 452 | 453 | def wait 454 | wait_states(["READY"]) 455 | end 456 | end 457 | 458 | class BSTemplate < BS 459 | @@resource_class = Template 460 | @@pool_class = TemplatePool 461 | 462 | def create 463 | @resource = @@resource_class.new(@@resource_class.build_xml, CLIENT) 464 | 465 | template = TemplateParser.template_like_str(@hash["template"]) 466 | 467 | rc = @resource.allocate(template) 468 | error(rc) if OpenNebula.is_error?(rc) 469 | end 470 | end 471 | 472 | class BSUser < BS 473 | @@resource_class = User 474 | @@pool_class = UserPool 475 | 476 | def create 477 | @resource = @@resource_class.new(@@resource_class.build_xml, CLIENT) 478 | 479 | args = [@hash["name"], @hash["password"]] 480 | 481 | if (driver = @hash["driver"]) 482 | args << driver 483 | end 484 | 485 | rc = @resource.allocate(*args) 486 | error(rc) if OpenNebula.is_error?(rc) 487 | end 488 | end 489 | 490 | ################################################################################ 491 | # Create Resources 492 | ################################################################################ 493 | 494 | conf.each do |hash| 495 | r = BS.factory(hash) 496 | r.do! 497 | end 498 | -------------------------------------------------------------------------------- /onebootstrap: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | require "yaml" 4 | require "tempfile" 5 | require "erb" 6 | require "pp" 7 | 8 | begin 9 | require "colored" 10 | COLORED=true 11 | rescue Exception => e 12 | COLORED=false 13 | end 14 | 15 | DIR = File.dirname(File.realpath(__FILE__)) 16 | 17 | ################################################################################ 18 | # Load OpenNebula 19 | ################################################################################ 20 | 21 | ONE_LOCATION=ENV["ONE_LOCATION"] 22 | 23 | if !ONE_LOCATION 24 | RUBY_LIB_LOCATION = "/usr/lib/one/ruby" 25 | VAR_LOCATION = "/var/lib/one" 26 | LIB_LOCATION = "/usr/lib/one" 27 | ETC_LOCATION = "/etc/one" 28 | else 29 | RUBY_LIB_LOCATION = ONE_LOCATION + "/lib/ruby" 30 | VAR_LOCATION = ONE_LOCATION + "/var" 31 | LIB_LOCATION = ONE_LOCATION + "/lib" 32 | ETC_LOCATION = ONE_LOCATION + "/etc" 33 | end 34 | 35 | $: << RUBY_LIB_LOCATION 36 | 37 | require 'opennebula' 38 | include OpenNebula 39 | 40 | CLIENT = Client.new 41 | 42 | ################################################################################ 43 | # Read Configuration 44 | ################################################################################ 45 | 46 | yaml_location = ARGV[0] || File.join(DIR, "bootstrap", "default.d") 47 | 48 | if File.directory?(yaml_location) 49 | conf = [] 50 | conf_item = nil 51 | Dir[File.join(yaml_location, "*.yaml")].sort.each do |f| 52 | begin 53 | conf_item = YAML.load_file(f) 54 | rescue 55 | STDERR.puts "'#{f}' is not a valid yaml file." 56 | exit 1 57 | end 58 | if conf_item.instance_of? Array 59 | conf += conf_item 60 | elsif conf_item.instance_of? Hash 61 | conf << conf_item 62 | else 63 | STDERR.puts "'#{f}' contains an unknown type." 64 | exit 1 65 | end 66 | end 67 | else 68 | begin 69 | conf = YAML.load_file(yaml_location) 70 | rescue 71 | STDERR.puts "'#{yaml_location}' is not a valid yaml file." 72 | exit 1 73 | end 74 | end 75 | 76 | ################################################################################ 77 | # Helper 78 | ################################################################################ 79 | 80 | def error(e) 81 | m = if e.instance_of?(String) 82 | e 83 | else 84 | e.message 85 | end 86 | 87 | if COLORED 88 | STDERR.puts m.red 89 | else 90 | STDERR.puts m 91 | end 92 | 93 | exit 1 94 | end 95 | 96 | def log(e, level=nil) 97 | if COLORED 98 | m = case level 99 | when :ok 100 | e.green 101 | when :warn 102 | e.cyan 103 | when :info 104 | e.blue 105 | when :error 106 | e.red 107 | else 108 | e 109 | end 110 | else 111 | m = e 112 | end 113 | 114 | puts m 115 | end 116 | 117 | ############################################################################### 118 | # The TemplateParser Class parses a VM template file and builds a hash with 119 | # the info. It does not check syntax. 120 | ############################################################################### 121 | 122 | class TemplateParser 123 | ########################################################################## 124 | # Patterns to parse the template File 125 | ########################################################################## 126 | 127 | NAME_REG =/[\w\d_-]+/ 128 | VARIABLE_REG =/\s*(#{NAME_REG})\s*=\s*/ 129 | 130 | SIMPLE_VARIABLE_REG =/#{VARIABLE_REG}([^\[]+?)(#.*)?/ 131 | SINGLE_VARIABLE_REG =/^#{SIMPLE_VARIABLE_REG}$/ 132 | ARRAY_VARIABLE_REG =/^#{VARIABLE_REG}\[(.*?)\]/m 133 | 134 | ########################################################################## 135 | ########################################################################## 136 | 137 | def initialize(template_string) 138 | @conf=parse_conf(template_string) 139 | end 140 | 141 | def add_configuration_value(key,value) 142 | add_value(@conf,key,value) 143 | end 144 | 145 | def [](key) 146 | @conf[key.to_s.upcase] 147 | end 148 | 149 | def hash 150 | @conf 151 | end 152 | 153 | def self.template_like_str(attributes, indent=true) 154 | if indent 155 | ind_enter="\n" 156 | ind_tab=' ' 157 | else 158 | ind_enter='' 159 | ind_tab=' ' 160 | end 161 | 162 | str=attributes.collect do |key, value| 163 | if value 164 | str_line="" 165 | if value.class==Array 166 | 167 | value.each do |value2| 168 | str_line << key.to_s.upcase << "=[" << ind_enter 169 | if value2 && value2.class==Hash 170 | str_line << value2.collect do |key3, value3| 171 | str = ind_tab + key3.to_s.upcase + "=" 172 | str += "\"#{value3.to_s}\"" if value3 173 | str 174 | end.compact.join(",\n") 175 | end 176 | str_line << "\n]\n" 177 | end 178 | 179 | elsif value.class==Hash 180 | str_line << key.to_s.upcase << "=[" << ind_enter 181 | 182 | str_line << value.collect do |key3, value3| 183 | str = ind_tab + key3.to_s.upcase + "=" 184 | str += "\"#{value3.to_s}\"" if value3 185 | str 186 | end.compact.join(",\n") 187 | 188 | str_line << "\n]\n" 189 | 190 | else 191 | str_line< BSHost, 273 | "image" => BSImage, 274 | "template" => BSTemplate, 275 | "net" => BSNet, 276 | "datastore" => BSDatastore, 277 | "user" => BSUser, 278 | "cluster" => BSCluster, 279 | "marketapp" => BSMarketApp 280 | } 281 | return resources[hash["type"]].new(hash) 282 | end 283 | 284 | def initialize(hash) 285 | @hash = hash 286 | end 287 | 288 | def to_s 289 | hash = "@type:#{@hash["type"]}" 290 | 291 | if (name = @hash["name"] || @hash["template"]["name"]) 292 | hash << "/@name:#{name}" 293 | end 294 | 295 | if (the_id = @hash["id"]) 296 | hash << "/@id:#{the_id}" 297 | end 298 | 299 | return hash 300 | end 301 | 302 | def do! 303 | log("* #{self}", :info) 304 | 305 | case action = @hash["action"].to_sym 306 | when :create 307 | if id.nil? 308 | create 309 | wait 310 | 311 | log("> Create", :ok) 312 | else 313 | log("> Skipping: resource exists", :warn) 314 | end 315 | when :update 316 | if !id.nil? 317 | update 318 | wait 319 | 320 | log("> Update", :ok) 321 | else 322 | log("> Skipping: does not exist", :warn) 323 | end 324 | else 325 | error("Unknown action: '#{action}'.") 326 | end 327 | end 328 | 329 | def update 330 | resource_class = self.class.class_variable_get(:@@resource_class) 331 | 332 | append = @hash["append"] || true 333 | 334 | @resource = resource_class.new_with_id(id, CLIENT) 335 | 336 | bstmpl = @hash["template"] 337 | template = TemplateParser.template_like_str(bstmpl) if !bstmpl.nil? 338 | 339 | rc = @resource.update(template, append) 340 | error(rc) if OpenNebula.is_error?(rc) 341 | end 342 | 343 | def id 344 | if (id = @hash["id"]) 345 | return id 346 | end 347 | 348 | name = @hash["name"] || @hash["template"]["name"] rescue nil 349 | if name.nil? 350 | error("Fields 'NAME' or 'ID' are required") 351 | return nil 352 | end 353 | 354 | pool_class = self.class.class_variable_get(:@@pool_class) 355 | 356 | pool = pool_class.new(CLIENT) 357 | rc = pool.info 358 | error(rc) if OpenNebula.is_error?(rc) 359 | 360 | pool.each do |e| 361 | return e["ID"] if e["NAME"] == name 362 | end 363 | 364 | return nil 365 | end 366 | 367 | def wait 368 | return true 369 | end 370 | 371 | def wait_states(states) 372 | RETRIES.times do 373 | rc = @resource.info 374 | error(rc) if OpenNebula.is_error?(rc) 375 | 376 | if [states].flatten.include?(@resource.state_str) 377 | return true 378 | end 379 | 380 | sleep INTERVAL 381 | end 382 | 383 | return false 384 | end 385 | 386 | def resource_wait(&block) 387 | RETRIES.times do 388 | rc = @resource.info 389 | error(rc) if OpenNebula.is_error?(rc) 390 | 391 | return true if yield @resource 392 | 393 | sleep INTERVAL 394 | end 395 | 396 | return false 397 | end 398 | 399 | def set_resource 400 | resource_class = self.class.class_variable_get(:@@resource_class) 401 | @resource = resource_class.new(resource_class.build_xml(id), CLIENT) 402 | end 403 | end 404 | 405 | class BSHost < BS 406 | @@resource_class = Host 407 | @@pool_class = HostPool 408 | 409 | def create 410 | @resource = @@resource_class.new(@@resource_class.build_xml, CLIENT) 411 | 412 | args = [@hash["name"], 413 | @hash["im"], 414 | @hash["vmm"]] 415 | 416 | if (cluster_id = @hash["cluster_id"]) 417 | args << cluster_id 418 | end 419 | 420 | rc = @resource.allocate(*args) 421 | 422 | return error(rc) if OpenNebula.is_error?(rc) 423 | 424 | @resource.disable if @hash["disable"] 425 | end 426 | 427 | def wait 428 | return true if @hash["nowait"] 429 | wait_states(["MONITORING_MONITORED", "MONITORED"]) 430 | end 431 | end 432 | 433 | class BSImage < BS 434 | @@resource_class = Image 435 | @@pool_class = ImagePool 436 | 437 | def create 438 | @resource = @@resource_class.new(@@resource_class.build_xml, CLIENT) 439 | 440 | template = TemplateParser.template_like_str(@hash["template"]) 441 | 442 | rc = @resource.allocate(template, @hash["ds_id"]) 443 | error(rc) if OpenNebula.is_error?(rc) 444 | end 445 | 446 | def wait 447 | RETRIES.times do |t| 448 | rc = @resource.info 449 | error(rc) if OpenNebula.is_error?(rc) 450 | 451 | STDERR.puts "#{t}:#{@resource.state_str}" 452 | 453 | if @resource.state_str == "READY" 454 | return true 455 | end 456 | 457 | sleep INTERVAL 458 | end 459 | 460 | return false 461 | end 462 | end 463 | 464 | class BSNet < BS 465 | @@resource_class = VirtualNetwork 466 | @@pool_class = VirtualNetworkPool 467 | 468 | def create 469 | @resource = @@resource_class.new(@@resource_class.build_xml, CLIENT) 470 | 471 | template = TemplateParser.template_like_str(@hash["template"]) 472 | 473 | args = [template] 474 | 475 | if (cluster_id = @hash["cluster_id"] rescue nil) 476 | args << cluster_id 477 | end 478 | 479 | rc = @resource.allocate(*args) 480 | error(rc) if OpenNebula.is_error?(rc) 481 | end 482 | end 483 | 484 | class BSDatastore < BS 485 | @@resource_class = Datastore 486 | @@pool_class = DatastorePool 487 | 488 | def create 489 | @resource = @@resource_class.new(@@resource_class.build_xml, CLIENT) 490 | 491 | template = TemplateParser.template_like_str(@hash["template"]) 492 | 493 | args = [template] 494 | 495 | if (cluster_id = @hash["cluster_id"] rescue nil) 496 | args << cluster_id 497 | end 498 | 499 | rc = @resource.allocate(*args) 500 | error(rc) if OpenNebula.is_error?(rc) 501 | end 502 | 503 | def wait 504 | return false if !wait_states(["READY"]) 505 | 506 | unless @hash["nowait"] 507 | resource_wait {|res| res["TOTAL_MB"].to_s != "0" } 508 | end 509 | end 510 | end 511 | 512 | class BSTemplate < BS 513 | @@resource_class = Template 514 | @@pool_class = TemplatePool 515 | 516 | def create 517 | @resource = @@resource_class.new(@@resource_class.build_xml, CLIENT) 518 | 519 | template = TemplateParser.template_like_str(@hash["template"]) 520 | 521 | rc = @resource.allocate(template) 522 | error(rc) if OpenNebula.is_error?(rc) 523 | end 524 | end 525 | 526 | class BSUser < BS 527 | @@resource_class = User 528 | @@pool_class = UserPool 529 | 530 | def create 531 | @resource = @@resource_class.new(@@resource_class.build_xml, CLIENT) 532 | 533 | args = [@hash["name"], @hash["password"]] 534 | 535 | if (driver = @hash["driver"]) 536 | args << driver 537 | end 538 | 539 | rc = @resource.allocate(*args) 540 | error(rc) if OpenNebula.is_error?(rc) 541 | end 542 | end 543 | 544 | class BSCluster < BS 545 | @@resource_class = Cluster 546 | @@pool_class = ClusterPool 547 | 548 | def create 549 | 550 | @resource = @@resource_class.new(@@resource_class.build_xml, CLIENT) 551 | hosts = @hash["hosts"] 552 | vnets = @hash["vnets"] 553 | dss = @hash["datastores"] 554 | 555 | rc = @resource.allocate(@hash["name"]) 556 | return error(rc) if OpenNebula.is_error?(rc) 557 | 558 | hosts.each { |h| 559 | bsh = BSHost.new({"name" => h}) 560 | bshid = bsh.id 561 | 562 | @resource.addhost(bshid.to_i) if !bshid.nil? 563 | } 564 | 565 | vnets.each { |n| 566 | bsn = BSNet.new({"name" => n}) 567 | bsnid = bsn.id 568 | 569 | @resource.addvnet(bsnid.to_i) if !bsnid.nil? 570 | } 571 | 572 | dss.each { |d| 573 | bsd = BSDatastore.new({"name" => d}) 574 | bsdid = bsd.id 575 | 576 | @resource.adddatastore(bsdid.to_i) if !bsdid.nil? 577 | } 578 | 579 | update 580 | end 581 | end 582 | 583 | 584 | class BSMarketApp < BS 585 | @@resource_class = MarketPlaceApp 586 | @@pool_class = MarketPlaceAppPool 587 | 588 | def create 589 | @resource = @@resource_class.new(@@resource_class.build_xml(@hash["id"]), CLIENT) 590 | 591 | rc = @resource.info 592 | error(rc) if OpenNebula.is_error?(rc) 593 | 594 | rc = @resource.export( 595 | :dsid => @hash["ds_id"], 596 | :name => @hash["name"] 597 | ) 598 | 599 | error(rc) if OpenNebula.is_error?(rc) 600 | end 601 | 602 | def id 603 | t = BSTemplate.new({"name" => @hash["name"]}) 604 | i = BSImage.new({"name" => @hash["name"]}) 605 | 606 | return t if t.id 607 | return i if i.id 608 | 609 | nil 610 | end 611 | 612 | def wait 613 | i = BSImage.new({"name" => @hash["name"]}) 614 | i.set_resource 615 | i.wait 616 | end 617 | end 618 | 619 | ################################################################################ 620 | # Create Resources 621 | ################################################################################ 622 | 623 | conf.each do |hash| 624 | r = BS.factory(hash) 625 | r.do! 626 | end if conf && !conf.empty? 627 | --------------------------------------------------------------------------------