diff options
author | Andy Ning <andy.ning@windriver.com> | 2014-06-13 11:21:16 -0400 |
---|---|---|
committer | Bruce Ashfield <bruce.ashfield@windriver.com> | 2014-06-18 15:08:11 -0400 |
commit | 9b966a64a3bbf50f4661d4d8adac2a56794db5cb (patch) | |
tree | e664e1f8f29bae43f32cc50857c727005eb12198 | |
parent | b53f039deee13fe869aaceca27d4e30cd40efb48 (diff) | |
download | meta-cloud-services-9b966a64a3bbf50f4661d4d8adac2a56794db5cb.tar.gz |
Add metadata service support to controller node
The metadata service is working as the following:
- metadata is being served by nova-api on controller at port 8775.
- VM instance requests metadata by 169.254.169.254 (eg, curl http://169.254.169.254/latest/meta-data)
- metadata request comes to neutron-ns-metadata-proxy on controller in dhcp network name space.
- neutron-ns-metadata-proxy forwards the request to neutron-metadata-agent through a unix domain socket (/var/lib/neutron/metadata_proxy).
- neutron-metadata-agent sends the request to nova-api on port 8775 to be serviced.
To support metadata service, neutron-ns-metadata-proxy is baked into the controller image. Also neutron-metadata-agent startup script
(/etc/init.d/neutron-metadata-agent) and config file (/etc/neutron/metadata_agent.ini) are added to start up metadata agent at system
initialization. dhcp_agent.ini and nova.conf are updated as well.
A README.metadata is added in the Documentation/ directory.
Signed-off-by: Andy Ning <andy.ning@windriver.com>
Signed-off-by: Bruce Ashfield <bruce.ashfield@windriver.com>
8 files changed, 179 insertions, 2 deletions
diff --git a/meta-openstack/Documentation/README.metadata b/meta-openstack/Documentation/README.metadata new file mode 100644 index 0000000..46a7c2a --- /dev/null +++ b/meta-openstack/Documentation/README.metadata | |||
@@ -0,0 +1,117 @@ | |||
1 | Summary | ||
2 | ======= | ||
3 | |||
4 | This document is intended to provide an overview of what metadata service is, | ||
5 | how it works and how it is tested to ensure that metadata service is working correctly. | ||
6 | |||
7 | Metadata Service Introduction | ||
8 | ============================= | ||
9 | |||
10 | OpenStack Compute service uses a special metadata service to enable VM instances to retrieve instance-specific data (metadata). Instances access the metadata service at http://169.254.169.254. The metadata service supports two sets of APIs: an OpenStack metadata API and an EC2-compatible API. Each of the APIs is versioned by date. | ||
11 | |||
12 | To retrieve a list of supported versions for the OpenStack metadata API, make a GET request to http://169.254.169.254/openstack. | ||
13 | |||
14 | For example: | ||
15 | $ curl http://169.254.169.254/openstack | ||
16 | 2012-08-10 | ||
17 | latest | ||
18 | |||
19 | To list supported versions for the EC2-compatible metadata API, make a GET request to http://169.254.169.254. | ||
20 | |||
21 | For example: | ||
22 | $ curl http://169.254.169.254 | ||
23 | 1.0 | ||
24 | 2007-01-19 | ||
25 | 2007-03-01 | ||
26 | 2007-08-29 | ||
27 | 2007-10-10 | ||
28 | 2007-12-15 | ||
29 | 2008-02-01 | ||
30 | 2008-09-01 | ||
31 | 2009-04-04 | ||
32 | latest | ||
33 | |||
34 | If cloud-init is supported by the VM image, cloud-init can retrieve metadata from metadata service at instance initialization. | ||
35 | |||
36 | Metadata Service Implementation | ||
37 | =============================== | ||
38 | |||
39 | Metadata service is provided by nova-api on controller at port 8775. VM instance requests metadata by 169.254.169.254 | ||
40 | (eg, curl http://169.254.169.254/latest/meta-data). The requests from VM come to neutron-ns-metadata-proxy on controller | ||
41 | in dhcp network name space, neutron-ns-metadata-proxy forwards the requests to neutron-metadata-agent through a unix domain | ||
42 | socket (/var/lib/neutron/metadata_proxy), and neutron-metadata-agent sends the request to nova-api on port 8775 to be serviced. | ||
43 | |||
44 | Test Steps | ||
45 | ========== | ||
46 | 1. build controller and compute image as normal. | ||
47 | 2. setup a cloud with one controller and one compute on real hardware with a flat network. | ||
48 | - make sure controller and compute see each other by ping. | ||
49 | 3. on controller: | ||
50 | - checking metadata agent is running: | ||
51 | # ps -ef | grep neutron-metadata-agent | ||
52 | - create a network | ||
53 | example: | ||
54 | # neutron net-create --provider:physical_network=ph-eth0 --provider:network_type=flat --router:external=True MY_NET | ||
55 | - create a subnet on the network just created | ||
56 | example: | ||
57 | # neutron subnet-create MY_NET 128.224.149.0/24 --name MY_SUBNET --no-gateway --host-route destination=0.0.0.0/0,nexthop=128.224.149.1 --allocation-pool start=128.224.149.200,end=128.224.149.210 | ||
58 | - create an image from cirros 0.3.2 (0.3.0 doesn't work properly due to a bug in it) | ||
59 | example: | ||
60 | # glance image-create --name cirros-0.3.2 --is-public true --container-format bare --disk-format qcow2 --file cirros-0.3.2-x86_64-disk.img | ||
61 | - boot an instance from cirros-0.3.2 image | ||
62 | example: | ||
63 | # nova boot --image cirros-0.3.2 --flavor 1 OpenStack_1 | ||
64 | - checking dhcp domain is created | ||
65 | # ip netns list | ||
66 | example output: | ||
67 | qdhcp-229dd93f-a3da-4a21-be22-49c3f3a5dbbd | ||
68 | |||
69 | # ip netns exec qdhcp-229dd93f-a3da-4a21-be22-49c3f3a5dbbd ip addr | ||
70 | example output: | ||
71 | 16: tap5dfe0d76-c5: <BROADCAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN | ||
72 | link/ether fa:16:3e:c5:d9:65 brd ff:ff:ff:ff:ff:ff | ||
73 | inet 128.224.149.201/24 brd 128.224.149.255 scope global tap5dfe0d76-c5 | ||
74 | inet 169.254.169.254/16 brd 169.254.255.255 scope global tap5dfe0d76-c5 | ||
75 | inet6 fe80::f816:3eff:fec5:d965/64 scope link | ||
76 | valid_lft forever preferred_lft forever | ||
77 | 17: lo: <LOOPBACK,UP,LOWER_UP> mtu 16436 qdisc noqueue state UNKNOWN | ||
78 | link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 | ||
79 | inet 127.0.0.1/8 scope host lo | ||
80 | inet6 ::1/128 scope host | ||
81 | valid_lft forever preferred_lft forever | ||
82 | 18: sit0: <NOARP> mtu 1480 qdisc noop state DOWN | ||
83 | link/sit 0.0.0.0 brd 0.0.0.0 | ||
84 | |||
85 | # ip netns exec qdhcp-229dd93f-a3da-4a21-be22-49c3f3a5dbbd netstat -anpe | ||
86 | - ensure 0.0.0.0:80 is in there | ||
87 | example output: | ||
88 | Active Internet connections (servers and established) | ||
89 | Proto Recv-Q Send-Q Local Address Foreign Address State User Inode PID/Program name | ||
90 | tcp 0 0 128.224.149.201:53 0.0.0.0:* LISTEN 0 159928 8508/dnsmasq | ||
91 | tcp 0 0 169.254.169.254:53 0.0.0.0:* LISTEN 0 159926 8508/dnsmasq | ||
92 | tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 0 164930 8522/python | ||
93 | tcp6 0 0 fe80::f816:3eff:fec5:53 :::* LISTEN 65534 161016 8508/dnsmasq | ||
94 | udp 0 0 128.224.149.201:53 0.0.0.0:* 0 159927 8508/dnsmasq | ||
95 | udp 0 0 169.254.169.254:53 0.0.0.0:* 0 159925 8508/dnsmasq | ||
96 | udp 0 0 0.0.0.0:67 0.0.0.0:* 0 159918 8508/dnsmasq | ||
97 | udp6 0 0 fe80::f816:3eff:fec5:53 :::* 65534 161015 8508/dnsmasq | ||
98 | Active UNIX domain sockets (servers and established) | ||
99 | Proto RefCnt Flags Type State I-Node PID/Program name Path | ||
100 | unix 2 [ ] DGRAM 37016 8508/dnsmasq | ||
101 | |||
102 | 4. on VM instance: | ||
103 | - check instance log, ensure the instance gets a dhcp IP address and a static route, as well as the instance-id | ||
104 | - login to the instance, and do the following test | ||
105 | $ hostname | ||
106 | the host name should be the name specified in "nova boot" when instance is created. | ||
107 | $ ifconfig | ||
108 | it should have a valid IP on eth0 in the range specified in "neutron subnet-create" when subnet is created. | ||
109 | $ route | ||
110 | there should be an entry for "169.254.169.254 x.x.x.x 255.255.255.255 eth0" | ||
111 | $ curl http://169.254.169.254/latest/meta-data | ||
112 | it should return a list of metadata (hostname, instance-id, etc). | ||
113 | $ nova reboot <instance>, nova stop <instance>, nova start <instance>, nova rebuild <instance> <image> | ||
114 | metadata should be working | ||
115 | $ nova boot --user-data <userdata.txt> --image <image> --flavor 1 <instance> | ||
116 | curl http://169.254.169.254/latest/user-data should retrieve the userdata.txt | ||
117 | |||
diff --git a/meta-openstack/classes/identity.bbclass b/meta-openstack/classes/identity.bbclass index d1eb276..70191a5 100644 --- a/meta-openstack/classes/identity.bbclass +++ b/meta-openstack/classes/identity.bbclass | |||
@@ -4,3 +4,4 @@ SERVICE_PASSWORD = "password" | |||
4 | SERVICE_TENANT_NAME = "service" | 4 | SERVICE_TENANT_NAME = "service" |
5 | DB_USER = "admin" | 5 | DB_USER = "admin" |
6 | DB_PASSWORD = "admin" | 6 | DB_PASSWORD = "admin" |
7 | METADATA_SHARED_SECRET = "password" | ||
diff --git a/meta-openstack/recipes-devtools/python/python-neutron/dhcp_agent.ini b/meta-openstack/recipes-devtools/python/python-neutron/dhcp_agent.ini index f9b1523..7cc648f 100644 --- a/meta-openstack/recipes-devtools/python/python-neutron/dhcp_agent.ini +++ b/meta-openstack/recipes-devtools/python/python-neutron/dhcp_agent.ini | |||
@@ -37,6 +37,7 @@ interface_driver = neutron.agent.linux.interface.OVSInterfaceDriver | |||
37 | # be activated when the subnet does not contain any router port. The guest | 37 | # be activated when the subnet does not contain any router port. The guest |
38 | # instance must be configured to request host routes via DHCP (Option 121). | 38 | # instance must be configured to request host routes via DHCP (Option 121). |
39 | # enable_isolated_metadata = False | 39 | # enable_isolated_metadata = False |
40 | enable_isolated_metadata = True | ||
40 | 41 | ||
41 | # Allows for serving metadata requests coming from a dedicated metadata | 42 | # Allows for serving metadata requests coming from a dedicated metadata |
42 | # access network whose cidr is 169.254.169.254/16 (or larger prefix), and | 43 | # access network whose cidr is 169.254.169.254/16 (or larger prefix), and |
diff --git a/meta-openstack/recipes-devtools/python/python-neutron/metadata_agent.ini b/meta-openstack/recipes-devtools/python/python-neutron/metadata_agent.ini new file mode 100644 index 0000000..98d958d --- /dev/null +++ b/meta-openstack/recipes-devtools/python/python-neutron/metadata_agent.ini | |||
@@ -0,0 +1,29 @@ | |||
1 | [DEFAULT] | ||
2 | # Show debugging output in log (sets DEBUG log level output) | ||
3 | # debug = True | ||
4 | |||
5 | # The Neutron user information for accessing the Neutron API. | ||
6 | auth_url = http://localhost:5000/v2.0 | ||
7 | auth_region = RegionOne | ||
8 | admin_tenant_name = %SERVICE_TENANT_NAME% | ||
9 | admin_user = %SERVICE_USER% | ||
10 | admin_password = %SERVICE_PASSWORD% | ||
11 | |||
12 | # Network service endpoint type to pull from the keystone catalog | ||
13 | # endpoint_type = adminURL | ||
14 | |||
15 | # IP address used by Nova metadata server | ||
16 | # nova_metadata_ip = 127.0.0.1 | ||
17 | |||
18 | # TCP Port used by Nova metadata server | ||
19 | # nova_metadata_port = 8775 | ||
20 | |||
21 | # When proxying metadata requests, Neutron signs the Instance-ID header with a | ||
22 | # shared secret to prevent spoofing. You may select any string for a secret, | ||
23 | # but it must match here and in the configuration used by the Nova Metadata | ||
24 | # Server. NOTE: Nova uses a different key: neutron_metadata_proxy_shared_secret | ||
25 | # metadata_proxy_shared_secret = | ||
26 | metadata_proxy_shared_secret = %METADATA_SHARED_SECRET% | ||
27 | |||
28 | # Location of Metadata Proxy UNIX domain socket | ||
29 | # metadata_proxy_socket = $state_path/metadata_proxy | ||
diff --git a/meta-openstack/recipes-devtools/python/python-neutron_git.bb b/meta-openstack/recipes-devtools/python/python-neutron_git.bb index ab803f8..5fbad17 100644 --- a/meta-openstack/recipes-devtools/python/python-neutron_git.bb +++ b/meta-openstack/recipes-devtools/python/python-neutron_git.bb | |||
@@ -14,6 +14,7 @@ SRC_URI = "git://github.com/openstack/${SRCNAME}.git;branch=stable/icehouse \ | |||
14 | file://neutron-agent.init \ | 14 | file://neutron-agent.init \ |
15 | file://l3_agent.ini \ | 15 | file://l3_agent.ini \ |
16 | file://dhcp_agent.ini \ | 16 | file://dhcp_agent.ini \ |
17 | file://metadata_agent.ini \ | ||
17 | file://neutron-dhcp-agent-netns-cleanup.cron \ | 18 | file://neutron-dhcp-agent-netns-cleanup.cron \ |
18 | file://0001-neutron.conf-jumpstart-nova-state-reporting-configur.patch \ | 19 | file://0001-neutron.conf-jumpstart-nova-state-reporting-configur.patch \ |
19 | " | 20 | " |
@@ -91,6 +92,22 @@ do_install_append() { | |||
91 | install -m 0755 ${WORKDIR}/neutron-$AGENT.init.sh ${D}${sysconfdir}/init.d/neutron-$AGENT-agent | 92 | install -m 0755 ${WORKDIR}/neutron-$AGENT.init.sh ${D}${sysconfdir}/init.d/neutron-$AGENT-agent |
92 | install -m 600 ${WORKDIR}/${AGENT}_agent.ini ${NEUTRON_CONF_DIR}/ | 93 | install -m 600 ${WORKDIR}/${AGENT}_agent.ini ${NEUTRON_CONF_DIR}/ |
93 | fi | 94 | fi |
95 | |||
96 | AGENT=metadata | ||
97 | ARGS="--config-file=${sysconfdir}/${SRCNAME}/neutron.conf --config-file=${sysconfdir}/${SRCNAME}/metadata_agent.ini" | ||
98 | if ${@base_contains('DISTRO_FEATURES', 'sysvinit', 'true', 'false', d)}; then | ||
99 | sed "s:@suffix@:$AGENT:;s:@args@:$ARGS:" < ${WORKDIR}/neutron-agent.init >${WORKDIR}/neutron-$AGENT.init.sh | ||
100 | install -m 0755 ${WORKDIR}/neutron-$AGENT.init.sh ${D}${sysconfdir}/init.d/neutron-$AGENT-agent | ||
101 | install -m 600 ${WORKDIR}/${AGENT}_agent.ini ${NEUTRON_CONF_DIR}/ | ||
102 | fi | ||
103 | sed -e "s:%SERVICE_TENANT_NAME%:${SERVICE_TENANT_NAME}:g" \ | ||
104 | -i ${NEUTRON_CONF_DIR}/metadata_agent.ini | ||
105 | sed -e "s:%SERVICE_USER%:${SRCNAME}:g" \ | ||
106 | -i ${NEUTRON_CONF_DIR}/metadata_agent.ini | ||
107 | sed -e "s:%SERVICE_PASSWORD%:${SERVICE_PASSWORD}:g" \ | ||
108 | -i ${NEUTRON_CONF_DIR}/metadata_agent.ini | ||
109 | sed -e "s:%METADATA_SHARED_SECRET%:${METADATA_SHARED_SECRET}:g" \ | ||
110 | -i ${NEUTRON_CONF_DIR}/metadata_agent.ini | ||
94 | 111 | ||
95 | cp run_tests.sh ${NEUTRON_CONF_DIR} | 112 | cp run_tests.sh ${NEUTRON_CONF_DIR} |
96 | } | 113 | } |
@@ -182,8 +199,9 @@ FILES_${SRCNAME}-l3-agent = "${bindir}/neutron-l3-agent \ | |||
182 | " | 199 | " |
183 | 200 | ||
184 | FILES_${SRCNAME}-metadata-agent = "${bindir}/neutron-metadata-agent \ | 201 | FILES_${SRCNAME}-metadata-agent = "${bindir}/neutron-metadata-agent \ |
202 | ${bindir}/neutron-ns-metadata-proxy \ | ||
185 | ${sysconfdir}/${SRCNAME}/metadata_agent.ini \ | 203 | ${sysconfdir}/${SRCNAME}/metadata_agent.ini \ |
186 | ${sysconfdir}/init.d/metadata_agent \ | 204 | ${sysconfdir}/init.d/neutron-metadata-agent \ |
187 | " | 205 | " |
188 | 206 | ||
189 | FILES_${SRCNAME}-extra-agents = "${bindir}/*" | 207 | FILES_${SRCNAME}-extra-agents = "${bindir}/*" |
@@ -233,7 +251,7 @@ RDEPENDS_${SRCNAME}-setup = "postgresql sudo" | |||
233 | 251 | ||
234 | RRECOMMENDS_${SRCNAME}-server = "${SRCNAME}-plugin-openvswitch" | 252 | RRECOMMENDS_${SRCNAME}-server = "${SRCNAME}-plugin-openvswitch" |
235 | 253 | ||
236 | INITSCRIPT_PACKAGES = "${SRCNAME}-server ${SRCNAME}-plugin-openvswitch ${SRCNAME}-plugin-linuxbridge ${SRCNAME}-dhcp-agent ${SRCNAME}-l3-agent" | 254 | INITSCRIPT_PACKAGES = "${SRCNAME}-server ${SRCNAME}-plugin-openvswitch ${SRCNAME}-plugin-linuxbridge ${SRCNAME}-dhcp-agent ${SRCNAME}-l3-agent ${SRCNAME}-metadata-agent" |
237 | INITSCRIPT_NAME_${SRCNAME}-server = "neutron-server" | 255 | INITSCRIPT_NAME_${SRCNAME}-server = "neutron-server" |
238 | INITSCRIPT_PARAMS_${SRCNAME}-server = "${OS_DEFAULT_INITSCRIPT_PARAMS}" | 256 | INITSCRIPT_PARAMS_${SRCNAME}-server = "${OS_DEFAULT_INITSCRIPT_PARAMS}" |
239 | INITSCRIPT_NAME_${SRCNAME}-plugin-openvswitch = "neutron-openvswitch-agent" | 257 | INITSCRIPT_NAME_${SRCNAME}-plugin-openvswitch = "neutron-openvswitch-agent" |
@@ -244,3 +262,5 @@ INITSCRIPT_NAME_${SRCNAME}-dhcp-agent = "neutron-dhcp-agent" | |||
244 | INITSCRIPT_PARAMS_${SRCNAME}-dhcp-agent = "${OS_DEFAULT_INITSCRIPT_PARAMS}" | 262 | INITSCRIPT_PARAMS_${SRCNAME}-dhcp-agent = "${OS_DEFAULT_INITSCRIPT_PARAMS}" |
245 | INITSCRIPT_NAME_${SRCNAME}-l3-agent = "neutron-l3-agent" | 263 | INITSCRIPT_NAME_${SRCNAME}-l3-agent = "neutron-l3-agent" |
246 | INITSCRIPT_PARAMS_${SRCNAME}-l3-agent = "${OS_DEFAULT_INITSCRIPT_PARAMS}" | 264 | INITSCRIPT_PARAMS_${SRCNAME}-l3-agent = "${OS_DEFAULT_INITSCRIPT_PARAMS}" |
265 | INITSCRIPT_NAME_${SRCNAME}-metadata-agent = "neutron-metadata-agent" | ||
266 | INITSCRIPT_PARAMS_${SRCNAME}-metadata-agent = "${OS_DEFAULT_INITSCRIPT_PARAMS}" | ||
diff --git a/meta-openstack/recipes-devtools/python/python-nova/nova.conf b/meta-openstack/recipes-devtools/python/python-nova/nova.conf index 35eed8b..fbaaa78 100644 --- a/meta-openstack/recipes-devtools/python/python-nova/nova.conf +++ b/meta-openstack/recipes-devtools/python/python-nova/nova.conf | |||
@@ -73,6 +73,12 @@ libvirt_images_rbd_ceph_conf=/etc/ceph/ceph.conf | |||
73 | rbd_user=cinder-volume | 73 | rbd_user=cinder-volume |
74 | #rbd_secret_uuid= | 74 | #rbd_secret_uuid= |
75 | 75 | ||
76 | # nova-api configuration for metadata | ||
77 | # neutron_metadata_proxy_shared_secret must match | ||
78 | # metadata_proxy_shared_secret in metadata_agent.ini | ||
79 | service_neutron_metadata_proxy = true | ||
80 | neutron_metadata_proxy_shared_secret=%METADATA_SHARED_SECRET% | ||
81 | |||
76 | [spice] | 82 | [spice] |
77 | agent_enabled=True | 83 | agent_enabled=True |
78 | enabled=True | 84 | enabled=True |
diff --git a/meta-openstack/recipes-devtools/python/python-nova_git.bb b/meta-openstack/recipes-devtools/python/python-nova_git.bb index 0c6686d..0af38db 100644 --- a/meta-openstack/recipes-devtools/python/python-nova_git.bb +++ b/meta-openstack/recipes-devtools/python/python-nova_git.bb | |||
@@ -81,6 +81,8 @@ do_install_append() { | |||
81 | sed -e "s:%DB_USER%:${DB_USER}:g" -i ${NOVA_CONF_DIR}/nova.conf | 81 | sed -e "s:%DB_USER%:${DB_USER}:g" -i ${NOVA_CONF_DIR}/nova.conf |
82 | sed -e "s:%DB_PASSWORD%:${DB_PASSWORD}:g" -i ${NOVA_CONF_DIR}/nova.conf | 82 | sed -e "s:%DB_PASSWORD%:${DB_PASSWORD}:g" -i ${NOVA_CONF_DIR}/nova.conf |
83 | 83 | ||
84 | sed -e "s:%METADATA_SHARED_SECRET%:${METADATA_SHARED_SECRET}:g" -i ${NOVA_CONF_DIR}/nova.conf | ||
85 | |||
84 | sed -e "s:%CONTROLLER_IP%:${CONTROLLER_IP}:g" -i ${NOVA_CONF_DIR}/nova.conf | 86 | sed -e "s:%CONTROLLER_IP%:${CONTROLLER_IP}:g" -i ${NOVA_CONF_DIR}/nova.conf |
85 | sed -e "s:%CONTROLLER_HOST%:${CONTROLLER_HOST}:g" -i ${NOVA_CONF_DIR}/nova.conf | 87 | sed -e "s:%CONTROLLER_HOST%:${CONTROLLER_HOST}:g" -i ${NOVA_CONF_DIR}/nova.conf |
86 | 88 | ||
diff --git a/meta-openstack/recipes-extended/packagegroups/packagegroup-cloud-network.bb b/meta-openstack/recipes-extended/packagegroups/packagegroup-cloud-network.bb index 5240aee..6134124 100644 --- a/meta-openstack/recipes-extended/packagegroups/packagegroup-cloud-network.bb +++ b/meta-openstack/recipes-extended/packagegroups/packagegroup-cloud-network.bb | |||
@@ -10,6 +10,7 @@ RDEPENDS_${PN} = " \ | |||
10 | neutron-plugin-openvswitch \ | 10 | neutron-plugin-openvswitch \ |
11 | neutron-dhcp-agent \ | 11 | neutron-dhcp-agent \ |
12 | neutron-l3-agent \ | 12 | neutron-l3-agent \ |
13 | neutron-metadata-agent \ | ||
13 | openvswitch-switch \ | 14 | openvswitch-switch \ |
14 | dhcp-server \ | 15 | dhcp-server \ |
15 | dhcp-client \ | 16 | dhcp-client \ |