From 614b60bcf96ac48f953853b0cb53b206335fd222 Mon Sep 17 00:00:00 2001 From: "Yvan E. Watchman" Date: Thu, 27 Oct 2022 01:42:30 +0200 Subject: [PATCH 01/10] add initial code for endpoint/request. --- lib/fog/proxmox/cluster.rb | 83 +++++++++++++++++++ lib/fog/proxmox/cluster/models/resource.rb | 57 +++++++++++++ lib/fog/proxmox/cluster/models/resources.rb | 39 +++++++++ .../proxmox/cluster/requests/get_resources.rb | 40 +++++++++ 4 files changed, 219 insertions(+) create mode 100644 lib/fog/proxmox/cluster.rb create mode 100644 lib/fog/proxmox/cluster/models/resource.rb create mode 100644 lib/fog/proxmox/cluster/models/resources.rb create mode 100644 lib/fog/proxmox/cluster/requests/get_resources.rb diff --git a/lib/fog/proxmox/cluster.rb b/lib/fog/proxmox/cluster.rb new file mode 100644 index 0000000..6520af1 --- /dev/null +++ b/lib/fog/proxmox/cluster.rb @@ -0,0 +1,83 @@ +# frozen_string_literal: true + +# Copyright 2018 Tristan Robert + +# This file is part of Fog::Proxmox. + +# Fog::Proxmox is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# Fog::Proxmox is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with Fog::Proxmox. If not, see . + +require 'fog/proxmox/core' + +module Fog + module Proxmox + # Proxmox cluster service + class Cluster < Fog::Service + requires :proxmox_url, :proxmox_auth_method + recognizes :proxmox_token, :proxmox_tokenid, :proxmox_userid, :persistent, :proxmox_username, :proxmox_password + + # Models + model_path 'fog/proxmox/cluster/models' + model :resource + collection :resources + + # Requests + request_path 'fog/proxmox/cluster/requests' + + # Manage nodes cluster + request :get_resources + + # Mock class + class Mock + attr_reader :config + + def initialize(options = {}) + @proxmox_uri = URI.parse(options[:proxmox_url]) + @proxmox_auth_method = options[:proxmox_auth_method] + @proxmox_tokenid = options[:proxmox_tokenid] + @proxmox_userid = options[:proxmox_userid] + @proxmox_username = options[:proxmox_username] + @proxmox_password = options[:proxmox_password] + @proxmox_token = options[:proxmox_token] + @proxmox_path = @proxmox_uri.path + @config = options + end + end + + # Real class + class Real + include Fog::Proxmox::Core + + def self.not_found_class + Fog::Proxmox::Cluster::NotFound + end + + def config + self + end + + def config_service? + true + end + + private + + def configure(source) + source.instance_variables.each do |v| + instance_variable_set(v, source.instance_variable_get(v)) + end + end + end + end + end +end diff --git a/lib/fog/proxmox/cluster/models/resource.rb b/lib/fog/proxmox/cluster/models/resource.rb new file mode 100644 index 0000000..5934cd7 --- /dev/null +++ b/lib/fog/proxmox/cluster/models/resource.rb @@ -0,0 +1,57 @@ +# Copyright 2018 Tristan Robert + +# This file is part of Fog::Proxmox. + +# Fog::Proxmox is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# Fog::Proxmox is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with Fog::Proxmox. If not, see . + +# frozen_string_literal: true + +module Fog + module Proxmox + class Cluster + # class Disk model + class Resource < Fog::Model + identity :id + + attribute :name + attribute :type + attribute :node + + # generic + attribute :maxdisk + + # vm/lxc specific + attribute :status + attribute :uptime + attribute :template + # resources are written in bytes, proxmox displays gibibytes + attribute :maxcpu + attribute :maxmem + + # storage specific + attribute :content + attribute :shared + attribute :storage + + def is_template? + template === 1 + end + + def to_s + Fog::Proxmox::Hash.flatten(flatten) + end + end + end + end +end diff --git a/lib/fog/proxmox/cluster/models/resources.rb b/lib/fog/proxmox/cluster/models/resources.rb new file mode 100644 index 0000000..804508a --- /dev/null +++ b/lib/fog/proxmox/cluster/models/resources.rb @@ -0,0 +1,39 @@ +# frozen_string_literal: true + +# Copyright 2018 Tristan Robert + +# This file is part of Fog::Proxmox. + +# Fog::Proxmox is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# Fog::Proxmox is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with Fog::Proxmox. If not, see . + +require 'fog/proxmox/cluster/models/resource' + +module Fog + module Proxmox + class Cluster + # class Disks Collection of disk + class Resources < Fog::Collection + model Fog::Proxmox::Cluster::Resource + + def all + self + end + + def get(id) + all.find { |resource| resource.identity === id } + end + end + end + end +end diff --git a/lib/fog/proxmox/cluster/requests/get_resources.rb b/lib/fog/proxmox/cluster/requests/get_resources.rb new file mode 100644 index 0000000..3a4315c --- /dev/null +++ b/lib/fog/proxmox/cluster/requests/get_resources.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true + +# Copyright 2018 Tristan Robert + +# This file is part of Fog::Proxmox. + +# Fog::Proxmox is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# Fog::Proxmox is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with Fog::Proxmox. If not, see . + +module Fog + module Proxmox + class Cluster + # class Real get_vnc request + class Real + def get_resources + request( + expects: [200], + method: 'GET', + path: 'cluster/resources' + ) + end + end + + # class Mock get_vnc request + class Mock + def get_resources; end + end + end + end +end From f007c890e6af4a5cc137a8bed2dd05daa34a41ed Mon Sep 17 00:00:00 2001 From: "Yvan E. Watchman" Date: Thu, 27 Oct 2022 13:32:21 +0200 Subject: [PATCH 02/10] add autoloader --- bin/setup | 6 ++---- fog-proxmox.gemspec | 2 +- lib/fog/proxmox.rb | 2 ++ 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/bin/setup b/bin/setup index d141400..8954d11 100755 --- a/bin/setup +++ b/bin/setup @@ -8,11 +8,9 @@ # this file is here to facilitate running it. # -require "pathname" -ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", - Pathname.new(__FILE__).realpath) +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__) -bundle_binstub = File.expand_path("../bundle", __FILE__) +bundle_binstub = File.expand_path("bundle", __dir__) if File.file?(bundle_binstub) if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/ diff --git a/fog-proxmox.gemspec b/fog-proxmox.gemspec index d183739..8489d52 100644 --- a/fog-proxmox.gemspec +++ b/fog-proxmox.gemspec @@ -41,7 +41,7 @@ Gem::Specification.new do |spec| spec.add_development_dependency 'bundler', '~> 2.1' spec.add_development_dependency 'bundler-audit', '~> 0.6' - spec.add_development_dependency 'debase', '~> 0.2.2' + spec.add_development_dependency 'debase', '~> 0.2.5.beta1' spec.add_development_dependency 'debride', '~> 1.8' spec.add_development_dependency 'fasterer', '~> 0.3' spec.add_development_dependency 'fastri', '~> 0.3' diff --git a/lib/fog/proxmox.rb b/lib/fog/proxmox.rb index 9afbee5..f13502d 100644 --- a/lib/fog/proxmox.rb +++ b/lib/fog/proxmox.rb @@ -30,6 +30,7 @@ module Proxmox autoload :Core, 'fog/proxmox/core' autoload :Errors, 'fog/proxmox/errors' autoload :Identity, 'fog/proxmox/identity' + autoload :Cluster, 'fog/proxmox/cluster' autoload :Compute, 'fog/proxmox/compute' autoload :Storage, 'fog/proxmox/storage' autoload :Network, 'fog/proxmox/network' @@ -37,6 +38,7 @@ module Proxmox extend Fog::Provider service(:identity, 'Identity') + service(:cluster, 'Cluster') service(:compute, 'Compute') service(:storage, 'Storage') service(:network, 'Network') From c1ff250737a756d772ef65738fc7a1db7e1bd9f9 Mon Sep 17 00:00:00 2001 From: "Yvan E. Watchman" Date: Fri, 28 Oct 2022 13:46:17 +0200 Subject: [PATCH 03/10] add list resources type --- lib/fog/proxmox/cluster.rb | 2 +- lib/fog/proxmox/cluster/models/resources.rb | 2 +- .../{get_resources.rb => list_resources.rb} | 23 +- spec/cluster_spec.rb | 446 ++++++++++++++++++ spec/fixtures/proxmox/cluster/cluster.yml | 40 ++ spec/fixtures/proxmox/cluster/common_auth.yml | 40 ++ 6 files changed, 548 insertions(+), 5 deletions(-) rename lib/fog/proxmox/cluster/requests/{get_resources.rb => list_resources.rb} (63%) create mode 100644 spec/cluster_spec.rb create mode 100644 spec/fixtures/proxmox/cluster/cluster.yml create mode 100644 spec/fixtures/proxmox/cluster/common_auth.yml diff --git a/lib/fog/proxmox/cluster.rb b/lib/fog/proxmox/cluster.rb index 6520af1..87aab8d 100644 --- a/lib/fog/proxmox/cluster.rb +++ b/lib/fog/proxmox/cluster.rb @@ -35,7 +35,7 @@ class Cluster < Fog::Service request_path 'fog/proxmox/cluster/requests' # Manage nodes cluster - request :get_resources + request :list_resources # Mock class class Mock diff --git a/lib/fog/proxmox/cluster/models/resources.rb b/lib/fog/proxmox/cluster/models/resources.rb index 804508a..0e43afb 100644 --- a/lib/fog/proxmox/cluster/models/resources.rb +++ b/lib/fog/proxmox/cluster/models/resources.rb @@ -27,7 +27,7 @@ class Resources < Fog::Collection model Fog::Proxmox::Cluster::Resource def all - self + load service.list_resources end def get(id) diff --git a/lib/fog/proxmox/cluster/requests/get_resources.rb b/lib/fog/proxmox/cluster/requests/list_resources.rb similarity index 63% rename from lib/fog/proxmox/cluster/requests/get_resources.rb rename to lib/fog/proxmox/cluster/requests/list_resources.rb index 3a4315c..2c47755 100644 --- a/lib/fog/proxmox/cluster/requests/get_resources.rb +++ b/lib/fog/proxmox/cluster/requests/list_resources.rb @@ -22,18 +22,35 @@ module Proxmox class Cluster # class Real get_vnc request class Real - def get_resources + def list_resources(resource_type = nil) + query = resource_type.nil? ? '' : "type=#{resource_type}" request( expects: [200], method: 'GET', - path: 'cluster/resources' + path: 'cluster/resources', + query: query || '' ) end + + def list_qemu_resources + list_resources('qemu') + end + + def list_lxc_resources + list_resources('lxc') + end + + def list_storage_resources + list_resources('storage') + end end # class Mock get_vnc request class Mock - def get_resources; end + def get_resources(resource_type); end + def list_qemu_resources; end + def list_lxc_resources; end + def list_storage_resources; end end end end diff --git a/spec/cluster_spec.rb b/spec/cluster_spec.rb new file mode 100644 index 0000000..74eb451 --- /dev/null +++ b/spec/cluster_spec.rb @@ -0,0 +1,446 @@ +# frozen_string_literal: true + +# Copyright 2018 Tristan Robert + +# This file is part of Fog::Proxmox. + +# Fog::Proxmox is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# Fog::Proxmox is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with Fog::Proxmox. If not, see . + +require 'spec_helper' +require_relative './proxmox_vcr' + +describe Fog::Proxmox::Compute do + before :all do + @proxmox_vcr = ProxmoxVCR.new( + vcr_directory: 'spec/fixtures/proxmox/compute', + service_class: Fog::Proxmox::Compute + ) + @service = @proxmox_vcr.service + @proxmox_url = @proxmox_vcr.url + @username = @proxmox_vcr.username + @password = @proxmox_vcr.password + @tokenid = @proxmox_vcr.tokenid + @token = @proxmox_vcr.token + end + + it 'Manage tasks' do + VCR.use_cassette('tasks') do + # List all tasks + filters = { limit: 1 } + node_name = 'pve' + node = @service.nodes.get node_name + tasks = node.tasks.all(filters) + _(tasks).wont_be_nil + _(tasks).wont_be_empty + _(tasks.size).must_equal 1 + # Get task + upid = tasks[0].upid + task = node.tasks.get(upid) + _(task).wont_be_nil + # Stop task + task.stop + task.wait_for { finished? } + _(task.finished?).must_equal true + end + end + + it 'Manage nodes' do + VCR.use_cassette('nodes') do + # Get node + node_name = 'pve' + node = @service.nodes.get node_name + # Get statistics data + data = node.statistics + _(data).wont_be_nil + _(data).wont_be_empty + # Get statistics image + data = node.statistics('rrd', { timeframe: 'hour', ds: 'cpu,memused', cf: 'AVERAGE' }) + _(data).wont_be_nil + _(data['image']).wont_be_nil + end + end + + it 'Manage storages' do + VCR.use_cassette('storages') do + # Get node + node_name = 'pve' + node = @service.nodes.get node_name + # List all storages + storages = node.storages.all + _(storages).wont_be_nil + _(storages).wont_be_empty + _(storages.size).must_equal 2 + # List by content type + storages = node.storages.list_by_content_type 'iso' + _(storages).wont_be_nil + _(storages).wont_be_empty + _(storages.size).must_equal 1 + # Get storage + storage = node.storages.get('local') + _(storage).wont_be_nil + _(storage.identity).must_equal 'local' + end + end + + it 'CRUD servers' do + VCR.use_cassette('servers') do + node_name = 'pve' + node = @service.nodes.get node_name + # Get next vmid + vmid = node.servers.next_id + server_hash = { vmid: vmid } + # Check valid vmid + valid = node.servers.id_valid? vmid + _(valid).must_equal true + # Check not valid vmid + valid = node.servers.id_valid? 99 + _(valid).must_equal false + # Create 1st time + server = node.servers.create(server_hash) + ok = server.persisted? + _(ok).must_equal true + # Check already used vmid + valid = node.servers.id_valid? vmid + _(valid).must_equal false + # Clone server + newid = node.servers.next_id + # Get server + server = node.servers.get vmid + _(server).wont_be_nil + # Backup it + server.backup(compress: 'lzo') + # Get this backup image + # Find available backup volumes + volume = server.backups.first + _(volume).wont_be_nil + # Restore it + server.restore(volume, storage: 'local') + # Delete it + volume.destroy + # Add hdd + # Find available storages with images + storages = node.storages.list_by_content_type 'images' + storage = storages[0] + virtio0 = { id: 'virtio0', storage: storage.storage, size: '1' } + ide0 = { id: 'ide0', storage: storage.storage, size: '1' } + options = { backup: 0, replicate: 0 } + server.attach(virtio0, options) + server.attach(ide0, options) + server.detach('ide0') + server.detach('unused0') + sleep 1 + # Clone it (linked fails) + server.clone(newid, full: 1) + # Get clone + clone = node.servers.get newid + # Template this clone (read-only) + clone.create_template + # Get clone disk image + image = clone.images.first + _(image).wont_be_nil + # Delete clone + clone.destroy + _(proc do + clone = node.servers.get newid + end).must_raise Fog::Errors::NotFound + # Create 2nd time must fails + _(proc do + node.servers.create server_hash + end).must_raise Excon::Errors::InternalServerError + # Update config server + # Add empty cdrom + config_hash = { ide2: 'none,media=cdrom' } + server.update(config_hash) + # Resize disk server + server.extend('virtio0', '+1G') + # Move disk server + server.move('virtio0', 'local') + # Add network interface + config_hash = { net0: 'virtio,bridge=vmbr0' } + server.update(config_hash) + # Add start at boot, keyboard fr, + # linux 4.x os type, kvm hardware disabled (proxmox guest in virtualbox) and vga enabled to console + config_hash = { onboot: 1, keyboard: 'fr', ostype: 'l26', kvm: 0 } + server.update(config_hash) + # server config + config = server.config + _(config.identity).must_equal vmid + disks = server.config.disks + interfaces = server.config.interfaces + _(interfaces).wont_be_nil + _(interfaces).wont_be_empty + net0 = interfaces.get('net0') + _(net0).wont_be_nil + _(disks).wont_be_nil + _(disks).wont_be_empty + virtio0 = disks.get('virtio0') + _(virtio0).wont_be_nil + ide2 = disks.get('ide2') + _(ide2).wont_be_nil + # Get a mac adress + mac_address = server.config.mac_addresses.first + _(mac_address).wont_be_nil + # all servers + servers_all = node.servers.all + _(servers_all).wont_be_empty + _(servers_all).must_include server + # server not running exception + _(proc do + server.start_console(websocket: 1) + end).must_raise Fog::Proxmox::Errors::ServiceError + # Start server + server.action('start') + server.wait_for { ready? } + status = server.ready? + _(status).must_equal true + # server vga not set exception + _(proc do + server.start_console(websocket: 1) + end).must_raise Fog::Proxmox::Errors::ServiceError + # Stop server + server.action('stop') + server.wait_for { server.status == 'stopped' } + status = server.status + _(status).must_equal 'stopped' + server.update(vga: 'std') + # Start server + server.action('start') + server.wait_for { ready? } + status = server.ready? + _(status).must_equal true + vnc = server.start_console(websocket: 1) + _(vnc['cert']).wont_be_nil + port = server.connect_vnc(vnc) + _(port).wont_be_nil + # Stop server + server.action('stop') + server.wait_for { server.status == 'stopped' } + status = server.status + _(status).must_equal 'stopped' + server.update(serial0: 'socket', vga: 'serial0') + # Start server + server.action('start') + server.wait_for { ready? } + status = server.ready? + _(status).must_equal true + term = server.start_console + _(term['ticket']).wont_be_nil + # Stop server + server.action('stop') + server.wait_for { server.status == 'stopped' } + status = server.status + _(status).must_equal 'stopped' + server.update(vga: 'qxl') + # Start server + server.action('start') + server.wait_for { ready? } + status = server.ready? + _(status).must_equal true + spice = server.start_console + _(spice['password']).wont_be_nil + # Suspend server + server.action('suspend') + server.wait_for { server.qmpstatus == 'paused' } + qmpstatus = server.qmpstatus + _(qmpstatus).must_equal 'paused' + # Resume server + server.action('resume') + server.wait_for { ready? } + status = server.ready? + _(status).must_equal true + # Stop server + server.action('stop') + server.wait_for { server.status == 'stopped' } + status = server.status + _(status).must_equal 'stopped' + _(proc do + server.action('hello') + end).must_raise Fog::Errors::Error + # Delete + server.destroy + _(proc do + node.servers.get vmid + end).must_raise Fog::Errors::NotFound + end + end + + it 'CRUD snapshots' do + VCR.use_cassette('snapshots') do + node_name = 'pve' + node = @service.nodes.get node_name + vmid = node.servers.next_id + server_hash = { vmid: vmid } + node.servers.create server_hash + # Create + snapname = 'snapshot1' + server = node.servers.get vmid + snapshot_hash = { name: snapname } + server.snapshots.create(snapshot_hash) + # Find by id + snapshot = server.snapshots.get snapname + _(snapshot).wont_be_nil + # Update + snapshot.description = 'Snapshot 1' + snapshot.update + # all snapshots + snapshots_all = server.snapshots.all + _(snapshots_all).wont_be_nil + _(snapshots_all).wont_be_empty + _(snapshots_all).must_include snapshot + # Delete + snapshot.destroy + server.destroy + end + end + + it 'CRUD containers' do + VCR.use_cassette('containers') do + node_name = 'pve' + node = @service.nodes.get node_name + _(node).wont_be_nil + # Get next vmid + vmid = node.containers.next_id + ostemplate = 'local:vztmpl/alpine-3.12-default_20200823_amd64.tar.xz' + container_hash = { ostemplate: ostemplate, storage: 'local-lvm', password: 'proxmox01', rootfs: 'local-lvm:1' } + # Check valid vmid + valid = node.containers.id_valid? vmid + _(valid).must_equal true + # Check not valid vmid + valid = node.containers.id_valid? 99 + _(valid).must_equal false + # Create 1st time + node.containers.create(container_hash.merge(vmid: vmid)) + # Check already used vmid + valid = node.containers.id_valid? vmid + _(valid).must_equal false + # Clone container + newid = node.containers.next_id + # Get container + container = node.containers.get vmid + _(container).wont_be_nil + rootfs_a = container.config.disks.select { |disk| disk.rootfs? } + _(rootfs_a).wont_be_empty + rootfs = rootfs_a.first + _(rootfs).wont_be_nil + # Backup it + container.backup(compress: 'lzo') + # Get this backup image + # Find available backup volumes + backup = container.backups.first + _(container).wont_be_nil + # Restore it + container.restore(backup, storage: 'local-lvm') + # Delete it + backup.destroy + _(container.backups).must_be_empty + # Add mount points + # Find available storages with images + storages = node.storages.list_by_content_type 'images' + storage = storages[0] + mp0 = { id: 'mp0', storage: storage.storage, size: '1' } + options = { mp: '/opt/app', backup: 0, replicate: 0, quota: 1 } + container.attach(mp0, options) + # Fetch mount points + mount_points = container.config.disks.select { |disk| disk.mount_point? } + _(mount_points).wont_be_empty + _(mount_points.get('mp0')).wont_be_nil + # Remove mount points + container.detach('mp0') + container.detach('unused0') + sleep 1 + # Clone it + container.clone(newid) + # Get clone + clone = node.containers.get newid + # Template this clone (read-only) + clone.template + # Get clone disk image + image = clone.images.first + _(image).wont_be_nil + # Delete clone + clone.destroy + _(proc do + node.containers.get newid + end).must_raise Fog::Errors::NotFound + # Create 2nd time must fails + _(proc do + node.containers.create(container_hash.merge(vmid: vmid)) + end).must_raise Excon::Errors::InternalServerError + # Update config container + # Resize rootfs container + container.extend('rootfs', '+5M') + # Move rootfs container and delete original + container.move('rootfs', 'local-lvm', delete: 1) + # Add network interface + config_hash = { net0: 'bridge=vmbr0,name=eth0,ip=dhcp,ip6=dhcp' } + container.update(config_hash) + # Add start at boot, keyboard fr, + # linux os type alpine + config_hash = { onboot: 1, ostype: 'alpine' } + container.update(config_hash) + # get container config + config = container.config + _(config).wont_be_nil + _(config.identity).must_equal vmid + # Fetch nics + interfaces = container.config.interfaces + _(interfaces).wont_be_empty + _(interfaces.get('net0')).wont_be_nil + # Get a mac address + mac_address = container.config.mac_addresses.first + _(mac_address).wont_be_nil + # all containers + containers_all = node.containers.all + _(containers_all).wont_be_nil + _(containers_all).wont_be_empty + _(containers_all.first.vmid).must_equal container.vmid.to_s + # Start container + container.action('start') + container.wait_for { ready? } + status = container.ready? + _(status).must_equal true + # Start console + _(proc do + container.start_console + end).must_raise Fog::Errors::Error + spice = container.start_console(console: 'spice') + _(spice['password']).wont_be_nil + # Suspend container (: command 'lxc-checkpoint -n 100 -s -D /var/lib/vz/dump' failed: exit code 1) + # container.action('suspend') + # container.wait_for { container.qmpstatus == 'paused' } + # qmpstatus = container.qmpstatus + # _(qmpstatus).must_equal 'paused' + # Resume server + # container.action('resume') + # container.wait_for { ready? } + # status = container.ready? + # _(status).must_equal true + # Stop container + container.action('stop') + container.wait_for { container.status == 'stopped' } + status = container.status + _(status).must_equal 'stopped' + _(proc do + container.action('hello') + end).must_raise Fog::Errors::Error + # Delete + container.destroy + # Delete container does not delete images + storage.volumes.each(&:destroy) + _(proc do + node.containers.get vmid + end).must_raise Fog::Errors::NotFound + end + end +end diff --git a/spec/fixtures/proxmox/cluster/cluster.yml b/spec/fixtures/proxmox/cluster/cluster.yml new file mode 100644 index 0000000..bcde7ad --- /dev/null +++ b/spec/fixtures/proxmox/cluster/cluster.yml @@ -0,0 +1,40 @@ +--- +http_interactions: +- request: + method: get + uri: https://192.168.56.101:8006/api2/json/cluster/resources + body: + encoding: US-ASCII + string: '' + headers: + User-Agent: + - fog-core/2.2.3 + Cookie: + - PVEAuthCookie=PVE:root@pam:5FBE5F93::J4UGO/cW6NJLxU0fQy8AnxuJhKDkIa+ZLBLUIxlXYO3Nb1ocZ15jqoPl0EEOQpI2sohhmtGYo9bptqaPPH48rmaNKzIUtHjDAg/c425GgbhkSo2jYVeCWcTTEC+nDskOiMkjdE4HIiFLpk71IMEP93hGWJ4+mnUxOLfHsRDodWdJXoGoBlxiUBu0zirFLXR60i6WCK2oX82nPYXRJbsl4VRLYcOkYXnnfaUxYgOL0veZhKRcAWlVRKQ7/lkdG1iu3XlOvEeynqcT2xHs+Z158zALA+ZzAEQ6GYdvFFKr/xR57Kd8hfOhRumKx5EaDfdeYkZP/8ZVH48tEbTXrOEQHg== + response: + status: + code: 200 + message: OK + headers: + Cache-Control: + - max-age=0 + Connection: + - Keep-Alive + Date: + - Wed, 25 Nov 2020 13:43:47 GMT + Pragma: + - no-cache + Server: + - pve-api-daemon/3.0 + Content-Length: + - '209' + Content-Type: + - application/json;charset=UTF-8 + Expires: + - Wed, 25 Nov 2020 13:43:47 GMT + body: + encoding: ASCII-8BIT + string: '{"data":[{"cpu":0.486288911006624,"disk":6172704768,"id":"node/pve","level":"b","maxcpu":32,"maxdisk":773845024768,"maxmem":134936813568,"mem":114900549632,"node":"pve","status":"online","type":"node","uptime":6909898},{"cpu":0.00538129953557645,"disk":1983594496,"diskread":0,"diskwrite":0,"id":"qemu/105","maxcpu":4,"maxdisk":34573647872,"maxmem":17179869184,"mem":0,"name":"test01","netin":0,"netout":0,"node":"pve","status":"stopped","template":0,"type":"qemu","uptime":0,"vmid":100},{"cpu":0.00538129953557645,"disk":1983594496,"diskread":10794659840,"diskwrite":45429886976,"id":"lxc/101","maxcpu":1,"maxdisk":8350298112,"maxmem":2147483648,"mem":116183040,"name":"test02","netin":2258649906,"netout":9957850155,"node":"pve","status":"running","template":0,"type":"lxc","uptime":6907061,"vmid":101},{"content":"vztmpl,iso,backup","disk":5444206592,"id":"storage/pve/local","maxdisk":773845024768,"node":"pve","plugintype":"dir","shared":0,"status":"available","storage":"local","type":"storage"},{"content":"images,rootdir","disk":6525668992656,"id":"storage/pve/storage","maxdisk":31831680352256,"node":"pve","plugintype":"zfspool","shared":0,"status":"available","storage":"storage","type":"storage"}]}' + http_version: + recorded_at: Wed, 25 Nov 2020 13:43:48 GMT +recorded_with: VCR 4.0.0 diff --git a/spec/fixtures/proxmox/cluster/common_auth.yml b/spec/fixtures/proxmox/cluster/common_auth.yml new file mode 100644 index 0000000..e9e1ad4 --- /dev/null +++ b/spec/fixtures/proxmox/cluster/common_auth.yml @@ -0,0 +1,40 @@ +--- +http_interactions: +- request: + method: post + uri: https://192.168.56.101:8006/api2/json/access/ticket + body: + encoding: US-ASCII + string: username=root%40pam&password=proxmox01 + headers: + User-Agent: + - fog-core/2.2.3 + Accept: + - application/json + response: + status: + code: 200 + message: OK + headers: + Cache-Control: + - max-age=0 + Connection: + - close, Keep-Alive + Date: + - Wed, 25 Nov 2020 13:43:47 GMT + Pragma: + - no-cache + Server: + - pve-api-daemon/3.0 + Content-Length: + - '1167' + Content-Type: + - application/json;charset=UTF-8 + Expires: + - Wed, 25 Nov 2020 13:43:47 GMT + body: + encoding: ASCII-8BIT + string: '{"data":{"CSRFPreventionToken":"5FBE5F93:tNCo7nHYIIdA46RVo8yPQg9ZcbtzibFl3lhAwDPkSqc","ticket":"PVE:root@pam:5FBE5F93::J4UGO/cW6NJLxU0fQy8AnxuJhKDkIa+ZLBLUIxlXYO3Nb1ocZ15jqoPl0EEOQpI2sohhmtGYo9bptqaPPH48rmaNKzIUtHjDAg/c425GgbhkSo2jYVeCWcTTEC+nDskOiMkjdE4HIiFLpk71IMEP93hGWJ4+mnUxOLfHsRDodWdJXoGoBlxiUBu0zirFLXR60i6WCK2oX82nPYXRJbsl4VRLYcOkYXnnfaUxYgOL0veZhKRcAWlVRKQ7/lkdG1iu3XlOvEeynqcT2xHs+Z158zALA+ZzAEQ6GYdvFFKr/xR57Kd8hfOhRumKx5EaDfdeYkZP/8ZVH48tEbTXrOEQHg==","cap":{"nodes":{"Sys.Console":1,"Sys.Audit":1,"Sys.PowerMgmt":1,"Permissions.Modify":1,"Sys.Modify":1,"Sys.Syslog":1},"access":{"Group.Allocate":1,"Permissions.Modify":1,"User.Modify":1},"dc":{"Sys.Audit":1},"vms":{"VM.Config.HWType":1,"VM.Migrate":1,"VM.Snapshot.Rollback":1,"VM.Config.Memory":1,"VM.Config.Disk":1,"VM.PowerMgmt":1,"VM.Monitor":1,"VM.Backup":1,"VM.Audit":1,"VM.Config.CDROM":1,"VM.Config.Network":1,"Permissions.Modify":1,"VM.Clone":1,"VM.Allocate":1,"VM.Config.CPU":1,"VM.Console":1,"VM.Config.Options":1,"VM.Snapshot":1},"storage":{"Datastore.Allocate":1,"Permissions.Modify":1,"Datastore.Audit":1,"Datastore.AllocateSpace":1,"Datastore.AllocateTemplate":1}},"username":"root@pam"}}' + http_version: + recorded_at: Wed, 25 Nov 2020 13:43:48 GMT +recorded_with: VCR 4.0.0 From d4826016cfe8c31f85ca3a842a097808ee41452a Mon Sep 17 00:00:00 2001 From: "Yvan E. Watchman" Date: Fri, 28 Oct 2022 13:49:05 +0200 Subject: [PATCH 04/10] add cluster spec --- spec/cluster_spec.rb | 425 ++----------------------------------------- 1 file changed, 15 insertions(+), 410 deletions(-) diff --git a/spec/cluster_spec.rb b/spec/cluster_spec.rb index 74eb451..f8d9ede 100644 --- a/spec/cluster_spec.rb +++ b/spec/cluster_spec.rb @@ -20,11 +20,11 @@ require 'spec_helper' require_relative './proxmox_vcr' -describe Fog::Proxmox::Compute do +describe Fog::Proxmox::Cluster do before :all do @proxmox_vcr = ProxmoxVCR.new( - vcr_directory: 'spec/fixtures/proxmox/compute', - service_class: Fog::Proxmox::Compute + vcr_directory: 'spec/fixtures/proxmox/cluster', + service_class: Fog::Proxmox::Cluster ) @service = @proxmox_vcr.service @proxmox_url = @proxmox_vcr.url @@ -34,413 +34,18 @@ @token = @proxmox_vcr.token end - it 'Manage tasks' do - VCR.use_cassette('tasks') do - # List all tasks - filters = { limit: 1 } - node_name = 'pve' - node = @service.nodes.get node_name - tasks = node.tasks.all(filters) - _(tasks).wont_be_nil - _(tasks).wont_be_empty - _(tasks.size).must_equal 1 - # Get task - upid = tasks[0].upid - task = node.tasks.get(upid) - _(task).wont_be_nil - # Stop task - task.stop - task.wait_for { finished? } - _(task.finished?).must_equal true - end - end - - it 'Manage nodes' do - VCR.use_cassette('nodes') do - # Get node - node_name = 'pve' - node = @service.nodes.get node_name - # Get statistics data - data = node.statistics - _(data).wont_be_nil - _(data).wont_be_empty - # Get statistics image - data = node.statistics('rrd', { timeframe: 'hour', ds: 'cpu,memused', cf: 'AVERAGE' }) - _(data).wont_be_nil - _(data['image']).wont_be_nil - end - end - - it 'Manage storages' do - VCR.use_cassette('storages') do - # Get node - node_name = 'pve' - node = @service.nodes.get node_name - # List all storages - storages = node.storages.all - _(storages).wont_be_nil - _(storages).wont_be_empty - _(storages.size).must_equal 2 - # List by content type - storages = node.storages.list_by_content_type 'iso' - _(storages).wont_be_nil - _(storages).wont_be_empty - _(storages.size).must_equal 1 - # Get storage - storage = node.storages.get('local') - _(storage).wont_be_nil - _(storage.identity).must_equal 'local' - end - end - - it 'CRUD servers' do - VCR.use_cassette('servers') do - node_name = 'pve' - node = @service.nodes.get node_name - # Get next vmid - vmid = node.servers.next_id - server_hash = { vmid: vmid } - # Check valid vmid - valid = node.servers.id_valid? vmid - _(valid).must_equal true - # Check not valid vmid - valid = node.servers.id_valid? 99 - _(valid).must_equal false - # Create 1st time - server = node.servers.create(server_hash) - ok = server.persisted? - _(ok).must_equal true - # Check already used vmid - valid = node.servers.id_valid? vmid - _(valid).must_equal false - # Clone server - newid = node.servers.next_id - # Get server - server = node.servers.get vmid - _(server).wont_be_nil - # Backup it - server.backup(compress: 'lzo') - # Get this backup image - # Find available backup volumes - volume = server.backups.first - _(volume).wont_be_nil - # Restore it - server.restore(volume, storage: 'local') - # Delete it - volume.destroy - # Add hdd - # Find available storages with images - storages = node.storages.list_by_content_type 'images' - storage = storages[0] - virtio0 = { id: 'virtio0', storage: storage.storage, size: '1' } - ide0 = { id: 'ide0', storage: storage.storage, size: '1' } - options = { backup: 0, replicate: 0 } - server.attach(virtio0, options) - server.attach(ide0, options) - server.detach('ide0') - server.detach('unused0') - sleep 1 - # Clone it (linked fails) - server.clone(newid, full: 1) - # Get clone - clone = node.servers.get newid - # Template this clone (read-only) - clone.create_template - # Get clone disk image - image = clone.images.first - _(image).wont_be_nil - # Delete clone - clone.destroy - _(proc do - clone = node.servers.get newid - end).must_raise Fog::Errors::NotFound - # Create 2nd time must fails - _(proc do - node.servers.create server_hash - end).must_raise Excon::Errors::InternalServerError - # Update config server - # Add empty cdrom - config_hash = { ide2: 'none,media=cdrom' } - server.update(config_hash) - # Resize disk server - server.extend('virtio0', '+1G') - # Move disk server - server.move('virtio0', 'local') - # Add network interface - config_hash = { net0: 'virtio,bridge=vmbr0' } - server.update(config_hash) - # Add start at boot, keyboard fr, - # linux 4.x os type, kvm hardware disabled (proxmox guest in virtualbox) and vga enabled to console - config_hash = { onboot: 1, keyboard: 'fr', ostype: 'l26', kvm: 0 } - server.update(config_hash) - # server config - config = server.config - _(config.identity).must_equal vmid - disks = server.config.disks - interfaces = server.config.interfaces - _(interfaces).wont_be_nil - _(interfaces).wont_be_empty - net0 = interfaces.get('net0') - _(net0).wont_be_nil - _(disks).wont_be_nil - _(disks).wont_be_empty - virtio0 = disks.get('virtio0') - _(virtio0).wont_be_nil - ide2 = disks.get('ide2') - _(ide2).wont_be_nil - # Get a mac adress - mac_address = server.config.mac_addresses.first - _(mac_address).wont_be_nil - # all servers - servers_all = node.servers.all - _(servers_all).wont_be_empty - _(servers_all).must_include server - # server not running exception - _(proc do - server.start_console(websocket: 1) - end).must_raise Fog::Proxmox::Errors::ServiceError - # Start server - server.action('start') - server.wait_for { ready? } - status = server.ready? - _(status).must_equal true - # server vga not set exception - _(proc do - server.start_console(websocket: 1) - end).must_raise Fog::Proxmox::Errors::ServiceError - # Stop server - server.action('stop') - server.wait_for { server.status == 'stopped' } - status = server.status - _(status).must_equal 'stopped' - server.update(vga: 'std') - # Start server - server.action('start') - server.wait_for { ready? } - status = server.ready? - _(status).must_equal true - vnc = server.start_console(websocket: 1) - _(vnc['cert']).wont_be_nil - port = server.connect_vnc(vnc) - _(port).wont_be_nil - # Stop server - server.action('stop') - server.wait_for { server.status == 'stopped' } - status = server.status - _(status).must_equal 'stopped' - server.update(serial0: 'socket', vga: 'serial0') - # Start server - server.action('start') - server.wait_for { ready? } - status = server.ready? - _(status).must_equal true - term = server.start_console - _(term['ticket']).wont_be_nil - # Stop server - server.action('stop') - server.wait_for { server.status == 'stopped' } - status = server.status - _(status).must_equal 'stopped' - server.update(vga: 'qxl') - # Start server - server.action('start') - server.wait_for { ready? } - status = server.ready? - _(status).must_equal true - spice = server.start_console - _(spice['password']).wont_be_nil - # Suspend server - server.action('suspend') - server.wait_for { server.qmpstatus == 'paused' } - qmpstatus = server.qmpstatus - _(qmpstatus).must_equal 'paused' - # Resume server - server.action('resume') - server.wait_for { ready? } - status = server.ready? - _(status).must_equal true - # Stop server - server.action('stop') - server.wait_for { server.status == 'stopped' } - status = server.status - _(status).must_equal 'stopped' - _(proc do - server.action('hello') - end).must_raise Fog::Errors::Error - # Delete - server.destroy - _(proc do - node.servers.get vmid - end).must_raise Fog::Errors::NotFound - end - end - - it 'CRUD snapshots' do - VCR.use_cassette('snapshots') do - node_name = 'pve' - node = @service.nodes.get node_name - vmid = node.servers.next_id - server_hash = { vmid: vmid } - node.servers.create server_hash - # Create - snapname = 'snapshot1' - server = node.servers.get vmid - snapshot_hash = { name: snapname } - server.snapshots.create(snapshot_hash) - # Find by id - snapshot = server.snapshots.get snapname - _(snapshot).wont_be_nil - # Update - snapshot.description = 'Snapshot 1' - snapshot.update - # all snapshots - snapshots_all = server.snapshots.all - _(snapshots_all).wont_be_nil - _(snapshots_all).wont_be_empty - _(snapshots_all).must_include snapshot - # Delete - snapshot.destroy - server.destroy - end - end - - it 'CRUD containers' do - VCR.use_cassette('containers') do - node_name = 'pve' - node = @service.nodes.get node_name - _(node).wont_be_nil - # Get next vmid - vmid = node.containers.next_id - ostemplate = 'local:vztmpl/alpine-3.12-default_20200823_amd64.tar.xz' - container_hash = { ostemplate: ostemplate, storage: 'local-lvm', password: 'proxmox01', rootfs: 'local-lvm:1' } - # Check valid vmid - valid = node.containers.id_valid? vmid - _(valid).must_equal true - # Check not valid vmid - valid = node.containers.id_valid? 99 - _(valid).must_equal false - # Create 1st time - node.containers.create(container_hash.merge(vmid: vmid)) - # Check already used vmid - valid = node.containers.id_valid? vmid - _(valid).must_equal false - # Clone container - newid = node.containers.next_id - # Get container - container = node.containers.get vmid - _(container).wont_be_nil - rootfs_a = container.config.disks.select { |disk| disk.rootfs? } - _(rootfs_a).wont_be_empty - rootfs = rootfs_a.first - _(rootfs).wont_be_nil - # Backup it - container.backup(compress: 'lzo') - # Get this backup image - # Find available backup volumes - backup = container.backups.first - _(container).wont_be_nil - # Restore it - container.restore(backup, storage: 'local-lvm') - # Delete it - backup.destroy - _(container.backups).must_be_empty - # Add mount points - # Find available storages with images - storages = node.storages.list_by_content_type 'images' - storage = storages[0] - mp0 = { id: 'mp0', storage: storage.storage, size: '1' } - options = { mp: '/opt/app', backup: 0, replicate: 0, quota: 1 } - container.attach(mp0, options) - # Fetch mount points - mount_points = container.config.disks.select { |disk| disk.mount_point? } - _(mount_points).wont_be_empty - _(mount_points.get('mp0')).wont_be_nil - # Remove mount points - container.detach('mp0') - container.detach('unused0') - sleep 1 - # Clone it - container.clone(newid) - # Get clone - clone = node.containers.get newid - # Template this clone (read-only) - clone.template - # Get clone disk image - image = clone.images.first - _(image).wont_be_nil - # Delete clone - clone.destroy - _(proc do - node.containers.get newid - end).must_raise Fog::Errors::NotFound - # Create 2nd time must fails - _(proc do - node.containers.create(container_hash.merge(vmid: vmid)) - end).must_raise Excon::Errors::InternalServerError - # Update config container - # Resize rootfs container - container.extend('rootfs', '+5M') - # Move rootfs container and delete original - container.move('rootfs', 'local-lvm', delete: 1) - # Add network interface - config_hash = { net0: 'bridge=vmbr0,name=eth0,ip=dhcp,ip6=dhcp' } - container.update(config_hash) - # Add start at boot, keyboard fr, - # linux os type alpine - config_hash = { onboot: 1, ostype: 'alpine' } - container.update(config_hash) - # get container config - config = container.config - _(config).wont_be_nil - _(config.identity).must_equal vmid - # Fetch nics - interfaces = container.config.interfaces - _(interfaces).wont_be_empty - _(interfaces.get('net0')).wont_be_nil - # Get a mac address - mac_address = container.config.mac_addresses.first - _(mac_address).wont_be_nil - # all containers - containers_all = node.containers.all - _(containers_all).wont_be_nil - _(containers_all).wont_be_empty - _(containers_all.first.vmid).must_equal container.vmid.to_s - # Start container - container.action('start') - container.wait_for { ready? } - status = container.ready? - _(status).must_equal true - # Start console - _(proc do - container.start_console - end).must_raise Fog::Errors::Error - spice = container.start_console(console: 'spice') - _(spice['password']).wont_be_nil - # Suspend container (: command 'lxc-checkpoint -n 100 -s -D /var/lib/vz/dump' failed: exit code 1) - # container.action('suspend') - # container.wait_for { container.qmpstatus == 'paused' } - # qmpstatus = container.qmpstatus - # _(qmpstatus).must_equal 'paused' - # Resume server - # container.action('resume') - # container.wait_for { ready? } - # status = container.ready? - # _(status).must_equal true - # Stop container - container.action('stop') - container.wait_for { container.status == 'stopped' } - status = container.status - _(status).must_equal 'stopped' - _(proc do - container.action('hello') - end).must_raise Fog::Errors::Error - # Delete - container.destroy - # Delete container does not delete images - storage.volumes.each(&:destroy) - _(proc do - node.containers.get vmid - end).must_raise Fog::Errors::NotFound + it 'Manage Clusters' do + VCR.use_cassette('cluster') do + # List all resources + resources = @service.resources.all + _(resources).wont_be_nil + _(resources).wont_be_empty + _(resources.size).must_equal 3 # TODO: add mock resources + # List all resources of type qemu + qemu_resources = @service.resources.get('qemu') + _(qemu_resources).wont_be_nil + _(qemu_resources).wont_be_empty + _(qemu_resources.size).must_equal 1 # TODO: add mock resources end end end From 15935e7613307f6d58003841f6d3a585cf4c9ed2 Mon Sep 17 00:00:00 2001 From: "Yvan E. Watchman" Date: Fri, 28 Oct 2022 14:05:08 +0200 Subject: [PATCH 05/10] add mocks and update spec to comply --- lib/fog/proxmox/cluster/models/resources.rb | 4 ++ .../cluster/requests/list_resources.rb | 49 +++++++++++++++++-- spec/cluster_spec.rb | 6 +-- 3 files changed, 52 insertions(+), 7 deletions(-) diff --git a/lib/fog/proxmox/cluster/models/resources.rb b/lib/fog/proxmox/cluster/models/resources.rb index 0e43afb..6948262 100644 --- a/lib/fog/proxmox/cluster/models/resources.rb +++ b/lib/fog/proxmox/cluster/models/resources.rb @@ -33,6 +33,10 @@ def all def get(id) all.find { |resource| resource.identity === id } end + + def by_type(type) + all.select { |resource| resource.type === type } + end end end end diff --git a/lib/fog/proxmox/cluster/requests/list_resources.rb b/lib/fog/proxmox/cluster/requests/list_resources.rb index 2c47755..1b5b900 100644 --- a/lib/fog/proxmox/cluster/requests/list_resources.rb +++ b/lib/fog/proxmox/cluster/requests/list_resources.rb @@ -47,10 +47,51 @@ def list_storage_resources # class Mock get_vnc request class Mock - def get_resources(resource_type); end - def list_qemu_resources; end - def list_lxc_resources; end - def list_storage_resources; end + def list_resources(resource_type) + case resource_type + when 'qemu' + list_qemu_resources + when 'lxc' + list_lxc_resources + when 'storage' + list_storage_resources + else + (list_qemu_resources + list_lxc_resources + list_storage_resources) + end + end + def list_qemu_resources + [ + { + 'node' => 'pve', + 'type' => 'qemu', + 'vmid' => '100' + } + ] + end + + def list_lxc_resources + [ + { + 'node' => 'pve', + 'type' => 'lxc', + 'vmid' => '101' + } + ] + end + def list_storage_resources + [ + { + 'node' => 'pve', + 'type' => 'storage', + 'storage' => 'local' + }, + { + 'node' => 'pve', + 'type' => 'storage', + 'storage' => 'local' + } + ] + end end end end diff --git a/spec/cluster_spec.rb b/spec/cluster_spec.rb index f8d9ede..4c2b041 100644 --- a/spec/cluster_spec.rb +++ b/spec/cluster_spec.rb @@ -40,12 +40,12 @@ resources = @service.resources.all _(resources).wont_be_nil _(resources).wont_be_empty - _(resources.size).must_equal 3 # TODO: add mock resources + _(resources.size).must_equal 4 # List all resources of type qemu - qemu_resources = @service.resources.get('qemu') + qemu_resources = @service.resources.by_type('qemu') _(qemu_resources).wont_be_nil _(qemu_resources).wont_be_empty - _(qemu_resources.size).must_equal 1 # TODO: add mock resources + _(qemu_resources.size).must_equal 1 end end end From 20e277565ee2b98936d4226567acd9b47005433f Mon Sep 17 00:00:00 2001 From: "Yvan E. Watchman" Date: Fri, 28 Oct 2022 16:25:03 +0200 Subject: [PATCH 06/10] code style --- lib/fog/proxmox/cluster/models/resource.rb | 1 + lib/fog/proxmox/cluster/requests/list_resources.rb | 8 +++++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/fog/proxmox/cluster/models/resource.rb b/lib/fog/proxmox/cluster/models/resource.rb index 5934cd7..e81ea93 100644 --- a/lib/fog/proxmox/cluster/models/resource.rb +++ b/lib/fog/proxmox/cluster/models/resource.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true # Copyright 2018 Tristan Robert # This file is part of Fog::Proxmox. diff --git a/lib/fog/proxmox/cluster/requests/list_resources.rb b/lib/fog/proxmox/cluster/requests/list_resources.rb index 1b5b900..713fdf3 100644 --- a/lib/fog/proxmox/cluster/requests/list_resources.rb +++ b/lib/fog/proxmox/cluster/requests/list_resources.rb @@ -22,8 +22,8 @@ module Proxmox class Cluster # class Real get_vnc request class Real - def list_resources(resource_type = nil) - query = resource_type.nil? ? '' : "type=#{resource_type}" + def list_resources(resource_type = '') + query = resource_type.blank? ? '' : "type=#{resource_type}" request( expects: [200], method: 'GET', @@ -59,6 +59,7 @@ def list_resources(resource_type) (list_qemu_resources + list_lxc_resources + list_storage_resources) end end + def list_qemu_resources [ { @@ -78,7 +79,8 @@ def list_lxc_resources } ] end - def list_storage_resources + + def list_storage_resources # rubocop:disable Metrics/MethodLength [ { 'node' => 'pve', From fc7fbc953fa41cd0cd820c0b4be3b849a915c370 Mon Sep 17 00:00:00 2001 From: "Yvan E. Watchman" Date: Fri, 28 Oct 2022 22:03:42 +0200 Subject: [PATCH 07/10] fix vm filter --- lib/fog/proxmox/cluster/requests/list_resources.rb | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/fog/proxmox/cluster/requests/list_resources.rb b/lib/fog/proxmox/cluster/requests/list_resources.rb index 713fdf3..1231e3a 100644 --- a/lib/fog/proxmox/cluster/requests/list_resources.rb +++ b/lib/fog/proxmox/cluster/requests/list_resources.rb @@ -33,11 +33,15 @@ def list_resources(resource_type = '') end def list_qemu_resources - list_resources('qemu') + list_vm_resources.select { |vm| vm['type'] == 'qemu' } end def list_lxc_resources - list_resources('lxc') + list_vm_resources.select { |vm| vm['type'] == 'lxc' } + end + + def list_vm_resources + list_resources('vm') end def list_storage_resources From 24b7f9a7489557a4f5496d0b24e28e8c52e79811 Mon Sep 17 00:00:00 2001 From: "Yvan E. Watchman" Date: Sat, 29 Oct 2022 01:43:53 +0200 Subject: [PATCH 08/10] fix attribute hashing and copyright --- lib/fog/proxmox/cluster/models/resource.rb | 5 ++++- lib/fog/proxmox/compute/models/storage.rb | 8 -------- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/lib/fog/proxmox/cluster/models/resource.rb b/lib/fog/proxmox/cluster/models/resource.rb index e81ea93..9769b84 100644 --- a/lib/fog/proxmox/cluster/models/resource.rb +++ b/lib/fog/proxmox/cluster/models/resource.rb @@ -18,6 +18,8 @@ # frozen_string_literal: true +require 'fog/proxmox/hash' + module Fog module Proxmox class Cluster @@ -33,6 +35,7 @@ class Resource < Fog::Model attribute :maxdisk # vm/lxc specific + attribute :vmid attribute :status attribute :uptime attribute :template @@ -50,7 +53,7 @@ def is_template? end def to_s - Fog::Proxmox::Hash.flatten(flatten) + Fog::Proxmox::Hash.flatten(attributes) end end end diff --git a/lib/fog/proxmox/compute/models/storage.rb b/lib/fog/proxmox/compute/models/storage.rb index b0e05e1..44adf6e 100644 --- a/lib/fog/proxmox/compute/models/storage.rb +++ b/lib/fog/proxmox/compute/models/storage.rb @@ -3,14 +3,6 @@ # This file is part of Fog::Proxmox. -# Fog::Proxmox is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# Copyright 2018 Tristan Robert - -# This file is part of Fog::Proxmox. - # Fog::Proxmox is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or From ea1d7bd4c2439b380173473bdf4366e7cd336014 Mon Sep 17 00:00:00 2001 From: "Yvan E. Watchman" Date: Sat, 29 Oct 2022 13:33:41 +0200 Subject: [PATCH 09/10] update version --- lib/fog/proxmox/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/fog/proxmox/version.rb b/lib/fog/proxmox/version.rb index 9e8f98c..187eb88 100644 --- a/lib/fog/proxmox/version.rb +++ b/lib/fog/proxmox/version.rb @@ -19,6 +19,6 @@ module Fog module Proxmox - VERSION = '0.14.0' + VERSION = '0.15.0' end end From 0316bda83170102b730ea062d86b231771039a01 Mon Sep 17 00:00:00 2001 From: "Yvan E. Watchman" Date: Tue, 2 Apr 2024 17:45:26 +0200 Subject: [PATCH 10/10] add nextid call --- lib/fog/proxmox/cluster.rb | 1 + .../proxmox/cluster/requests/get_nextid.rb | 46 +++++++++++++++++++ 2 files changed, 47 insertions(+) create mode 100644 lib/fog/proxmox/cluster/requests/get_nextid.rb diff --git a/lib/fog/proxmox/cluster.rb b/lib/fog/proxmox/cluster.rb index 87aab8d..2c2e51e 100644 --- a/lib/fog/proxmox/cluster.rb +++ b/lib/fog/proxmox/cluster.rb @@ -36,6 +36,7 @@ class Cluster < Fog::Service # Manage nodes cluster request :list_resources + request :get_nextid # Mock class class Mock diff --git a/lib/fog/proxmox/cluster/requests/get_nextid.rb b/lib/fog/proxmox/cluster/requests/get_nextid.rb new file mode 100644 index 0000000..6c81720 --- /dev/null +++ b/lib/fog/proxmox/cluster/requests/get_nextid.rb @@ -0,0 +1,46 @@ +# frozen_string_literal: true + +# Copyright 2018 Tristan Robert + +# This file is part of Fog::Proxmox. + +# Fog::Proxmox is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# Fog::Proxmox is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with Fog::Proxmox. If not, see . + +module Fog + module Proxmox + class Cluster + # class Real get_nextid request + class Real + def get_nextid(vmid = nil) + query = "vmid=#{vmid}" unless vmid.nil? + request( + expects: [200], + method: 'GET', + path: 'cluster/nextid', + query: query || '' + ) + end + end + + # class Mock get_nextid request + class Mock + def get_nextid(vmid = nil) + return "4002" unless vmid + + vmid.to_s + end + end + end + end +end