From 0b5a36f9704419dd3b9d9425eeb24edd6d3a9e0a Mon Sep 17 00:00:00 2001 From: Andrey Shestakov Date: Tue, 27 Sep 2016 18:56:06 +0300 Subject: [PATCH] Add Ironic This change introduces services required for Ironic support. Change-Id: Ic21d6379450471d91b2d7681911ca8b36c3fb0bf --- .gitignore | 69 +++++++++++++++++++++ docker/ironic-api/Dockerfile.j2 | 8 +++ docker/ironic-base/Dockerfile.j2 | 15 +++++ docker/ironic-conductor/Dockerfile.j2 | 11 ++++ docker/ironic-ipxe/Dockerfile.j2 | 12 ++++ docker/ironic-pxe/Dockerfile.j2 | 14 +++++ docker/ironic-pxe/tftp-map-file | 2 + service/files/defaults.yaml | 37 +++++++++++ service/files/ironic.conf.j2 | 88 +++++++++++++++++++++++++++ service/files/nginx-ipxe.conf.j2 | 4 ++ service/files/pxe-bootstrap.sh | 14 +++++ service/files/ssh_key.j2 | 3 + service/ironic-api.yaml | 73 ++++++++++++++++++++++ service/ironic-conductor.yaml | 87 ++++++++++++++++++++++++++ test-requirements.txt | 2 + tools/yamllint.sh | 5 ++ tools/yamllint.yaml | 21 +++++++ tox.ini | 15 +++++ 18 files changed, 480 insertions(+) create mode 100644 .gitignore create mode 100644 docker/ironic-api/Dockerfile.j2 create mode 100644 docker/ironic-base/Dockerfile.j2 create mode 100644 docker/ironic-conductor/Dockerfile.j2 create mode 100644 docker/ironic-ipxe/Dockerfile.j2 create mode 100644 docker/ironic-pxe/Dockerfile.j2 create mode 100644 docker/ironic-pxe/tftp-map-file create mode 100644 service/files/defaults.yaml create mode 100644 service/files/ironic.conf.j2 create mode 100644 service/files/nginx-ipxe.conf.j2 create mode 100644 service/files/pxe-bootstrap.sh create mode 100644 service/files/ssh_key.j2 create mode 100644 service/ironic-api.yaml create mode 100644 service/ironic-conductor.yaml create mode 100644 test-requirements.txt create mode 100755 tools/yamllint.sh create mode 100644 tools/yamllint.yaml create mode 100644 tox.ini diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d537f0c --- /dev/null +++ b/.gitignore @@ -0,0 +1,69 @@ +*.py[cod] + +# C extensions +*.so + +# Packages +*.egg +*.egg-info +dist +build +.eggs +eggs +parts +bin +var +sdist +develop-eggs +.installed.cfg +lib +lib64 + +# Installer logs +pip-log.txt + +# Unit test / coverage reports +.coverage +cover +.tox +nosetests.xml +.testrepository +.venv + +# Translations +*.mo + +# Mr Developer +.mr.developer.cfg +.project +.pydevproject + +# Complexity +output/*.html +output/*/index.html + +# Sphinx +doc/build + +# oslo-config-generator +etc/*.sample + +# pbr generates these +AUTHORS +ChangeLog + +# Editors +*~ +.*.swp +.*sw? + +# Vagrant +.vagrant +vagrant/Vagrantfile.custom +vagrant/vagrantkey* + +# generated openrc +openrc + +# tests +tests/.cache/* diff --git a/docker/ironic-api/Dockerfile.j2 b/docker/ironic-api/Dockerfile.j2 new file mode 100644 index 0000000..00fc3c7 --- /dev/null +++ b/docker/ironic-api/Dockerfile.j2 @@ -0,0 +1,8 @@ +FROM {{ image_spec("ironic-base") }} +MAINTAINER {{ maintainer }} + +RUN apt-get install -y --no-install-recommends \ + mysql-client \ + && apt-get clean + +USER ironic diff --git a/docker/ironic-base/Dockerfile.j2 b/docker/ironic-base/Dockerfile.j2 new file mode 100644 index 0000000..3a34d7d --- /dev/null +++ b/docker/ironic-base/Dockerfile.j2 @@ -0,0 +1,15 @@ +FROM {{ image_spec("openstack-base") }} +MAINTAINER {{ maintainer }} + +{{ copy_sources("openstack/ironic", "/ironic") }} +{{ copy_sources("openstack/ironic-staging-drivers", "/ironic-staging-drivers") }} + +RUN useradd -U -m -d /home/ironic -G microservices ironic \ + && /var/lib/microservices/venv/bin/pip install --upgrade -c /ironic/requirements.txt /ironic \ + && /var/lib/microservices/venv/bin/pip install --upgrade -r /ironic-staging-drivers/ironic_staging_drivers/ansible/python-requirements.txt \ + && /var/lib/microservices/venv/bin/pip install --upgrade -c /ironic-staging-drivers/requirements.txt /ironic-staging-drivers \ + && mkdir -p /etc/ironic /etc/ironic/keys /var/lib/ironic /home/ironic/.ssh /var/log/ironic \ + && cp -r /ironic/etc/ironic/* /etc/ironic/ \ + && chown -R ironic: /etc/ironic /var/lib/ironic /var/log/ironic /home/ironic \ + && chmod -R 700 /home/ironic \ + && rm -rf /ironic /ironic-staging-drivers \ No newline at end of file diff --git a/docker/ironic-conductor/Dockerfile.j2 b/docker/ironic-conductor/Dockerfile.j2 new file mode 100644 index 0000000..7876af8 --- /dev/null +++ b/docker/ironic-conductor/Dockerfile.j2 @@ -0,0 +1,11 @@ +FROM {{ image_spec("ironic-base") }} +MAINTAINER {{ maintainer }} + +RUN apt-get install -y --no-install-recommends \ + qemu-utils \ + ipmitool \ + socat \ + openssh-client \ + && apt-get clean + +USER ironic diff --git a/docker/ironic-ipxe/Dockerfile.j2 b/docker/ironic-ipxe/Dockerfile.j2 new file mode 100644 index 0000000..4c34e81 --- /dev/null +++ b/docker/ironic-ipxe/Dockerfile.j2 @@ -0,0 +1,12 @@ +FROM {{ image_spec("ironic-base") }} +MAINTAINER {{ maintainer }} + +RUN apt-get install -y --no-install-recommends \ + nginx-light \ + && apt-get clean \ + && rm /etc/nginx/sites-available/default /etc/nginx/sites-enabled/default \ + && chown -R ironic: /etc/nginx /var/lib/nginx /var/log/nginx + +RUN chmod 777 /run + +USER ironic diff --git a/docker/ironic-pxe/Dockerfile.j2 b/docker/ironic-pxe/Dockerfile.j2 new file mode 100644 index 0000000..8d861ab --- /dev/null +++ b/docker/ironic-pxe/Dockerfile.j2 @@ -0,0 +1,14 @@ +FROM {{ image_spec("ironic-base") }} +MAINTAINER {{ maintainer }} + +RUN apt-get install -y --no-install-recommends \ + tftpd-hpa \ + syslinux-common \ + syslinux \ + pxelinux \ + ipxe \ + && apt-get clean + +COPY tftp-map-file /map-file + +USER root diff --git a/docker/ironic-pxe/tftp-map-file b/docker/ironic-pxe/tftp-map-file new file mode 100644 index 0000000..a99c3b3 --- /dev/null +++ b/docker/ironic-pxe/tftp-map-file @@ -0,0 +1,2 @@ +r ^([^/]) /var/lib/ironic/tftpboot/\1 +r ^(/tftpboot/) /var/lib/ironic/tftpboot/\2 diff --git a/service/files/defaults.yaml b/service/files/defaults.yaml new file mode 100644 index 0000000..a011da5 --- /dev/null +++ b/service/files/defaults.yaml @@ -0,0 +1,37 @@ +configs: + ironic: + api_port: + cont: 6385 + ingress: ironic + + username: ironic + password: password + + db: + username: ironic + password: password + name: ironic + + logging_debug: false + + automated_clean: false + enabled_drivers: "fake,pxe_ssh_ansible,pxe_ipmitool_ansible" + swift: + temp_url_key: password + + ipxe: + external_port: 6388 + use_swift: false + + ssh_key: false + + ansible: + use_ramdisk_callback: true + +sources: + openstack/ironic: + git_url: https://git.openstack.org/openstack/ironic.git + git_ref: stable/newton + openstack/ironic-staging-drivers: + git_url: https://git.openstack.org/openstack/ironic-staging-drivers + git_ref: master diff --git a/service/files/ironic.conf.j2 b/service/files/ironic.conf.j2 new file mode 100644 index 0000000..17805c7 --- /dev/null +++ b/service/files/ironic.conf.j2 @@ -0,0 +1,88 @@ +[DEFAULT] +debug = {{ ironic.logging_debug }} +use_syslog = false +use_stderr = true + +my_ip = {{ network_topology["private"]["address"] }} + +transport_url = rabbit://{{ rabbitmq.user }}:{{ rabbitmq.password }}@{{ address('rabbitmq', rabbitmq.port) }} + +enabled_drivers = {{ ironic.enabled_drivers }} + +enabled_network_interfaces = noop,flat +default_network_interface = flat + +[api] +public_endpoint = http://{{ address('ironic', ironic.api_port, external=True, with_scheme=False) }} +host_ip = {{ network_topology["private"]["address"] }} +port = {{ ironic.api_port.cont }} + +[database] +connection = mysql+pymysql://{{ ironic.db.username }}:{{ ironic.db.password }}@{{ address('mariadb', mariadb.port) }}/{{ ironic.db.name }} +max_retries = -1 + +[keystone_authtoken] +auth_uri = {{ address('keystone', keystone.public_port, with_scheme=True) }} +auth_url = {{ address('keystone', keystone.admin_port, with_scheme=True) }} +auth_type = password +project_domain_id = default +user_domain_id = default +project_name = service +username = {{ ironic.username }} +password = {{ ironic.password }} +memcached_servers = {{ address('memcached', memcached.port) }} + +[service_catalog] +auth_type = password +auth_url = {{ address('keystone', keystone.public_port, with_scheme=True) }} +project_domain_id = default +user_domain_id = default +project_name = service +username = {{ ironic.username }} +password = {{ ironic.password }} + +[conductor] +api_url = http://{{ address('ironic', ironic.api_port, external=True, with_scheme=False) }} +automated_clean = {{ ironic.automated_clean }} + +[neutron] +auth_type = password +auth_url = {{ address('keystone', keystone.public_port, with_scheme=True) }} +project_domain_id = default +user_domain_id = default +project_name = service +username = {{ ironic.username }} +password = {{ ironic.password }} + +url={{ address('neutron-server', neutron.server_port, with_scheme=True) }} + +[glance] +auth_type = password +auth_url = {{ address('keystone', keystone.public_port, with_scheme=True) }} +project_domain_id = default +user_domain_id = default +project_name = service +username = {{ ironic.username }} +password = {{ ironic.password }} + +glance_api_servers = {{ address('glance-api', glance.api_port, with_scheme=True) }} + +swift_endpoint_url = http://{{ address('radosgw', radosgw.port, external=True, with_scheme=False) }} +swift_temp_url_key = {{ ironic.swift.temp_url_key }} +temp_url_endpoint_type = radosgw + +[pxe] +pxe_append_params = nofb nomodeset vga=normal +tftp_root = /var/lib/ironic/tftpboot +tftp_master_path = /var/lib/ironic/tftpboot/master_images +ipxe_enabled = true +ipxe_use_swift = {{ ironic.ipxe.use_swift }} +pxe_bootfile_name=undionly.kpxe +pxe_config_template=$pybasedir/drivers/modules/ipxe_config.template + +[deploy] +http_root=/var/lib/ironic/httpboot +http_url=http://{{ network_topology["private"]["address"] }}:{{ ironic.ipxe.external_port }} + +[ansible] +use_ramdisk_callback = {{ ironic.ansible.use_ramdisk_callback }} diff --git a/service/files/nginx-ipxe.conf.j2 b/service/files/nginx-ipxe.conf.j2 new file mode 100644 index 0000000..04f7732 --- /dev/null +++ b/service/files/nginx-ipxe.conf.j2 @@ -0,0 +1,4 @@ +server { + listen {{ network_topology["private"]["address"] }}:{{ ironic.ipxe.external_port }}; + root /var/lib/ironic/httpboot; +} diff --git a/service/files/pxe-bootstrap.sh b/service/files/pxe-bootstrap.sh new file mode 100644 index 0000000..3bd9f23 --- /dev/null +++ b/service/files/pxe-bootstrap.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +set -e + +mkdir -p /var/lib/ironic/tftpboot /var/lib/ironic/httpboot + +cp \ + /usr/lib/PXELINUX/pxelinux.0 \ + /usr/lib/syslinux/modules/bios/chain.c32 \ + /usr/lib/syslinux/modules/bios/ldlinux.c32 \ + /usr/lib/ipxe/undionly.kpxe \ + /var/lib/ironic/tftpboot + +chown -R ironic:ironic /var/lib/ironic diff --git a/service/files/ssh_key.j2 b/service/files/ssh_key.j2 new file mode 100644 index 0000000..f9f31b6 --- /dev/null +++ b/service/files/ssh_key.j2 @@ -0,0 +1,3 @@ +{% if ironic.ssh_key -%} +{{ ironic.ssh_key}} +{% endif %} diff --git a/service/ironic-api.yaml b/service/ironic-api.yaml new file mode 100644 index 0000000..755a3e8 --- /dev/null +++ b/service/ironic-api.yaml @@ -0,0 +1,73 @@ +dsl_version: 0.1.0 +service: + name: ironic-api + ports: + - {{ ironic.api_port }} + containers: + - name: ironic-api + image: ironic-api + privileged: true + probes: + readiness: "true" + liveness: + command: "true" + type: "exec" + pre: + - name: ironic-db-create + type: single + command: mysql -v -u root -p{{ db.root_password }} -h {{ address('mariadb') }} -P {{ mariadb.port.cont }} -e + 'create database `{{ ironic.db.name }}`; grant all privileges on `{{ ironic.db.name }}`.* to + "{{ ironic.db.username }}"@"%" identified by "{{ ironic.db.password }}"' + dependencies: + - mariadb + - name: ironic-db-sync + type: single + command: ironic-dbsync + dependencies: + - ironic-db-create + files: + - ironic.conf + - name: ironic-user-create + type: single + command: openstack user create --project service --password {{ ironic.password }} {{ ironic.username }} + dependencies: + - keystone-create-project + - name: ironic-role-add + dependencies: + - ironic-user-create + type: single + command: openstack role add --project service --user {{ ironic.username }} admin + - name: ironic-service-create + dependencies: + - keystone + type: single + command: openstack service create --name ironic --description "OpenStack Baremetal" baremetal + - name: ironic-public-endpoint-create + dependencies: + - ironic-service-create + type: single + command: openstack endpoint create --region RegionOne baremetal public + {{ address('ironic-api', ironic.api_port, external=True, with_scheme=True) }} + - name: ironic-internal-endpoint-create + dependencies: + - ironic-service-create + type: single + command: openstack endpoint create --region RegionOne baremetal internal + {{ address('ironic-api', ironic.api_port, with_scheme=True) }} + - name: ironic-admin-endpoint-create + dependencies: + - ironic-service-create + type: single + command: openstack endpoint create --region RegionOne baremetal admin + {{ address('ironic-api', ironic.api_port, with_scheme=True) }} + daemon: + command: ironic-api --config-file /etc/ironic/ironic.conf + files: + - ironic.conf + dependencies: + - rabbitmq +files: + ironic.conf: + path: /etc/ironic/ironic.conf + content: ironic.conf.j2 + perm: "0600" diff --git a/service/ironic-conductor.yaml b/service/ironic-conductor.yaml new file mode 100644 index 0000000..1deb695 --- /dev/null +++ b/service/ironic-conductor.yaml @@ -0,0 +1,87 @@ +dsl_version: 0.1.0 +service: + name: ironic-conductor + hostNetwork: true + kind: DaemonSet + containers: + - name: ironic-conductor + image: ironic-conductor + probes: + readiness: "true" + liveness: + command: "true" + type: "exec" + volumes: + - name: ironic + type: host + path: /var/lib/ironic + pre: + - name: ironic-post-swift-tempurl-key + dependencies: + - radosgw + type: single + command: swift --insecure + --os-auth-url {{ address('keystone', keystone.public_port, with_scheme=True) }}/v3 + --os-project-name service --os-project-domain-name default --os-user-domain-name default + --os-username {{ glance.user }} --os-password {{ glance.password }} --os-endpoint-type internalURL + post -m "Temp-URL-Key:{{ ironic.swift.temp_url_key }}" + daemon: + command: ironic-conductor --config-file /etc/ironic/ironic.conf + files: + - ironic.conf + - ssh_key + dependencies: + - ironic-db-sync + - ironic-post-swift-tempurl-key + - name: ironic-pxe + image: ironic-pxe + probes: + readiness: "true" + liveness: + command: "true" + type: "exec" + volumes: + - name: ironic + type: host + path: /var/lib/ironic + pre: + - name: pxe-bootstrap + command: /opt/ccp/bin/pxe-bootstrap.sh + daemon: + command: in.tftpd --verbose --foreground --user root --map-file /map-file + --address {% raw %}{{ network_topology["private"]["address"] }}{% endraw %}:69 + /var/lib/ironic/tftpboot + files: + - pxe-bootstrap.sh + - name: ironic-ipxe + image: ironic-ipxe + probes: + readiness: "true" + liveness: + command: "true" + type: "exec" + volumes: + - name: ironic + type: host + path: /var/lib/ironic + daemon: + command: nginx -g 'daemon off; error_log stderr;' + files: + - nginx-ipxe.conf +files: + ironic.conf: + path: /etc/ironic/ironic.conf + content: ironic.conf.j2 + perm: "0600" + pxe-bootstrap.sh: + path: /opt/ccp/bin/pxe-bootstrap.sh + content: pxe-bootstrap.sh + perm: "0755" + nginx-ipxe.conf: + path: /etc/nginx/sites-enabled/nginx-ipxe.conf + content: nginx-ipxe.conf.j2 + perm: "0644" + ssh_key: + path: /home/ironic/.ssh/id_rsa + content: ssh_key.j2 + perm: "0400" diff --git a/test-requirements.txt b/test-requirements.txt new file mode 100644 index 0000000..f4b690a --- /dev/null +++ b/test-requirements.txt @@ -0,0 +1,2 @@ +yamllint>=1.3.2 +bashate>=0.2 diff --git a/tools/yamllint.sh b/tools/yamllint.sh new file mode 100755 index 0000000..6e84445 --- /dev/null +++ b/tools/yamllint.sh @@ -0,0 +1,5 @@ +#!/bin/bash +set -ex + +workdir=$(dirname $0) +yamllint -c $workdir/yamllint.yaml $(find . -not -path '*/\.*' -type f -name '*.yaml') diff --git a/tools/yamllint.yaml b/tools/yamllint.yaml new file mode 100644 index 0000000..6c2e4a7 --- /dev/null +++ b/tools/yamllint.yaml @@ -0,0 +1,21 @@ +extends: default + +rules: + braces: + max-spaces-inside: 1 + comments: + level: error + comments-indentation: + level: warning + document-end: + present: no + document-start: + level: error + present: no + empty-lines: + max: 1 + max-start: 0 + max-end: 0 + line-length: + level: warning + max: 120 diff --git a/tox.ini b/tox.ini new file mode 100644 index 0000000..a554d09 --- /dev/null +++ b/tox.ini @@ -0,0 +1,15 @@ +[tox] +minversion = 1.6 +envlist = linters,bashate +skipsdist = True + +[testenv] +deps = -r{toxinidir}/test-requirements.txt + +[testenv:linters] +commands = + {toxinidir}/tools/yamllint.sh + +[testenv:bashate] +whitelist_externals = bash +commands = bash -c "find {toxinidir} -type f -name '*.sh' -not -path '*/.tox/*' -print0 | xargs -0 bashate -v"