nsxctl 1.0.0__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.
- nsx_toolkit/__init__.py +0 -0
- nsx_toolkit/__main__.py +9 -0
- nsx_toolkit/actions/__init__.py +0 -0
- nsx_toolkit/actions/audit_view.py +150 -0
- nsx_toolkit/actions/author.py +874 -0
- nsx_toolkit/actions/bulk.py +206 -0
- nsx_toolkit/actions/change_ticket.py +138 -0
- nsx_toolkit/actions/dashboard.py +108 -0
- nsx_toolkit/actions/doctor.py +260 -0
- nsx_toolkit/actions/drift.py +69 -0
- nsx_toolkit/actions/groups.py +81 -0
- nsx_toolkit/actions/hygiene.py +502 -0
- nsx_toolkit/actions/inspect.py +377 -0
- nsx_toolkit/actions/parity.py +151 -0
- nsx_toolkit/actions/recommend.py +145 -0
- nsx_toolkit/actions/reverse.py +161 -0
- nsx_toolkit/actions/tags.py +288 -0
- nsx_toolkit/actions/trace.py +371 -0
- nsx_toolkit/actions/verify.py +57 -0
- nsx_toolkit/api.py +317 -0
- nsx_toolkit/audit.py +214 -0
- nsx_toolkit/authoring.py +503 -0
- nsx_toolkit/baseline.py +171 -0
- nsx_toolkit/cli.py +372 -0
- nsx_toolkit/commands/__init__.py +216 -0
- nsx_toolkit/commands/analysis.py +100 -0
- nsx_toolkit/commands/apply.py +58 -0
- nsx_toolkit/commands/group.py +139 -0
- nsx_toolkit/commands/inspect.py +75 -0
- nsx_toolkit/commands/recommend.py +70 -0
- nsx_toolkit/commands/rule.py +436 -0
- nsx_toolkit/commands/setup.py +298 -0
- nsx_toolkit/commands/shell.py +427 -0
- nsx_toolkit/commands/snapshot.py +322 -0
- nsx_toolkit/commands/tag.py +134 -0
- nsx_toolkit/commands/trace.py +76 -0
- nsx_toolkit/config.py +210 -0
- nsx_toolkit/creds.py +240 -0
- nsx_toolkit/diff.py +254 -0
- nsx_toolkit/errors.py +28 -0
- nsx_toolkit/export.py +154 -0
- nsx_toolkit/flows.py +339 -0
- nsx_toolkit/http.py +515 -0
- nsx_toolkit/legacy.py +167 -0
- nsx_toolkit/menu.py +323 -0
- nsx_toolkit/namecache.py +196 -0
- nsx_toolkit/output.py +340 -0
- nsx_toolkit/paths.py +58 -0
- nsx_toolkit/policy.py +200 -0
- nsx_toolkit/render.py +89 -0
- nsx_toolkit/report.py +144 -0
- nsx_toolkit/sinks.py +316 -0
- nsx_toolkit/snapshot.py +326 -0
- nsx_toolkit/taxonomy.py +143 -0
- nsx_toolkit/trace.py +779 -0
- nsx_toolkit/version.py +6 -0
- nsx_toolkit/wizard.py +231 -0
- nsxctl-1.0.0.dist-info/METADATA +834 -0
- nsxctl-1.0.0.dist-info/RECORD +63 -0
- nsxctl-1.0.0.dist-info/WHEEL +5 -0
- nsxctl-1.0.0.dist-info/entry_points.txt +3 -0
- nsxctl-1.0.0.dist-info/licenses/LICENSE +201 -0
- nsxctl-1.0.0.dist-info/top_level.txt +1 -0
nsx_toolkit/__init__.py
ADDED
|
File without changes
|
nsx_toolkit/__main__.py
ADDED
|
File without changes
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
"""Audit log viewing and single-entry undo.
|
|
2
|
+
|
|
3
|
+
Two eras of entry live in the log -- VM tag changes, and the group and rule
|
|
4
|
+
changes authoring writes -- so everything here reads the normalised shape
|
|
5
|
+
`audit.normalise_entry` produces and dispatches undo on `object_type`. A log
|
|
6
|
+
written before authoring existed lists and undoes exactly as it always did.
|
|
7
|
+
|
|
8
|
+
**Undo is asymmetric, and the messages say which case they are in.** Undoing
|
|
9
|
+
a create is a delete and undoing a modify is a write of the before-body: both
|
|
10
|
+
exact. Undoing a delete recreates an object whose references may have been
|
|
11
|
+
cleaned up underneath it, and that cannot be guaranteed -- a snapshot restore
|
|
12
|
+
is the reliable way back from a delete.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from ..api import F_EXTERNAL_ID
|
|
16
|
+
from ..audit import OBJ_GROUP, OBJ_RULE, OBJ_VM_TAGS, summarise_entry
|
|
17
|
+
from ..errors import NsxError
|
|
18
|
+
from ..output import (
|
|
19
|
+
ask,
|
|
20
|
+
cB,
|
|
21
|
+
cBY,
|
|
22
|
+
cC,
|
|
23
|
+
cD,
|
|
24
|
+
cG,
|
|
25
|
+
confirm,
|
|
26
|
+
cR,
|
|
27
|
+
err,
|
|
28
|
+
hr,
|
|
29
|
+
is_interactive,
|
|
30
|
+
ok_msg,
|
|
31
|
+
say,
|
|
32
|
+
)
|
|
33
|
+
from ..render import fmt_tags_plain, tags_of
|
|
34
|
+
from .author import undo_object_entry
|
|
35
|
+
|
|
36
|
+
AUDIT_HEADERS = ["timestamp", "user", "manager", "action", "object_type",
|
|
37
|
+
"object", "added", "removed", "status"]
|
|
38
|
+
|
|
39
|
+
UNDOABLE_OBJECTS = (OBJ_GROUP, OBJ_RULE)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def _entry_row(entry, added, removed):
|
|
43
|
+
return [entry["timestamp"], entry["user"], entry["manager"],
|
|
44
|
+
entry["action"], entry["object_type"], entry["object_name"],
|
|
45
|
+
fmt_tags_plain(added) if added else "",
|
|
46
|
+
fmt_tags_plain(removed) if removed else "",
|
|
47
|
+
entry["status"]]
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def _print_entry(index, entry):
|
|
51
|
+
say(" {:5s} {} {:28s} {} [{}]".format(
|
|
52
|
+
cD(str(index) + "."), cD(str(entry["timestamp"])[:19]),
|
|
53
|
+
str(entry["object_name"])[:28], cD(entry["object_type"]),
|
|
54
|
+
cC(entry["manager"])))
|
|
55
|
+
if entry["object_type"] == OBJ_VM_TAGS:
|
|
56
|
+
added, removed = summarise_entry(entry)
|
|
57
|
+
if added:
|
|
58
|
+
say(" {}".format(cG("+ " + fmt_tags_plain(added))))
|
|
59
|
+
if removed:
|
|
60
|
+
say(" {}".format(cR("- " + fmt_tags_plain(removed))))
|
|
61
|
+
return
|
|
62
|
+
if entry["before"] is None:
|
|
63
|
+
say(" {}".format(cG("created")))
|
|
64
|
+
elif entry["after"] is None:
|
|
65
|
+
say(" {}".format(cR("deleted")))
|
|
66
|
+
else:
|
|
67
|
+
say(" {}".format(cBY("modified")))
|
|
68
|
+
if entry["status"] and entry["status"] != "success":
|
|
69
|
+
say(" {} {}".format(cR(entry["status"]), cD(entry["detail"])))
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def act_audit_log(audit, sessions, write_enabled, exporter=None, limit=20,
|
|
73
|
+
domain="default"):
|
|
74
|
+
entries = audit.last_n_normalised(limit)
|
|
75
|
+
if not entries:
|
|
76
|
+
say(" Audit log empty.")
|
|
77
|
+
if exporter is not None:
|
|
78
|
+
exporter.stage("audit_log", AUDIT_HEADERS, [])
|
|
79
|
+
return
|
|
80
|
+
say("\n Last {} entries:".format(cC(str(len(entries)))))
|
|
81
|
+
hr()
|
|
82
|
+
rows = []
|
|
83
|
+
for index, entry in enumerate(entries, 1):
|
|
84
|
+
_print_entry(index, entry)
|
|
85
|
+
added, removed = summarise_entry(entry)
|
|
86
|
+
rows.append(_entry_row(entry, added, removed))
|
|
87
|
+
if exporter is not None:
|
|
88
|
+
exporter.stage("audit_log", AUDIT_HEADERS, rows)
|
|
89
|
+
|
|
90
|
+
if not write_enabled:
|
|
91
|
+
say("\n {}.".format(cBY("Undo needs write mode")))
|
|
92
|
+
return
|
|
93
|
+
if not is_interactive():
|
|
94
|
+
return
|
|
95
|
+
hr()
|
|
96
|
+
choice = ask(" Undo entry # (or b): ")
|
|
97
|
+
if not choice.isdigit() or not (1 <= int(choice) <= len(entries)):
|
|
98
|
+
say(" Cancelled.")
|
|
99
|
+
return
|
|
100
|
+
target = entries[int(choice) - 1]
|
|
101
|
+
try:
|
|
102
|
+
if target["object_type"] == OBJ_VM_TAGS:
|
|
103
|
+
_undo_vm_tags(target, sessions, audit)
|
|
104
|
+
elif target["object_type"] in UNDOABLE_OBJECTS:
|
|
105
|
+
undo_object_entry(target, sessions, domain, audit)
|
|
106
|
+
else:
|
|
107
|
+
err("Entries of type '{}' cannot be undone.".format(
|
|
108
|
+
target["object_type"]))
|
|
109
|
+
except NsxError as e:
|
|
110
|
+
err(str(e))
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def _undo_vm_tags(target, sessions, audit):
|
|
114
|
+
"""The original tag undo, unchanged in behaviour.
|
|
115
|
+
|
|
116
|
+
Reads `before`/`after` off the normalised entry, which for a tag entry
|
|
117
|
+
comes from `tags_before`/`tags_after` whether it was written this release
|
|
118
|
+
or three releases ago.
|
|
119
|
+
"""
|
|
120
|
+
restore_to = target["before"] or []
|
|
121
|
+
raw = target["raw"]
|
|
122
|
+
vm_name = raw.get("vm_display_name", target["object_name"])
|
|
123
|
+
mgr_name = target["manager"]
|
|
124
|
+
ext = raw.get("vm_external_id", "?")
|
|
125
|
+
|
|
126
|
+
nsx = next((s for s in sessions if s.name == mgr_name), None)
|
|
127
|
+
if not nsx:
|
|
128
|
+
err("Manager '{}' is not in this session.".format(mgr_name))
|
|
129
|
+
return
|
|
130
|
+
vm = nsx.get_vm_by_external_id(ext)
|
|
131
|
+
if not vm:
|
|
132
|
+
err("VM '{}' (external_id {}) not found on {}.".format(
|
|
133
|
+
vm_name, ext, mgr_name))
|
|
134
|
+
return
|
|
135
|
+
current = sorted(tags_of(vm))
|
|
136
|
+
say("\n Restore '{}' on [{}]".format(cB(vm_name), cC(mgr_name)))
|
|
137
|
+
say(" current : {}".format(fmt_tags_plain(current)))
|
|
138
|
+
say(" restore : {}".format(fmt_tags_plain(sorted(restore_to))))
|
|
139
|
+
if current == sorted(restore_to):
|
|
140
|
+
say(" Already in that state -- nothing to undo.")
|
|
141
|
+
return
|
|
142
|
+
if not confirm(" Apply undo? [y/N]: "):
|
|
143
|
+
say(" Cancelled.")
|
|
144
|
+
return
|
|
145
|
+
fresh = nsx.refresh_vm(vm) or vm
|
|
146
|
+
nsx.update_vm_tags(fresh, restore_to)
|
|
147
|
+
audit.log("undo", nsx.name, vm_name, fresh.get(F_EXTERNAL_ID),
|
|
148
|
+
current, restore_to, detail="undo of {}".format(
|
|
149
|
+
target.get("timestamp", "?")))
|
|
150
|
+
ok_msg("Undo applied.")
|