kcli 99.0.202512170917__py3-none-any.whl → 99.0.202512181208__py3-none-any.whl

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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: kcli
3
- Version: 99.0.202512170917
3
+ Version: 99.0.202512181208
4
4
  Summary: Provisioner/Manager for Libvirt/Vsphere/Aws/Gcp/Hcloud/Kubevirt/Ovirt/Openstack/IBM Cloud and containers
5
5
  Home-page: http://github.com/karmab/kcli
6
6
  Author: Karim Boumedhel
@@ -1,4 +1,4 @@
1
- kcli-99.0.202512170917.dist-info/licenses/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
1
+ kcli-99.0.202512181208.dist-info/licenses/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
2
2
  kvirt/__init__.py,sha256=eoZ6GfifbqhMLNzjlqRDVil-yyBkOmVN9ujSgJWNBlY,15
3
3
  kvirt/baseconfig.py,sha256=QG_AHI1_HAgHwIdZSm1BXkpn9pW35kTMUkFOb7UE_wY,83513
4
4
  kvirt/bottle.py,sha256=K24aCQYSylDpkxmLYGygSpAJ4MlMqMk85AMpbCWA43c,175729
@@ -390,7 +390,7 @@ kvirt/providers/fake/__init__.py,sha256=TYJe0iwO0Y7QrksKx4E63-Lxgc6WYNcjAHAq_Lwh
390
390
  kvirt/providers/gcp/__init__.py,sha256=_8qln7pO0_3MSmZ1P4X-THlTbbwFuR_a4wVCCeL0WSI,102731
391
391
  kvirt/providers/gcp/gcp-hack.service,sha256=gG35O6KTLlGqIMwrSBqb_id-h3SWm_us_yLkLfQelOw,175
392
392
  kvirt/providers/gcp/gcp-hack.sh,sha256=kH051zNphRtJe-eVi8CX28_mxP6ID1f3pSTDzvE9XzE,220
393
- kvirt/providers/hcloud/__init__.py,sha256=JJqL0aGHdDMQAqC45W3n1Gv53OGffNgZEql2YgalzsQ,22919
393
+ kvirt/providers/hcloud/__init__.py,sha256=5MxO2zb63byBItwWalEUu2PYdewRyaKz_E4nJCLgUxg,23714
394
394
  kvirt/providers/ibm/__init__.py,sha256=OTGDRCwvvOZCTNGD_QXx52-9_tsBzA7Y079RAo9XL9M,66129
395
395
  kvirt/providers/kubevirt/__init__.py,sha256=NSnx2RwtRQSrrhpqLK8Fb_ye9YgJdMbkO-_wBFd7DZg,94602
396
396
  kvirt/providers/kvm/__init__.py,sha256=j6ZtyemdHJWvvgKeL3ZtG1IW5k_0hlknqxeepaz3rNg,195464
@@ -403,7 +403,7 @@ kvirt/providers/vsphere/helpers.py,sha256=eJnwVGdWArTurH5ckzScvLThNJaMWeakdxBbDT
403
403
  kvirt/providers/vsphere/tagging.py,sha256=7RqFIUETSzHAjS0F_8-j145-_8lca7aDUsCxs4DhQVQ,4893
404
404
  kvirt/providers/web/__init__.py,sha256=_9fv0_x5VomFrMZqTsMLHkIRkvujmFgTxggtRctvMD0,22053
405
405
  kvirt/version/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
406
- kvirt/version/git,sha256=EpE3A7JywrxF2DIRwNFc2c5jNZ_QvS_2LtTwoOwabLM,19
406
+ kvirt/version/git,sha256=tbEiyHYz_uJA2vq6-d0ceABuPqgz2r6VuX5P-F-g9eY,19
407
407
  kvirt/web/__init__.py,sha256=QW-FVaQGYogXwgV2g4f0J9s0QqUI6qIyX1ruRaiI8Yk,46658
408
408
  kvirt/web/main.py,sha256=DIb6tW3ce7wCc83kD9HBCG4ALJuLItp9uaP6tzdsm_Y,261
409
409
  kvirt/web/static/css/bootstrap-notify.css,sha256=ibUTW-jDj-F8d1T1KZ4DOujRmVTFfvMKL9y14QgEaPQ,408
@@ -645,8 +645,8 @@ kvirt/web/templates/vmprofiles.html,sha256=T65Cv7povhBtD2dyuWkWJE6byaA9EYtLSk5gt
645
645
  kvirt/web/templates/vmprofilestable.html,sha256=-8viNOqSvN_yzimENxq7Q0187zbflOn8p8zpgx0Vyek,1420
646
646
  kvirt/web/templates/vms.html,sha256=k2ptKeiLFdpzgfbk6xi__sduu0UALYXXrnrmDEmAfaQ,470
647
647
  kvirt/web/templates/vmstable.html,sha256=ikuYkIm_ocvGIBXFyJt1-tBjwQWCyqkgC08leoXgR54,4894
648
- kcli-99.0.202512170917.dist-info/METADATA,sha256=ZQ_5Z3pcGlXPQ18eGPt53Oojmu-JfN4WDvmQVy3ANQE,4645
649
- kcli-99.0.202512170917.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
650
- kcli-99.0.202512170917.dist-info/entry_points.txt,sha256=e5EB5e2acrwl3_sYA0GrjE42UMcMfiijMJqXb6TZRmQ,245
651
- kcli-99.0.202512170917.dist-info/top_level.txt,sha256=FwVTxtMIWdr8QBk5mTfd0f_GheFlRR_vn4zl6p5N57s,6
652
- kcli-99.0.202512170917.dist-info/RECORD,,
648
+ kcli-99.0.202512181208.dist-info/METADATA,sha256=J0A8xE1CdM1gmrFh0ckifzDwHahUqdChBD3vc51yUA8,4645
649
+ kcli-99.0.202512181208.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
650
+ kcli-99.0.202512181208.dist-info/entry_points.txt,sha256=e5EB5e2acrwl3_sYA0GrjE42UMcMfiijMJqXb6TZRmQ,245
651
+ kcli-99.0.202512181208.dist-info/top_level.txt,sha256=FwVTxtMIWdr8QBk5mTfd0f_GheFlRR_vn4zl6p5N57s,6
652
+ kcli-99.0.202512181208.dist-info/RECORD,,
@@ -9,7 +9,7 @@ from hcloud.load_balancers import LoadBalancerAlgorithm, LoadBalancerService, Lo
9
9
  from hcloud.load_balancers import LoadBalancerTarget
10
10
  import json
11
11
  from kvirt import common
12
- from kvirt.common import error, pprint, warning, get_ssh_pub_key
12
+ from kvirt.common import error, pprint, warning, get_ssh_pub_key, pprint
13
13
  from kvirt.defaults import METADATA_FIELDS
14
14
  import os
15
15
 
@@ -31,10 +31,6 @@ class Khcloud():
31
31
  sharedfolders=[], cmdline=None, placement=[], autostart=False, cpuhotplug=False, memoryhotplug=False,
32
32
  numamode=None, numa=[], pcidevices=[], tpm=False, rng=False, metadata={}, securitygroups=[],
33
33
  vmuser=None, guestagent=True):
34
- location = self.location
35
- if overrides.get("location", False):
36
- location = self.conn.locations.get_by_name(overrides.get("location"))
37
-
38
34
  if self.exists(name):
39
35
  return {'result': 'failure', 'reason': f"VM {name} already exists"}
40
36
 
@@ -42,22 +38,6 @@ class Khcloud():
42
38
  if len(disks) > 0:
43
39
  disks = disks[1:]
44
40
 
45
- volumeresponses = []
46
- for index, disk in enumerate(disks):
47
- if isinstance(disk, int):
48
- disksize = disk
49
- elif isinstance(disk, str) and disk.isdigit():
50
- disksize = int(disk)
51
- elif isinstance(disk, dict):
52
- disksize = disk.get('size', '10')
53
-
54
- diskname = f"{name}-disk{index}"
55
- volumeresponse = self.conn.volumes.get_by_name(diskname)
56
- if volumeresponse is None:
57
- volumeresponse = self.conn.volumes.create(disksize, diskname, location=location,
58
- labels={"kcli-managed": "volume"})
59
- volumeresponses.append(volumeresponse)
60
-
61
41
  if not keys:
62
42
  publickeyfile = get_ssh_pub_key()
63
43
  if publickeyfile is not None:
@@ -118,40 +98,67 @@ class Khcloud():
118
98
 
119
99
  placement_group = response.placement_group
120
100
 
101
+ # If "location_options" is specified use it, otherwise "location", otherwise use self.location
102
+ location_options = overrides.get("location_options", [overrides.get("location", self.location.name)])
121
103
  flavor_options = overrides.get("flavor_options", [flavor] if flavor is not None else [])
122
104
 
123
- for idx, flavor_option in enumerate(flavor_options):
124
- servertype = self.conn.server_types.get_by_name(flavor_option)
125
- if "snapshot_id" in overrides:
126
- hetzner_image = self.conn.images.get_by_id(overrides.get("snapshot_id"))
127
- else:
128
- hetzner_image = self.conn.images.get_by_name_and_architecture(image, servertype.architecture)
129
-
130
- try:
131
- created_vm = self.conn.servers.create(
132
- name=name,
133
- server_type=servertype,
134
- image=hetzner_image,
135
- start_after_create=False,
136
- user_data=userdata,
137
- volumes=[],
138
- ssh_keys=hetzner_ssh_keys,
139
- location=location,
140
- public_net=ServerCreatePublicNetwork(enable_ipv4=False, enable_ipv6=False),
141
- labels=labels,
142
- placement_group=placement_group
143
- )
144
-
145
- created_vm.action.wait_until_finished(300)
146
- break
147
- except APIException as e:
148
- if e.code == "resource_unavailable":
149
- msg = f"Could not get server of type '{flavor_option}' in location '{location.name}'"
150
- if len(flavor_options) > (idx + 1):
151
- warning(f"{msg}' trying the next configured flavor option.")
105
+ volumeresponses = []
106
+ for location_option in location_options:
107
+ location = self.conn.locations.get_by_name(location_option)
108
+ created_vm = None
109
+ for idx, flavor_option in enumerate(flavor_options):
110
+ if self.debug:
111
+ pprint(f"Trying to create VM {name} in location {location.name} with flavor {flavor_option}")
112
+ servertype = self.conn.server_types.get_by_name(flavor_option)
113
+ if "snapshot_id" in overrides:
114
+ hetzner_image = self.conn.images.get_by_id(overrides.get("snapshot_id"))
115
+ else:
116
+ hetzner_image = self.conn.images.get_by_name_and_architecture(image, servertype.architecture)
117
+
118
+ try:
119
+ created_vm = self.conn.servers.create(
120
+ name=name,
121
+ server_type=servertype,
122
+ image=hetzner_image,
123
+ start_after_create=False,
124
+ user_data=userdata,
125
+ volumes=[],
126
+ ssh_keys=hetzner_ssh_keys,
127
+ location=location,
128
+ public_net=ServerCreatePublicNetwork(enable_ipv4=False, enable_ipv6=False),
129
+ labels=labels,
130
+ placement_group=placement_group
131
+ )
132
+
133
+ for index, disk in enumerate(disks):
134
+ if isinstance(disk, int):
135
+ disksize = disk
136
+ elif isinstance(disk, str) and disk.isdigit():
137
+ disksize = int(disk)
138
+ elif isinstance(disk, dict):
139
+ disksize = disk.get('size', '10')
140
+
141
+ diskname = f"{name}-disk{index}"
142
+ volumeresponse = self.conn.volumes.get_by_name(diskname)
143
+ if volumeresponse is None:
144
+ volumeresponse = self.conn.volumes.create(disksize, diskname, location=location,
145
+ labels={"kcli-managed": "volume"})
146
+ volumeresponses.append(volumeresponse)
147
+
148
+ created_vm.action.wait_until_finished(300)
149
+ break
150
+ except APIException as e:
151
+ if e.code == "resource_unavailable":
152
+ msg = f"Could not get server of type '{flavor_option}' in location '{location.name}'"
153
+ if len(flavor_options) > (idx + 1):
154
+ warning(f"{msg}, trying the next configured flavor option.")
155
+ else:
156
+ warning(msg)
157
+ error("No more flavors available to try. Define more flavors in 'flavor_options'.")
152
158
  else:
153
- warning(msg)
154
- error("No more flavors available to try. Define more flavors in 'flavor_options'.")
159
+ return {'result': 'failure', 'reason': json.dumps(e)}
160
+ if created_vm is not None:
161
+ break
155
162
 
156
163
  created_vm = created_vm.server
157
164
 
kvirt/version/git CHANGED
@@ -1 +1 @@
1
- c6042e7 2025/12/17
1
+ 2269979 2025/12/18