pve 0.1.2 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e2f41d6fba5690429b625a55d147bf468834c1e705d6e73fdcd879566037dd47
4
- data.tar.gz: 5237da733be939f52f26818f6c12a20d2389c5a26e8ba7343cbce62bcb280001
3
+ metadata.gz: a06ddcb47642c05e1741f36743dddc8549fe0a662d72246b8965d63474f437a2
4
+ data.tar.gz: 458054ab599bc236cbae0e708180778a38b4d9136d6278f4c3866047af0f4819
5
5
  SHA512:
6
- metadata.gz: adfe44900fc74f93932b12ffed27abced7d33e04c910fad519b406755d8d9f9de140347341da45a3a35d4e315f4c5e7b5286af2ec4fbdf6ec2f9116a94221224
7
- data.tar.gz: 3b55ec2a97b1973ae66d08e17cb50c70ec765305292748fe306bb99e3dd30bf33a46c5bc824570a8786e832c767f422e4da814ad14dd0497ab83ec707d46e0e9
6
+ metadata.gz: e967e72848d1ca823b8ebb85737a78018116e3ac28c7bc070d1d3a8936ad6c79e9e09a2ff11344f0ce1aa62fa54634602e3993f5081126bf8f72d2b7ac841a32
7
+ data.tar.gz: 673189e3d7318103b2dad96f653c072c1cef4a1a9a329aa920b17e8f43ecc8741763379b2a2a3f07ccaaf8af8c46eac2c9cef715225f6b6faa8353edaafa1a8a
data/lib/pve/cli.rb CHANGED
@@ -59,16 +59,18 @@ class PVE::Cli
59
59
  secs ||= 0.1
60
60
  spinners, spin, logn = "▖▘▝▗", 0, 0
61
61
  STDERR.puts task.upid
62
+ host = task.host&.name
62
63
  loop do
63
64
  s = task.status
64
65
  if s[:exitstatus]
65
- STDERR.printf "\r[%s] %s %s\e[J\n",
66
- task.host ? task.host.name : s[:id],
66
+ STDERR.printf "\r[%s] %s %s %s\e[J\n",
67
+ host || s[:id],
67
68
  case s[:exitstatus]
68
69
  when "OK" then "\e[32;1m✓\e[0m"
69
70
  else "\e[31;1m✗\e[0m"
70
71
  end,
71
- s[:status]
72
+ text && "#{text}:",
73
+ s[:status] == 'stopped' ? :finished : s[:status]
72
74
  return task
73
75
  end
74
76
  log = task.log start: logn
@@ -78,7 +80,10 @@ class PVE::Cli
78
80
  log.each {|l| puts l[:t] }
79
81
  logn = log.last[:n]
80
82
  end
81
- STDERR.printf "\r[%s] \e[33;1m%s\e[0m %s...\e[J", task.host ? task.host.name : s[:id], spinners[spin = (spin + 1) % 4], text || "Working"
83
+ STDERR.printf "\r[%s] \e[33;1m%s\e[0m %s...\e[J",
84
+ host || s[:id],
85
+ spinners[spin = (spin + 1) % 4],
86
+ text || "Working"
82
87
  sleep secs
83
88
  end
84
89
  end
@@ -112,12 +117,12 @@ class PVE::Cli
112
117
  end
113
118
 
114
119
  def create klass, template, timeout: nil, fire: nil, secs: nil, start: nil, **options
115
- options[:start] = true if fire and start
120
+ options[:start] = fire && start
116
121
  task = klass.create template, **options
117
122
  return if fire
118
123
  wait task, text: "Creating"
119
124
  host = task.host.refresh!
120
- start host, timeout: timeout, secs: secs
125
+ start host, timeout: timeout, secs: secs if start
121
126
  end
122
127
 
123
128
  def destroy ct, timeout: nil, fire: nil, secs: nil
@@ -151,7 +156,7 @@ class PVE::Cli
151
156
  def call *argv
152
157
  cli.call *argv
153
158
  rescue RestClient::ExceptionWithResponse
154
- STDERR.puts "#$! - #{$!.response} (#{$!.class})", $!.backtrace.map {|b|" #{b}"}
159
+ STDERR.puts "#$! - #{$!.response} (#{$!.class})" #, $!.backtrace.map {|b|" #{b}"}
155
160
  rescue UsageError, DenCli::UsageError
156
161
  STDERR.puts $!
157
162
  exit 1
data/lib/pve/cli/base.rb CHANGED
@@ -2,6 +2,8 @@ require 'pmap'
2
2
 
3
3
  class PVE::Cli
4
4
 
5
+ using IPAddress::ToSWithNetmaskForNetworks
6
+
5
7
  def cli_base
6
8
  cli.cmd :list, "List CT/VM-IDs", aliases: ['ls'], &lambda {|target=nil|
7
9
  connect
data/lib/pve/cli/ct.rb CHANGED
@@ -57,13 +57,19 @@ def cli_ct
57
57
  if %w[-h --help].include? template
58
58
  STDERR.puts "Usage: ct create TEMPLATE -h # Shows template-related options"
59
59
  STDERR.puts " ct create TEMPLATE [OPTIONS] # Creates a container"
60
+ STDERR.puts " ct create -l # Listing available templates"
60
61
  exit 1
62
+ elsif %w[-l --list].include? template
63
+ STDERR.puts PVE::CTTemplate.constants.reject {|c|:Base==c}.map {|c|c.to_s.titlecase.dasherize.downcase}
64
+ exit 0
61
65
  end
62
66
  ctopts = {}
63
67
  OptionParser.new do |opts|
68
+ ctt = PVE::CTTemplate.const_get template.classify
64
69
  opts.banner = <<EOU
65
70
  Usage: ct create #{template} [options]
66
71
 
72
+ #{ctt.help}
67
73
  Options: (*=Required)
68
74
  EOU
69
75
  opts.on '-h', '--help', " Help!" do
@@ -75,7 +81,6 @@ EOU
75
81
  opts.on( '-f', '--[no-]-fire', " Do not wait till running") {|v| ctopts[:start] = v }
76
82
  opts.on( '-t', '--timeout=TIMEOUT', " Wait for max TIMEOUT seconds (default: endless)") {|v| ctopts[:timeout] = v }
77
83
  opts.on( '-s', '--seconds=SECONDS', " Check every SECONDS for state (default: 0.2)") {|v| ctopts[:seconds] = v }
78
- ctt = PVE::CTTemplate.const_get template.classify
79
84
  ctt.requirements.each do |name, (type, req, desc, *args)|
80
85
  req = req ? "*" : " "
81
86
  case type
@@ -94,12 +99,19 @@ EOU
94
99
  create Proxmox::LXC, template, **ctopts
95
100
  })
96
101
 
97
- ct_cli.cmd( :config, '', &lambda {|name_or_id|
102
+ ct_cli.cmd( :config, 'Shows current config', &lambda {|name_or_id|
98
103
  connect
99
104
  ct = Proxmox::LXC.find! name_or_id
100
105
  STDOUT.puts ct.config.to_json
101
106
  })
102
107
 
108
+ ct_cli.cmd( :resize, 'Resize a disk', &lambda {|name_or_id, disk, size|
109
+ connect
110
+ ct = Proxmox::LXC.find! name_or_id
111
+ task = ct.resize disk, size
112
+ wait task, text: "Resizing #{ct.sid} #{disk} to #{size}"
113
+ })
114
+
103
115
  ct_cli.cmd( :destroy, '', min: 7, &lambda {|name_or_id, fire:, secs:, timeout:, i_really_want_to_destroy:|
104
116
  raise UsageError, "Name/ID is not what you want to destroy" unless name_or_id == i_really_want_to_destroy
105
117
  connect
data/lib/pve/helper.rb CHANGED
@@ -1,3 +1,17 @@
1
+ module IPAddress::ToSWithNetmaskForNetworks
2
+ refine IPAddress::IPv6 do
3
+ def to_s
4
+ 128 == prefix ? super() : to_string
5
+ end
6
+ end
7
+ refine IPAddress::IPv4 do
8
+ def to_s
9
+ 32 == prefix ? super() : to_string
10
+ end
11
+ end
12
+ end
13
+
14
+
1
15
  class Measured
2
16
  class <<self
3
17
  def bytes1 v
data/lib/pve/proxmox.rb CHANGED
@@ -331,6 +331,11 @@ module Proxmox
331
331
  r.delete :delete if r[:delete].empty?
332
332
  rest_put "#{@rest_prefix}/config", r
333
333
  end
334
+
335
+ def resize disk, size
336
+ upid = rest_put "#{@rest_prefix}/resize", disk: disk, size: size
337
+ Task.send :__new__, node: @node, host: self, upid: upid
338
+ end
334
339
  end
335
340
 
336
341
  class Qemu < Hosted
@@ -490,9 +495,10 @@ module Proxmox
490
495
  swap: tmplt.swap,
491
496
  unprivileged: tmplt.unprivileged,
492
497
  }.delete_if {|k,v| v.nil? }
493
- @temp = LXC.send :__new__, node: node, vmid: options[:vmid], name: name, hostname: options[:hostname]
498
+
499
+ temp = LXC.send :__new__, node: node, vmid: options[:vmid], name: name, hostname: options[:hostname]
494
500
  upid = rest_post( "/nodes/%s/lxc" % node.node, **options)
495
- Task.send :__new__, node: node, host: @temp, upid: upid
501
+ Task.send :__new__, node: node, host: temp, upid: upid
496
502
  end
497
503
  end
498
504
 
data/lib/pve/templates.rb CHANGED
@@ -27,14 +27,27 @@ module PVE::CTTemplate
27
27
  File.read( options[:'ssh-public-keys-file'] || '/root/.ssh/authorized_keys')
28
28
  end
29
29
 
30
+ def _ipv4 ip, gw
31
+ return [ip, nil] if %w[dhcp].include? ip
32
+ ip = IPAddress::IPv4.new ip
33
+ [ip.to_string, gw || ip.hosts.last.to_s]
34
+ end
35
+
36
+ def _ipv6 ip, gw
37
+ return [ip, nil] if %w[dhcp auto].include? ip
38
+ ip = IPAddress::IPv6.new ip
39
+ [ip.to_string, gw || ip.hosts.last.to_s]
40
+ end
41
+
30
42
  def net0()
31
43
  if options.ipv4 || options.ipv6
32
- ipv4 = IPAddress::IPv4.new options.ipv4
44
+ ipv4, gw4 = _ipv4( options.ipv4, options.gateway4)
45
+ ipv6, gw6 = _ipv6( options.ipv6, options.gateway6)
33
46
  {
34
47
  name: 'eth0',
35
48
  bridge: 'vmbr1',
36
- ip: ipv4.to_string,
37
- gw: options.gateway || ipv4.hosts.last.to_s
49
+ ip: ipv4, ip6: ipv6,
50
+ gw: gw4, gw6: gw6,
38
51
  }
39
52
  end
40
53
  end
@@ -44,6 +57,10 @@ module PVE::CTTemplate
44
57
  end
45
58
 
46
59
  class Default < Base
60
+ def self.help
61
+ nil
62
+ end
63
+
47
64
  def self.requirements
48
65
  {
49
66
  node: [:string, false, "Create CT on this node."],
@@ -62,7 +79,7 @@ module PVE::CTTemplate
62
79
  :'ssh-public-keys-file' => [:string, false, "Read SSH-Public-Keys from file."],
63
80
  ipv4: [:string, false, "IPv4-Address with net-size."],
64
81
  gateway4: [:string, false, "IPv4-Address of gateway."],
65
- ipv6: [:string, false, "IPv6-Address with net-size."],
82
+ ipv6: [:string, false, "IPv6-Address with net-size or auto."],
66
83
  gateway6: [:string, false, "IPv6-Address of gateway."],
67
84
  storage: [:string, false, "Device will be create on this Storage (default: local"],
68
85
  }
@@ -70,12 +87,24 @@ module PVE::CTTemplate
70
87
  end
71
88
 
72
89
  class Datacenter < Base
90
+ def self.help
91
+ <<-EOF.gsub /^ {6}/, ''
92
+ Datacenter provides an interface for special network-settings.
93
+ Networks in Datacenters are often based on this behaviour:
94
+ A Network has an ID like 99.
95
+ This defines the VLANs: 2099 for Layer2/3099 for Layer3.
96
+ The IPv4-Range would be 10.99.0.0/16, but container will be put static in 10.99.255.0/24.
97
+ IPv6 uses RADV, so we do not need to know the IPv6-Range => auto.
98
+ VMID can be generated by Network-ID, too: smallest unused VMID in 100*ID.
99
+ EOF
100
+ end
101
+
73
102
  def self.requirements
74
103
  {
75
104
  node: [:string, false, "Create CT on this node."],
76
105
  name: [:string, true, "Set (uniq) name"],
77
106
  arch: [:enum, false, "Architecture", %w[amd64 i386 arm64 armhf]],
78
- vmid: [:numeric, true, "VM-ID. Proxmox internal number (100...)"],
107
+ vmid: [:numeric, false, "VM-ID. Proxmox internal number (100...)"],
79
108
  ostype: [:string, true, "OS-Type (OS or distribution)"],
80
109
  cmode: [:enum, false, "Console-mode", %w[shell console tty]],
81
110
  cores: [:numeric, false, "Count of cores"],
@@ -87,11 +116,12 @@ module PVE::CTTemplate
87
116
  :'ssh-public-keys' => [:string, false, "SSH-Public-Keys, which should be added to root-user in CT."],
88
117
  :'ssh-public-keys-file' => [:string, false, "Read SSH-Public-Keys from file."],
89
118
  :'network-id' => [:numeric, true, "Put Container to this VLAN and use a random IPv4-Address for this CT."],
90
- ipv4: [:string, false, "IPv4-Address with net-size."],
119
+ ipv4: [:string, false, "IPv4-Address with net-size or dhcp."],
91
120
  gateway4: [:string, false, "IPv4-Address of gateway."],
92
- ipv6: [:string, false, "IPv6-Address with net-size."],
121
+ ipv6: [:string, false, "IPv6-Address with net-size or auto|dhcp."],
93
122
  gateway6: [:string, false, "IPv6-Address of gateway."],
94
123
  storage: [:string, false, "Device will be create on this Storage (default: root)"],
124
+ ostemplate: [:string, false, "OS-Template eg. local:vztmpl/superlinux-1.2-amd64.tar.xz"],
95
125
  }
96
126
  end
97
127
 
@@ -111,15 +141,27 @@ module PVE::CTTemplate
111
141
  end
112
142
 
113
143
  def net0
144
+ ipv4, gw4 =
145
+ if options.ipv4
146
+ _ipv4( options.ipv4, options.gateway4)
147
+ else
148
+ self.ipv4_gw
149
+ end
150
+ ipv6, gw6 =
151
+ if options.ipv6
152
+ _ipv6( options.ipv6, options.gateway6)
153
+ else
154
+ ['auto', nil]
155
+ end
114
156
  {
115
157
  name: 'eth0',
116
158
  bridge: 'vmbr1',
117
159
  tag: 2000+network_id,
118
160
  mtu: 9166,
119
161
  firewall: 1,
120
- ip: ipv4.to_string,
121
- gw: ipv4.hosts.last.to_s,
122
- }
162
+ ip: ipv4, gw: gw4,
163
+ ip6: ipv6, gw6: gw6,
164
+ }.delete_if {|k,v| v.nil? }
123
165
  end
124
166
 
125
167
  def vmid
@@ -130,14 +172,13 @@ module PVE::CTTemplate
130
172
  IPAddress::IPv4.new "10.#{network_id}.255.0/24"
131
173
  end
132
174
 
133
- def ipv4
134
- return options.ipv4 if options.ipv4
135
- return @ipv4 if @ipv4
175
+ def ipv4_gw
176
+ return @ipv4_gw if @ipv4_gw
136
177
  ipv4s = network.hosts
137
178
  @virts.each do |v|
138
179
  v.config[:network].each {|n| ipv4s.delete n[:ip] if n[:ip] }
139
180
  end
140
- @ipv4 = ipv4s.first
181
+ @ipv4_gw = [ipv4s.first.to_string, network.last.to_s]
141
182
  end
142
183
 
143
184
  def ostemplate
data/lib/pve/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module PVE
2
- VERSION = '0.1.2'
2
+ VERSION = '0.1.3'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pve
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Denis Knauf
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-04-21 00:00:00.000000000 Z
11
+ date: 2021-06-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: dencli
@@ -117,7 +117,6 @@ files:
117
117
  - lib/pve/cli/task.rb
118
118
  - lib/pve/helper.rb
119
119
  - lib/pve/proxmox.rb
120
- - lib/pve/qm.rb
121
120
  - lib/pve/templates.rb
122
121
  - lib/pve/version.rb
123
122
  - pve.gemspec
data/lib/pve/qm.rb DELETED
@@ -1,32 +0,0 @@
1
- class PVE::Cli
2
- def cli_qm
3
- cli.sub :qm, "Virtual Machines", aliases: %w[v vm qemu], &lambda {|qm|
4
- qm.cmd :list, "List VM-IDs", aliases: ['ls'], &lambda {|node=nil|
5
- connect
6
- nodes = Proxmox::Node.all
7
- nodes = nodes.select {|n| node == n.name } if node
8
- nodes.flat_map do |n|
9
- n.qemu.map {|c| c.vmid.to_i }
10
- end.sort.each {|c| puts c }
11
- }
12
-
13
- qm.cmd :status, "List VMs with status", aliases: [nil], &lambda {|node=nil|
14
- connect
15
- to = TablizedOutput.new %w[Status HA ID Name Host Uptime CPU Mem/MiB Disk/MiB]
16
- nodes = Proxmox::Node.all
17
- nodes = nodes.select {|n| node == n.name } if node
18
- nodes.each do |n|
19
- n.qemu.each &to.method( :virt)
20
- end
21
- to.print order: [3]
22
- }
23
-
24
- qm.cmd :exec, "Executes Command in VM via qemu-guest-agent", min: 4, &lambda {|name_or_id, *command|
25
- connect
26
- STDERR.puts "! #{$?.exitstatus}" unless Proxmox::Qemu.find!( name_or_id).exec *command
27
- }
28
-
29
- qm.cmd 'help', '', aliases: ['-h', '--help'], &lambda {|*args| help qm, *args }
30
- }
31
- end
32
- end