require 'ostruct' module PVE::CTTemplate class Base attr_reader :options def initialize **opts @options = OpenStruct.new opts @virts = Proxmox::LXC.all + Proxmox::Qemu.all end def name() options.name end def node() options.node end def arch() options.arch || 'amd64' end def vmid() options.vmid end def ostype() options.ostype end def cmode() options.cmode || 'shell' end def cores() options.cores || 1 end def description() options.description || '' end def hostname() options.hostname || name end def memory() options.memory || 1024 end def swap() options.swap || 0 end def unprivileged() options.unprivileged() || 1 end def ssh_public_keys options[:'ssh-public-keys'] || File.read( options[:'ssh-public-keys-file'] || '/root/.ssh/authorized_keys') end def net0() if options.ipv4 || options.ipv6 ipv4 = IPAddress::IPv4.new options.ipv4 { name: 'eth0', bridge: 'vmbr1', ip: ipv4.to_string, gw: options.gateway || ipv4.hosts.last.to_s } end end def net1() nil end def net2() nil end def net3() nil end end class Default < Base def self.requirements { node: [:string, false, "Create CT on this node."], name: [:string, true, "Set (uniq) name"], arch: [:enum, false, "Architecture", %w[amd64 i386 arm64 armhf]], vmid: [:numeric, true, "VM-ID. Proxmox internal number (100...)"], ostype: [:string, true, "OS-Type (OS or distribution)"], cmode: [:enum, false, "Console-mode", %w[shell console tty]], cores: [:numeric, false, "Count of cores"], description: [:string, false, "Description. Eg. What should this CT do?"], hostname: [:string, false, "Hostname"], memory: [:numeric, false, "How much memory CT could use?"], swap: [:numeric, false, "How much CT can swap?"], unprivileged: [:boolean, false, "Unprivileged are restricted to own UID/GID-space."], :'ssh-public-keys' => [:string, false, "SSH-Public-Keys, which should be added to root-user in CT."], :'ssh-public-keys-file' => [:string, false, "Read SSH-Public-Keys from file."], ipv4: [:string, false, "IPv4-Address with net-size."], gateway4: [:string, false, "IPv4-Address of gateway."], ipv6: [:string, false, "IPv6-Address with net-size."], gateway6: [:string, false, "IPv6-Address of gateway."], storage: [:string, false, "Device will be create on this Storage (default: local"], } end end class Datacenter < Base def self.requirements { node: [:string, false, "Create CT on this node."], name: [:string, true, "Set (uniq) name"], arch: [:enum, false, "Architecture", %w[amd64 i386 arm64 armhf]], vmid: [:numeric, true, "VM-ID. Proxmox internal number (100...)"], ostype: [:string, true, "OS-Type (OS or distribution)"], cmode: [:enum, false, "Console-mode", %w[shell console tty]], cores: [:numeric, false, "Count of cores"], description: [:string, false, "Description. Eg. What should this CT do?"], hostname: [:string, false, "Hostname"], memory: [:numeric, false, "How much memory CT could use?"], swap: [:numeric, false, "How much CT can swap?"], unprivileged: [:boolean, false, "Unprivileged are restricted to own UID/GID-space."], :'ssh-public-keys' => [:string, false, "SSH-Public-Keys, which should be added to root-user in CT."], :'ssh-public-keys-file' => [:string, false, "Read SSH-Public-Keys from file."], :'network-id' => [:numeric, true, "Put Container to this VLAN and use a random IPv4-Address for this CT."], ipv4: [:string, false, "IPv4-Address with net-size."], gateway4: [:string, false, "IPv4-Address of gateway."], ipv6: [:string, false, "IPv6-Address with net-size."], gateway6: [:string, false, "IPv6-Address of gateway."], storage: [:string, false, "Device will be create on this Storage (default: root)"], } end def node() options.node || 'svc1' end def ostype() options.ostype || 'debian' end def memory() options.memory || 2048 end def storage() options.storage || 'root' end def network_id return @network_id if @network_id expect = 0..12 nid = options[:'network-id'] unless nid == nid.to_i.to_s && expect.include?( nid.to_i) raise ArgumentError, "Network ID must be #{expect.inspect}. Given: #{nid.inspect}" end @network_id = nid.to_i end def net0 { name: 'eth0', bridge: 'vmbr1', tag: 2000+network_id, mtu: 9166, firewall: 1, ip: ipv4.to_string, gw: ipv4.hosts.last.to_s, } end def vmid super || ((0...100).map {|i| "#{100*network_id+i}" } - @virts.map( &:vmid)).first end def network IPAddress::IPv4.new "10.#{network_id}.255.0/24" end def ipv4 return options.ipv4 if options.ipv4 return @ipv4 if @ipv4 ipv4s = network.hosts @virts.each do |v| v.config[:network].each {|n| ipv4s.delete n[:ip] if n[:ip] } end @ipv4 = ipv4s.first end def ostemplate @ostemplate ||= options.ostemplate || case ostype when 'debian' 'local:vztmpl/debian-10-standard_10.5-1_amd64.tar.gz' else raise ArgumentError, "OS-Template for ostype #{ostype} not found or ostemplate not provided." end end end end