Skip to content

Commit

Permalink
Add per-object "restart" option to control restarts.
Browse files Browse the repository at this point in the history
  • Loading branch information
AshleyYakeley committed Sep 21, 2024
1 parent 99e1ace commit 7d489a3
Show file tree
Hide file tree
Showing 6 changed files with 62 additions and 23 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
# Changelog

## [UNRELEASED]

* Modules:
* Improve change detection for domain restarts.
* Add per-object "restart" option to control restarts.
* Lib:
* XML domain generation:
* Allow in feature section, customization of the `smbios` option
Expand Down
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ Each set represents a libvirt domain, and has these attributes:
* `active` (bool or `null`, default `null`)
State to put the domain in (running/stopped), or null to ignore.

* `restart` (bool or `null`, default `null`)
Whether to restart the domain, or null to restart only if its definition has changed.

:warning: If this option is specified and not null, any libvirt domain not defined in the list will be deleted.
Deleting a domain will not delete its volumes, NVRAM, or TPM state.

Expand All @@ -70,6 +73,9 @@ Each set represents a libvirt network, and has these attributes:
* `active` (bool or `null`, default `null`)
State to put the network in, or null to ignore.

* `restart` (bool or `null`, default `null`)
Whether to restart the network, or null to restart only if its definition has changed.

:warning: If this option is specified and not null, any libvirt network not defined in the list will be deleted.

* `virtualisation.libvirt.connections.<connection>.pools` (list of sets or `null`, default `null`)
Expand All @@ -82,6 +88,9 @@ Each set represents a libvirt storage pool, and has these attributes:
* `active` (bool or `null`, default `null`)
State to put the pool in, or null to ignore.

* `restart` (bool or `null`, default `null`)
Whether to restart the pool, or null to restart only if its definition has changed.

* `volumes` (list of sets, default `[]`)
Volumes to create if not already existing.
Existing volumes not listed will be ignored (not deleted);
Expand Down
6 changes: 6 additions & 0 deletions modules.nix
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@ let
default = null;
description = "state to put the " + singular + " in (or null for ignore)";
};
restart = lib.mkOption
{
type = nullOr bool;
default = null;
description = "whether to restart on activation (or null to only restart when changed)";
};
};
}));
default = null;
Expand Down
2 changes: 1 addition & 1 deletion tool/nixvirt-module-helper
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ with open(args.settingspath,"r") as f:
class TypeSpec:
def __init__(self,session,type,itemlist):
self.oc = nixvirt.getObjectConnection(session,type)
self.specList = [nixvirt.ObjectSpec.fromDefinitionFile(self.oc,item["definition"],item.get("active"),item) for item in itemlist]
self.specList = [nixvirt.ObjectSpec.fromDefinitionFile(self.oc,item["definition"],item.get("active"),item.get("restart"),item) for item in itemlist]

def deleteOld(self):
allObjects = self.oc.getAll()
Expand Down
47 changes: 28 additions & 19 deletions tool/nixvirt.py
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,7 @@ def defineExtra(self,extra):
# what we want for an object
class ObjectSpec:

def __init__(self,oc,specUUID = None,specName = None,specDefXML = None,active = None,extra = None):
def __init__(self,oc,specUUID = None,specName = None,specDefXML = None,active = None,restart = None,extra = None):
if specUUID is not None:
self.subject = oc.fromUUIDOrNone(specUUID)
elif specName is not None:
Expand All @@ -335,28 +335,29 @@ def __init__(self,oc,specUUID = None,specName = None,specDefXML = None,active =
self.specUUID = specUUID
self.active = active
self.extra = extra
self.restart = restart

def vreport(self,msg):
self.oc.vreport(self.specUUID,msg)

def fromUUID(oc,specUUID,active):
return ObjectSpec(oc,specUUID = specUUID,active = active)
def fromUUID(oc,specUUID,active,restart):
return ObjectSpec(oc,specUUID = specUUID,active = active,restart = restart)

def fromName(oc,specName,active):
return ObjectSpec(oc,specName = specName,active = active)
def fromName(oc,specName,active,restart):
return ObjectSpec(oc,specName = specName,active = active,restart = restart)

def fromDefinition(oc,specDefXML,active,extra = None):
def fromDefinition(oc,specDefXML,active,restart,extra = None):
specDefETree = xmlToETree(specDefXML)
specUUID = uuid.UUID(specDefETree.find("uuid").text).bytes
specName = specDefETree.find("name").text
fixedDefETree = oc._fixDefinitionETree(specUUID,specDefETree)
if fixedDefETree is not None:
specDefXML = eTreeToXML(fixedDefETree)
return ObjectSpec(oc,specUUID = specUUID,specName = specName,specDefXML = specDefXML,active = active, extra = extra)
return ObjectSpec(oc,specUUID = specUUID,specName = specName,specDefXML = specDefXML,active = active,restart = restart, extra = extra)

def fromDefinitionFile(oc,path,active,extra = None):
def fromDefinitionFile(oc,path,active,restart,extra = None):
specDefXML = oc.getFile(path)
return ObjectSpec.fromDefinition(oc,specDefXML,active, extra = extra)
return ObjectSpec.fromDefinition(oc,specDefXML,active,restart, extra = extra)

def define(self):
if self.specDefXML is not None:
Expand All @@ -368,16 +369,24 @@ def define(self):
self.oc._cleanDefETree(self.specDefXML,oldDefETree)
self.vreport("redefine")
newvobject = self.oc._fromXML(self.specDefXML)
newDefETree = newvobject.descriptionETree()
self.oc._cleanDefETree(self.specDefXML,newDefETree)
diff = xmldiff.main.diff_trees(oldDefETree,newDefETree)
if len(diff) > 0:
if self.oc.session.verbose:
difftext = xmldiff.main.diff_trees(oldDefETree,newDefETree,formatter=xmldiff.formatting.DiffFormatter())
self.vreport("changed:\n" + difftext)
self.subject._deactivate()
else:
self.vreport("unchanged")
match self.restart:
case True:
self.vreport("always restart")
self.subject._deactivate()
case False:
self.vreport("never restart")
case None:
self.vreport("detect restart")
newDefETree = newvobject.descriptionETree()
self.oc._cleanDefETree(self.specDefXML,newDefETree)
diff = xmldiff.main.diff_trees(oldDefETree,newDefETree)
if len(diff) > 0:
if self.oc.session.verbose:
difftext = xmldiff.main.diff_trees(oldDefETree,newDefETree,formatter=xmldiff.formatting.DiffFormatter())
self.vreport("changed:\n" + difftext)
self.subject._deactivate()
else:
self.vreport("unchanged")
self.subject = newvobject
else:
self.vreport("define new")
Expand Down
17 changes: 14 additions & 3 deletions tool/virtdeclare
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ specgroup.add_argument('--define', action='store', metavar='PATH', help='XML obj
specgroup.add_argument('--uuid', action='store', metavar='ID', help='object UUID')
specgroup.add_argument('--name', action='store', metavar='ID', help='object name')
parser.add_argument('--state', action='store', choices = ['active','inactive'], help='state to put object in')
parser.add_argument('--restart', action='store', choices = ['always','never','ifchanged'], help='whether to restart the object')
parser.add_argument('--auto', action='store_true', help='set autostart to match state')
args = parser.parse_args()

Expand All @@ -23,18 +24,28 @@ match args.state:
case None:
active = None

match args.restart:
case "always":
restart = True
case "never":
restart = False
case "ifchanged":
restart = None
case None:
restart = None

try:
session = nixvirt.Session(args.connect,args.verbose)
oc = nixvirt.getObjectConnection(session,args.type)

# fetch object
if args.define:
spec = nixvirt.ObjectSpec.fromDefinitionFile(oc,args.define,active)
spec = nixvirt.ObjectSpec.fromDefinitionFile(oc,args.define,active,restart)
elif args.uuid:
specUUID = uuid.UUID(args.uuid).bytes
spec = nixvirt.ObjectSpec.fromUUID(oc,specUUID,active)
spec = nixvirt.ObjectSpec.fromUUID(oc,specUUID,active,restart)
else:
spec = nixvirt.ObjectSpec.fromName(oc,args.name,active)
spec = nixvirt.ObjectSpec.fromName(oc,args.name,active,restart)

# define object
spec.define()
Expand Down

0 comments on commit 7d489a3

Please sign in to comment.