diff --git a/docker/neutron-base/Dockerfile.j2 b/docker/neutron-base/Dockerfile.j2 index 86f0ea3..5b89211 100644 --- a/docker/neutron-base/Dockerfile.j2 +++ b/docker/neutron-base/Dockerfile.j2 @@ -19,6 +19,7 @@ RUN apt-get update \ {{ copy_sources("projectcalico/libcalico", "/libcalico") }} {{ copy_sources("projectcalico/calico", "/calico") }} {{ copy_sources("openstack/networking-calico", "/networking-calico") }} +{{ copy_sources("openstack/networking-odl", "/networking-odl") }} RUN cd /neutron \ && useradd --user-group neutron \ @@ -43,6 +44,8 @@ RUN /var/lib/microservices/venv/bin/pip install --upgrade /libcalico \ && /var/lib/microservices/venv/bin/pip install --upgrade /calico \ && rm -rf /calico \ && /var/lib/microservices/venv/bin/pip install --upgrade /networking-calico \ - && rm -rf /networking-calico + && rm -rf /networking-calico \ + && /var/lib/microservices/venv/bin/pip install --upgrade /networking-odl \ + && rm -rf /networking-odl ENV PATH /var/lib/microservices/venv/bin:$PATH diff --git a/docker/opendaylight/Dockerfile.j2 b/docker/opendaylight/Dockerfile.j2 new file mode 100644 index 0000000..66d685f --- /dev/null +++ b/docker/opendaylight/Dockerfile.j2 @@ -0,0 +1,16 @@ +FROM {{ image_spec("base-tools") }} +MAINTAINER {{ maintainer }} + +ENV JAVA_HOME /usr/lib/jvm/java-1.8.0-openjdk-amd64/ + +COPY {{ render('install_odl.sh.j2') }} /tmp/install_odl.sh + +RUN apt-get update && \ + apt-get install -y -t jessie-backports openjdk-8-jre-headless ca-certificates-java && \ + apt-get install -y openjdk-8-jre libxml-xpath-perl && \ + mkdir /odl && cd /odl && \ + sh -ex /tmp/install_odl.sh && \ + apt-get -y purge libxml-xpath-perl && \ + apt-get clean + +WORKDIR /odl/ diff --git a/docker/opendaylight/install_odl.sh.j2 b/docker/opendaylight/install_odl.sh.j2 new file mode 100644 index 0000000..0e16173 --- /dev/null +++ b/docker/opendaylight/install_odl.sh.j2 @@ -0,0 +1,6 @@ +curl -Lo maven-metadata.xml {{ url.opendaylight }}/{{ karaf_version }}/maven-metadata.xml + +BUNDLE_TIMESTAMP=`xpath -e "//snapshotVersion[extension='tar.gz'][1]/value/text()" maven-metadata.xml 2>/dev/null` +curl -Lo distribution-karaf.tar.gz {{ url.opendaylight }}/{{ karaf_version }}/distribution-karaf-${BUNDLE_TIMESTAMP}.tar.gz +tar -xvzf distribution-karaf.tar.gz --strip-components=1 +rm -rf distribution-karaf.tar.gz diff --git a/service/files/defaults.yaml b/service/files/defaults.yaml index c692c2e..cb70a8c 100644 --- a/service/files/defaults.yaml +++ b/service/files/defaults.yaml @@ -60,6 +60,31 @@ configs: ovs_db: loglevel: "info" + opendaylight: + api_port: + cont: 8080 + ovs_port: + cont: 6640 + openflow_port1: + cont: 6633 + openflow_port2: + cont: 6653 + dlux_port: + cont: 8181 + username: admin + password: password + karaf: + features_boot: + - odl-neutron-service + - odl-neutron-logger + - odl-restconf-all + - odl-aaa-authn + - odl-dlux-core + - odl-mdsal-apidocs + - odl-netvirt-openstack + - odl-ovsdb-ui + logging: + max_file_size: 1024GB sources: openstack/neutron: @@ -74,9 +99,14 @@ sources: openstack/networking-calico: git_url: https://github.com/openstack/networking-calico.git git_ref: master + openstack/networking-odl: + git_url: https://github.com/openstack/networking-odl.git + git_ref: stable/newton versions: + karaf_version: "0.5.3-SNAPSHOT" ovs_version: "system" url: ovs: http://openvswitch.org/releases + opendaylight: https://nexus.opendaylight.org/content/repositories/opendaylight.snapshot/org/opendaylight/integration/distribution-karaf diff --git a/service/files/ml2_conf.ini.j2 b/service/files/ml2_conf.ini.j2 index f62b99e..969a815 100644 --- a/service/files/ml2_conf.ini.j2 +++ b/service/files/ml2_conf.ini.j2 @@ -15,6 +15,8 @@ mechanism_drivers = openvswitch,l2population mechanism_drivers = linuxbridge,l2population {% elif neutron.plugin_agent == "calico" %} mechanism_drivers = calico +{% elif neutron.plugin_agent == "opendaylight" %} +mechanism_drivers = opendaylight, logger {% endif %} extension_drivers = port_security{% if neutron.enable_qos %},qos{% endif %} @@ -76,3 +78,11 @@ local_ip = {{ network_topology["private"]["address"] }} etcd_host = {{ neutron.calico.etcd_host }} etcd_port = {{ neutron.calico.etcd_port }} {% endif %} + +{% if neutron.plugin_agent == "opendaylight" %} +[ml2_odl] +port_binding_controller = network-topology +password = {{ opendaylight.password }} +username = {{ opendaylight.username }} +url = {{ address('opendaylight', port=opendaylight.api_port, with_scheme=True) }}/controller/nb/v2/neutron +{% endif %} diff --git a/service/files/neutron.conf.j2 b/service/files/neutron.conf.j2 index bcea232..89ca64b 100644 --- a/service/files/neutron.conf.j2 +++ b/service/files/neutron.conf.j2 @@ -13,7 +13,7 @@ endpoint_type = internalURL metadata_proxy_socket = /var/lib/neutron/ccp/metadata_proxy -{% if neutron.plugin_agent == "openvswitch" %} +{% if neutron.plugin_agent in ["openvswitch", "opendaylight"] %} interface_driver = neutron.agent.linux.interface.OVSInterfaceDriver {% elif neutron.plugin_agent == "linuxbridge" %} interface_driver = neutron.agent.linux.interface.BridgeInterfaceDriver @@ -22,7 +22,7 @@ interface_driver = neutron.agent.linux.interface.BridgeInterfaceDriver allow_overlapping_ips = true dhcp_agents_per_network = 2 core_plugin = {{ neutron.core_plugin }} -service_plugins = router{% if neutron.enable_lbaas %},neutron_lbaas.services.loadbalancer.plugin.LoadBalancerPluginv2{% endif %}{% if neutron.enable_qos %},qos{% endif %} +service_plugins = {% if neutron.plugin_agent == "opendaylight" %}odl-router{% else %}router{% endif %}{% if neutron.enable_lbaas %},neutron_lbaas.services.loadbalancer.plugin.LoadBalancerPluginv2{% endif %}{% if neutron.enable_qos %},qos{% endif %} # Enable HA mode for virtual routers. (boolean value) diff --git a/service/files/odl-set-admin-password.sh.j2 b/service/files/odl-set-admin-password.sh.j2 new file mode 100644 index 0000000..ec759db --- /dev/null +++ b/service/files/odl-set-admin-password.sh.j2 @@ -0,0 +1,5 @@ +#!/bin/bash -ex + +data='{"name":"admin", "description":"admin account", "enabled":"true", "email":"", "password":"{{ opendaylight.password }}"}' + +curl -u admin:admin -X PUT -H "Content-Type: application/json" --data "$data" {{ address('opendaylight', port=opendaylight.dlux_port, with_scheme=True) }}/auth/v1/users/admin@sdn diff --git a/service/files/odl-wait-boot.sh.j2 b/service/files/odl-wait-boot.sh.j2 new file mode 100644 index 0000000..34eff6b --- /dev/null +++ b/service/files/odl-wait-boot.sh.j2 @@ -0,0 +1,9 @@ +#!/bin/bash -ex + +odl_port={{ opendaylight.ovs_port.cont }} +odl_boot_wait_url=restconf/operational/network-topology:network-topology/topology/netvirt:1 + +odl_boot_wait_timeout=60 +odl_retry_check_interval=5 + +curl -o /dev/null --fail --silent --head -u admin:admin http://127.0.0.1:${odl_port}/${odl_boot_wait_url} diff --git a/service/files/org.apache.karaf.features.cfg.j2 b/service/files/org.apache.karaf.features.cfg.j2 new file mode 100644 index 0000000..62635ba --- /dev/null +++ b/service/files/org.apache.karaf.features.cfg.j2 @@ -0,0 +1,54 @@ +################################################################################ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You 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. +# +################################################################################ + +# +# Defines if the startlvl should be respected during feature startup. The default value is true. The default +# behavior for 2.x is false (!) for this property +# +# Be aware that this property is deprecated and will be removed in Karaf 4.0. So, if you need to +# set this to false, please use this only as a temporary solution! +# +#respectStartLvlDuringFeatureStartup=true + + +# +# Defines if the startlvl should be respected during feature uninstall. The default value is true. +# If true, means stop bundles respecting the descend order of start level in a certain feature. +# +#respectStartLvlDuringFeatureUninstall=true + +# +# Comma separated list of features repositories to register by default +# +featuresRepositories = mvn:org.apache.karaf.features/standard/3.0.7/xml/features,mvn:org.apache.karaf.features/enterprise/3.0.7/xml/features,mvn:org.ops4j.pax.web/pax-web-features/3.2.9/xml/features,mvn:org.apache.karaf.features/spring/3.0.7/xml/features,mvn:org.opendaylight.integration/features-integration-index/0.5.3-SNAPSHOT/xml/features + +# +# Comma separated list of features to install at startup +# +featuresBoot=config,standard,region,package,kar,ssh,management,{{ opendaylight.karaf.features_boot|join(',') }} + +# +# Defines if the boot features are started in asynchronous mode (in a dedicated thread) +# +featuresBootAsynchronous=false + +# +# Store cfg file for config element in feature +# +#configCfgStore=true diff --git a/service/files/org.ops4j.pax.logging.cfg.j2 b/service/files/org.ops4j.pax.logging.cfg.j2 new file mode 100644 index 0000000..a7ed529 --- /dev/null +++ b/service/files/org.ops4j.pax.logging.cfg.j2 @@ -0,0 +1,50 @@ +################################################################################ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You 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. +# +################################################################################ + +# Root logger +log4j.rootLogger=INFO, async, osgi:* +log4j.throwableRenderer=org.apache.log4j.OsgiThrowableRenderer + +# CONSOLE appender not used by default +log4j.appender.stdout=org.apache.log4j.ConsoleAppender +log4j.appender.stdout.layout=org.apache.log4j.PatternLayout +log4j.appender.stdout.layout.ConversionPattern=%d{ISO8601} | %-5.5p | %-16.16t | %-32.32c{1} | %X{bundle.id} - %X{bundle.name} - %X{bundle.version} | %m%n + +# Async appender forwarding to file appender +log4j.appender.async=org.apache.log4j.AsyncAppender +log4j.appender.async.appenders=out + +# File appender +log4j.appender.out=org.apache.log4j.RollingFileAppender +log4j.appender.out.layout=org.apache.log4j.PatternLayout +log4j.appender.out.layout.ConversionPattern=%d{ISO8601} | %-5.5p | %-16.16t | %-32.32c{1} | %X{bundle.id} - %X{bundle.name} - %X{bundle.version} | %m%n +log4j.appender.out.file=${karaf.data}/log/karaf.log +log4j.appender.out.append=true +log4j.appender.out.maxFileSize={{ opendaylight.logging.max_file_size }} +log4j.appender.out.maxBackupIndex=10 + +# Sift appender +log4j.appender.sift=org.apache.log4j.sift.MDCSiftingAppender +log4j.appender.sift.key=bundle.name +log4j.appender.sift.default=karaf +log4j.appender.sift.appender=org.apache.log4j.FileAppender +log4j.appender.sift.appender.layout=org.apache.log4j.PatternLayout +log4j.appender.sift.appender.layout.ConversionPattern=%d{ISO8601} | %-5.5p | %-16.16t | %-32.32c{1} | %m%n +log4j.appender.sift.appender.file=${karaf.data}/log/$\\{bundle.name\\}.log +log4j.appender.sift.appender.append=true diff --git a/service/files/ovs-set-managed-by-odl.sh.j2 b/service/files/ovs-set-managed-by-odl.sh.j2 new file mode 100644 index 0000000..6e1feab --- /dev/null +++ b/service/files/ovs-set-managed-by-odl.sh.j2 @@ -0,0 +1,20 @@ +#!/bin/bash + +set -e + +odl_ip={{ address('opendaylight') | gethostbyname }} + +odl_port={{ opendaylight.ovs_port.cont }} + +ovs-vsctl set-manager tcp:$odl_ip:$odl_port + +ovs_id=$(ovs-vsctl get Open_vSwitch . _uuid) +local_ip="{{ network_topology["private"]["address"] }}" +ovs-vsctl set Open_vSwitch $ovs_id other_config:local_ip=$local_ip + +provider_mappings= +{%- for net in neutron.physnets -%} +{%- if not loop.first %},{% endif -%} +{{ net.name }}:{{ net.interface }} +{%- endfor %} +ovs-vsctl set Open_vSwitch $ovs_id other_config:provider_mappings="$provider_mappings" diff --git a/service/neutron-server.yaml b/service/neutron-server.yaml index d3a37eb..7262eb5 100644 --- a/service/neutron-server.yaml +++ b/service/neutron-server.yaml @@ -1,6 +1,9 @@ dsl_version: 0.4.0 service: name: neutron-server + # {% if neutron.plugin_agent == "opendaylight" %} + hostNetwork: true + # {% endif %} ports: - {{ neutron.server_port }} annotations: @@ -61,6 +64,11 @@ service: files: - neutron.conf - ml2-conf.ini + # {% if neutron.plugin_agent == "opendaylight" %} + dependencies: + - openvswitch-vswitchd + # {% endif %} + files: neutron.conf: path: /etc/neutron/neutron.conf diff --git a/service/opendaylight.yaml b/service/opendaylight.yaml new file mode 100644 index 0000000..e88b3f2 --- /dev/null +++ b/service/opendaylight.yaml @@ -0,0 +1,50 @@ +dsl_version: 0.1.0 +service: + name: opendaylight + ports: + - {{ opendaylight.api_port }} + - {{ opendaylight.ovs_port }} + - {{ opendaylight.openflow_port1 }} + - {{ opendaylight.openflow_port2 }} + - {{ opendaylight.dlux_port }} + containers: + - name: opendaylight + image: opendaylight + probes: + readiness: + type: exec + command: /usr/local/bin/odl-wait-boot.sh + volumes: + - name: ovs-socket + type: host + path: /run/openvswitch + daemon: + command: ./bin/karaf + files: + - odl-wait-boot.sh + - org.apache.karaf.features.cfg + - org.ops4j.pax.logging.cfg + post: + - name: odl-set-admin-password + type: single + command: /tmp/odl-set-admin-password.sh + files: + - odl-set-admin-password.sh + +files: + odl-wait-boot.sh: + path: /usr/local/bin/odl-wait-boot.sh + content: odl-wait-boot.sh.j2 + perm: "0755" + odl-set-admin-password.sh: + path: /tmp/odl-set-admin-password.sh + content: odl-set-admin-password.sh.j2 + perm: "0755" + org.apache.karaf.features.cfg: + path: /odl/etc/org.apache.karaf.features.cfg + content: org.apache.karaf.features.cfg.j2 + perm: "0600" + org.ops4j.pax.logging.cfg: + path: /odl/etc/org.ops4j.pax.logging.cfg + content: org.ops4j.pax.logging.cfg.j2 + perm: "0600" diff --git a/service/openvswitch-db.yaml b/service/openvswitch-db.yaml index a40ce98..c4eef2e 100644 --- a/service/openvswitch-db.yaml +++ b/service/openvswitch-db.yaml @@ -14,7 +14,7 @@ service: - name: ovs-bootstrap command: /opt/ccp/bin/openvswitch-db-bootstrap.sh daemon: - command: "/usr/sbin/ovsdb-server /etc/openvswitch/conf.db -vconsole:{{ ovs_db.loglevel }} --remote=punix:/run/openvswitch/db.sock" + command: "/usr/sbin/ovsdb-server /etc/openvswitch/conf.db -vconsole:{{ ovs_db.loglevel }} --remote=punix:/run/openvswitch/db.sock --remote=db:Open_vSwitch,Open_vSwitch,manager_options" files: - openvswitch-db-bootstrap.sh files: diff --git a/service/openvswitch-vswitchd.yaml b/service/openvswitch-vswitchd.yaml index 7211671..b430723 100644 --- a/service/openvswitch-vswitchd.yaml +++ b/service/openvswitch-vswitchd.yaml @@ -7,6 +7,12 @@ service: - name: openvswitch-vswitchd image: openvswitch-vswitchd privileged: true + # {% if neutron.plugin_agent == "opendaylight" %} + probes: + readiness: + type: exec + command: "ovs-vsctl list Bridge | grep br-int > /dev/null" + # {% endif %} volumes: - name: ovs-socket type: host @@ -23,18 +29,36 @@ service: command: ovs-vsctl --no-wait show dependencies: - openvswitch-db:local + # {% if neutron.plugin_agent == "opendaylight" %} + - opendaylight + # {% endif %} + # {% if neutron.plugin_agent != "opendaylight" %} # {% for net in neutron.physnets %} - name: vswitchd-setup-ovs-bridge-{{ net.name }} command: /usr/local/bin/ovs-ensure-configured.sh {{ net.bridge_name }} {{ net.interface }} # {% endfor %} + # {% endif %} daemon: command: /usr/sbin/ovs-vswitchd unix:/run/openvswitch/db.sock --mlockall dependencies: - openvswitch-db:local + # {% if neutron.plugin_agent == "opendaylight" %} + - opendaylight + # {% endif %} files: - ovs-ensure-configured.sh + # {% if neutron.plugin_agent == "opendaylight" %} + - ovs-set-managed-by-odl.sh + post: + - name: ovs-set-managed-by-odl + command: /usr/local/bin/ovs-set-managed-by-odl.sh + # {% endif %} files: ovs-ensure-configured.sh: path: /usr/local/bin/ovs-ensure-configured.sh content: ovs-ensure-configured.sh perm: "0755" + ovs-set-managed-by-odl.sh: + path: /usr/local/bin/ovs-set-managed-by-odl.sh + content: ovs-set-managed-by-odl.sh.j2 + perm: "0755"