diff --git a/Makefile b/Makefile
index 79a685f..f402165 100644
--- a/Makefile
+++ b/Makefile
@@ -2,6 +2,7 @@
# IMG ?= controller:latest
CONTROLLER_IMG ?= quay.io/airshipit/vino
NODE_LABELER_IMG ?= quay.io/airshipit/nodelabeler
+VINO_BUILDER_IMG ?= quay.io/airshipit/vino-builder
# Produce CRDs that work back to Kubernetes 1.16
CRD_OPTIONS ?= crd:crdVersions=v1
@@ -78,6 +79,11 @@ docker-build-controller:
docker-build-nodelabeler:
docker build -f nodelabeler/Dockerfile . ${DOCKER_PROXY_FLAGS} -t ${NODE_LABELER_IMG}
+# Build the vino-builder docker image
+# If DOCKER_PROXY_FLAGS values are empty, we are fine with that
+docker-build-vino-builder:
+ docker build -f vino-builder/Dockerfile . ${DOCKER_PROXY_FLAGS} -t ${VINO_BUILDER_IMG}
+
# Push the controller docker image
docker-push-controller:
docker push ${CONTROLLER_IMG}
@@ -86,6 +92,10 @@ docker-push-controller:
docker-push-nodelabeler:
docker push ${NODE_LABELER_IMG}
+# Push the vino-builder docker image
+docker-push-vino-builder:
+ docker push ${VINO_BUILDER_IMG}
+
# Generate API reference documentation
api-docs: gen-crd-api-reference-docs
$(API_REF_GEN) -api-dir=./pkg/api/v1 -config=./hack/api-docs/config.json -template-dir=./hack/api-docs/template -out-file=./docs/api/vino.md
diff --git a/config/manager/daemonset-template.yaml b/config/manager/daemonset-template.yaml
index f6a3c76..86432db 100644
--- a/config/manager/daemonset-template.yaml
+++ b/config/manager/daemonset-template.yaml
@@ -114,7 +114,7 @@ spec:
ports:
- containerPort: 8001
hostPort: 8001
- image: quay.io/airshipit/vino-builder:latest-ubuntu_bionic
+ image: quay.io/airshipit/vino-builder
imagePullPolicy: IfNotPresent
volumeMounts:
- name: flavors
diff --git a/playbooks/integration-test-airshipctl.yaml b/playbooks/integration-test-airshipctl.yaml
index 1cce7da..199d117 100644
--- a/playbooks/integration-test-airshipctl.yaml
+++ b/playbooks/integration-test-airshipctl.yaml
@@ -22,6 +22,7 @@
./tools/deployment/install-airship.sh
./tools/deployment/configure-airship.sh
make docker-build-controller
+ make docker-build-vino-builder
./tools/deployment/run-test-plan.sh
args:
chdir: "{{ zuul.project.src_dir }}"
diff --git a/roles/vino-build-images/tasks/main.yaml b/roles/vino-build-images/tasks/main.yaml
index 597a602..f4c0d85 100644
--- a/roles/vino-build-images/tasks/main.yaml
+++ b/roles/vino-build-images/tasks/main.yaml
@@ -39,5 +39,19 @@
- name: Verify nodelabeler image exists
shell: docker image inspect quay.io/airshipit/nodelabeler
+ args:
+ chdir: "{{ zuul.project.src_dir }}"
+
+- name: Buid vino-builder image
+ make:
+ chdir: "{{ zuul.project.src_dir }}"
+ target: docker-build-vino-builder
+ params:
+ PROXY: "{{ proxy.http }}"
+ NO_PROXY: "{{ proxy.noproxy }}"
+ USE_PROXY: "{{ proxy.enabled | lower }}"
+
+- name: Verify vino-builder image exists
+ shell: docker image inspect quay.io/airshipit/vino-builder
args:
chdir: "{{ zuul.project.src_dir }}"
\ No newline at end of file
diff --git a/roles/vino-publish-images/tasks/main.yaml b/roles/vino-publish-images/tasks/main.yaml
index 2bd8e36..8e6f3ac 100644
--- a/roles/vino-publish-images/tasks/main.yaml
+++ b/roles/vino-publish-images/tasks/main.yaml
@@ -44,4 +44,9 @@
- name: Push nodelabeler image with latest tag
make:
chdir: "{{ zuul.project.src_dir }}"
- target: docker-push-nodelabeler
\ No newline at end of file
+ target: docker-push-nodelabeler
+
+ - name: Push vino-builder image with latest tag
+ make:
+ chdir: "{{ zuul.project.src_dir }}"
+ target: docker-push-vino-builder
\ No newline at end of file
diff --git a/tools/deployment/deploy-vino.sh b/tools/deployment/deploy-vino.sh
index 7dd4f98..e8130c9 100755
--- a/tools/deployment/deploy-vino.sh
+++ b/tools/deployment/deploy-vino.sh
@@ -3,6 +3,7 @@
set -xe
sudo snap install kustomize && sudo snap install go --classic
make docker-build-controller
+make docker-build-vino-builder
make deploy
kubectl get po -A
#Wait for vino controller manager Pod.
diff --git a/vino-builder/Dockerfile b/vino-builder/Dockerfile
new file mode 100644
index 0000000..7450c60
--- /dev/null
+++ b/vino-builder/Dockerfile
@@ -0,0 +1,45 @@
+FROM ubuntu:18.04
+
+SHELL ["bash", "-exc"]
+ENV DEBIAN_FRONTEND noninteractive
+
+ARG k8s_version=v1.18.3
+ARG kubectl_url=https://storage.googleapis.com/kubernetes-release/release/"${k8s_version}"/bin/linux/amd64/kubectl
+
+
+# Update distro and install common reqs
+RUN apt-get update ;\
+ apt-get dist-upgrade -y ;\
+ apt-get install -y \
+ python3-minimal \
+ python3-pip \
+ python3-setuptools \
+ python3-libvirt \
+ libvirt-clients \
+ python3-netaddr \
+ python3-lxml \
+ curl \
+ make \
+ sudo \
+ iproute2 \
+ bridge-utils \
+ iputils-ping \
+ net-tools \
+ less \
+ jq \
+ vim \
+ openssh-client ;\
+ curl -sSLo /usr/local/bin/kubectl "${kubectl_url}" ;\
+ chmod +x /usr/local/bin/kubectl ;\
+ pip3 install --upgrade pip ;\
+ pip3 install --upgrade wheel ;\
+ pip3 install --upgrade ansible ;\
+ rm -rf /var/lib/apt/lists/*
+
+COPY vino-builder/assets /opt/assets/
+RUN cp -ravf /opt/assets/* / ;\
+ rm -rf /opt/assets
+
+RUN chmod +x /entrypoint.sh
+
+ENTRYPOINT /entrypoint.sh
diff --git a/vino-builder/assets/entrypoint.sh b/vino-builder/assets/entrypoint.sh
new file mode 100644
index 0000000..b089f50
--- /dev/null
+++ b/vino-builder/assets/entrypoint.sh
@@ -0,0 +1,70 @@
+#!/bin/bash
+
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+READINESS_CHECK_FILE="/tmp/healthy"
+
+## Remove healthy status before starting
+[ -f "${READINESS_CHECK_FILE}" ] && rm ${READINESS_CHECK_FILE}
+
+# wait for libvirt socket to be ready
+TIMEOUT=300
+while [[ ! -e /var/run/libvirt/libvirt-sock ]]; do
+ if [[ ${TIMEOUT} -gt 0 ]]; then
+ let TIMEOUT-=1
+ echo "Waiting for libvirt socket at /var/run/libvirt/libvirt-sock"
+ sleep 1
+ else
+ echo "ERROR: libvirt did not start in time (socket missing) /var/run/libvirt/libvirt-sock"
+ exit 1
+ fi
+done
+
+# wait for dynamic data to be ready
+# data is node-specific, so it will be passed as a node annotations
+# of the form
+# metadata:
+# annotations:
+# airshipit.org/vino.network-values: |
+# bunch-of-yaml
+DYNAMIC_DATA_FILE=/var/lib/vino-builder/dynamic.yaml
+TIMEOUT=300
+while [[ ${TIMEOUT} -gt 0 ]]; do
+ let TIMEOUT-=10
+ if [[ ${TIMEOUT} -le 0 ]]; then
+ echo "ERROR: vino-builder dynamic data was not ready in time"
+ exit 1
+ fi
+ kubectl get node $HOSTNAME -o=jsonpath="{.metadata.annotations.airshipit\.org/vino\.network-values}" > $DYNAMIC_DATA_FILE
+ if [[ -s $DYNAMIC_DATA_FILE ]]; then
+ break
+ fi
+ echo "vino-builder dynamic data not ready yet - sleeping for 10 seconds..."
+ sleep 10
+done
+
+ansible-playbook -v \
+ -e @/var/lib/vino-builder/flavors/flavors.yaml \
+ -e @/var/lib/vino-builder/flavor-templates/flavor-templates.yaml \
+ -e @/var/lib/vino-builder/network-templates/network-templates.yaml \
+ -e @/var/lib/vino-builder/storage-templates/storage-templates.yaml \
+ -e @$DYNAMIC_DATA_FILE \
+ /playbooks/vino-builder.yaml
+
+touch ${READINESS_CHECK_FILE}
+
+while true; do
+ sleep infinity
+done
\ No newline at end of file
diff --git a/vino-builder/assets/playbooks/roles/libvirt/defaults/main.yml b/vino-builder/assets/playbooks/roles/libvirt/defaults/main.yml
new file mode 100644
index 0000000..d2a4f49
--- /dev/null
+++ b/vino-builder/assets/playbooks/roles/libvirt/defaults/main.yml
@@ -0,0 +1 @@
+libvirt_uri: qemu:///system
\ No newline at end of file
diff --git a/vino-builder/assets/playbooks/roles/libvirt/library/core_allocation.py b/vino-builder/assets/playbooks/roles/libvirt/library/core_allocation.py
new file mode 100644
index 0000000..eb25684
--- /dev/null
+++ b/vino-builder/assets/playbooks/roles/libvirt/library/core_allocation.py
@@ -0,0 +1,160 @@
+#!/usr/bin/python
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# generate_baremetal_macs method ripped from
+# openstack/tripleo-incubator/scripts/configure-vm
+
+import math
+import random
+import sys
+import fnmatch
+import os
+from itertools import chain
+import json
+
+DOCUMENTATION = '''
+---
+module: core_allocation
+version_added: "1.0"
+short_description: Allocate numa aligned cores for libvirt domains and track allocations
+description:
+ - Generate numa aligned cores for libvirt domains and track allocations
+'''
+
+PATH_SYS_DEVICES_NODE = "/sys/devices/system/node"
+
+def _parse_range(rng):
+ parts = rng.split('-')
+ if 1 > len(parts) > 2:
+ raise ValueError("Bad range: '%s'" % (rng,))
+ parts = [int(i) for i in parts]
+ start = parts[0]
+ end = start if len(parts) == 1 else parts[1]
+ if start > end:
+ end, start = start, end
+ return range(start, end + 1)
+
+def _parse_range_list(rngs):
+ return sorted(set(chain(*[_parse_range(rng) for rng in rngs.split(',')])))
+
+def get_numa_cores():
+ """Return cores as a dict of numas each with their expanded core lists"""
+ numa_core_dict = {}
+ for root, dir, files in os.walk(PATH_SYS_DEVICES_NODE):
+ for numa in fnmatch.filter(dir, "node*"):
+ numa_path = os.path.join(PATH_SYS_DEVICES_NODE, numa)
+ cpulist = os.path.join(numa_path, "cpulist")
+ with open(cpulist, 'r') as f:
+ parsed_range_list = _parse_range_list(f.read())
+ numa_core_dict[numa] = parsed_range_list
+ return numa_core_dict
+
+def allocate_cores(nodes, flavors, exclude_cpu):
+ """Return"""
+
+ core_state = {}
+
+ try:
+ f = open('/etc/libvirt/vino-cores.json', 'r')
+ core_state = json.loads(f.read())
+ except:
+ pass
+
+ # instantiate initial inventory - we don't support the inventory
+ # changing (e.g. adding cores)
+ if 'inventory' not in core_state:
+ core_state['inventory'] = get_numa_cores()
+
+ # explode exclude cpu list - we don't support adjusting this after-the-fact
+ # right now
+ if 'exclude' not in core_state:
+ exclude_core_list = _parse_range_list(exclude_cpu)
+ core_state['exclude'] = exclude_core_list
+
+ # reduce inventory by exclude
+ if 'available' not in core_state:
+ core_state['available'] = {}
+ for numa in core_state['inventory'].keys():
+ numa_available = [x for x in core_state['inventory'][numa] if x not in core_state['exclude']]
+ core_state['available'][numa] = numa_available
+
+ if 'assignments' not in core_state:
+ core_state['assignments'] = {}
+
+ # walk the nodes, consuming inventory or discovering previous allocations
+ # address the case where previous != desired - delete previous, re-run
+ for node in nodes:
+
+ flavor = node['bmhLabels']['airshipit.org/k8s-role']
+ vcpus = flavors[flavor]['vcpus']
+
+ for num_node in range(0, node['count']):
+
+ # generate a unique name such as master-0, master-1
+ node_name = node['name'] + '-' + str(num_node)
+
+ # extract the core count
+ core_count = int(vcpus)
+
+ # discover any previous allocation
+ if 'assignments' in core_state:
+ if node_name in core_state['assignments']:
+ if len(core_state['assignments'][node_name]) == core_count:
+ continue
+ else:
+ # TODO: support releasing the cores and adding them back
+ # to available
+ raise Exception("Existing assignment exists for node %s but does not match current core count needed" % node_name)
+
+ # allocate the cores
+ allocated=False
+ for numa in core_state['available']:
+ if core_count <= len(core_state['available'][numa]):
+ allocated=True
+ cores_to_use = core_state['available'][numa][:core_count]
+ core_state['assignments'][node_name] = cores_to_use
+ core_state['available'][numa] = core_state['available'][numa][core_count:]
+ break
+ else:
+ continue
+ if not allocated:
+ raise Exception("Unable to find sufficient cores (%s) for node %s (available was %r)" % (core_count, node_name, core_state['available']))
+
+ # return a dict of nodes: cores
+ # or error if insufficient
+ with open('/etc/libvirt/vino-cores.json', 'w') as f:
+ f.write(json.dumps(core_state))
+
+ return core_state['assignments']
+
+
+def main():
+ module = AnsibleModule(
+ argument_spec=dict(
+ nodes=dict(required=True, type='list'),
+ flavors=dict(required=True, type='dict'),
+ exclude_cpu=dict(required=True, type='str')
+ )
+ )
+ result = allocate_cores(module.params["nodes"],
+ module.params["flavors"],
+ module.params["exclude_cpu"])
+ module.exit_json(**result)
+
+# see http://docs.ansible.com/developing_modules.html#common-module-boilerplate
+from ansible.module_utils.basic import AnsibleModule # noqa
+
+
+if __name__ == '__main__':
+ main()
\ No newline at end of file
diff --git a/vino-builder/assets/playbooks/roles/libvirt/tasks/create-domain.yaml b/vino-builder/assets/playbooks/roles/libvirt/tasks/create-domain.yaml
new file mode 100644
index 0000000..f6768f5
--- /dev/null
+++ b/vino-builder/assets/playbooks/roles/libvirt/tasks/create-domain.yaml
@@ -0,0 +1,52 @@
+- name: debug print loop
+ debug:
+ msg: "outer item={{ node }} inner item={{item}}"
+ loop: "{{ range(0,node.count)|list }}"
+
+- name: debug print virsh xml domain
+ debug:
+ msg: "{{ flavorTemplates[node['bmhLabels']['airshipit.org/k8s-role']]['domainTemplate'] }}"
+ loop: "{{ range(0,node.count)|list }}"
+
+- name: get state of existing volumes
+ shell: |
+ virsh vol-list vino-default
+ register: vol_list
+
+- name: write out domain volume request xml
+ copy: content="{{ flavorTemplates[node['bmhLabels']['airshipit.org/k8s-role']]['volumeTemplate'] }}" dest=/tmp/vol-{{item}}.xml
+ loop: "{{ range(0,node.count)|list }}"
+
+- name: create domain volume if it doesn't exist
+ shell: |
+ virsh vol-create vino-default /tmp/vol-{{item}}.xml
+ loop: "{{ range(0,node.count)|list }}"
+ when: "node.name + '-' + item|string not in vol_list.stdout"
+
+- name: ensure vino instance state directory exists
+ file:
+ path: /var/lib/libvirt/vino-instances
+ state: directory
+ recurse: yes
+ owner: root
+ group: root
+
+# the virt community plugin does not handle pushing out updates
+# to domains, so we must shell out here instead
+
+- name: write out domain volume request xml
+ copy: content="{{ flavorTemplates[node['bmhLabels']['airshipit.org/k8s-role']]['domainTemplate'] }}" dest=/tmp/domain-{{item}}.xml
+ loop: "{{ range(0,node.count)|list }}"
+
+- name: virsh define domain
+ shell: |
+ virsh define /tmp/domain-{{item}}.xml
+ loop: "{{ range(0,node.count)|list }}"
+
+#- name: set vm to running
+# virt:
+# name: "{{ node.name + '-' + item|string}}"
+# state: running
+# autostart: yes
+# loop: "{{ range(0,node.count)|list }}"
+# ignore_errors: true
diff --git a/vino-builder/assets/playbooks/roles/libvirt/tasks/create-network.yaml b/vino-builder/assets/playbooks/roles/libvirt/tasks/create-network.yaml
new file mode 100644
index 0000000..d3e7b3d
--- /dev/null
+++ b/vino-builder/assets/playbooks/roles/libvirt/tasks/create-network.yaml
@@ -0,0 +1,36 @@
+# Facts will be available as 'ansible_libvirt_networks'
+- name: initially gather facts on existing virsh networks
+ virt_net:
+ command: facts
+ name: "" # this attribute is not needed but required
+ uri: "{{ libvirt_uri }}"
+ ignore_errors: true
+
+- name: Print value of ansible networks
+ debug:
+ msg: "Value of ansible_libvirt_networks is {{ ansible_libvirt_networks }}"
+
+# TODO(alanmeadows): deal with updates as once its defined we will
+# never re-define it
+- name: add networks defined if they do not already exist
+ virt_net:
+ state: present
+ # looks like setting name here is a redundant, the name is anyways taken from the template xml file, but should set it to make virt_pool module happy.
+ name: "{{ item.name }}"
+ xml: "{{ item.libvirtTemplate }}"
+ uri: "{{ libvirt_uri }}"
+ vars:
+ nodebridgegw: ipam.bridge_ip
+
+- name: activate the network
+ virt_net:
+ state: active
+ name: "{{ item.name }}"
+ uri: "{{ libvirt_uri }}"
+
+# these are idempotent so require no conditional checks
+- name: autostart the network
+ virt_net:
+ autostart: yes
+ name: "{{ item.name }}"
+ uri: "{{ libvirt_uri }}"
diff --git a/vino-builder/assets/playbooks/roles/libvirt/tasks/create-storage.yaml b/vino-builder/assets/playbooks/roles/libvirt/tasks/create-storage.yaml
new file mode 100644
index 0000000..64dfd23
--- /dev/null
+++ b/vino-builder/assets/playbooks/roles/libvirt/tasks/create-storage.yaml
@@ -0,0 +1,18 @@
+# Facts will be available as 'ansible_libvirt_pools'
+- name: initially gather facts on existing virsh pool
+ virt_pool:
+ command: facts
+ uri: "{{ libvirt_uri }}"
+
+- name: define storage the storage pool
+ virt_pool:
+ state: present
+ name: "{{ item.name }}"
+ uri: "{{ libvirt_uri }}"
+ xml: "{{item.libvirtTemplate}}"
+
+- name: activate the storage pool
+ virt_pool:
+ state: active
+ name: "{{ item.name }}"
+ uri: "{{ libvirt_uri }}"
diff --git a/vino-builder/assets/playbooks/roles/libvirt/tasks/main.yml b/vino-builder/assets/playbooks/roles/libvirt/tasks/main.yml
new file mode 100644
index 0000000..7e28516
--- /dev/null
+++ b/vino-builder/assets/playbooks/roles/libvirt/tasks/main.yml
@@ -0,0 +1,39 @@
+##########################################
+# configure storage #
+##########################################
+
+- name: create storage
+ include_tasks: create-storage.yaml
+ loop: "{{ libvirtStorage }}"
+
+##########################################
+# configure networks #
+##########################################
+
+# - name: create network
+# include_tasks: create-network.yaml
+# loop: "{{ libvirtNetworks }}"
+
+##########################################
+# configure domains #
+##########################################
+
+- name: allocate domain cores
+ core_allocation:
+ nodes: "{{ nodes }}"
+ flavors: "{{ flavors }}"
+ exclude_cpu: "{{ configuration.cpuExclude }}"
+ register: node_core_map
+ when: nodes
+
+- name: debug print node_core_map
+ debug:
+ msg: "node_core_map = {{ node_core_map }}"
+
+- name: define domain outer loop
+ include_tasks: create-domain.yaml
+ loop: "{{ nodes }}"
+ loop_control:
+ loop_var: node
+
+
diff --git a/vino-builder/assets/playbooks/sample-vino-ansible-input.yaml b/vino-builder/assets/playbooks/sample-vino-ansible-input.yaml
new file mode 100644
index 0000000..a73bc71
--- /dev/null
+++ b/vino-builder/assets/playbooks/sample-vino-ansible-input.yaml
@@ -0,0 +1,198 @@
+configuration:
+ cpuExclude: 0-1,54-60
+ redfishCredentialSecret:
+ name: redfishSecret
+ namespace: airship-system
+networks:
+ - name: management
+ subnet: 192.168.2.0/20
+ allocationStart: 192.168.2.10
+ allocationStop: 192.168.2.14 # docs should specify that the range should = number of vms (to permit future expansion over multiple vino crs etc)
+ routes:
+ - to: 10.0.0.0/24
+ via: "{{ ipam.bridge_ip | default(omit) }}" # vino will need to populate this from the nodelabel value `airshipit.org/vino.nodebridgegw`
+ dns_servers: ["135.188.34.124"]
+ - name: mobility-gn
+ subnet: 169.0.0.0/24
+ routes:
+ - to: 0.0.0.0/0
+ via: 169.0.0.1
+ allocationStart: 169.0.0.10
+ allocationStop: 169.0.0.254
+libvirtNetworks:
+ - name: management
+ libvirtTemplate: |
+
+ management
+
+
+
+
+
+
+
+
+
+
+# - name: mobility-gn
+# libvirtTemplate:
+libvirtStorage:
+ - name: vino-default
+ libvirtTemplate: |
+
+ vino-default
+
+ /var/lib/libvirt/vino
+
+ 0711
+ 0
+ 0
+
+
+
+libvirtDomains:
+ master:
+ volumeTemplate: |
+ {% set nodename = node.name + '-' + item|string %}
+
+ {{ nodename }}
+ 0
+ {{ node.instance.rootSize }}
+
+ domainTemplate: |
+ {% set nodename = node.name + '-' + item|string %}
+
+ {{ nodename }}
+ {{ nodename | hash('md5') }}
+
+ {% for flavor in node.labels %}
+ {% for key in flavor.keys() %}
+ {% if key == 'vm-flavor' %}
+ {{ flavor[key] }}
+ {% endif %}
+ {% endfor %}
+ {% endfor %}
+ {{ ansible_date_time.date }}
+
+ {{ node.instance.memory }}
+ {% if node.instance.hugepages %}
+
+
+
+
+ {% endif %}
+ {{ node.instance.vcpu }}
+ # function to produce list of cpus, in same numa (controled by bool), state will need to be tracked via file on hypervisor host. gotpl psudo:
+
+ 8192
+ {% for core in node_core_map[nodename] %}
+
+ {% endfor %}
+
+
+
+ /machine
+
+
+ hvm
+
+
+
+
+
+
+
+
+
+
+
+
+ destroy
+ restart
+ destroy
+
+ /usr/bin/qemu-system-x86_64
+
+ # for each disk requested
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ # for each interface defined in vino, e.g.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +42424:+104
+
+
+ worker-standard:
+ libvirtTemplate: ...
+nodes:
+ - name: master
+ labels:
+ - vm-flavor: master
+ instance:
+ memory: 8
+ vcpu: 2
+ hugepages: true
+ rootSize: 30
+ count: 2
+ BMHNetworkTemplate:
+ name: configMapFooThatsGoTplForNetwork
+ namespace: foo
+ field: bmhnetwork
+ - name: worker-standard
+ labels:
+ - vm-flavor: worker-standard
+ instance:
+ memory: 8
+ vcpu: 2
+ hugepages: true
+ rootSize: 30
+ count: 0
+ libvirtTemplate: |
+ foobar
+ BMHNetworkTemplate:
+ name: configMapFooThatsGoTplForNetwork
+ namespace: foo
+ field: bmhnetwork
\ No newline at end of file
diff --git a/vino-builder/assets/playbooks/vino-builder.yaml b/vino-builder/assets/playbooks/vino-builder.yaml
new file mode 100644
index 0000000..6ba068c
--- /dev/null
+++ b/vino-builder/assets/playbooks/vino-builder.yaml
@@ -0,0 +1,46 @@
+
+# Licensed under the Apache License, Version 2.0 (the "License");
+
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+ # - host-annotator that populates the k8s node object with approprite annotations
+ # - report back information such as:
+ # - vminfra-bridge ip address as label to k8s node
+ # - sushy-tools ip endpoint for BMC control
+ # - vino-builder (ansible) that that consumes the `ConfigMap` that contains everything necessary for libvirt to define the virtual machines and networks on the host and does both green-field generation of VM resources and understands if the `ConfigMap` changed and will handle those lifecycle updates. There is no need to stage or coordinate changes to these `ConfigMap` resources as they will result in a no-op `virsh update` which only take effect with a VM stop/start.
+ # - do the following (assumption is all of this is idempotent for day 2):
+ # - interogate host
+ # - prevalidate (is kvm loaded, etc)
+ # - define host facts (eg cpu list, vf list, etc)
+ # - interogate existing vms or state recording somewhere
+ # - collect resources in use
+ # - what cores are in use
+ # - what vfs are in use
+ # - memory in use
+ # - define libvirt networks
+ # - define libvirt storage pools
+ # - ensure appropriate qcows exist
+ # - define libvirt domains
+ # - ensure mem/cpu aligned in one numa
+ # - new domain validation (only on new domains):
+ # - do a simple domain start/destroy test via redfish.
+ # - wait for dhcp req on admin interface?
+
+---
+- hosts: localhost
+
+ tasks:
+
+ # generate libvirt definitions for storage, networks, and domains
+ - name: process libvirt definitions
+ include_role:
+ name: libvirt
\ No newline at end of file