Initialize config repository
diff --git a/nodepool/_local_hypervisor_k1s.yaml b/nodepool/_local_hypervisor_k1s.yaml
new file mode 100644
index 0000000..666c99a
--- /dev/null
+++ b/nodepool/_local_hypervisor_k1s.yaml
@@ -0,0 +1 @@
+# This file is managed by sfconfig, do not edit manually
diff --git a/nodepool/_local_hypervisor_openshift.yaml b/nodepool/_local_hypervisor_openshift.yaml
new file mode 100644
index 0000000..404b62b
--- /dev/null
+++ b/nodepool/_local_hypervisor_openshift.yaml
@@ -0,0 +1,2 @@
+# This file is managed by sfconfig, do not edit manually
+---
diff --git a/nodepool/_pods.yaml b/nodepool/_pods.yaml
new file mode 100644
index 0000000..491a749
--- /dev/null
+++ b/nodepool/_pods.yaml
@@ -0,0 +1,5 @@
+# This file is managed by sfconfig, do not edit manually
+---
+labels:
+  - name: pod-centos-7
+
diff --git a/nodepool/elements/README b/nodepool/elements/README
new file mode 100644
index 0000000..257e142
--- /dev/null
+++ b/nodepool/elements/README
@@ -0,0 +1,5 @@
+Customs diskimage builder elements to be used by nodepool-builder.
+
+Nodepool is configured to use by default (with low precedence):
+* https://softwarefactory-project.io/r/software-factory/sf-elements
+* git://git.openstack.org/openstack-infra/project-config/nodepool/elements
diff --git a/nodepool/nodepool.yaml b/nodepool/nodepool.yaml
new file mode 100644
index 0000000..d9cb250
--- /dev/null
+++ b/nodepool/nodepool.yaml
@@ -0,0 +1,41 @@
+# Uncomment to enable openstack provider
+#---
+#diskimages:
+#  - name: dib-centos-7
+#    elements:
+#      - centos-minimal
+#      - nodepool-minimal
+#      - zuul-worker-user
+#  - name: cloud-fedora-rawhide
+#    python-path: /usr/bin/python3
+#    dib-cmd: /usr/bin/dib-virt-customize /etc/nodepool/virt_images/cloud-fedora-rawhide.yaml
+#
+#
+#labels:
+#  - name: dib-centos-7
+#    min-ready: 1
+#  - name: cloud-fedora-rawhide
+#    min-ready: 1
+#
+#providers:
+#  - name: default
+#    cloud: default
+#    clean-floating-ips: true
+#    image-name-format: '{image_name}-{timestamp}'
+#    boot-timeout: 120
+#    rate: 10.0
+#    diskimages:
+#      - name: dib-centos-7
+#      - name: cloud-fedora-rawhide
+#    pools:
+#      - name: main
+#        max-servers: 5
+#        networks:
+#          - worker-net-name
+#        labels:
+#          - name: dib-centos-7
+#            min-ram: 1024
+#            diskimage: dib-centos-7
+#          - name: cloud-fedora-rawhide
+#            min-ram: 1024
+#            diskimage: cloud-fedora-rawhide
diff --git a/nodepool/openshift.yaml b/nodepool/openshift.yaml
new file mode 100644
index 0000000..64bb998
--- /dev/null
+++ b/nodepool/openshift.yaml
@@ -0,0 +1,45 @@
+# Uncomment to enable openshift provider
+#---
+# After the provider is registered in sfconfig.yaml, grab the context name using:
+#  sudo -u nodepool oc config get-contexts
+#
+#
+# To use the openshift driver, a self provisioner service account is needed:
+# Request the cluster operator to create:
+#   oc create sa nodepool
+#   oc adm policy add-cluster-role-to-user self-provisioner --serviceaccount=nodepool
+#   oc policy add-role-to-user admin --serviceaccount=nodepool
+#   oc sa get-token nodepool
+# Then register the token in sfconfig.yaml
+#
+#providers:
+#  - name: openshift01
+#    driver: openshift
+#    context: self-provisioner-service-account-context-name
+#    pools:
+#      - name: zuul-ci
+#        labels:
+#          - name: openshift-project
+#            type: project
+#          - name: openshift-pod-fedora
+#            type: pod
+#            image: docker.io/fedora:28
+#
+#
+###############################################################################
+# Or use the openshiftpods driver with a regular service account:
+#   oc new-project nodepool
+#   oc create sa nodepool
+#   oc policy add-role-to-user admin --serviceaccount=nodepool
+#   oc sa get-token nodepool
+# Then register the token in sfconfig.yaml
+#
+#providers:
+#  - name: openshift01
+#    driver: openshiftpods
+#    context: "nodepool/openshift-example-com:8443/system:serviceaccount:nodepool:nodepool"
+#    pools:
+#      - name: nodepool
+#        labels:
+#          - name: openshift-pod
+#            image: docker.io/fedora:28
diff --git a/nodepool/static_config/README.md b/nodepool/static_config/README.md
new file mode 100644
index 0000000..55b446b
--- /dev/null
+++ b/nodepool/static_config/README.md
@@ -0,0 +1,5 @@
+# Nodepool static configuration
+
+To create a static configuration for a nodepool service, create a file named
+'hostname.yaml' with the nodepool configuration in this directory. The file will
+be installed on the host instead the generated configuration.
diff --git a/nodepool/virt_images/README.md b/nodepool/virt_images/README.md
new file mode 100644
index 0000000..3fed60e
--- /dev/null
+++ b/nodepool/virt_images/README.md
@@ -0,0 +1,12 @@
+# Virt-customize based nodepool image
+
+This directory contains nodepool image built using virt-customize-dib elements.
+
+To use a playbook, add this to a nodepool yaml file:
+
+```yaml
+diskimages:
+  - name: cloud-fedora-rawhide
+    python-path: /usr/bin/python3
+    dib-cmd: /usr/bin/dib-virt-customize /etc/nodepool/virt_images/cloud-fedora-rawhide.yaml
+```
diff --git a/nodepool/virt_images/cloud-fedora-rawhide.yaml b/nodepool/virt_images/cloud-fedora-rawhide.yaml
new file mode 100644
index 0000000..07d2ecc
--- /dev/null
+++ b/nodepool/virt_images/cloud-fedora-rawhide.yaml
@@ -0,0 +1,38 @@
+---
+- name: Build a fedora cloud image suitable for Zuul
+  hosts: localhost
+  vars:
+    image: Fedora-Cloud-Base-Rawhide.x86_64.qcow2
+    extra_packages:
+      # Extra system tools
+      - pigz
+      - bridge-utils
+      - wget
+      - unzip
+      # Basic CI tools
+      - make
+      - gcc
+      - patch
+  tasks:
+    - block:
+      - import_role:
+          name: discover-rawhide
+      - import_role:
+          name: base-appliance
+      - import_role:
+          name: base
+      - import_role:
+          name: sshd-config
+      - import_role:
+          name: network-config
+      - import_role:
+          name: zuul-user
+      - import_role:
+          name: base-install-packages
+      - import_role:
+          name: base-customize
+      - import_role:
+          name: base-finalize
+      always:
+      - import_role:
+          name: base-cleanup
diff --git a/nodepool/virt_images/roles/base-appliance/tasks/main.yaml b/nodepool/virt_images/roles/base-appliance/tasks/main.yaml
new file mode 100644
index 0000000..e5e83fd
--- /dev/null
+++ b/nodepool/virt_images/roles/base-appliance/tasks/main.yaml
@@ -0,0 +1,12 @@
+- name: Download appliance
+  unarchive:
+    src: http://download.libguestfs.org/binaries/appliance/appliance-1.46.0.tar.xz
+    remote_src: yes
+    dest: /tmp
+  args:
+    creates: /tmp/appliance
+
+- set_fact:
+    virt_customize_env:
+      LIBGUESTFS_PATH: '/tmp/appliance'
+      LIBGUESTFS_BACKEND: 'direct'
diff --git a/nodepool/virt_images/roles/base-cleanup/defaults/main.yaml b/nodepool/virt_images/roles/base-cleanup/defaults/main.yaml
new file mode 100644
index 0000000..dd9240b
--- /dev/null
+++ b/nodepool/virt_images/roles/base-cleanup/defaults/main.yaml
@@ -0,0 +1,2 @@
+---
+image_tmp_dir: "/var/tmp/{{ image_output | basename }}"
diff --git a/nodepool/virt_images/roles/base-cleanup/tasks/main.yaml b/nodepool/virt_images/roles/base-cleanup/tasks/main.yaml
new file mode 100644
index 0000000..29c01ea
--- /dev/null
+++ b/nodepool/virt_images/roles/base-cleanup/tasks/main.yaml
@@ -0,0 +1,5 @@
+---
+- name: Remove tmp directory
+  file:
+    path: "{{ image_tmp_dir }}"
+    state: absent
diff --git a/nodepool/virt_images/roles/base-customize/defaults/main.yaml b/nodepool/virt_images/roles/base-customize/defaults/main.yaml
new file mode 100644
index 0000000..ed97d53
--- /dev/null
+++ b/nodepool/virt_images/roles/base-customize/defaults/main.yaml
@@ -0,0 +1 @@
+---
diff --git a/nodepool/virt_images/roles/base-customize/tasks/main.yaml b/nodepool/virt_images/roles/base-customize/tasks/main.yaml
new file mode 100644
index 0000000..c1d397d
--- /dev/null
+++ b/nodepool/virt_images/roles/base-customize/tasks/main.yaml
@@ -0,0 +1,7 @@
+---
+- debug:
+    msg: "Running: {{ ' '.join(virt_customize_cmd) }}"
+
+- name: Run virt-customize
+  command: "{{ ' '.join(virt_customize_cmd) }}"
+  environment: "{{ virt_customize_env|default({}) }}"
diff --git a/nodepool/virt_images/roles/base-finalize/defaults/main.yaml b/nodepool/virt_images/roles/base-finalize/defaults/main.yaml
new file mode 100644
index 0000000..ed97d53
--- /dev/null
+++ b/nodepool/virt_images/roles/base-finalize/defaults/main.yaml
@@ -0,0 +1 @@
+---
diff --git a/nodepool/virt_images/roles/base-finalize/tasks/main.yaml b/nodepool/virt_images/roles/base-finalize/tasks/main.yaml
new file mode 100644
index 0000000..9fb8968
--- /dev/null
+++ b/nodepool/virt_images/roles/base-finalize/tasks/main.yaml
@@ -0,0 +1,8 @@
+---
+- name: Create raw file
+  command: "qemu-img convert -O raw {{ image_file }} {{ image_output }}.raw"
+  when: raw_type | default(False) | bool
+
+- name: Create qcow file
+  command: "mv {{ image_file }} {{ image_output }}.qcow2"
+  when: qcow2_type | default(False) | bool
diff --git a/nodepool/virt_images/roles/base-install-packages/defaults/main.yaml b/nodepool/virt_images/roles/base-install-packages/defaults/main.yaml
new file mode 100644
index 0000000..ed97d53
--- /dev/null
+++ b/nodepool/virt_images/roles/base-install-packages/defaults/main.yaml
@@ -0,0 +1 @@
+---
diff --git a/nodepool/virt_images/roles/base-install-packages/tasks/main.yaml b/nodepool/virt_images/roles/base-install-packages/tasks/main.yaml
new file mode 100644
index 0000000..588de54
--- /dev/null
+++ b/nodepool/virt_images/roles/base-install-packages/tasks/main.yaml
@@ -0,0 +1,7 @@
+---
+- set_fact:
+    cmd:
+      - "--install '{{ extra_packages | join(',') }}'"
+
+- set_fact:
+    virt_customize_cmd: "{{ virt_customize_cmd + cmd }}"
diff --git a/nodepool/virt_images/roles/base/defaults/main.yaml b/nodepool/virt_images/roles/base/defaults/main.yaml
new file mode 100644
index 0000000..a1cdfac
--- /dev/null
+++ b/nodepool/virt_images/roles/base/defaults/main.yaml
@@ -0,0 +1,10 @@
+---
+image_cache_dir: "/var/cache/nodepool"
+image_wipe_cache: False
+memsize: 1024
+base_packages:
+  - traceroute
+  - iproute
+  - git
+  - rsync
+extra_packages: []
diff --git a/nodepool/virt_images/roles/base/tasks/main.yaml b/nodepool/virt_images/roles/base/tasks/main.yaml
new file mode 100644
index 0000000..88f8799
--- /dev/null
+++ b/nodepool/virt_images/roles/base/tasks/main.yaml
@@ -0,0 +1,70 @@
+---
+- assert:
+    that:
+      - image_url is defined
+      - image_checksum is defined
+      - image is defined
+      - image_url != ''
+      - image_checksum != ''
+      - image != ''
+
+- name: Set some runtime facts
+  set_fact:
+    image_cache_file: "{{ image_cache_dir }}/{{ image }}"
+    image_tmp_dir: "/var/tmp/{{ image_output | basename }}"
+
+- name: Make sure cache directory exist
+  file:
+    path: "{{ image_cache_dir }}"
+    state: directory
+
+- name: Delete previous image cache
+  file:
+    path: "{{ image_cache_file }}"
+    state: absent
+  when: image_wipe_cache
+
+- name: Check if image is already downloaded
+  stat:
+    path: "{{ image_cache_file }}"
+  register: _image_cache_file_stat
+
+- name: Download if checksum doesn't match
+  get_url:
+    url: "{{ image_url }}"
+    dest: "{{ image_cache_file }}"
+    checksum: "{{ image_checksum }}"
+  when: not _image_cache_file_stat.stat.exists
+
+- name: Extract the image if necessary
+  command: "xz -k -d {{ image_cache_file }}.xz"
+  args:
+    chdir: "{{ image_cache_dir }}"
+    creates: "{{ image_cache_file }}"
+
+- name: Update the cache
+  command: "virt-customize -m {{ memsize }} -a {{ image_cache_file }} --update"
+  environment: "{{ virt_customize_env|default({}) }}"
+
+- name: Create tmp directory
+  file:
+    path: "{{ image_tmp_dir }}"
+    state: directory
+    mode: '0755'
+
+- name: Set filename copy fact
+  set_fact:
+    image_file: "{{ image_tmp_dir }}/{{ image_cache_file | basename }}"
+
+- name: Copy the image
+  copy:
+    src: "{{ image_cache_file }}"
+    dest: "{{ image_file }}"
+    remote_src: true
+    mode: '0644'
+
+- set_fact:
+    virt_customize_cmd:
+      - "virt-customize -m {{ memsize }} -a {{ image_file }}"
+      - "--selinux-relabel"
+      - "--install '{{ base_packages | join(',') }}'"
diff --git a/nodepool/virt_images/roles/discover-rawhide/defaults/main.yaml b/nodepool/virt_images/roles/discover-rawhide/defaults/main.yaml
new file mode 100644
index 0000000..e87cb9c
--- /dev/null
+++ b/nodepool/virt_images/roles/discover-rawhide/defaults/main.yaml
@@ -0,0 +1 @@
+base_url: https://dl.fedoraproject.org/pub/fedora/linux/development/rawhide/Cloud/x86_64/images/
diff --git a/nodepool/virt_images/roles/discover-rawhide/tasks/main.yaml b/nodepool/virt_images/roles/discover-rawhide/tasks/main.yaml
new file mode 100644
index 0000000..51e47c8
--- /dev/null
+++ b/nodepool/virt_images/roles/discover-rawhide/tasks/main.yaml
@@ -0,0 +1,45 @@
+- tempfile:
+    state: file
+  register: tempfile
+
+- file:
+    path: "{{ tempfile.path }}"
+    state: absent
+
+- name: Fetch publication page
+  get_url:
+    url: "{{ base_url }}"
+    dest: "{{ tempfile.path }}"
+
+- name: Find rawhide qcow2 url
+  command: sed -n "/qcow2/ s/.*\(Fedora-Cloud-Base-Rawhide-.*\)<\/a>.*/\1/p" {{ tempfile.path }}
+  register: get_qcow_image_name
+
+- name: Find checksum file url
+  command: sed -n "/CHECKSUM/ s/.*\(Fedora-Cloud-Rawhide-.*\)<\/a>.*/\1/p" {{ tempfile.path }}
+  register: get_checksum_name
+
+- set_fact:
+    checksums_url: "{{ base_url }}{{ get_checksum_name.stdout }}"
+
+- file:
+    path: "{{ tempfile.path }}"
+    state: absent
+
+- name: Fetch checksum file
+  get_url:
+    url: "{{ checksums_url }}"
+    dest: "{{ tempfile.path }}"
+
+- name: Find checksum
+  command: sed -n "/SHA256 ({{ get_qcow_image_name.stdout }}) = / s/.* = \(.*\)/\1/p" {{ tempfile.path }}
+  register: get_checksum
+
+- set_fact:
+    image_url: "{{ base_url }}{{ get_qcow_image_name.stdout }}"
+    image_checksum: "sha256:{{ get_checksum.stdout }}"
+
+- debug:
+    msg: |
+      Discovered image_url: {{ image_url }}
+      Discovered image_checksum: {{ image_checksum }}
diff --git a/nodepool/virt_images/roles/network-config/defaults/main.yaml b/nodepool/virt_images/roles/network-config/defaults/main.yaml
new file mode 100644
index 0000000..dd9240b
--- /dev/null
+++ b/nodepool/virt_images/roles/network-config/defaults/main.yaml
@@ -0,0 +1,2 @@
+---
+image_tmp_dir: "/var/tmp/{{ image_output | basename }}"
diff --git a/nodepool/virt_images/roles/network-config/tasks/main.yaml b/nodepool/virt_images/roles/network-config/tasks/main.yaml
new file mode 100644
index 0000000..5d49314
--- /dev/null
+++ b/nodepool/virt_images/roles/network-config/tasks/main.yaml
@@ -0,0 +1,12 @@
+---
+- set_fact:
+    cmd:
+      - "--append-line '/etc/sysctl.conf:net.ipv6.conf.all.disable_ipv6 = 1'"
+      - "--append-line '/etc/sysctl.conf:net.ipv6.conf.default.disable_ipv6 = 1'"
+      - "--append-line '/etc/sysconfig/network:IPV6INIT=no'"
+      - "--append-line '/etc/sysconfig/network:IPV6_AUTOCONF=no'"
+      - "--append-line '/etc/sysconfig/network:IPV6_DEFROUTE=no'"
+      - "--append-line '/etc/yum.conf:ip_resolve=4'"
+
+- set_fact:
+    virt_customize_cmd: "{{ virt_customize_cmd + cmd }}"
diff --git a/nodepool/virt_images/roles/sshd-config/defaults/main.yaml b/nodepool/virt_images/roles/sshd-config/defaults/main.yaml
new file mode 100644
index 0000000..dd9240b
--- /dev/null
+++ b/nodepool/virt_images/roles/sshd-config/defaults/main.yaml
@@ -0,0 +1,2 @@
+---
+image_tmp_dir: "/var/tmp/{{ image_output | basename }}"
diff --git a/nodepool/virt_images/roles/sshd-config/files/sshd_config b/nodepool/virt_images/roles/sshd-config/files/sshd_config
new file mode 100644
index 0000000..df17bfa
--- /dev/null
+++ b/nodepool/virt_images/roles/sshd-config/files/sshd_config
@@ -0,0 +1,20 @@
+HostKey /etc/ssh/ssh_host_rsa_key
+HostKey /etc/ssh/ssh_host_ecdsa_key
+HostKey /etc/ssh/ssh_host_ed25519_key
+KexAlgorithms curve25519-sha256@libssh.org,ecdh-sha2-nistp521,ecdh-sha2-nistp384,ecdh-sha2-nistp256,diffie-hellman-group-exchange-sha256
+Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr
+MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-512,hmac-sha2-256,umac-128@openssh.com
+SyslogFacility AUTHPRIV
+AuthorizedKeysFile .ssh/authorized_keys
+PasswordAuthentication no
+ChallengeResponseAuthentication no
+GSSAPIAuthentication no
+GSSAPICleanupCredentials no
+UsePAM yes
+X11Forwarding no
+UseDNS no
+AcceptEnv LANG LC_CTYPE LC_NUMERIC LC_TIME LC_COLLATE LC_MONETARY LC_MESSAGES
+AcceptEnv LC_PAPER LC_NAME LC_ADDRESS LC_TELEPHONE LC_MEASUREMENT
+AcceptEnv LC_IDENTIFICATION LC_ALL LANGUAGE
+AcceptEnv XMODIFIERS
+Subsystem sftp  /usr/libexec/openssh/sftp-server
diff --git a/nodepool/virt_images/roles/sshd-config/tasks/main.yaml b/nodepool/virt_images/roles/sshd-config/tasks/main.yaml
new file mode 100644
index 0000000..ff62665
--- /dev/null
+++ b/nodepool/virt_images/roles/sshd-config/tasks/main.yaml
@@ -0,0 +1,13 @@
+---
+- name: Prepare sshd_config file
+  copy:
+    src: files/sshd_config
+    dest: "{{ image_tmp_dir }}/sshd_config"
+
+- set_fact:
+    cmd:
+      - "--copy-in '{{ image_tmp_dir }}/sshd_config:/etc/ssh/'"
+      - "--chmod '0600:/etc/ssh/sshd_config'"
+
+- set_fact:
+    virt_customize_cmd: "{{ virt_customize_cmd + cmd }}"
diff --git a/nodepool/virt_images/roles/zuul-user/defaults/main.yaml b/nodepool/virt_images/roles/zuul-user/defaults/main.yaml
new file mode 100644
index 0000000..dd9240b
--- /dev/null
+++ b/nodepool/virt_images/roles/zuul-user/defaults/main.yaml
@@ -0,0 +1,2 @@
+---
+image_tmp_dir: "/var/tmp/{{ image_output | basename }}"
diff --git a/nodepool/virt_images/roles/zuul-user/tasks/main.yaml b/nodepool/virt_images/roles/zuul-user/tasks/main.yaml
new file mode 100644
index 0000000..2382ba4
--- /dev/null
+++ b/nodepool/virt_images/roles/zuul-user/tasks/main.yaml
@@ -0,0 +1,27 @@
+---
+- name: Prepare the sudoers file
+  copy:
+    content: |
+      Defaults    !requiretty
+      zuul-worker ALL=(ALL) NOPASSWD:ALL
+    dest: "{{ image_tmp_dir }}/zuul-worker"
+
+- name: Prepare the authorized_keys file
+  copy:
+    src: /var/lib/nodepool/.ssh/zuul_rsa.pub
+    dest: "{{ image_tmp_dir }}/authorized_keys"
+    remote_src: true
+
+- set_fact:
+    cmd:
+      - "--run-command 'adduser -m zuul-worker'"
+      - "--mkdir '/home/zuul-worker/.ssh'"
+      - "--chmod '0700:/home/zuul-worker/.ssh'"
+      - "--copy-in '{{ image_tmp_dir }}/authorized_keys:/home/zuul-worker/.ssh/'"
+      - "--chmod '0600:/home/zuul-worker/.ssh/authorized_keys'"
+      - "--run-command 'chown -R zuul-worker:zuul-worker /home/zuul-worker/.ssh/'"
+      - "--copy-in '{{ image_tmp_dir }}/zuul-worker:/etc/sudoers.d/'"
+      - "--chmod '0440:/etc/sudoers.d/zuul-worker'"
+
+- set_fact:
+    virt_customize_cmd: "{{ virt_customize_cmd + cmd }}"