[libvirt] [jenkins-ci PATCH v2 12/12] lcitool: Implement the 'dockerfile' action

Andrea Bolognani posted 12 patches 7 years, 7 months ago
There is a newer version of this series
[libvirt] [jenkins-ci PATCH v2 12/12] lcitool: Implement the 'dockerfile' action
Posted by Andrea Bolognani 7 years, 7 months ago
This is basically the exact same algorithm used by the
Ansible playbooks to process package mappings, implemented
in pure Python.

Signed-off-by: Andrea Bolognani <abologna@redhat.com>
---
 guests/lcitool | 86 ++++++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 80 insertions(+), 6 deletions(-)

diff --git a/guests/lcitool b/guests/lcitool
index d42b7e7..61cae97 100755
--- a/guests/lcitool
+++ b/guests/lcitool
@@ -299,7 +299,10 @@ class Application:
                   hosts     list all known hosts
                   projects  list all known projects
 
-                glob patterns are supported for HOSTS
+                uncommon actions:
+                  dockerfile  generate Dockerfile (doesn't access the host)
+
+                glob patterns are supported for HOSTS and PROJECTS
                 """),
         )
         self._parser.add_argument(
@@ -313,16 +316,21 @@ class Application:
             metavar = "HOSTS",
             help = "list of hosts to act on",
         )
+        self._parser.add_argument(
+            "-p",
+            metavar = "PROJECTS",
+            help = "list of projects to consider",
+        )
 
-    def _action_list(self, hosts):
+    def _action_hosts(self, hosts, projects):
         for host in self._inventory.expand_pattern("all"):
             print(host)
 
-    def _action_projects(self, hosts):
+    def _action_projects(self, hosts, projects):
         for project in self._projects.expand_pattern("all"):
             print(project)
 
-    def _action_install(self, hosts):
+    def _action_install(self, hosts, projects):
         flavor = self._config.get_flavor()
 
         for host in self._inventory.expand_pattern(hosts):
@@ -380,7 +388,7 @@ class Application:
             except:
                 raise Error("Failed to install '{}'".format(host))
 
-    def _action_update(self, hosts):
+    def _action_update(self, hosts, projects):
         flavor = self._config.get_flavor()
         vault_pass_file = self._config.get_vault_password_file()
         root_pass_file = self._config.get_root_password_file()
@@ -409,15 +417,81 @@ class Application:
         except:
             raise Error("Failed to update '{}'".format(hosts))
 
+    def _action_dockerfile(self, hosts, projects):
+        mappings = self._projects.get_mappings()
+
+        hosts = self._inventory.expand_pattern(hosts)
+        if len(hosts) > 1:
+            raise Error("Can't generate Dockerfile for multiple hosts")
+        host = hosts[0]
+
+        facts = self._inventory.get_facts(host)
+        package_format = facts["package_format"]
+        os_name = facts["os_name"]
+        os_full = os_name + str(facts["os_version"])
+
+        if package_format != "deb" and package_format != "rpm":
+            raise Error("Host {} doesn't support Dockerfiles".format(host))
+
+        projects = self._projects.expand_pattern(projects)
+        for project in projects:
+            if project not in facts['projects']:
+                raise Error(
+                    "Host {} doesn't support project {}".format(
+                        host,
+                        project,
+                    )
+                )
+
+        temp = {}
+
+        # We need to add the base project manually here: the standard
+        # machinery hides it because it's an implementation detail
+        for project in projects + [ "base" ]:
+            for package in self._projects.get_packages(project):
+                if "default" in mappings[package]:
+                    temp[package] = mappings[package]["default"]
+                if package_format in mappings[package]:
+                    temp[package] = mappings[package][package_format]
+                if os_name in mappings[package]:
+                    temp[package] = mappings[package][os_name]
+                if os_full in mappings[package]:
+                    temp[package] = mappings[package][os_full]
+
+        flattened = []
+        for item in temp:
+            if temp[item] != None and temp[item] not in flattened:
+                flattened += [ temp[item] ]
+
+        print("FROM {}".format(facts['docker_base']))
+
+        sys.stdout.write("ENV PACKAGES ")
+        sys.stdout.write(" \\\n             ".join(sorted(flattened)))
+
+        if package_format == "deb":
+            sys.stdout.write(textwrap.dedent("""
+                RUN apt-get update && \\
+                    apt-get install -y ${PACKAGES} && \\
+                    apt-get autoremove -y && \\
+                    apt-get autoclean -y
+            """))
+        elif package_format == "rpm":
+            sys.stdout.write(textwrap.dedent("""
+                RUN yum install -y ${PACKAGES} && \\
+                    yum autoremove -y && \\
+                    yum clean all -y
+                """))
+
     def run(self):
         cmdline = self._parser.parse_args()
         action = cmdline.a
         hosts = cmdline.h
+        projects = cmdline.p
 
         method = "_action_{}".format(action.replace("-", "_"))
 
         if hasattr(self, method):
-            getattr(self, method).__call__(hosts)
+            getattr(self, method).__call__(hosts, projects)
         else:
             raise Error("Invalid action '{}'".format(action))
 
-- 
2.17.1

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [jenkins-ci PATCH v2 12/12] lcitool: Implement the 'dockerfile' action
Posted by Katerina Koukiou 7 years, 6 months ago
On Thu, Jul 12, 2018 at 05:19:29PM +0200, Andrea Bolognani wrote:
> This is basically the exact same algorithm used by the
> Ansible playbooks to process package mappings, implemented
> in pure Python.
> 
> Signed-off-by: Andrea Bolognani <abologna@redhat.com>
> ---
>  guests/lcitool | 86 ++++++++++++++++++++++++++++++++++++++++++++++----
>  1 file changed, 80 insertions(+), 6 deletions(-)
> 
> diff --git a/guests/lcitool b/guests/lcitool
> index d42b7e7..61cae97 100755
> --- a/guests/lcitool
> +++ b/guests/lcitool
> @@ -299,7 +299,10 @@ class Application:
>                    hosts     list all known hosts
>                    projects  list all known projects
>  
> -                glob patterns are supported for HOSTS
> +                uncommon actions:
> +                  dockerfile  generate Dockerfile (doesn't access the host)
> +
> +                glob patterns are supported for HOSTS and PROJECTS
>                  """),
>          )
>          self._parser.add_argument(
> @@ -313,16 +316,21 @@ class Application:
>              metavar = "HOSTS",
>              help = "list of hosts to act on",
>          )
> +        self._parser.add_argument(
> +            "-p",
> +            metavar = "PROJECTS",
> +            help = "list of projects to consider",
> +        )
>  
> -    def _action_list(self, hosts):
> +    def _action_hosts(self, hosts, projects):
>          for host in self._inventory.expand_pattern("all"):
>              print(host)
>  
> -    def _action_projects(self, hosts):
> +    def _action_projects(self, hosts, projects):
>          for project in self._projects.expand_pattern("all"):
>              print(project)
>  
> -    def _action_install(self, hosts):
> +    def _action_install(self, hosts, projects):
>          flavor = self._config.get_flavor()
>  
>          for host in self._inventory.expand_pattern(hosts):
> @@ -380,7 +388,7 @@ class Application:
>              except:
>                  raise Error("Failed to install '{}'".format(host))
>  
> -    def _action_update(self, hosts):
> +    def _action_update(self, hosts, projects):
>          flavor = self._config.get_flavor()
>          vault_pass_file = self._config.get_vault_password_file()
>          root_pass_file = self._config.get_root_password_file()
> @@ -409,15 +417,81 @@ class Application:
>          except:
>              raise Error("Failed to update '{}'".format(hosts))
>  
> +    def _action_dockerfile(self, hosts, projects):
> +        mappings = self._projects.get_mappings()
> +
> +        hosts = self._inventory.expand_pattern(hosts)
> +        if len(hosts) > 1:
> +            raise Error("Can't generate Dockerfile for multiple hosts")
> +        host = hosts[0]
> +
> +        facts = self._inventory.get_facts(host)
> +        package_format = facts["package_format"]
> +        os_name = facts["os_name"]
> +        os_full = os_name + str(facts["os_version"])
> +
> +        if package_format != "deb" and package_format != "rpm":

More pythonic would be "package_format not in ('deb', 'rpm')"

> +            raise Error("Host {} doesn't support Dockerfiles".format(host))
> +
> +        projects = self._projects.expand_pattern(projects)
> +        for project in projects:
> +            if project not in facts['projects']:
> +                raise Error(
> +                    "Host {} doesn't support project {}".format(
> +                        host,
> +                        project,
> +                    )
> +                )
> +
> +        temp = {}
> +
> +        # We need to add the base project manually here: the standard
> +        # machinery hides it because it's an implementation detail
> +        for project in projects + [ "base" ]:
> +            for package in self._projects.get_packages(project):
> +                if "default" in mappings[package]:
> +                    temp[package] = mappings[package]["default"]
> +                if package_format in mappings[package]:
> +                    temp[package] = mappings[package][package_format]
> +                if os_name in mappings[package]:
> +                    temp[package] = mappings[package][os_name]
> +                if os_full in mappings[package]:
> +                    temp[package] = mappings[package][os_full]
> +
> +        flattened = []
> +        for item in temp:
> +            if temp[item] != None and temp[item] not in flattened:
> +                flattened += [ temp[item] ]
> +
> +        print("FROM {}".format(facts['docker_base']))
> +
> +        sys.stdout.write("ENV PACKAGES ")
> +        sys.stdout.write(" \\\n             ".join(sorted(flattened)))
> +
> +        if package_format == "deb":
> +            sys.stdout.write(textwrap.dedent("""
> +                RUN apt-get update && \\
> +                    apt-get install -y ${PACKAGES} && \\
> +                    apt-get autoremove -y && \\
> +                    apt-get autoclean -y
> +            """))
> +        elif package_format == "rpm":
> +            sys.stdout.write(textwrap.dedent("""
> +                RUN yum install -y ${PACKAGES} && \\
> +                    yum autoremove -y && \\
> +                    yum clean all -y
> +                """))
> +
>      def run(self):
>          cmdline = self._parser.parse_args()
>          action = cmdline.a
>          hosts = cmdline.h
> +        projects = cmdline.p
>  
>          method = "_action_{}".format(action.replace("-", "_"))
>  
>          if hasattr(self, method):
> -            getattr(self, method).__call__(hosts)
> +            getattr(self, method).__call__(hosts, projects)
>          else:
>              raise Error("Invalid action '{}'".format(action))
>  
> -- 
> 2.17.1
> 
> --
> libvir-list mailing list
> libvir-list@redhat.com
> https://www.redhat.com/mailman/listinfo/libvir-list
--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list