[libvirt] [sandbox PATCH] allow to use a templated unit in virt-sandbox

This permit to create a templated unit inside the sandbox, using the sandbox name as a variable and so running the same unit with a different configuration without too much hassle. For example, someone could have several different configuration of website in /etc/nginx/websites.d/ and have each of them started in a different sandbox, with a sample templated unit using the sandbox name as a option to read the proper configuration file directly. --- bin/virt-sandbox-service | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/bin/virt-sandbox-service b/bin/virt-sandbox-service index 2096be1..0d89b54 100755 --- a/bin/virt-sandbox-service +++ b/bin/virt-sandbox-service @@ -345,6 +345,10 @@ class GenericContainer(Container): def set_command(self, command): self.config.set_command(command) + +def is_template_unit(unit): + return '@' in unit + class SystemdContainer(Container): IGNORE_DIRS = [ "/var/run/", "/etc/logrotate.d/", "/etc/pam.d" ] DEFAULT_DIRS = [ "/etc", "/var" ] @@ -624,14 +628,22 @@ WantedBy=%(TARGET)s source = "%s%s" % ( self.dest, d) self.add_bind_mount(source, d) + def get_expanded_unit_template(self, unit): + return unit.replace('@', '@' + self.name) + def create_container_unit(self, src, dest, unit): - fd = open(dest + "/" + unit, "w") - fd.write(""".include %s + if is_template_unit(unit): + expanded_unit_name = self.get_expanded_unit_template(unit) + os.symlink(src, dest + "/" + expanded_unit_name) + shutil.copy(src, dest + "/" + unit) + else: + fd = open(dest + "/" + unit, "w") + fd.write(""".include %s [Service] PrivateTmp=false PrivateNetwork=false """ % src ) - fd.close() + fd.close() def gen_content(self): if self.copy: @@ -677,6 +689,8 @@ PrivateNetwork=false for i, src in self.unit_file_list: self.create_container_unit(src, self.dest + unitdir, i) + if is_template_unit(i): + i = self.get_expanded_unit_template(i) os.symlink("../" + i, self.dest + tgtdir + "/" + i) tgtfile = unitdir + "/multi-user.target" -- 1.8.2.1

On Fri, May 03, 2013 at 04:32:45PM +0200, Michael Scherer wrote:
This permit to create a templated unit inside the sandbox, using the sandbox name as a variable and so running the same unit with a different configuration without too much hassle.
For example, someone could have several different configuration of website in /etc/nginx/websites.d/ and have each of them started in a different sandbox, with a sample templated unit using the sandbox name as a option to read the proper configuration file directly.
Can you expand on this a little showing example unit file contents and how you'd invoke virt-sandbox-service with it. Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

Le vendredi 03 mai 2013 à 15:38 +0100, Daniel P. Berrange a écrit :
On Fri, May 03, 2013 at 04:32:45PM +0200, Michael Scherer wrote:
This permit to create a templated unit inside the sandbox, using the sandbox name as a variable and so running the same unit with a different configuration without too much hassle.
For example, someone could have several different configuration of website in /etc/nginx/websites.d/ and have each of them started in a different sandbox, with a sample templated unit using the sandbox name as a option to read the proper configuration file directly.
Can you expand on this a little showing example unit file contents and how you'd invoke virt-sandbox-service with it.
You mean in the commit log, or on the list ? Basically, what i am doing is the following : Here is the unit file ( copy from nginx, as I cannot include it sine ExecStart cannot be replaced ) : [Unit] Description=Test of a specific nginx running in lxc After=syslog.target network.target remote-fs.target nss-lookup.target [Service] PIDFile=/run/nginx.%i.pid ExecStartPre=/usr/sbin/nginx -t -c /etc/nginx/nginx.%i.conf ExecStart=/usr/sbin/nginx -c /etc/nginx/nginx.%i.conf Type=forking ExecReload=/bin/kill -s HUP $MAINPID ExecStop=/bin/kill -s QUIT $MAINPID PrivateTmp=true [Install] WantedBy=multi-user.target And to run it : # virt-sandbox-service create -u nginx_lxc@ test.example.org --package nginx So this create a container using /etc/nginx.test.example.org.conf as a configuration file, with the unit being linked and properly templated ( http://0pointer.de/blog/projects/instances.html ). If that's enough explanation, I will write something in the commit log, and also add some documentation as I totally forgot about it. -- Michael Scherer

On Fri, May 03, 2013 at 04:59:58PM +0200, Michael Scherer wrote:
Le vendredi 03 mai 2013 à 15:38 +0100, Daniel P. Berrange a écrit :
On Fri, May 03, 2013 at 04:32:45PM +0200, Michael Scherer wrote:
This permit to create a templated unit inside the sandbox, using the sandbox name as a variable and so running the same unit with a different configuration without too much hassle.
For example, someone could have several different configuration of website in /etc/nginx/websites.d/ and have each of them started in a different sandbox, with a sample templated unit using the sandbox name as a option to read the proper configuration file directly.
Can you expand on this a little showing example unit file contents and how you'd invoke virt-sandbox-service with it.
You mean in the commit log, or on the list ?
Basically, what i am doing is the following :
Here is the unit file ( copy from nginx, as I cannot include it sine ExecStart cannot be replaced ) :
[Unit] Description=Test of a specific nginx running in lxc After=syslog.target network.target remote-fs.target nss-lookup.target
[Service] PIDFile=/run/nginx.%i.pid ExecStartPre=/usr/sbin/nginx -t -c /etc/nginx/nginx.%i.conf ExecStart=/usr/sbin/nginx -c /etc/nginx/nginx.%i.conf Type=forking ExecReload=/bin/kill -s HUP $MAINPID ExecStop=/bin/kill -s QUIT $MAINPID PrivateTmp=true
[Install] WantedBy=multi-user.target
And to run it :
# virt-sandbox-service create -u nginx_lxc@ test.example.org --package nginx
So this create a container using /etc/nginx.test.example.org.conf as a configuration file, with the unit being linked and properly templated ( http://0pointer.de/blog/projects/instances.html ).
If that's enough explanation, I will write something in the commit log, and also add some documentation as I totally forgot about it.
Thanks, that makes some sense now. Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

On Fri, May 03, 2013 at 04:32:45PM +0200, Michael Scherer wrote:
This permit to create a templated unit inside the sandbox, using the sandbox name as a variable and so running the same unit with a different configuration without too much hassle.
For example, someone could have several different configuration of website in /etc/nginx/websites.d/ and have each of them started in a different sandbox, with a sample templated unit using the sandbox name as a option to read the proper configuration file directly. --- bin/virt-sandbox-service | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-)
diff --git a/bin/virt-sandbox-service b/bin/virt-sandbox-service index 2096be1..0d89b54 100755 --- a/bin/virt-sandbox-service +++ b/bin/virt-sandbox-service @@ -345,6 +345,10 @@ class GenericContainer(Container): def set_command(self, command): self.config.set_command(command)
+ +def is_template_unit(unit): + return '@' in unit + class SystemdContainer(Container): IGNORE_DIRS = [ "/var/run/", "/etc/logrotate.d/", "/etc/pam.d" ] DEFAULT_DIRS = [ "/etc", "/var" ] @@ -624,14 +628,22 @@ WantedBy=%(TARGET)s source = "%s%s" % ( self.dest, d) self.add_bind_mount(source, d)
+ def get_expanded_unit_template(self, unit): + return unit.replace('@', '@' + self.name) + def create_container_unit(self, src, dest, unit): - fd = open(dest + "/" + unit, "w") - fd.write(""".include %s + if is_template_unit(unit): + expanded_unit_name = self.get_expanded_unit_template(unit) + os.symlink(src, dest + "/" + expanded_unit_name) + shutil.copy(src, dest + "/" + unit) + else: + fd = open(dest + "/" + unit, "w") + fd.write(""".include %s [Service] PrivateTmp=false PrivateNetwork=false """ % src ) - fd.close() + fd.close()
So originally we would create /etc/systemd/system/$NAME.service inside the container containing: .include /lib/systemd/system/$NAME.service [Service] PrivateTmp=false PrivateNetwork=false with your change, we're symlinking /etc/systemd/system/$NAME.service to /lib/systemd/system/$UNITNAME@.service which means we loose the disablement of PrivateTmp and PrivateNetwork. Required because we're already in private namespaces & don't want to be creating more. I think you need to create /etc/systemd/system/$UNITNAME@.service containing .include /lib/systemd/system/$UNITNAME@.service [Service] PrivateTmp=false PrivateNetwork=false and then also /etc/systemd/system/$NAME.service symlinking to the overrideden $UNITNAME@.service instead of the original Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

Le vendredi 03 mai 2013 à 16:10 +0100, Daniel P. Berrange a écrit :
On Fri, May 03, 2013 at 04:32:45PM +0200, Michael Scherer wrote:
This permit to create a templated unit inside the sandbox, using the sandbox name as a variable and so running the same unit with a different configuration without too much hassle.
For example, someone could have several different configuration of website in /etc/nginx/websites.d/ and have each of them started in a different sandbox, with a sample templated unit using the sandbox name as a option to read the proper configuration file directly. --- bin/virt-sandbox-service | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-)
diff --git a/bin/virt-sandbox-service b/bin/virt-sandbox-service index 2096be1..0d89b54 100755 --- a/bin/virt-sandbox-service +++ b/bin/virt-sandbox-service @@ -345,6 +345,10 @@ class GenericContainer(Container): def set_command(self, command): self.config.set_command(command)
+ +def is_template_unit(unit): + return '@' in unit + class SystemdContainer(Container): IGNORE_DIRS = [ "/var/run/", "/etc/logrotate.d/", "/etc/pam.d" ] DEFAULT_DIRS = [ "/etc", "/var" ] @@ -624,14 +628,22 @@ WantedBy=%(TARGET)s source = "%s%s" % ( self.dest, d) self.add_bind_mount(source, d)
+ def get_expanded_unit_template(self, unit): + return unit.replace('@', '@' + self.name) + def create_container_unit(self, src, dest, unit): - fd = open(dest + "/" + unit, "w") - fd.write(""".include %s + if is_template_unit(unit): + expanded_unit_name = self.get_expanded_unit_template(unit) + os.symlink(src, dest + "/" + expanded_unit_name) + shutil.copy(src, dest + "/" + unit) + else: + fd = open(dest + "/" + unit, "w") + fd.write(""".include %s [Service] PrivateTmp=false PrivateNetwork=false """ % src ) - fd.close() + fd.close()
So originally we would create /etc/systemd/system/$NAME.service inside the container containing:
.include /lib/systemd/system/$NAME.service [Service] PrivateTmp=false PrivateNetwork=false
with your change, we're symlinking
/etc/systemd/system/$NAME.service
to
/lib/systemd/system/$UNITNAME@.service
which means we loose the disablement of PrivateTmp and PrivateNetwork. Required because we're already in private namespaces & don't want to be creating more.
I think you need to create /etc/systemd/system/$UNITNAME@.service containing
.include /lib/systemd/system/$UNITNAME@.service [Service] PrivateTmp=false PrivateNetwork=false
But we are not sure of the location of the service file in the first place, so we cannot include it like this. And I want to be able to use it on custom unit sitting in /etc, as most unit in /lib do not support templating ( my use case is "massive" vhost hosting ). What about using the system based on /etc/systemd/system/$NAME.service.d/virt_sandbox.conf for config file inclusion ? ( didn't test yet ) Would it be a problem to depend on a recent enough systemd version for this feature to work ? ( it is in since systemd 198, drop-in file support : http://lists.freedesktop.org/archives/systemd-devel/2013-March/009496.html ) -- Michael Scherer

On Fri, May 03, 2013 at 05:25:06PM +0200, Michael Scherer wrote:
Le vendredi 03 mai 2013 à 16:10 +0100, Daniel P. Berrange a écrit :
On Fri, May 03, 2013 at 04:32:45PM +0200, Michael Scherer wrote:
This permit to create a templated unit inside the sandbox, using the sandbox name as a variable and so running the same unit with a different configuration without too much hassle.
For example, someone could have several different configuration of website in /etc/nginx/websites.d/ and have each of them started in a different sandbox, with a sample templated unit using the sandbox name as a option to read the proper configuration file directly. --- bin/virt-sandbox-service | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-)
diff --git a/bin/virt-sandbox-service b/bin/virt-sandbox-service index 2096be1..0d89b54 100755 --- a/bin/virt-sandbox-service +++ b/bin/virt-sandbox-service @@ -345,6 +345,10 @@ class GenericContainer(Container): def set_command(self, command): self.config.set_command(command)
+ +def is_template_unit(unit): + return '@' in unit + class SystemdContainer(Container): IGNORE_DIRS = [ "/var/run/", "/etc/logrotate.d/", "/etc/pam.d" ] DEFAULT_DIRS = [ "/etc", "/var" ] @@ -624,14 +628,22 @@ WantedBy=%(TARGET)s source = "%s%s" % ( self.dest, d) self.add_bind_mount(source, d)
+ def get_expanded_unit_template(self, unit): + return unit.replace('@', '@' + self.name) + def create_container_unit(self, src, dest, unit): - fd = open(dest + "/" + unit, "w") - fd.write(""".include %s + if is_template_unit(unit): + expanded_unit_name = self.get_expanded_unit_template(unit) + os.symlink(src, dest + "/" + expanded_unit_name) + shutil.copy(src, dest + "/" + unit) + else: + fd = open(dest + "/" + unit, "w") + fd.write(""".include %s [Service] PrivateTmp=false PrivateNetwork=false """ % src ) - fd.close() + fd.close()
So originally we would create /etc/systemd/system/$NAME.service inside the container containing:
.include /lib/systemd/system/$NAME.service [Service] PrivateTmp=false PrivateNetwork=false
with your change, we're symlinking
/etc/systemd/system/$NAME.service
to
/lib/systemd/system/$UNITNAME@.service
which means we loose the disablement of PrivateTmp and PrivateNetwork. Required because we're already in private namespaces & don't want to be creating more.
I think you need to create /etc/systemd/system/$UNITNAME@.service containing
.include /lib/systemd/system/$UNITNAME@.service [Service] PrivateTmp=false PrivateNetwork=false
But we are not sure of the location of the service file in the first place, so we cannot include it like this.
And I want to be able to use it on custom unit sitting in /etc, as most unit in /lib do not support templating ( my use case is "massive" vhost hosting ).
What about using the system based on /etc/systemd/system/$NAME.service.d/virt_sandbox.conf for config file inclusion ? ( didn't test yet )
Would it be a problem to depend on a recent enough systemd version for this feature to work ? ( it is in since systemd 198, drop-in file support : http://lists.freedesktop.org/archives/systemd-devel/2013-March/009496.html )
Yeah that looks like a much nicer approach. I've no problem with us declaring systemd 198 as a min requirement, since we're still a very nice project in a fairly experimental state. Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|
participants (2)
-
Daniel P. Berrange
-
Michael Scherer