aboutsummaryrefslogtreecommitdiff
path: root/contrib
diff options
context:
space:
mode:
authorChristian Berendt <berendt@betacloud-solutions.de>2016-10-14 12:55:26 +0200
committerChristian Berendt <berendt@betacloud-solutions.de>2016-10-14 12:57:49 +0200
commitb725bd09dd73edf22bdd67bd13359e2a7d8b0796 (patch)
treeb088b5f48a51df9dfb40938b1f573f0b6f1685d5 /contrib
parentdbf05f076fb2394439afcee95de3922a83f92219 (diff)
downloadkolla-ansible-b725bd09dd73edf22bdd67bd13359e2a7d8b0796.tar.gz
kolla-ansible-b725bd09dd73edf22bdd67bd13359e2a7d8b0796.zip
Move demos and dev directory into a new contrib directory
TrivialFix Change-Id: Ifb8f19afa1514488bd288670d08b96f84982a4e1
Diffstat (limited to 'contrib')
-rw-r--r--contrib/demos/heat/README.rst15
-rwxr-xr-xcontrib/demos/heat/launch11
-rw-r--r--contrib/demos/heat/steak-rg.yaml43
-rw-r--r--contrib/demos/heat/steak.yaml54
-rwxr-xr-xcontrib/demos/magnum/redis5
-rw-r--r--contrib/demos/magnum/redis-kube/README.rst197
-rw-r--r--contrib/demos/magnum/redis-kube/redis-controller.yaml28
-rw-r--r--contrib/demos/magnum/redis-kube/redis-master.yaml33
-rw-r--r--contrib/demos/magnum/redis-kube/redis-proxy.yaml14
-rw-r--r--contrib/demos/magnum/redis-kube/redis-sentinel-controller.yaml23
-rw-r--r--contrib/demos/magnum/redis-kube/redis-sentinel-service.yaml13
-rwxr-xr-xcontrib/demos/magnum/start40
-rwxr-xr-xcontrib/demos/magnum/stop8
-rw-r--r--contrib/dev/vagrant/Vagrantfile252
-rw-r--r--contrib/dev/vagrant/Vagrantfile.custom.example92
-rw-r--r--contrib/dev/vagrant/bootstrap.sh226
-rw-r--r--contrib/dev/vagrant/newest_dhcp_lease.py134
17 files changed, 1188 insertions, 0 deletions
diff --git a/contrib/demos/heat/README.rst b/contrib/demos/heat/README.rst
new file mode 100644
index 000000000..b634febd8
--- /dev/null
+++ b/contrib/demos/heat/README.rst
@@ -0,0 +1,15 @@
+A Kolla Demo using Heat
+=======================
+
+By default, the launch script will spawn 3 Nova instances on a Neutron
+network created from the tools/init-runonce script. Edit the VM\_COUNT
+parameter in the launch script if you would like to spawn a different
+amount of Nova instances. Edit the IMAGE\_FLAVOR if you would like to
+launch images using a flavor other than m1.tiny.
+
+Then run the script:
+
+::
+
+ $ ./launch
+
diff --git a/contrib/demos/heat/launch b/contrib/demos/heat/launch
new file mode 100755
index 000000000..768b69eb0
--- /dev/null
+++ b/contrib/demos/heat/launch
@@ -0,0 +1,11 @@
+VM_COUNT=3
+IMAGE_FLAVOR=m1.small
+PUBLIC_NET_ID=$(neutron net-list | grep public | awk '{print $2}')
+DEMO_NET_ID=$(neutron net-list | grep demo | awk '{print $2}')
+DEMO_SUBNET_ID=$(neutron net-list | grep demo | awk '{print $6}')
+
+echo Public net id is $PUBLIC_NET_ID
+echo Demo net id is $DEMO_NET_ID
+echo Demo subnet id is $DEMO_SUBNET_ID
+
+heat stack-create steak --template-file steak-rg.yaml --parameters="vm_count=$VM_COUNT;image_flavor=$IMAGE_FLAVOR;public_net_id=$PUBLIC_NET_ID;demo_net_id=$DEMO_NET_ID;demo_subnet_id=$DEMO_SUBNET_ID"
diff --git a/contrib/demos/heat/steak-rg.yaml b/contrib/demos/heat/steak-rg.yaml
new file mode 100644
index 000000000..4c0a1db93
--- /dev/null
+++ b/contrib/demos/heat/steak-rg.yaml
@@ -0,0 +1,43 @@
+heat_template_version: 2013-05-23
+
+parameters:
+ public_net_id:
+ type: string
+ description: uuid of a network to use for floating ip addresses
+
+ demo_net_id:
+ type: string
+ description: uuid of a subnet on the fixed network to use for creating ports
+
+ demo_subnet_id:
+ type: string
+ description: uuid of a subnet on the fixed network to use for creating ports
+
+ vm_count:
+ type: string
+ description: Number of VMs to launch
+
+ image_flavor:
+ type: string
+ description: Image flavor to use when launching VMs
+
+resources:
+ steak:
+ type: OS::Heat::ResourceGroup
+ properties:
+ count:
+ get_param: vm_count
+ resource_def:
+ type: steak.yaml
+ properties:
+ image_flavor: {get_param: image_flavor}
+ public_net_id: {get_param: public_net_id}
+ demo_net_id: {get_param: demo_net_id}
+ demo_subnet_id: {get_param: demo_subnet_id}
+
+outputs:
+ eth0:
+ value: {get_attr: [steak, eth0]}
+
+ float:
+ value: {get_attr: [steak, float]}
diff --git a/contrib/demos/heat/steak.yaml b/contrib/demos/heat/steak.yaml
new file mode 100644
index 000000000..9b9bd9fc7
--- /dev/null
+++ b/contrib/demos/heat/steak.yaml
@@ -0,0 +1,54 @@
+heat_template_version: 2013-05-23
+
+parameters:
+ public_net_id:
+ type: string
+ description: uuid of a network to use for floating ip addresses
+
+ demo_net_id:
+ type: string
+ description: uuid of a subnet on the fixed network to use for creating ports
+
+ demo_subnet_id:
+ type: string
+ description: uuid of a subnet on the fixed network to use for creating ports
+
+ image_flavor:
+ type: string
+ description: Number of VMs to launch
+
+resources:
+ steak_node:
+ type: "OS::Nova::Server"
+ properties:
+ key_name: mykey
+ image: cirros
+ flavor:
+ get_param: image_flavor
+ networks:
+ - port:
+ get_resource: steak_node_eth0
+
+ steak_node_eth0:
+ type: "OS::Neutron::Port"
+ properties:
+ network_id:
+ get_param: demo_net_id
+ fixed_ips:
+ - subnet_id:
+ get_param: demo_subnet_id
+
+ steak_node_floating:
+ type: "OS::Neutron::FloatingIP"
+ properties:
+ floating_network_id:
+ get_param: public_net_id
+ port_id:
+ get_resource: steak_node_eth0
+
+outputs:
+ eth0:
+ value: {get_attr: [steak_node_eth0, fixed_ips, 0, ip_address]}
+
+ float:
+ value: {get_attr: [steak_node_floating, floating_ip_address]}
diff --git a/contrib/demos/magnum/redis b/contrib/demos/magnum/redis
new file mode 100755
index 000000000..cf8c61463
--- /dev/null
+++ b/contrib/demos/magnum/redis
@@ -0,0 +1,5 @@
+magnum pod-create --manifest redis-kube/redis-master.yaml --bay testbay
+magnum service-create --manifest redis-kube/redis-sentinel-service.yaml --bay testbay
+magnum rc-create --manifest redis-kube/redis-controller.yaml --bay testbay
+magnum rc-create --manifest redis-kube/redis-sentinel-controller.yaml --bay testbay
+
diff --git a/contrib/demos/magnum/redis-kube/README.rst b/contrib/demos/magnum/redis-kube/README.rst
new file mode 100644
index 000000000..0a0ede6ab
--- /dev/null
+++ b/contrib/demos/magnum/redis-kube/README.rst
@@ -0,0 +1,197 @@
+Reliable, Scalable Redis on Kubernetes
+--------------------------------------
+
+The following document describes the deployment of a reliable,
+multi-node Redis on Kubernetes. It deploys a master with replicated
+slaves, as well as replicated redis sentinels which are use for health
+checking and failover.
+
+Prerequisites
+~~~~~~~~~~~~~
+
+This example assumes that you have a Kubernetes cluster installed and
+running, and that you have installed the ``kubectl`` command line tool
+somewhere in your path. Please see the `getting
+started <https://github.com/GoogleCloudPlatform/kubernetes/tree/master/docs/getting-started-guides>`__
+for installation instructions for your platform.
+
+A note for the impatient
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+This is a somewhat long tutorial. If you want to jump straight to the
+"do it now" commands, please see the `tl; dr <#tl-dr>`__ at the end.
+
+Turning up an initial master/sentinel pod.
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+is a
+`*Pod* <https://github.com/GoogleCloudPlatform/kubernetes/blob/master/docs/user-guide/pods.md>`__.
+A Pod is one or more containers that *must* be scheduled onto the same
+host. All containers in a pod share a network namespace, and may
+optionally share mounted volumes.
+
+We will used the shared network namespace to bootstrap our Redis
+cluster. In particular, the very first sentinel needs to know how to
+find the master (subsequent sentinels just ask the first sentinel).
+Because all containers in a Pod share a network namespace, the sentinel
+can simply look at ``$(hostname -i):6379``.
+
+Here is the config for the initial master and sentinel pod:
+`redis-master.yaml <redis-master.yaml>`__
+
+Create this master as follows:
+
+.. code:: sh
+
+ kubectl create -f examples/redis/v1beta3/redis-master.yaml
+
+Turning up a sentinel service
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+In Kubernetes a *Service* describes a set of Pods that perform the same
+task. For example, the set of nodes in a Cassandra cluster, or even the
+single node we created above. An important use for a Service is to
+create a load balancer which distributes traffic across members of the
+set. But a *Service* can also be used as a standing query which makes a
+dynamically changing set of Pods (or the single Pod we've already
+created) available via the Kubernetes API.
+
+In Redis, we will use a Kubernetes Service to provide a discoverable
+endpoints for the Redis sentinels in the cluster. From the sentinels
+Redis clients can find the master, and then the slaves and other
+relevant info for the cluster. This enables new members to join the
+cluster when failures occur.
+
+Here is the definition of the sentinel
+service:\ `redis-sentinel-service.yaml <redis-sentinel-service.yaml>`__
+
+Create this service:
+
+.. code:: sh
+
+ kubectl create -f examples/redis/v1beta3/redis-sentinel-service.yaml
+
+Turning up replicated redis servers
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+So far, what we have done is pretty manual, and not very fault-tolerant.
+If the ``redis-master`` pod that we previously created is destroyed for
+some reason (e.g. a machine dying) our Redis service goes away with it.
+
+In Kubernetes a *Replication Controller* is responsible for replicating
+sets of identical pods. Like a *Service* it has a selector query which
+identifies the members of it's set. Unlike a *Service* it also has a
+desired number of replicas, and it will create or delete *Pods* to
+ensure that the number of *Pods* matches up with it's desired state.
+
+Replication Controllers will "adopt" existing pods that match their
+selector query, so let's create a Replication Controller with a single
+replica to adopt our existing Redis server.
+`redis-controller.yaml <redis-controller.yaml>`__
+
+The bulk of this controller config is actually identical to the
+redis-master pod definition above. It forms the template or "cookie
+cutter" that defines what it means to be a member of this set.
+
+Create this controller:
+
+.. code:: sh
+
+ kubectl create -f examples/redis/v1beta3/redis-controller.yaml
+
+We'll do the same thing for the sentinel. Here is the controller
+config:\ `redis-sentinel-controller.yaml <redis-sentinel-controller.yaml>`__
+
+We create it as follows:
+
+.. code:: sh
+
+ kubectl create -f examples/redis/v1beta3/redis-sentinel-controller.yaml
+
+Resize our replicated pods
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Initially creating those pods didn't actually do anything, since we only
+asked for one sentinel and one redis server, and they already existed,
+nothing changed. Now we will add more replicas:
+
+.. code:: sh
+
+ kubectl resize rc redis --replicas=3
+
+.. code:: sh
+
+ kubectl resize rc redis-sentinel --replicas=3
+
+This will create two additional replicas of the redis server and two
+additional replicas of the redis sentinel.
+
+Unlike our original redis-master pod, these pods exist independently,
+and they use the ``redis-sentinel-service`` that we defined above to
+discover and join the cluster.
+
+Delete our manual pod
+~~~~~~~~~~~~~~~~~~~~~
+
+The final step in the cluster turn up is to delete the original
+redis-master pod that we created manually. While it was useful for
+bootstrapping discovery in the cluster, we really don't want the
+lifespan of our sentinel to be tied to the lifespan of one of our redis
+servers, and now that we have a successful, replicated redis sentinel
+service up and running, the binding is unnecessary.
+
+Delete the master as follows:
+
+.. code:: sh
+
+ kubectl delete pods redis-master
+
+Now let's take a close look at what happens after this pod is deleted.
+There are three things that happen:
+
+1. The redis replication controller notices that its desired state is 3
+ replicas, but there are currently only 2 replicas, and so it creates
+ a new redis server to bring the replica count back up to 3
+2. The redis-sentinel replication controller likewise notices the
+ missing sentinel, and also creates a new sentinel.
+3. The redis sentinels themselves, realize that the master has
+ disappeared from the cluster, and begin the election procedure for
+ selecting a new master. They perform this election and selection, and
+ chose one of the existing redis server replicas to be the new master.
+
+Conclusion
+~~~~~~~~~~
+
+At this point we now have a reliable, scalable Redis installation. By
+resizing the replication controller for redis servers, we can increase
+or decrease the number of read-slaves in our cluster. Likewise, if
+failures occur, the redis-sentinels will perform master election and
+select a new master.
+
+tl; dr
+~~~~~~
+
+For those of you who are impatient, here is the summary of commands we
+ran in this tutorial
+
+.. code:: sh
+
+ # Create a bootstrap master
+ kubectl create -f examples/redis/v1beta3/redis-master.yaml
+
+ # Create a service to track the sentinels
+ kubectl create -f examples/redis/v1beta3/redis-sentinel-service.yaml
+
+ # Create a replication controller for redis servers
+ kubectl create -f examples/redis/v1beta3/redis-controller.yaml
+
+ # Create a replication controller for redis sentinels
+ kubectl create -f examples/redis/v1beta3/redis-sentinel-controller.yaml
+
+ # Resize both replication controllers
+ kubectl resize rc redis --replicas=3
+ kubectl resize rc redis-sentinel --replicas=3
+
+ # Delete the original master pod
+ kubectl delete pods redis-master
+
diff --git a/contrib/demos/magnum/redis-kube/redis-controller.yaml b/contrib/demos/magnum/redis-kube/redis-controller.yaml
new file mode 100644
index 000000000..4eaf61eae
--- /dev/null
+++ b/contrib/demos/magnum/redis-kube/redis-controller.yaml
@@ -0,0 +1,28 @@
+apiVersion: v1beta3
+kind: ReplicationController
+metadata:
+ name: redis
+spec:
+ replicas: 2
+ selector:
+ name: redis
+ template:
+ metadata:
+ labels:
+ name: redis
+ spec:
+ containers:
+ - name: redis
+ image: kubernetes/redis:v1
+ ports:
+ - containerPort: 6379
+ resources:
+ limits:
+ cpu: "1"
+ volumeMounts:
+ - mountPath: /redis-master-data
+ name: data
+ volumes:
+ - name: data
+ emptyDir: {}
+
diff --git a/contrib/demos/magnum/redis-kube/redis-master.yaml b/contrib/demos/magnum/redis-kube/redis-master.yaml
new file mode 100644
index 000000000..02abada97
--- /dev/null
+++ b/contrib/demos/magnum/redis-kube/redis-master.yaml
@@ -0,0 +1,33 @@
+apiVersion: v1beta3
+kind: Pod
+metadata:
+ labels:
+ name: redis
+ redis-sentinel: "true"
+ role: master
+ name: redis-master
+spec:
+ containers:
+ - name: master
+ image: kubernetes/redis:v1
+ env:
+ - name: MASTER
+ value: "true"
+ ports:
+ - containerPort: 6379
+ resources:
+ limits:
+ cpu: "1"
+ volumeMounts:
+ - mountPath: /redis-master-data
+ name: data
+ - name: sentinel
+ image: kubernetes/redis:v1
+ env:
+ - name: SENTINEL
+ value: "true"
+ ports:
+ - containerPort: 26379
+ volumes:
+ - name: data
+ emptyDir: {}
diff --git a/contrib/demos/magnum/redis-kube/redis-proxy.yaml b/contrib/demos/magnum/redis-kube/redis-proxy.yaml
new file mode 100644
index 000000000..2993a45bf
--- /dev/null
+++ b/contrib/demos/magnum/redis-kube/redis-proxy.yaml
@@ -0,0 +1,14 @@
+apiVersion: v1beta3
+kind: Pod
+metadata:
+ labels:
+ name: redis-proxy
+ role: proxy
+ name: redis-proxy
+spec:
+ containers:
+ - name: proxy
+ image: kubernetes/redis-proxy:v1
+ ports:
+ - containerPort: 6379
+ name: api
diff --git a/contrib/demos/magnum/redis-kube/redis-sentinel-controller.yaml b/contrib/demos/magnum/redis-kube/redis-sentinel-controller.yaml
new file mode 100644
index 000000000..157b09e8a
--- /dev/null
+++ b/contrib/demos/magnum/redis-kube/redis-sentinel-controller.yaml
@@ -0,0 +1,23 @@
+apiVersion: v1beta3
+kind: ReplicationController
+metadata:
+ name: redis-sentinel
+spec:
+ replicas: 2
+ selector:
+ redis-sentinel: "true"
+ template:
+ metadata:
+ labels:
+ name: redis-sentinel
+ redis-sentinel: "true"
+ role: sentinel
+ spec:
+ containers:
+ - name: sentinel
+ image: kubernetes/redis:v1
+ env:
+ - name: SENTINEL
+ value: "true"
+ ports:
+ - containerPort: 26379
diff --git a/contrib/demos/magnum/redis-kube/redis-sentinel-service.yaml b/contrib/demos/magnum/redis-kube/redis-sentinel-service.yaml
new file mode 100644
index 000000000..7078d182f
--- /dev/null
+++ b/contrib/demos/magnum/redis-kube/redis-sentinel-service.yaml
@@ -0,0 +1,13 @@
+apiVersion: v1beta3
+kind: Service
+metadata:
+ labels:
+ name: sentinel
+ role: service
+ name: redis-sentinel
+spec:
+ ports:
+ - port: 26379
+ targetPort: 26379
+ selector:
+ redis-sentinel: "true"
diff --git a/contrib/demos/magnum/start b/contrib/demos/magnum/start
new file mode 100755
index 000000000..3a3cd29a6
--- /dev/null
+++ b/contrib/demos/magnum/start
@@ -0,0 +1,40 @@
+#!/bin/bash
+
+NETWORK_MANAGER=$(grep -sri NETWORK_MANAGER ../../compose/openstack.env | cut -f2 -d "=")
+if [ "$NETWORK_MANAGER" != "neutron" ]; then
+ echo 'Magnum depends on the Neutron network manager to operate.'
+ echo 'Exiting because the network manager is' "$NETWORK_MANAGER".
+ exit 1
+fi
+
+echo Downloading glance image.
+IMAGE_URL=https://fedorapeople.org/groups/magnum
+IMAGE=fedora-21-atomic-3.qcow2
+if ! [ -f "$IMAGE" ]; then
+ curl -L -o ./$IMAGE $IMAGE_URL/$IMAGE
+fi
+
+NIC_ID=$(neutron net-show public1 | awk '/ id /{print $4}')
+
+glance image-delete fedora-21-atomic-3 2> /dev/null
+
+echo Loading fedora-atomic image into glance
+glance image-create --name fedora-21-atomic-3 --progress --is-public true --disk-format qcow2 --container-format bare --file ./$IMAGE
+GLANCE_IMAGE_ID=$(glance image-show fedora-21-atomic-3 | grep id | awk '{print $4}')
+
+echo registering os-distro property with image
+glance image-update $GLANCE_IMAGE_ID --property os_distro=fedora-atomic
+
+echo Creating baymodel
+magnum baymodel-create \
+ --name testbaymodel \
+ --image-id $GLANCE_IMAGE_ID \
+ --keypair-id mykey \
+ --fixed-network 10.0.3.0/24 \
+ --external-network-id $NIC_ID \
+ --dns-nameserver 8.8.8.8 --flavor-id m1.small \
+ --docker-volume-size 5 --coe kubernetes
+
+echo Creating Bay
+magnum bay-create --name testbay --baymodel testbaymodel --node-count 2
+
diff --git a/contrib/demos/magnum/stop b/contrib/demos/magnum/stop
new file mode 100755
index 000000000..67da543e0
--- /dev/null
+++ b/contrib/demos/magnum/stop
@@ -0,0 +1,8 @@
+#!/bin/bash
+
+magnum bay-delete testbay
+while magnum bay-list | grep -q testbay; do
+ sleep 1
+done
+magnum baymodel-delete testbaymodel
+
diff --git a/contrib/dev/vagrant/Vagrantfile b/contrib/dev/vagrant/Vagrantfile
new file mode 100644
index 000000000..f59fafaec
--- /dev/null
+++ b/contrib/dev/vagrant/Vagrantfile
@@ -0,0 +1,252 @@
+# -*- mode: ruby -*-
+# vi: set ft=ruby :
+
+require "ipaddr"
+
+# Check for required plugin(s)
+['vagrant-hostmanager'].each do |plugin|
+ unless Vagrant.has_plugin?(plugin)
+ raise "#{plugin} plugin not found. Please install it via 'vagrant plugin install #{plugin}'"
+ end
+end
+
+class VagrantConfigMissing < StandardError
+end
+
+vagrant_dir = File.expand_path(File.dirname(__FILE__))
+
+# Vagrantfile.custom contains user customization for the Vagrantfile
+# You shouldn't have to edit the Vagrantfile, ever.
+if File.exists?(File.join(vagrant_dir, 'Vagrantfile.custom'))
+ eval(IO.read(File.join(vagrant_dir, 'Vagrantfile.custom')), binding)
+end
+
+# Either libvirt or virtualbox
+PROVIDER ||= "libvirt"
+# Either centos or ubuntu
+DISTRO ||= "centos"
+
+# The libvirt graphics_ip used for each guest. Only applies if PROVIDER
+# is libvirt.
+GRAPHICSIP ||= "127.0.0.1"
+
+# The bootstrap.sh provision_script requires CentOS 7 or Ubuntu 15.10.
+# Provisioning other boxes than the default ones may therefore
+# require changes to bootstrap.sh.
+PROVISION_SCRIPT ||= "bootstrap.sh"
+
+PROVIDER_DEFAULTS ||= {
+ libvirt: {
+ centos: {
+ base_image: "centos/7",
+ bridge_interface: "virbr0",
+ vagrant_shared_folder: "/home/vagrant/sync",
+ sync_method: "nfs",
+ kolla_path: "/home/vagrant/kolla"
+ }
+ },
+ virtualbox: {
+ centos: {
+ base_image: "puppetlabs/centos-7.0-64-puppet",
+ bridge_interface: "wlp3s0b1",
+ vagrant_shared_folder: "/home/vagrant/sync",
+ sync_method: "virtualbox",
+ kolla_path: "/home/vagrant/kolla"
+ },
+ ubuntu: {
+ base_image: "ubuntu/wily64",
+ bridge_interface: "wlp3s0b1",
+ vagrant_shared_folder: "/home/vagrant/sync",
+ sync_method: "virtualbox",
+ kolla_path: "/home/vagrant/kolla"
+ }
+ }
+}
+
+# Whether the host network adapter is Wi-Fi.
+# On VirtualBox, the user must first manually create a NAT-Network
+# named "OSNetwork". The default network CIDR must be changed.
+# The Neutron external interface will be connected to this Network.
+WIFI = false unless self.class.const_defined?(:WIFI)
+
+# Whether to do Multi-node or All-in-One deployment
+MULTINODE = false unless self.class.const_defined?(:MULTINODE)
+
+# The following is only used when deploying in Multi-nodes
+NUMBER_OF_CONTROL_NODES ||= 3
+NUMBER_OF_COMPUTE_NODES ||= 1
+NUMBER_OF_STORAGE_NODES ||= 1
+NUMBER_OF_NETWORK_NODES ||= 1
+
+NODE_SETTINGS ||= {
+ aio: {
+ cpus: 4,
+ memory: 4096
+ },
+ operator: {
+ cpus: 1,
+ memory: 1024
+ },
+ control: {
+ cpus: 1,
+ memory: 2048
+ },
+ compute: {
+ cpus: 1,
+ memory: 1024
+ },
+ storage: {
+ cpus: 1,
+ memory: 1024
+ },
+ network: {
+ cpus: 1,
+ memory: 1024
+ }
+}
+
+# Configure a new SSH key and config so the operator is able to connect with
+# the other cluster nodes.
+unless File.file?(File.join(vagrant_dir, 'vagrantkey'))
+ system("ssh-keygen -f #{File.join(vagrant_dir, 'vagrantkey')} -N '' -C this-is-vagrant")
+end
+
+def get_default(setting)
+ PROVIDER_DEFAULTS[PROVIDER.to_sym][DISTRO.to_sym][setting]
+rescue
+ raise VagrantConfigMissing,
+ "Missing configuration for PROVIDER_DEFAULTS[#{PROVIDER}][#{DISTRO}][#{setting}]"
+end
+
+def get_setting(node, setting)
+ NODE_SETTINGS[node][setting]
+rescue
+ raise VagrantConfigMissing,
+ "Missing configuration for NODE_SETTINGS[#{node}][#{setting}]"
+end
+
+def configure_wifi_vbox_networking(vm)
+ # Even if adapters 1 & 2 don't need to be modified, if the order is to be
+ # maintained, some modification has to be done to them. This will maintain
+ # the association inside the guest OS: NIC1 -> eth0, NIC2 -> eth1, NIC3 ->
+ # eht2. The modifications for adapters 1 & 2 only change optional properties.
+ # Adapter 3 is enabled and connected to the NAT-Network named "OSNetwork",
+ # while also changing its optional properties. Since adapter 3 is used by
+ # Neutron for the external network, promiscuous mode is set to "allow-all".
+ # Also, use virtio as the adapter type, for better performance.
+ vm.customize ["modifyvm", :id, "--nictype1", "virtio"]
+ vm.customize ["modifyvm", :id, "--cableconnected1", "on"]
+ vm.customize ["modifyvm", :id, "--nicpromisc2", "deny"]
+ vm.customize ["modifyvm", :id, "--nictype2", "virtio"]
+ vm.customize ["modifyvm", :id, "--cableconnected2", "on"]
+ vm.customize ["modifyvm", :id, "--nic3", "natnetwork"]
+ vm.customize ["modifyvm", :id, "--nat-network3", "OSNetwork"]
+ vm.customize ["modifyvm", :id, "--nicpromisc3", "allow-all"]
+ vm.customize ["modifyvm", :id, "--nictype3", "virtio"]
+ vm.customize ["modifyvm", :id, "--cableconnected3", "on"]
+end
+
+def configure_wifi_if_enabled(vm)
+ if WIFI
+ case PROVIDER
+ when "virtualbox"
+ configure_wifi_vbox_networking(vm)
+# TODO(lucian-serb): Configure networking on Wi-Fi for other hypervisors.
+# when "libvirt"
+# configure_wifi_libvirt_networking(vm)
+ end
+ end
+end
+
+Vagrant.configure(2) do |config|
+ config.vm.box = get_default(:base_image)
+
+ # Next to the hostonly NAT-network there is a host-only network with all
+ # nodes attached. Plus, each node receives a 3rd adapter connected to the
+ # outside public network.
+ config.vm.network "private_network", type: "dhcp"
+ # On VirtualBox hosts with Wi-Fi, do not create a public bridged interface.
+ # A NAT-Network will be used instead.
+ # TODO(lucian-serb): Do the same for other hypervisors as well?
+ unless PROVIDER == "virtualbox" && WIFI
+ config.vm.network "public_network", dev: get_default(:bridge_interface), mode: 'bridge', type: 'bridge'
+ end
+
+ my_privatekey = File.read(File.join(vagrant_dir, "vagrantkey"))
+ my_publickey = File.read(File.join(vagrant_dir, "vagrantkey.pub"))
+
+ config.vm.provision :shell, inline: <<-EOS
+ mkdir -p /root/.ssh
+ echo '#{my_privatekey}' > /root/.ssh/id_rsa
+ chmod 600 /root/.ssh/id_rsa
+ echo '#{my_publickey}' > /root/.ssh/authorized_keys
+ chmod 600 /root/.ssh/authorized_keys
+ echo '#{my_publickey}' > /root/.ssh/id_rsa.pub
+ chmod 644 /root/.ssh/id_rsa.pub
+ mkdir -p /home/vagrant/.ssh
+ echo '#{my_privatekey}' >> /home/vagrant/.ssh/id_rsa
+ chmod 600 /home/vagrant/.ssh/*
+ echo 'Host *' > ~vagrant/.ssh/config
+ echo StrictHostKeyChecking no >> ~vagrant/.ssh/config
+ chown -R vagrant: /home/vagrant/.ssh
+ EOS
+
+ config.hostmanager.enabled = true
+ # Make sure hostmanager picks IP address of eth1
+ config.hostmanager.ip_resolver = proc do |vm, resolving_vm|
+ case PROVIDER
+ when "libvirt"
+ if vm.name
+ `python newest_dhcp_lease.py #{vm.name}`.chop
+ end
+ when "virtualbox"
+ if vm.id
+ `VBoxManage guestproperty get #{vm.id} "/VirtualBox/GuestInfo/Net/1/V4/IP"`.split()[1]
+ end
+ end
+ end
+
+ # The operator controls the deployment
+ config.vm.define "operator", primary: true do |admin|
+ admin.vm.hostname = "operator.local"
+ admin.vm.provision :shell, path: PROVISION_SCRIPT, args: "operator #{MULTINODE ? 'multinode' : 'aio'} #{get_default(:kolla_path)}"
+ admin.vm.synced_folder File.join(vagrant_dir, '..', '..'), get_default(:kolla_path), create:"True", type: get_default(:sync_method)
+ admin.vm.synced_folder File.join(vagrant_dir, 'storage', 'operator'), "/data/host", create:"True", type: get_default(:sync_method)
+ admin.vm.synced_folder File.join(vagrant_dir, 'storage', 'shared'), "/data/shared", create:"True", type: get_default(:sync_method)
+ admin.vm.synced_folder ".", get_default(:vagrant_shared_folder), disabled: true
+ admin.vm.provider PROVIDER do |vm|
+ vm.memory = MULTINODE ? get_setting(:operator, :memory) : get_setting(:aio, :memory)
+ vm.cpus = MULTINODE ? get_setting(:operator, :cpus) : get_setting(:aio, :cpus)
+ if PROVIDER == "libvirt"
+ vm.graphics_ip = GRAPHICSIP
+ end
+ configure_wifi_if_enabled(vm)
+ end
+ admin.hostmanager.aliases = "operator"
+ end
+
+ if MULTINODE
+ ['compute', 'storage', 'network', 'control'].each do |node_type|
+ (1..self.class.const_get("NUMBER_OF_#{node_type.upcase}_NODES")).each do |i|
+ hostname = "#{node_type}0#{i}"
+ config.vm.define hostname do |node|
+ node.vm.hostname = "#{hostname}.local"
+ node.vm.provision :shell, path: PROVISION_SCRIPT, args: "#{hostname} multinode #{get_default(:kolla_path)}"
+ node.vm.synced_folder File.join(vagrant_dir, 'storage', node_type), "/data/host", create:"True", type: get_default(:sync_method)
+ node.vm.synced_folder File.join(vagrant_dir, 'storage', 'shared'), "/data/shared", create:"True", type: get_default(:sync_method)
+ node.vm.synced_folder ".", get_default(:vagrant_shared_folder), disabled: true
+ node.vm.provider PROVIDER do |vm|
+ vm.memory = get_setting(node_type.to_sym, :memory)
+ vm.cpus = get_setting(node_type.to_sym, :cpus)
+ if PROVIDER == "libvirt"
+ vm.graphics_ip = GRAPHICSIP
+ end
+ configure_wifi_if_enabled(vm)
+ end
+ node.hostmanager.aliases = hostname
+ end
+ end
+ end
+ end
+
+end
diff --git a/contrib/dev/vagrant/Vagrantfile.custom.example b/contrib/dev/vagrant/Vagrantfile.custom.example
new file mode 100644
index 000000000..09af72f5b
--- /dev/null
+++ b/contrib/dev/vagrant/Vagrantfile.custom.example
@@ -0,0 +1,92 @@
+# -*- mode: ruby -*-
+# vi: set ft=ruby :
+
+# This file is an example of Vagrant configuration.
+# Copy it to Vagrantfile.custom and configure it to your liking to customize
+# the Vagrant deployment. The Vagrantfile.custom file is sourced by the
+# Vagrantfile, it has to be valid ruby code.
+
+# Either libvirt or virtualbox
+# PROVIDER = "libvirt"
+
+# Either centos or ubuntu
+# DISTRO = "centos"
+
+# The libvirt graphics_ip used for each guest. Only applies if PROVIDER
+# is libvirt.
+# GRAPHICSIP = "127.0.0.1"
+
+# The bootstrap.sh provision_script requires CentOS 7 or Ubuntu 15.10.
+# Provisioning other boxes than the default ones may therefore
+# require changes to bootstrap.sh.
+# PROVISION_SCRIPT = "bootstrap.sh"
+
+# PROVIDER_DEFAULTS = {
+# libvirt: {
+# centos: {
+# base_image: "centos/7",
+# bridge_interface: "virbr0",
+# vagrant_shared_folder: "/home/vagrant/sync",
+# sync_method: "nfs",
+# kolla_path: "/home/vagrant/kolla"
+# }
+# },
+# virtualbox: {
+# centos: {
+# base_image: "puppetlabs/centos-7.0-64-puppet",
+# bridge_interface: "wlp3s0b1",
+# vagrant_shared_folder: "/home/vagrant/sync",
+# sync_method: "virtualbox",
+# kolla_path: "/home/vagrant/kolla"
+# },
+# ubuntu: {
+# base_image: "ubuntu/wily64",
+# bridge_interface: "wlp3s0b1",
+# vagrant_shared_folder: "/home/vagrant/sync",
+# sync_method: "virtualbox",
+# kolla_path: "/home/vagrant/kolla"
+# }
+# }
+# }
+
+# Whether the host network adapter is Wi-Fi.
+# On VirtualBox, the user must first manually create a NAT-Network
+# named OSNetwork. The default network CIDR must be changed.
+# The Neutron external interface will be connected to this Network.
+# WIFI = false
+
+# Whether to do Multi-node or All-in-One deployment
+# MULTINODE = false
+
+# The following is only used when deploying in Multi-nodes
+# NUMBER_OF_CONTROL_NODES = 3
+# NUMBER_OF_COMPUTE_NODES = 1
+# NUMBER_OF_STORAGE_NODES = 1
+# NUMBER_OF_NETWORK_NODES = 1
+
+# NODE_SETTINGS = {
+# aio: {
+# cpus: 4,
+# memory: 4096
+# },
+# operator: {
+# cpus: 1,
+# memory: 1024
+# },
+# control: {
+# cpus: 1,
+# memory: 2048
+# },
+# compute: {
+# cpus: 1,
+# memory: 1024
+# },
+# storage: {
+# cpus: 1,
+# memory: 1024
+# },
+# network: {
+# cpus: 1,
+# memory: 1024
+# }
+# }
diff --git a/contrib/dev/vagrant/bootstrap.sh b/contrib/dev/vagrant/bootstrap.sh
new file mode 100644
index 000000000..ec89440b8
--- /dev/null
+++ b/contrib/dev/vagrant/bootstrap.sh
@@ -0,0 +1,226 @@
+#!/usr/bin/env bash
+#
+# Bootstrap script to configure all nodes.
+#
+# This script is intended to be used by vagrant to provision nodes.
+# To use it, set it as 'PROVISION_SCRIPT' inside your Vagrantfile.custom.
+# You can use Vagrantfile.custom.example as a template for this.
+
+VM=$1
+MODE=$2
+KOLLA_PATH=$3
+
+export http_proxy=
+export https_proxy=
+
+if [ "$MODE" = 'aio' ]; then
+ # Run registry on port 4000 since it may collide with keystone when doing AIO
+ REGISTRY_PORT=4000
+else
+ REGISTRY_PORT=5000
+fi
+REGISTRY_URL="operator.local"
+REGISTRY=${REGISTRY_URL}:${REGISTRY_PORT}
+ADMIN_PROTOCOL="http"
+
+function _ensure_lsb_release {
+ if [[ -x $(type lsb_release 2>/dev/null) ]]; then
+ return
+ fi
+
+ if [[ -x $(type apt-get 2>/dev/null) ]]; then
+ apt-get -y install lsb-release
+ elif [[ -x $(type yum 2>/dev/null) ]]; then
+ yum -y install redhat-lsb-core
+ fi
+}
+
+function _is_distro {
+ if [[ -z "$DISTRO" ]]; then
+ _ensure_lsb_release
+ DISTRO=$(lsb_release -si)
+ fi
+
+ [[ "$DISTRO" == "$1" ]]
+}
+
+function is_ubuntu {
+ _is_distro "Ubuntu"
+}
+
+function is_centos {
+ _is_distro "CentOS"
+}
+
+# Install common packages and do some prepwork.
+function prep_work {
+ if [[ "$(systemctl is-enabled firewalld)" = "enabled" ]]; then
+ systemctl stop firewalld
+ systemctl disable firewalld
+ fi
+
+ # This removes the fqdn from /etc/hosts's 127.0.0.1. This name.local will
+ # resolve to the public IP instead of localhost.
+ sed -i -r "s,^127\.0\.0\.1\s+.*,127\.0\.0\.1 localhost localhost.localdomain localhost4 localhost4.localdomain4," /etc/hosts
+
+ if is_centos; then
+ yum -y install epel-release
+ rpm --import /etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-7
+ yum -y install MySQL-python vim-enhanced python-pip python-devel gcc openssl-devel libffi-devel libxml2-devel libxslt-devel
+ elif is_ubuntu; then
+ apt-get update
+ apt-get -y install python-mysqldb python-pip python-dev build-essential libssl-dev libffi-dev libxml2-dev libxslt-dev
+ else
+ echo "Unsupported Distro: $DISTRO" 1>&2
+ exit 1
+ fi
+
+ pip install --upgrade docker-py
+}
+
+# Do some cleanup after the installation of kolla
+function cleanup {
+ if is_centos; then
+ yum clean all
+ elif is_ubuntu; then
+ apt-get clean
+ else
+ echo "Unsupported Distro: $DISTRO" 1>&2
+ exit 1
+ fi
+}
+
+# Install and configure a quick&dirty docker daemon.
+function install_docker {
+ if is_centos; then
+ cat >/etc/yum.repos.d/docker.repo <<-EOF
+[dockerrepo]
+name=Docker Repository
+baseurl=https://yum.dockerproject.org/repo/main/centos/7
+enabled=1
+gpgcheck=1
+gpgkey=https://yum.dockerproject.org/gpg
+EOF
+ # Also upgrade device-mapper here because of:
+ # https://github.com/docker/docker/issues/12108
+ # Upgrade lvm2 to get device-mapper installed
+ yum -y install docker-engine lvm2 device-mapper
+
+ # Despite it shipping with /etc/sysconfig/docker, Docker is not configured to
+ # load it from it's service file.
+ sed -i -r "s|(ExecStart)=(.+)|\1=/usr/bin/docker daemon --insecure-registry ${REGISTRY} --registry-mirror=http://${REGISTRY}|" /usr/lib/systemd/system/docker.service
+ sed -i 's|^MountFlags=.*|MountFlags=shared|' /usr/lib/systemd/system/docker.service
+
+ usermod -aG docker vagrant
+ elif is_ubuntu; then
+ apt-key adv --keyserver hkp://pgp.mit.edu:80 --recv-keys 58118E89F3A912897C070ADBF76221572C52609D
+ echo "deb https://apt.dockerproject.org/repo ubuntu-wily main" > /etc/apt/sources.list.d/docker.list
+ apt-get update
+ apt-get -y install docker-engine
+ sed -i -r "s,(ExecStart)=(.+),\1=/usr/bin/docker daemon --insecure-registry ${REGISTRY} --registry-mirror=http://${REGISTRY}|" /lib/systemd/system/docker.service
+ else
+ echo "Unsupported Distro: $DISTRO" 1>&2
+ exit 1
+ fi
+
+ if [[ "${http_proxy}" != "" ]]; then
+ mkdir -p /etc/systemd/system/docker.service.d
+ cat >/etc/systemd/system/docker.service.d/http-proxy.conf <<-EOF
+[Service]
+Environment="HTTP_PROXY=${http_proxy}" "HTTPS_PROXY=${https_proxy}" "NO_PROXY=localhost,127.0.0.1,${REGISTRY_URL}"
+EOF
+
+ if [[ "$(grep http_ /etc/bashrc)" == "" ]]; then
+ echo "export http_proxy=${http_proxy}" >> /etc/bashrc
+ echo "export https_proxy=${https_proxy}" >> /etc/bashrc
+ fi
+ fi
+
+ systemctl daemon-reload
+ systemctl enable docker
+ systemctl start docker
+}
+
+function configure_kolla {
+ # Use local docker registry
+ sed -i -r "s,^[# ]*namespace *=.+$,namespace = ${REGISTRY}/lokolla," /etc/kolla/kolla-build.conf
+ sed -i -r "s,^[# ]*push *=.+$,push = True," /etc/kolla/kolla-build.conf
+ sed -i -r "s,^[# ]*docker_registry:.+$,docker_registry: \"${REGISTRY}\"," /etc/kolla/globals.yml
+ sed -i -r "s,^[# ]*docker_namespace:.+$,docker_namespace: \"lokolla\"," /etc/kolla/globals.yml
+ sed -i -r "s,^[# ]*docker_insecure_registry:.+$,docker_insecure_registry: \"True\"," /etc/kolla/globals.yml
+ # Set network interfaces
+ sed -i -r "s,^[# ]*network_interface:.+$,network_interface: \"eth1\"," /etc/kolla/globals.yml
+ sed -i -r "s,^[# ]*neutron_external_interface:.+$,neutron_external_interface: \"eth2\"," /etc/kolla/globals.yml
+ # Set VIP address to be on the vagrant private network
+ sed -i -r "s,^[# ]*kolla_internal_vip_address:.+$,kolla_internal_vip_address: \"172.28.128.254\"," /etc/kolla/globals.yml
+}
+
+# Configure the operator node and install some additional packages.
+function configure_operator {
+ if is_centos; then
+ yum -y install git mariadb
+ elif is_ubuntu; then
+ apt-get -y install git mariadb-client selinux-utils
+ else
+ echo "Unsupported Distro: $DISTRO" 1>&2
+ exit 1
+ fi
+
+ pip install --upgrade "ansible>=2" python-openstackclient python-neutronclient tox
+
+ pip install ${KOLLA_PATH}
+
+ # Set selinux to permissive
+ if [[ "$(getenforce)" == "Enforcing" ]]; then
+ sed -i -r "s,^SELINUX=.+$,SELINUX=permissive," /etc/selinux/config
+ setenforce permissive
+ fi
+
+ tox -c ${KOLLA_PATH}/tox.ini -e genconfig
+ cp -r ${KOLLA_PATH}/etc/kolla/ /etc/kolla
+ ${KOLLA_PATH}/tools/generate_passwords.py
+ mkdir -p /usr/share/kolla
+ chown -R vagrant: /etc/kolla /usr/share/kolla
+
+ configure_kolla
+
+ # Make sure Ansible uses scp.
+ cat > ~vagrant/.ansible.cfg <<EOF
+[defaults]
+forks=100
+remote_user = root
+
+[ssh_connection]
+scp_if_ssh=True
+EOF
+ chown vagrant: ~vagrant/.ansible.cfg
+
+ mkdir -p /etc/kolla/config/nova/
+ cat > /etc/kolla/config/nova/nova-compute.conf <<EOF
+[libvirt]
+virt_type=qemu
+EOF
+
+ # Launch a local registry (and mirror) to speed up pulling images.
+ if [[ ! $(docker ps -a -q -f name=registry) ]]; then
+ docker run -d \
+ --name registry \
+ --restart=always \
+ -p ${REGISTRY_PORT}:5000 \
+ -e STANDALONE=True \
+ -e MIRROR_SOURCE=https://registry-1.docker.io \
+ -e MIRROR_SOURCE_INDEX=https://index.docker.io \
+ -e STORAGE_PATH=/var/lib/registry \
+ -v /data/host/registry-storage:/var/lib/registry \
+ registry:2
+ fi
+}
+
+prep_work
+install_docker
+
+if [[ "$VM" = "operator" ]]; then
+ configure_operator
+fi
+
+cleanup
diff --git a/contrib/dev/vagrant/newest_dhcp_lease.py b/contrib/dev/vagrant/newest_dhcp_lease.py
new file mode 100644
index 000000000..bb229af1d
--- /dev/null
+++ b/contrib/dev/vagrant/newest_dhcp_lease.py
@@ -0,0 +1,134 @@
+#!/usr/bin/env 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.
+
+"""
+Command-line utility to get the IP address from the newest DHCP lease.
+
+It's written for using with vagrant-hostmanager and vagrant-libvirt plugins.
+Vagrant-hostmanager by default fetches only IP addresses from eth0 interfaces
+on VM-s. Therefore, the first purpose of this utility is to be able to fetch
+the address also from the other interfaces.
+
+Libvirt/virsh only lists all DHCP leases for the given network with timestamps.
+DHCP leases have their expiration time, but are not cleaned up after destroying
+VM. If someone destroys and sets up the VM with the same hostname, we have
+many DHCP leases for the same hostname and we have to look up for timestamp.
+That's the second purpose of this script.
+"""
+
+import argparse
+import csv
+import functools
+import operator
+import xml.etree.ElementTree as etree
+
+import libvirt
+
+
+class NoPrivateDHCPInterfaceException(Exception):
+ pass
+
+
+class NoDHCPLeaseException(Exception):
+ pass
+
+
+def libvirt_conn(f):
+ @functools.wraps(f)
+ def wrapper(*args, **kwargs):
+ conn = libvirt.openReadOnly('qemu:///system')
+ return f(conn, *args, **kwargs)
+ return wrapper
+
+
+@libvirt_conn
+def get_vir_network_dhcp_lease(conn, vm_name):
+ """Libvirt since 1.2.6 version provides DHCPLeases method in virNetwork.
+
+ That's the current official way for getting DHCP leases and this
+ information isn't stored anywhere else anymore.
+ """
+ domain_name = 'vagrant_' + vm_name
+ mac_address = get_mac_address(conn, domain_name)
+
+ network = conn.networkLookupByName('vagrant-private-dhcp')
+ dhcp_leases = libvirt.virNetwork.DHCPLeases(network)
+
+ vm_dhcp_leases = [lease for lease in dhcp_leases
+ if lease['mac'] == mac_address]
+
+ newest_vm_dhcp_lease = sorted(vm_dhcp_leases,
+ key=operator.itemgetter('expirytime'),
+ reverse=True)[0]['ipaddr']
+ return newest_vm_dhcp_lease
+
+
+def get_mac_address(conn, domain_name):
+ """Get MAC address from domain XML."""
+ domain = conn.lookupByName(domain_name)
+ domain_xml = domain.XMLDesc()
+ domain_tree = etree.fromstring(domain_xml)
+ devices = domain_tree.find('devices')
+ interfaces = devices.iterfind('interface')
+
+ for interface in interfaces:
+ source = interface.find('source')
+ if source is None or source.get('network') != 'vagrant-private-dhcp':
+ continue
+ mac_element = interface.find('mac')
+ mac_address = mac_element.get('address')
+ return mac_address
+
+ raise NoPrivateDHCPInterfaceException()
+
+
+@libvirt_conn
+def get_dnsmasq_dhcp_lease(conn, vm_name):
+ """In libvirt under 1.2.6 DHCP leases are stored in file.
+
+ There is no API for DHCP leases yet.
+ """
+ domain_name = 'vagrant_' + vm_name
+ mac_address = get_mac_address(conn, domain_name)
+
+ with open(
+ '/var/lib/libvirt/dnsmasq/vagrant-private-dhcp.leases'
+ ) as leases_file:
+ reader = csv.reader(leases_file, delimiter=' ')
+ for row in reader:
+ lease_mac, lease_ip, lease_vm_name = row[1:4]
+ if not (lease_mac == mac_address and lease_vm_name == vm_name):
+ continue
+ return lease_ip
+
+ raise NoDHCPLeaseException()
+
+
+def main():
+ parser = argparse.ArgumentParser()
+ parser.add_argument('vm_name', help='Name of the virtual machine')
+
+ args = parser.parse_args()
+ vm_name = args.vm_name
+
+ if libvirt.getVersion() >= 1002006:
+ newest_dhcp_lease = get_vir_network_dhcp_lease(vm_name)
+ else:
+ newest_dhcp_lease = get_dnsmasq_dhcp_lease(vm_name)
+
+ print(newest_dhcp_lease)
+
+
+if __name__ == '__main__':
+ main()