zbuilder 0.2.2__tar.gz → 0.2.4__tar.gz

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.
Files changed (24) hide show
  1. {zbuilder-0.2.2 → zbuilder-0.2.4}/PKG-INFO +6 -19
  2. {zbuilder-0.2.2 → zbuilder-0.2.4}/README.md +4 -12
  3. {zbuilder-0.2.2 → zbuilder-0.2.4}/pyproject.toml +5 -12
  4. {zbuilder-0.2.2 → zbuilder-0.2.4}/pyproject.toml.orig +5 -17
  5. {zbuilder-0.2.2 → zbuilder-0.2.4}/src/zbuilder/base.py +1 -1
  6. {zbuilder-0.2.2 → zbuilder-0.2.4}/src/zbuilder/cfg.py +2 -4
  7. {zbuilder-0.2.2 → zbuilder-0.2.4}/src/zbuilder/cli.py +31 -35
  8. {zbuilder-0.2.2 → zbuilder-0.2.4}/src/zbuilder/dns/__init__.py +11 -14
  9. {zbuilder-0.2.2 → zbuilder-0.2.4}/src/zbuilder/dns/aws.py +11 -10
  10. {zbuilder-0.2.2 → zbuilder-0.2.4}/src/zbuilder/dns/bind.py +6 -6
  11. {zbuilder-0.2.2 → zbuilder-0.2.4}/src/zbuilder/dns/powerdns.py +10 -10
  12. {zbuilder-0.2.2 → zbuilder-0.2.4}/src/zbuilder/helpers.py +31 -31
  13. {zbuilder-0.2.2 → zbuilder-0.2.4}/src/zbuilder/ipam/__init__.py +5 -5
  14. {zbuilder-0.2.2 → zbuilder-0.2.4}/src/zbuilder/ipam/phpipam.py +15 -16
  15. {zbuilder-0.2.2 → zbuilder-0.2.4}/src/zbuilder/options.py +1 -1
  16. {zbuilder-0.2.2 → zbuilder-0.2.4}/src/zbuilder/vm/aws.py +12 -9
  17. {zbuilder-0.2.2 → zbuilder-0.2.4}/src/zbuilder/vm/kvm.py +46 -47
  18. {zbuilder-0.2.2 → zbuilder-0.2.4}/src/zbuilder/vm/proxmox.py +34 -33
  19. zbuilder-0.2.2/src/zbuilder/dns/gcp.py +0 -90
  20. zbuilder-0.2.2/src/zbuilder/vm/gcp.py +0 -305
  21. {zbuilder-0.2.2 → zbuilder-0.2.4}/LICENSE +0 -0
  22. {zbuilder-0.2.2 → zbuilder-0.2.4}/src/zbuilder/__init__.py +0 -0
  23. {zbuilder-0.2.2 → zbuilder-0.2.4}/src/zbuilder/plugins.py +2 -2
  24. {zbuilder-0.2.2 → zbuilder-0.2.4}/src/zbuilder/vm/__init__.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: zbuilder
3
- Version: 0.2.2
3
+ Version: 0.2.4
4
4
  Summary: Create VMs
5
5
  Author: Nikos Chasiotis
6
6
  Author-email: Nikos Chasiotis <hasiotis@gmail.com>
@@ -29,16 +29,11 @@ Requires-Dist: massedit>=0.71.0
29
29
  Requires-Dist: ruamel-yaml>=0.19.1
30
30
  Requires-Dist: boto3>=1.43.73
31
31
  Requires-Dist: tabulate>=0.10.0
32
- Requires-Dist: libvirt-python>=11,<12
32
+ Requires-Dist: libvirt-python>=12,<13
33
33
  Requires-Dist: pycdlib>=1.14,<2
34
- Requires-Dist: google-auth-oauthlib>=0.4,<1.5 ; extra == 'gcp'
35
- Requires-Dist: oauthlib>=3.2.1,<4 ; extra == 'gcp'
36
- Requires-Dist: google-api-python-client>=2.198.0,<3 ; extra == 'gcp'
37
- Requires-Dist: google-cloud-dns>=0.37.0,<0.38 ; extra == 'gcp'
38
34
  Requires-Dist: proxmoxer>=1.1,<3 ; extra == 'proxmox'
39
35
  Requires-Python: >=3.12, <4
40
36
  Project-URL: Repository, https://github.com/hasiotis/zbuilder
41
- Provides-Extra: gcp
42
37
  Provides-Extra: proxmox
43
38
  Description-Content-Type: text/markdown
44
39
 
@@ -47,7 +42,6 @@ Description-Content-Type: text/markdown
47
42
  [![PyPi version](https://badge.fury.io/py/zbuilder.svg)](https://pypi.org/project/zbuilder/)
48
43
  [![PyPi downloads](https://img.shields.io/pypi/dm/zbuilder.svg)](https://pypistats.org/packages/zbuilder)
49
44
  [![Build status](https://github.com/hasiotis/zbuilder/workflows/master/badge.svg)](https://github.com/hasiotis/zbuilder/actions?query=workflow%3A%22master%22)
50
- [![Documentation Status](https://readthedocs.org/projects/zbuilder/badge/?version=stable)](https://zbuilder.readthedocs.io/en/stable/?badge=stable)
51
45
  [![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://github.com/hasiotis/zbuilder/blob/master/LICENSE)
52
46
 
53
47
  ZBuilder is a tool to help you build VMs ready to be transferred to ansible.
@@ -73,11 +67,6 @@ or
73
67
  pip3 install --user --upgrade zbuilder
74
68
  ```
75
69
 
76
- The `gcp` provider needs the google client libraries, which ship as an extra:
77
- ```
78
- pipx install --force 'zbuilder[gcp]'
79
- ```
80
-
81
70
  The `proxmox` provider needs `proxmoxer`, which ships as an extra:
82
71
  ```
83
72
  pipx install --force 'zbuilder[proxmox]'
@@ -87,12 +76,11 @@ pipx install --force 'zbuilder[proxmox]'
87
76
 
88
77
  | Family | Providers |
89
78
  |---|---|
90
- | VM | `aws`, `gcp`, `kvm`, `proxmox` |
91
- | DNS | `aws`, `bind`, `gcp`, `powerdns` |
79
+ | VM | `aws`, `kvm`, `proxmox` |
80
+ | DNS | `aws`, `bind`, `powerdns` |
92
81
  | IPAM | `phpipam` |
93
82
 
94
- See the [documentation](https://zbuilder.readthedocs.io/en/stable/) for the
95
- settings each one accepts, or run `zbuilder providers`.
83
+ Run `zbuilder providers` to see the settings each one accepts.
96
84
 
97
85
  ## Development
98
86
  During development you can:
@@ -106,6 +94,5 @@ prek run --all-files # lint and format
106
94
 
107
95
  ## Links
108
96
 
109
- [Documentation](https://zbuilder.readthedocs.io/en/stable/?badge=stable)
110
- | [Releases](https://pypi.org/project/zbuilder/)
97
+ [Releases](https://pypi.org/project/zbuilder/)
111
98
  | [Code](https://github.com/hasiotis/zbuilder)
@@ -3,7 +3,6 @@
3
3
  [![PyPi version](https://badge.fury.io/py/zbuilder.svg)](https://pypi.org/project/zbuilder/)
4
4
  [![PyPi downloads](https://img.shields.io/pypi/dm/zbuilder.svg)](https://pypistats.org/packages/zbuilder)
5
5
  [![Build status](https://github.com/hasiotis/zbuilder/workflows/master/badge.svg)](https://github.com/hasiotis/zbuilder/actions?query=workflow%3A%22master%22)
6
- [![Documentation Status](https://readthedocs.org/projects/zbuilder/badge/?version=stable)](https://zbuilder.readthedocs.io/en/stable/?badge=stable)
7
6
  [![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://github.com/hasiotis/zbuilder/blob/master/LICENSE)
8
7
 
9
8
  ZBuilder is a tool to help you build VMs ready to be transferred to ansible.
@@ -29,11 +28,6 @@ or
29
28
  pip3 install --user --upgrade zbuilder
30
29
  ```
31
30
 
32
- The `gcp` provider needs the google client libraries, which ship as an extra:
33
- ```
34
- pipx install --force 'zbuilder[gcp]'
35
- ```
36
-
37
31
  The `proxmox` provider needs `proxmoxer`, which ships as an extra:
38
32
  ```
39
33
  pipx install --force 'zbuilder[proxmox]'
@@ -43,12 +37,11 @@ pipx install --force 'zbuilder[proxmox]'
43
37
 
44
38
  | Family | Providers |
45
39
  |---|---|
46
- | VM | `aws`, `gcp`, `kvm`, `proxmox` |
47
- | DNS | `aws`, `bind`, `gcp`, `powerdns` |
40
+ | VM | `aws`, `kvm`, `proxmox` |
41
+ | DNS | `aws`, `bind`, `powerdns` |
48
42
  | IPAM | `phpipam` |
49
43
 
50
- See the [documentation](https://zbuilder.readthedocs.io/en/stable/) for the
51
- settings each one accepts, or run `zbuilder providers`.
44
+ Run `zbuilder providers` to see the settings each one accepts.
52
45
 
53
46
  ## Development
54
47
  During development you can:
@@ -62,6 +55,5 @@ prek run --all-files # lint and format
62
55
 
63
56
  ## Links
64
57
 
65
- [Documentation](https://zbuilder.readthedocs.io/en/stable/?badge=stable)
66
- | [Releases](https://pypi.org/project/zbuilder/)
58
+ [Releases](https://pypi.org/project/zbuilder/)
67
59
  | [Code](https://github.com/hasiotis/zbuilder)
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "zbuilder"
3
- version = "0.2.2"
3
+ version = "0.2.4"
4
4
  description = "Create VMs"
5
5
  license = "GPL-3.0-or-later"
6
6
  license-files = ["LICENSE"]
@@ -32,7 +32,7 @@ dependencies = [
32
32
  "ruamel-yaml>=0.19.1",
33
33
  "boto3>=1.43.73",
34
34
  "tabulate>=0.10.0",
35
- "libvirt-python>=11,<12",
35
+ "libvirt-python>=12,<13",
36
36
  "pycdlib>=1.14,<2",
37
37
  ]
38
38
 
@@ -41,12 +41,6 @@ name = "Nikos Chasiotis"
41
41
  email = "hasiotis@gmail.com"
42
42
 
43
43
  [project.optional-dependencies]
44
- gcp = [
45
- "google-auth-oauthlib>=0.4,<1.5",
46
- "oauthlib>=3.2.1,<4",
47
- "google-api-python-client>=2.198.0,<3",
48
- "google-cloud-dns>=0.37.0,<0.38",
49
- ]
50
44
  proxmox = ["proxmoxer>=1.1,<3"]
51
45
 
52
46
  [project.urls]
@@ -57,14 +51,12 @@ zbuilder = "zbuilder.cli:cli"
57
51
 
58
52
  [project.entry-points."zbuilder.vm"]
59
53
  aws = "zbuilder.vm.aws:vmProvider"
60
- gcp = "zbuilder.vm.gcp:vmProvider"
61
54
  kvm = "zbuilder.vm.kvm:vmProvider"
62
55
  proxmox = "zbuilder.vm.proxmox:vmProvider"
63
56
 
64
57
  [project.entry-points."zbuilder.dns"]
65
58
  aws = "zbuilder.dns.aws:dnsProvider"
66
59
  bind = "zbuilder.dns.bind:dnsProvider"
67
- gcp = "zbuilder.dns.gcp:dnsProvider"
68
60
  powerdns = "zbuilder.dns.powerdns:dnsProvider"
69
61
 
70
62
  [project.entry-points."zbuilder.ipam"]
@@ -75,19 +67,20 @@ dev = [
75
67
  "pytest>=9.1.1,<10",
76
68
  "pytest-md-report>=0.8.0",
77
69
  ]
78
- docs = ["sphinx>=7.2.6,<8"]
79
70
 
80
71
  [tool.uv]
81
72
  default-groups = ["dev"]
82
73
 
83
74
  [[tool.uv.dependency-metadata]]
84
75
  name = "libvirt-python"
85
- version = "11.10.0"
76
+ version = "12.8.0"
86
77
  requires-dist = []
87
78
 
88
79
  [tool.ruff]
89
80
  line-length = 120
90
81
 
82
+ [tool.ruff.lint]
83
+
91
84
  [tool.pytest.ini_options]
92
85
  testpaths = ["tests"]
93
86
  filterwarnings = ["ignore:This process .* is multi-threaded, use of fork.*:DeprecationWarning:multiprocessing.popen_fork"]
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "zbuilder"
3
- version = "0.2.2"
3
+ version = "0.2.4"
4
4
  description = "Create VMs"
5
5
  authors = [{ name = "Nikos Chasiotis", email = "hasiotis@gmail.com" }]
6
6
  license = "GPL-3.0-or-later"
@@ -35,20 +35,11 @@ dependencies = [
35
35
  "tabulate>=0.10.0",
36
36
  # The kvm provider. libvirt-python compiles against libvirt-dev, which has
37
37
  # to be present before `uv sync` - see the dependency-metadata block below.
38
- "libvirt-python>=11,<12",
38
+ "libvirt-python>=12,<13",
39
39
  "pycdlib>=1.14,<2",
40
40
  ]
41
41
 
42
42
  [project.optional-dependencies]
43
- # The gcp providers (vm and dns) pull in the whole google client stack, which
44
- # is a large dependency tree nobody outside GCP needs. zbuilder/vm/gcp.py and
45
- # zbuilder/dns/gcp.py import it lazily and say what to install when missing.
46
- gcp = [
47
- "google-auth-oauthlib>=0.4,<1.5",
48
- "oauthlib>=3.2.1,<4",
49
- "google-api-python-client>=2.198.0,<3",
50
- "google-cloud-dns>=0.37.0,<0.38",
51
- ]
52
43
  # The proxmox provider talks to PVE through proxmoxer, which nobody outside a
53
44
  # proxmox cluster needs. zbuilder/vm/proxmox.py imports it lazily and says what
54
45
  # to install when it is missing.
@@ -66,14 +57,12 @@ zbuilder = "zbuilder.cli:cli"
66
57
  # distribution can register providers under the same groups.
67
58
  [project.entry-points."zbuilder.vm"]
68
59
  aws = "zbuilder.vm.aws:vmProvider"
69
- gcp = "zbuilder.vm.gcp:vmProvider"
70
60
  kvm = "zbuilder.vm.kvm:vmProvider"
71
61
  proxmox = "zbuilder.vm.proxmox:vmProvider"
72
62
 
73
63
  [project.entry-points."zbuilder.dns"]
74
64
  aws = "zbuilder.dns.aws:dnsProvider"
75
65
  bind = "zbuilder.dns.bind:dnsProvider"
76
- gcp = "zbuilder.dns.gcp:dnsProvider"
77
66
  powerdns = "zbuilder.dns.powerdns:dnsProvider"
78
67
 
79
68
  [project.entry-points."zbuilder.ipam"]
@@ -84,9 +73,6 @@ dev = [
84
73
  "pytest>=9.1.1,<10",
85
74
  "pytest-md-report>=0.8.0",
86
75
  ]
87
- docs = [
88
- "sphinx>=7.2.6,<8",
89
- ]
90
76
 
91
77
  [tool.uv]
92
78
  default-groups = ["dev"]
@@ -98,7 +84,7 @@ default-groups = ["dev"]
98
84
  # built the normal way at install time, which does need the libvirt headers.
99
85
  [[tool.uv.dependency-metadata]]
100
86
  name = "libvirt-python"
101
- version = "11.10.0"
87
+ version = "12.8.0"
102
88
  requires-dist = []
103
89
 
104
90
  [build-system]
@@ -108,6 +94,8 @@ build-backend = "uv_build"
108
94
  [tool.ruff]
109
95
  line-length = 120
110
96
 
97
+ [tool.ruff.lint]
98
+
111
99
  [tool.pytest.ini_options]
112
100
  testpaths = [ "tests" ]
113
101
  filterwarnings = [
@@ -14,7 +14,7 @@ class UnsupportedAction(click.ClickException):
14
14
  """Raised when a provider does not implement an optional action"""
15
15
 
16
16
  def __init__(self, provider, action):
17
- super().__init__("Provider [{}] does not implement action [{}]".format(provider, action))
17
+ super().__init__(f"Provider [{provider}] does not implement action [{action}]")
18
18
 
19
19
 
20
20
  class Provider(ABC):
@@ -1,9 +1,8 @@
1
1
  import os
2
+ from pathlib import Path
2
3
 
3
4
  import zbuilder.helpers
4
5
 
5
- from pathlib import Path
6
-
7
6
  CONFIG_PATH = "~/.config/zbuilder/zbuilder.yaml"
8
7
  CONFIG_EMPTY = """# ZBuilder configuration
9
8
  main: {}
@@ -14,8 +13,7 @@ providers: {}
14
13
 
15
14
  def initConfig(fname):
16
15
  Path(fname).parent.mkdir(parents=True, exist_ok=True)
17
- Path(fname).touch()
18
- Path(fname).open("w").write(CONFIG_EMPTY)
16
+ Path(fname).write_text(CONFIG_EMPTY)
19
17
 
20
18
 
21
19
  def load(touch=False):
@@ -1,26 +1,25 @@
1
- # -*- coding: utf-8 -*-
2
1
  import os
2
+ import sys
3
3
  import time
4
+
4
5
  import click
5
- import tabulate
6
- import dpath.util
7
6
  import distutils.dir_util
7
+ import dpath.util
8
+ import tabulate
9
+ from click.shell_completion import get_completion_class
8
10
 
9
- import zbuilder.vm
10
11
  import zbuilder.cfg
11
12
  import zbuilder.plugins
12
-
13
+ import zbuilder.vm
13
14
  from zbuilder.helpers import (
15
+ fixKeys,
14
16
  getHosts,
15
17
  getProviders,
16
- runPlaybook,
17
- fixKeys,
18
- runCmd,
19
18
  humanize_time,
19
+ runCmd,
20
+ runPlaybook,
20
21
  )
21
- from zbuilder.options import pass_state, common_options
22
-
23
- from click.shell_completion import get_completion_class
22
+ from zbuilder.options import common_options, pass_state
24
23
 
25
24
 
26
25
  @click.group()
@@ -42,11 +41,11 @@ def init(state, template):
42
41
  tmpl_path = dpath.util.get(cfg, "/main/templates/path")
43
42
  TEMPLATE_PATH = os.path.join(os.path.expanduser(tmpl_path), template)
44
43
  if os.path.exists(TEMPLATE_PATH):
45
- click.echo("Initializing {} based zbuilder environment".format(template))
44
+ click.echo(f"Initializing {template} based zbuilder environment")
46
45
  distutils.dir_util.copy_tree(TEMPLATE_PATH, os.getcwd())
47
46
  else:
48
- click.echo("Template path dose not exist: [{}]".format(TEMPLATE_PATH))
49
- exit(1)
47
+ click.echo(f"Template path dose not exist: [{TEMPLATE_PATH}]")
48
+ sys.exit(1)
50
49
 
51
50
 
52
51
  @cli.command()
@@ -57,7 +56,7 @@ def build(state):
57
56
  start_time = time.time()
58
57
  click.echo("Building VMs")
59
58
  vmProviders = getHosts(state)
60
- for _, vmProvider in vmProviders.items():
59
+ for vmProvider in vmProviders.values():
61
60
  vmProvider["cloud"].build(vmProvider["hosts"])
62
61
  click.echo("Fixing ssh keys VMs")
63
62
  fixKeys(state)
@@ -65,7 +64,7 @@ def build(state):
65
64
  click.echo("Running bootstrap.yml")
66
65
  runPlaybook(state, "bootstrap.yml")
67
66
  end_time = time.time()
68
- click.echo("Time elapsed: {}".format(humanize_time(end_time - start_time)))
67
+ click.echo(f"Time elapsed: {humanize_time(end_time - start_time)}")
69
68
 
70
69
 
71
70
  @cli.command()
@@ -75,7 +74,7 @@ def up(state):
75
74
  """Boot the VMs"""
76
75
  click.echo("Booting VMs")
77
76
  vmProviders = getHosts(state)
78
- for _, vmProvider in vmProviders.items():
77
+ for vmProvider in vmProviders.values():
79
78
  vmProvider["cloud"].up(vmProvider["hosts"])
80
79
 
81
80
 
@@ -86,7 +85,7 @@ def halt(state):
86
85
  """Halt the VMs"""
87
86
  click.echo("Halting VMs")
88
87
  vmProviders = getHosts(state)
89
- for _, vmProvider in vmProviders.items():
88
+ for vmProvider in vmProviders.values():
90
89
  vmProvider["cloud"].halt(vmProvider["hosts"])
91
90
 
92
91
 
@@ -97,7 +96,7 @@ def destroy(state):
97
96
  """Destroy the VMs"""
98
97
  click.echo("Destroying VMs")
99
98
  vmProviders = getHosts(state)
100
- for _, vmProvider in vmProviders.items():
99
+ for vmProvider in vmProviders.values():
101
100
  zbuilder_env = None
102
101
  for h in vmProvider["hosts"]:
103
102
  if "ZBUILDER_ENV" in vmProvider["hosts"][h]:
@@ -108,7 +107,7 @@ def destroy(state):
108
107
  zbuilder_env = vmProvider["hosts"][h]["ZBUILDER_ENV"]
109
108
  break
110
109
  if zbuilder_env:
111
- if click.confirm(" The ZBUILDER_ENV is set to [{}] Do you want to continue?".format(zbuilder_env)):
110
+ if click.confirm(f" The ZBUILDER_ENV is set to [{zbuilder_env}] Do you want to continue?"):
112
111
  vmProvider["cloud"].destroy(vmProvider["hosts"])
113
112
  else:
114
113
  click.echo(" Aborting!")
@@ -128,7 +127,6 @@ def fixkeys(state):
128
127
  @cli.group()
129
128
  def dns():
130
129
  """DNS management"""
131
- pass
132
130
 
133
131
 
134
132
  @dns.command(name="update")
@@ -138,7 +136,7 @@ def dns_update(state):
138
136
  """Update DNS records"""
139
137
  click.echo("Updating DNS records")
140
138
  vmProviders = getHosts(state)
141
- for _, vmProvider in vmProviders.items():
139
+ for vmProvider in vmProviders.values():
142
140
  vmProvider["cloud"].dnsupdate(vmProvider["hosts"])
143
141
 
144
142
 
@@ -149,14 +147,13 @@ def remove(state):
149
147
  """Remove DNS records"""
150
148
  click.echo("Removing DNS records")
151
149
  vmProviders = getHosts(state)
152
- for _, vmProvider in vmProviders.items():
150
+ for vmProvider in vmProviders.values():
153
151
  vmProvider["cloud"].dnsremove(vmProvider["hosts"])
154
152
 
155
153
 
156
154
  @cli.group()
157
155
  def snapshot():
158
156
  """Manage VM snapshots"""
159
- pass
160
157
 
161
158
 
162
159
  @snapshot.command()
@@ -166,7 +163,7 @@ def create(state):
166
163
  """Create VM snapshots"""
167
164
  click.echo("Creating VMs snapshots")
168
165
  vmProviders = getHosts(state)
169
- for _, vmProvider in vmProviders.items():
166
+ for vmProvider in vmProviders.values():
170
167
  vmProvider["cloud"].snapCreate(vmProvider["hosts"])
171
168
 
172
169
 
@@ -177,7 +174,7 @@ def restore(state):
177
174
  """Restore VM snapshots"""
178
175
  click.echo("Restoring VMs snapshots")
179
176
  vmProviders = getHosts(state)
180
- for _, vmProvider in vmProviders.items():
177
+ for vmProvider in vmProviders.values():
181
178
  vmProvider["cloud"].snapRestore(vmProvider["hosts"])
182
179
 
183
180
 
@@ -188,7 +185,7 @@ def delete(state):
188
185
  """Delete VM snapshots"""
189
186
  click.echo("Deleting VMs snapshots")
190
187
  vmProviders = getHosts(state)
191
- for _, vmProvider in vmProviders.items():
188
+ for vmProvider in vmProviders.values():
192
189
  vmProvider["cloud"].snapDelete(vmProvider["hosts"])
193
190
 
194
191
 
@@ -207,7 +204,7 @@ def summary(state):
207
204
  """Display environment summary"""
208
205
  vmProviders = getHosts(state)
209
206
  data = []
210
- for _, vmProvider in vmProviders.items():
207
+ for vmProvider in vmProviders.values():
211
208
  for h, v in vmProvider["hosts"].items():
212
209
  data.append([vmProvider["cloud"].factory, h, vmProvider["cloud"].params(v)])
213
210
  click.echo(tabulate.tabulate(data, headers=["Provider", "Host", "Parameters"], tablefmt="psql"))
@@ -227,7 +224,6 @@ def providers(state):
227
224
  @cli.group()
228
225
  def config():
229
226
  """Zbuilder configuration"""
230
- pass
231
227
 
232
228
 
233
229
  @config.command()
@@ -255,9 +251,9 @@ def main(state, args):
255
251
  sub_path, value = args[1].split("=")
256
252
  if "," in value:
257
253
  value = value.split(",")
258
- cfg_path = "main/{}/{}".format(base_path, sub_path)
254
+ cfg_path = f"main/{base_path}/{sub_path}"
259
255
 
260
- click.echo("Setting config /{} to {}".format(cfg_path, value))
256
+ click.echo(f"Setting config /{cfg_path} to {value}")
261
257
  dpath.util.new(cfg, cfg_path, value)
262
258
  zbuilder.cfg.save(cfg)
263
259
 
@@ -277,9 +273,9 @@ def provider(state, args):
277
273
  value = True
278
274
  if value in ["False", "false"]:
279
275
  value = False
280
- cfg_path = "providers/{}/{}".format(base_path, sub_path)
276
+ cfg_path = f"providers/{base_path}/{sub_path}"
281
277
 
282
- click.echo("Setting config /{} to {}".format(cfg_path, value))
278
+ click.echo(f"Setting config /{cfg_path} to {value}")
283
279
  dpath.util.new(cfg, cfg_path, value)
284
280
  zbuilder.cfg.save(cfg)
285
281
 
@@ -298,7 +294,7 @@ def update(state, yes):
298
294
  tmpl_path = dpath.util.get(cfg, "/main/templates/path")
299
295
  if tmpl_repo and tmpl_path:
300
296
  click.echo(" * Updating templates")
301
- runCmd("git -C {path} pull || git clone {repo} {path}".format(repo=tmpl_repo, path=tmpl_path))
297
+ runCmd(f"git -C {tmpl_path} pull || git clone {tmpl_repo} {tmpl_path}")
302
298
  except KeyError:
303
299
  pass
304
300
 
@@ -313,7 +309,7 @@ def plugins(state):
313
309
  p = zbuilder.vm.vmProvider(plugin)
314
310
  if p.enabled():
315
311
  click.echo(f" - {plugin:8}: enabled")
316
- except Exception:
312
+ except Exception: # noqa: BLE001, S110 - a provider that can't even construct just isn't listed
317
313
  pass
318
314
 
319
315
 
@@ -1,5 +1,7 @@
1
1
  import time
2
+
2
3
  import click
4
+ import dns.exception
3
5
  import dns.resolver
4
6
 
5
7
  import zbuilder.cfg
@@ -8,34 +10,29 @@ import zbuilder.plugins
8
10
 
9
11
  def waitDNS(hostname, ip):
10
12
  synced = False
11
- click.echo(" - Waiting for host [{}] DNS to sync".format(hostname))
13
+ click.echo(f" - Waiting for host [{hostname}] DNS to sync")
12
14
  while not synced:
13
15
  try:
14
16
  answers = dns.resolver.query(hostname, "A")
15
17
  ttl = answers.rrset.ttl
16
18
  rip = answers[0].address
17
19
  if rip == ip:
18
- click.echo(" - Host [{}] is synced with ip [{}]".format(hostname, rip))
20
+ click.echo(f" - Host [{hostname}] is synced with ip [{rip}]")
19
21
  synced = True
20
22
  else:
21
- click.echo(
22
- " - Host [{}] is not synced with ip [{} != {}], sleeping for [{}]".format(
23
- hostname, ip, rip, ttl + 1
24
- )
25
- )
23
+ click.echo(f" - Host [{hostname}] is not synced with ip [{ip} != {rip}], sleeping for [{ttl + 1}]")
26
24
  time.sleep(ttl + 1)
27
25
  except dns.resolver.NXDOMAIN:
28
26
  click.echo(" Sleeping 20s due to NXDOMAIN")
29
27
  time.sleep(20)
30
- except Exception as e:
31
- click.echo(e)
32
- exit()
28
+ except dns.exception.DNSException as e:
29
+ raise click.ClickException(str(e)) from e
33
30
 
34
31
 
35
32
  def getProvider(zone, cfg):
36
- for p, v in cfg.items():
33
+ for v in cfg.values():
37
34
  if "dns" in v and "zones" in v["dns"] and zone == v["dns"]["zones"]:
38
- return dnsProvider(cfg[p]["type"], cfg[p])
35
+ return dnsProvider(v["type"], v)
39
36
  return None
40
37
 
41
38
 
@@ -50,7 +47,7 @@ def dnsUpdate(ips):
50
47
  provider.update(host, zone, ip)
51
48
  waitList[hostname] = ip
52
49
  else:
53
- click.echo("No DNS provider found for zone [{}]".format(zone))
50
+ click.echo(f"No DNS provider found for zone [{zone}]")
54
51
 
55
52
  for hostname, ip in waitList.items():
56
53
  waitDNS(hostname, ip)
@@ -65,7 +62,7 @@ def dnsRemove(hosts):
65
62
  if provider:
66
63
  provider.remove(host, zone)
67
64
  else:
68
- click.echo("No DNS provider found for zone [{}]".format(zone))
65
+ click.echo(f"No DNS provider found for zone [{zone}]")
69
66
 
70
67
 
71
68
  def dnsProvider(factory, cfg=None):
@@ -1,5 +1,6 @@
1
- import click
2
1
  import boto3
2
+ import click
3
+ from botocore.exceptions import BotoCoreError, ClientError
3
4
 
4
5
  from zbuilder.base import DNSProvider
5
6
 
@@ -21,8 +22,8 @@ class dnsProvider(DNSProvider):
21
22
  response = self.route53.list_hosted_zones_by_name(DNSName=zone)
22
23
  if response["HostedZones"]:
23
24
  zoneID = response["HostedZones"][0]["Id"]
24
- fqdn = "{}.{}".format(host, zone)
25
- click.echo(" - Update record [{}] with ip [{}]".format(fqdn, ip))
25
+ fqdn = f"{host}.{zone}"
26
+ click.echo(f" - Update record [{fqdn}] with ip [{ip}]")
26
27
 
27
28
  oldIP = None
28
29
  record_set = self.route53.list_resource_record_sets(
@@ -57,14 +58,14 @@ class dnsProvider(DNSProvider):
57
58
  ChangeInfoID = response["ChangeInfo"]["Id"]
58
59
  waiter = self.route53.get_waiter("resource_record_sets_changed")
59
60
  waiter.wait(Id=ChangeInfoID)
60
- except Exception as e:
61
- click.echo(" Error: [{}]".format(e))
61
+ except (BotoCoreError, ClientError) as e:
62
+ click.echo(f" Error: [{e}]")
62
63
 
63
64
  def remove(self, host, zone):
64
65
  response = self.route53.list_hosted_zones_by_name(DNSName=zone)
65
66
  if response["HostedZones"]:
66
67
  zoneID = response["HostedZones"][0]["Id"]
67
- fqdn = "{}.{}".format(host, zone)
68
+ fqdn = f"{host}.{zone}"
68
69
  ip = None
69
70
  record_set = self.route53.list_resource_record_sets(
70
71
  HostedZoneId=zoneID,
@@ -76,7 +77,7 @@ class dnsProvider(DNSProvider):
76
77
  ip = rs["ResourceRecords"][0]["Value"]
77
78
 
78
79
  if ip is not None:
79
- click.echo(" - Remove record [{}] with IP [{}]".format(fqdn, ip))
80
+ click.echo(f" - Remove record [{fqdn}] with IP [{ip}]")
80
81
  try:
81
82
  response = self.route53.change_resource_record_sets(
82
83
  HostedZoneId=zoneID,
@@ -95,7 +96,7 @@ class dnsProvider(DNSProvider):
95
96
  ],
96
97
  },
97
98
  )
98
- except Exception as e:
99
- click.echo(" Error: [{}]".format(e))
99
+ except (BotoCoreError, ClientError) as e:
100
+ click.echo(f" Error: [{e}]")
100
101
  else:
101
- click.echo(" - DNS record [{}] does not exist".format(fqdn))
102
+ click.echo(f" - DNS record [{fqdn}] does not exist")
@@ -22,27 +22,27 @@ class dnsProvider(DNSProvider):
22
22
  response = dns.query.tcp(update, srv)
23
23
  if response.rcode():
24
24
  err = dns.rcode.to_text(response.rcode())
25
- click.echo(" Failed to update DNS record [{}] on server [{}]".format(err, srv))
25
+ click.echo(f" Failed to update DNS record [{err}] on server [{srv}]")
26
26
 
27
27
  def update(self, host, zone, ip):
28
28
  if ip is None:
29
29
  click.echo(" - Skipping due to empty ip")
30
30
  return
31
- fqdn = "{}.{}".format(host, zone)
32
- click.echo(" - Creating/Updating record [{}] with ip [{}]".format(fqdn, ip))
31
+ fqdn = f"{host}.{zone}"
32
+ click.echo(f" - Creating/Updating record [{fqdn}] with ip [{ip}]")
33
33
  update = dns.update.Update(zone, keyring=self.keyring)
34
34
  update.replace(host, 300, "a", str(ip))
35
35
  self._dns_query(update)
36
36
 
37
37
  def remove(self, host, zone):
38
- fqdn = "{}.{}".format(host, zone)
39
- click.echo(" - Removing record {}".format(fqdn))
38
+ fqdn = f"{host}.{zone}"
39
+ click.echo(f" - Removing record {fqdn}")
40
40
  update = dns.update.Update(zone, keyring=self.keyring)
41
41
  update.delete(host)
42
42
  self._dns_query(update)
43
43
 
44
44
  def config(self):
45
- return "server: {}, keyname: {}".format(self.server, self.keyname)
45
+ return f"server: {self.server}, keyname: {self.keyname}"
46
46
 
47
47
  def status(self):
48
48
  return "PASS"