├── .coveragerc ├── .gitignore ├── .gitreview ├── .stestr.conf ├── .zuul.yaml ├── CONTRIBUTING.rst ├── Dockerfile ├── HACKING.rst ├── LICENSE ├── README.rst ├── __init__.py ├── contrib ├── busybox │ ├── Dockerfile │ ├── build_image.sh │ └── busybox.tar.xz ├── docker │ ├── run_kuryr.sh │ └── v2plugin │ │ ├── config.json │ │ └── v2plugin_rootfs.sh ├── tls │ └── kuryr.json └── vagrant │ ├── README.md │ ├── Vagrantfile │ ├── add_vagrant_user.sh │ ├── config │ └── kuryr_rc │ ├── devstack.sh │ └── vagrant.sh ├── devstack ├── local.conf.sample ├── plugin.sh └── settings ├── doc ├── Makefile ├── requirements.txt └── source │ ├── conf.py │ ├── config-sriov.rst │ ├── devref │ ├── index.rst │ └── libnetwork_remote_driver_design.rst │ ├── fullstack-test.rst │ ├── index.rst │ ├── install │ ├── compute-install-ubuntu.rst │ ├── compute-install.rst │ ├── controller-install.rst │ ├── get_started.rst │ ├── index.rst │ ├── next-steps.rst │ └── verify.rst │ └── readme.rst ├── etc ├── README-config.txt ├── kuryr.json ├── kuryr.spec └── oslo-config-generator │ └── kuryr.conf ├── init └── kuryr.conf ├── kuryr_libnetwork ├── __init__.py ├── config.py ├── constants.py ├── controllers.py ├── opts.py ├── port_driver │ ├── __init__.py │ ├── base.py │ ├── driver.py │ └── drivers │ │ ├── __init__.py │ │ ├── nested.py │ │ ├── sriov.py │ │ ├── veth.py │ │ └── vlan.py ├── schemata │ ├── __init__.py │ ├── commons.py │ ├── endpoint_create.py │ ├── endpoint_delete.py │ ├── endpoint_info.py │ ├── join.py │ ├── leave.py │ ├── network_create.py │ ├── network_delete.py │ ├── release_address.py │ ├── release_pool.py │ ├── request_address.py │ └── request_pool.py ├── server.py ├── tests │ ├── __init__.py │ ├── contrib │ │ ├── gate_hook.sh │ │ └── post_test_hook.sh │ ├── fullstack │ │ ├── __init__.py │ │ ├── kuryr_base.py │ │ ├── test_container.py │ │ ├── test_ipam.py │ │ └── test_network.py │ └── unit │ │ ├── __init__.py │ │ ├── base.py │ │ ├── port_driver │ │ ├── __init__.py │ │ ├── drivers │ │ │ ├── __init__.py │ │ │ ├── test_nested.py │ │ │ ├── test_sriov.py │ │ │ ├── test_veth.py │ │ │ └── test_vlan.py │ │ ├── test_base.py │ │ └── test_driver.py │ │ ├── test_config.py │ │ ├── test_external_connectivity.py │ │ ├── test_ipam_pool.py │ │ ├── test_join.py │ │ ├── test_kuryr.py │ │ ├── test_kuryr_endpoint.py │ │ ├── test_kuryr_existing_network.py │ │ ├── test_kuryr_ipam.py │ │ ├── test_kuryr_network.py │ │ ├── test_leave.py │ │ ├── test_schema.py │ │ └── test_utils.py ├── utils.py └── version.py ├── playbooks ├── post_fullstack_job.yaml └── run_fullstack_job.yaml ├── rally-jobs ├── README.rst ├── extra │ └── README.rst ├── kuryr-libnetwork.yaml ├── plugins │ ├── README.rst │ ├── __init__.py │ ├── context │ │ ├── __init__.py │ │ └── docker_networks.py │ └── scenarios │ │ ├── __init__.py │ │ ├── kuryr.py │ │ └── utils.py └── tasks │ └── scenarios │ ├── create_and_delete_networks_with_kuryr.json │ ├── create_and_delete_networks_without_kuryr.json │ └── list_networks.json ├── releasenotes ├── notes │ ├── add_support_ipv6_subnet-a024ffd6f7acc883.yaml │ ├── bp-existing-subnetpool-aa454cf843cba47c.yaml │ ├── bug-1668803-c39f746e38878239.yaml │ ├── bug-1671222-9ea0cf3ab39f0abc.yaml │ ├── drop-py-2-7-033606554411d7c6.yaml │ ├── started-using-reno-8411d91eb3fe9e6c.yaml │ └── use-uwsgi-to-run-server-4f43e615fd277c73.yaml └── source │ ├── 2023.1.rst │ ├── 2023.2.rst │ ├── 2024.1.rst │ ├── 2024.2.rst │ ├── 2025.1.rst │ ├── _static │ └── .placeholder │ ├── _templates │ └── .placeholder │ ├── conf.py │ ├── index.rst │ ├── queens.rst │ ├── rocky.rst │ ├── stein.rst │ ├── train.rst │ ├── unreleased.rst │ ├── ussuri.rst │ ├── victoria.rst │ ├── wallaby.rst │ ├── xena.rst │ ├── yoga.rst │ └── zed.rst ├── requirements.txt ├── scripts ├── run_kuryr.sh └── run_server.py ├── setup.cfg ├── setup.py ├── test-requirements.txt ├── tools └── generate_config_file_samples.sh └── tox.ini /.coveragerc: -------------------------------------------------------------------------------- 1 | [run] 2 | branch = True 3 | source = kuryr_libnetwork 4 | omit = kuryr_libnetwork/tests/* 5 | 6 | [report] 7 | ignore_errors = True 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.py[cod] 2 | 3 | # C extensions 4 | *.so 5 | 6 | # Packages 7 | *.egg 8 | *.egg-info 9 | dist 10 | build 11 | eggs 12 | parts 13 | bin 14 | var 15 | sdist 16 | develop-eggs 17 | lib 18 | lib64 19 | cover 20 | 21 | # Installer logs 22 | pip-log.txt 23 | 24 | # Translations 25 | *.mo 26 | 27 | # Complexity 28 | output/*.html 29 | output/*/index.html 30 | 31 | # Sphinx 32 | doc/build 33 | 34 | # pbr generates these 35 | AUTHORS 36 | ChangeLog 37 | 38 | # Editors 39 | *~ 40 | *.sw? 41 | 42 | # Hidden directories 43 | /.* 44 | !/.coveragerc 45 | !/.gitignore 46 | !/.gitreview 47 | !/.mailmap 48 | !/.pylintrc 49 | !/.stestr.conf 50 | !/.testr.conf 51 | 52 | contrib/vagrant/.vagrant 53 | 54 | # Configuration files 55 | etc/kuryr.conf 56 | etc/kuryr.conf.sample 57 | 58 | # Ignore user specific local.conf settings for vagrant 59 | contrib/vagrant/user_local.conf 60 | -------------------------------------------------------------------------------- /.gitreview: -------------------------------------------------------------------------------- 1 | [gerrit] 2 | host=review.opendev.org 3 | port=29418 4 | project=openstack/kuryr-libnetwork.git 5 | -------------------------------------------------------------------------------- /.stestr.conf: -------------------------------------------------------------------------------- 1 | [DEFAULT] 2 | test_path=${OS_TEST_PATH:-./kuryr_libnetwork/tests/unit} 3 | top_dir=./ 4 | -------------------------------------------------------------------------------- /.zuul.yaml: -------------------------------------------------------------------------------- 1 | - job: 2 | name: kuryr-libnetwork-fullstack-base 3 | parent: devstack-tox-functional 4 | vars: &base_vars 5 | use_python3: 1 6 | use_src: 0 7 | devstack_localrc: 8 | KURYR_CONFIG_DIR: /etc/kuryr-libnetwork 9 | tox_envlist: fullstack 10 | tox_install_siblings: false 11 | devstack_plugins: 12 | kuryr-libnetwork: https://opendev.org/openstack/kuryr-libnetwork 13 | devstack-plugin-container: https://opendev.org/openstack/devstack-plugin-container 14 | timeout: 7800 15 | required-projects: 16 | - opendev.org/openstack/devstack 17 | - opendev.org/openstack/devstack-plugin-container 18 | - opendev.org/openstack/kuryr 19 | - opendev.org/openstack/kuryr-libnetwork 20 | roles: 21 | - zuul: opendev.org/openstack/devstack 22 | irrelevant-files: &base_irrelevant_files 23 | - ^.*\.rst$ 24 | - ^doc/.*$ 25 | 26 | - job: 27 | name: kuryr-libnetwork-rally-base 28 | parent: rally-task-at-devstack 29 | timeout: 7800 30 | vars: 31 | use_src: 0 32 | devstack_plugins: 33 | rally-openstack: https://opendev.org/openstack/rally-openstack 34 | kuryr-libnetwork: http://opendev.org/openstack/kuryr-libnetwork 35 | devstack-plugin-container: https://opendev.org/openstack/devstack-plugin-container 36 | devstack_localrc: 37 | USE_PYTHON3: True 38 | devstack_local_config: 39 | KURYR_CONFIG_DIR: /etc/kuryr-libnetwork 40 | rally_task: rally-jobs/kuryr-libnetwork.yaml 41 | required-projects: 42 | - opendev.org/openstack/rally-openstack 43 | - opendev.org/openstack/kuryr 44 | - opendev.org/openstack/kuryr-libnetwork 45 | - opendev.org/openstack/devstack-plugin-container 46 | voting: false 47 | 48 | - job: 49 | name: kuryr-libnetwork-install 50 | parent: devstack 51 | timeout: 7800 52 | required-projects: 53 | - opendev.org/openstack/devstack 54 | - opendev.org/openstack/devstack-plugin-container 55 | - opendev.org/openstack/kuryr 56 | - opendev.org/openstack/kuryr-libnetwork 57 | roles: 58 | - zuul: opendev.org/openstack/devstack 59 | vars: 60 | devstack_localrc: 61 | KURYR_CONFIG_DIR: /etc/kuryr-libnetwork 62 | devstack_plugins: 63 | devstack-plugin-container: https://opendev.org/openstack/devstack-plugin-container 64 | kuryr-libnetwork: https://opendev.org/openstack/kuryr-libnetwork 65 | voting: false 66 | 67 | - job: 68 | name: kuryr-libnetwork-fullstack-py3 69 | parent: kuryr-libnetwork-fullstack-base 70 | 71 | - job: 72 | name: kuryr-libnetwork-fullstack-ipv6-only 73 | parent: devstack-tempest-ipv6 74 | irrelevant-files: *base_irrelevant_files 75 | required-projects: 76 | - opendev.org/openstack/devstack 77 | - opendev.org/openstack/devstack-plugin-container 78 | - opendev.org/openstack/kuryr 79 | - opendev.org/openstack/kuryr-libnetwork 80 | - opendev.org/openstack/tempest 81 | vars: 82 | <<: *base_vars 83 | devstack_services: 84 | s-account: false 85 | s-object: false 86 | s-container: false 87 | s-proxy: false 88 | run: playbooks/run_fullstack_job.yaml 89 | post-run: playbooks/post_fullstack_job.yaml 90 | 91 | - job: 92 | name: kuryr-libnetwork-kuryr_lib-src-fullstack 93 | parent: kuryr-libnetwork-fullstack-base 94 | vars: 95 | use_src: 1 96 | branches: master 97 | voting: false 98 | 99 | - job: 100 | name: kuryr-libnetwork-rally 101 | parent: kuryr-libnetwork-rally-base 102 | 103 | - job: 104 | name: kuryr-libnetwork-kuryr_lib-src-rally 105 | parent: kuryr-libnetwork-rally-base 106 | vars: 107 | use_src: 1 108 | branches: master 109 | voting: false 110 | 111 | - project: 112 | templates: 113 | - openstack-cover-jobs 114 | - openstack-python3-jobs 115 | - release-notes-jobs-python3 116 | - publish-openstack-docs-pti 117 | - check-requirements 118 | check: 119 | jobs: 120 | - kuryr-libnetwork-install 121 | - kuryr-libnetwork-kuryr_lib-src-fullstack 122 | - kuryr-libnetwork-kuryr_lib-src-rally 123 | - kuryr-libnetwork-fullstack-py3 124 | - kuryr-libnetwork-rally 125 | - kuryr-libnetwork-fullstack-ipv6-only 126 | gate: 127 | jobs: 128 | - kuryr-libnetwork-kuryr_lib-src-fullstack 129 | - kuryr-libnetwork-fullstack-py3 130 | - kuryr-libnetwork-fullstack-ipv6-only 131 | -------------------------------------------------------------------------------- /CONTRIBUTING.rst: -------------------------------------------------------------------------------- 1 | If you would like to contribute to the development of OpenStack, you must 2 | follow the steps in this page: 3 | 4 | https://docs.openstack.org/infra/manual/developers.html 5 | 6 | If you already have a good understanding of how the system works and your 7 | OpenStack accounts are set up, you can skip to the development workflow 8 | section of this documentation to learn how changes to OpenStack should be 9 | submitted for review via the Gerrit tool: 10 | 11 | https://docs.openstack.org/infra/manual/developers.html#development-workflow 12 | 13 | Please note that the team is currently pretty small, so we decided to adopt a 14 | policy of a single +2 in Gerrit required to merge the patches. 15 | 16 | Pull requests submitted through GitHub will be ignored. 17 | 18 | Bugs should be filed on Launchpad, not GitHub: 19 | 20 | https://bugs.launchpad.net/kuryr 21 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine:3.4 2 | MAINTAINER Antoni Segura Puimedon "toni@kuryr.org" 3 | WORKDIR / 4 | COPY . /opt/kuryr-libnetwork 5 | RUN \ 6 | apk add --no-cache \ 7 | bash \ 8 | iproute2 \ 9 | openvswitch \ 10 | py-pip \ 11 | python \ 12 | uwsgi-python \ 13 | && apk add --no-cache --virtual build-deps \ 14 | gcc \ 15 | git \ 16 | linux-headers \ 17 | musl-dev \ 18 | python-dev \ 19 | && pip --no-cache-dir install -U pip setuptools \ 20 | \ 21 | && cd /opt/kuryr-libnetwork \ 22 | && pip --no-cache-dir install . \ 23 | && cd / \ 24 | && apk del build-deps 25 | 26 | ENV SERVICE_USER="admin" 27 | ENV SERVICE_PROJECT_NAME="admin" 28 | ENV SERVICE_PASSWORD="pass" 29 | ENV SERVICE_DOMAIN_NAME="Default" 30 | ENV USER_DOMAIN_NAME="Default" 31 | ENV IDENTITY_URL="http://127.0.0.1:5000/v3" 32 | ENV CAPABILITY_SCOPE="local" 33 | ENV HTTP_SOCKET=":23750" 34 | ENV LOG_LEVEL="INFO" 35 | ENV PROCESSES=2 36 | 37 | VOLUME /var/log/kuryr 38 | 39 | CMD ["/opt/kuryr-libnetwork/contrib/docker/run_kuryr.sh"] 40 | -------------------------------------------------------------------------------- /HACKING.rst: -------------------------------------------------------------------------------- 1 | kuryr Style Commandments 2 | =============================================== 3 | 4 | Read the OpenStack Style Commandments https://docs.openstack.org/hacking/latest/ 5 | -------------------------------------------------------------------------------- /__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 4 | # not use this file except in compliance with the License. You may obtain 5 | # a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 | # License for the specific language governing permissions and limitations 13 | # under the License. 14 | 15 | import pbr.version 16 | 17 | 18 | __version__ = pbr.version.VersionInfo('kuryr').version_string() 19 | -------------------------------------------------------------------------------- /contrib/busybox/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM scratch 2 | ADD busybox.tar.xz / 3 | CMD ["sh"] 4 | -------------------------------------------------------------------------------- /contrib/busybox/build_image.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | tar cv --files-from /dev/null | docker import - scratch 4 | 5 | sudo docker build -t kuryr/busybox . 6 | -------------------------------------------------------------------------------- /contrib/busybox/busybox.tar.xz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openstack/kuryr-libnetwork/70676593993a8c370be3fc27a8fecc4e84661e24/contrib/busybox/busybox.tar.xz -------------------------------------------------------------------------------- /contrib/docker/run_kuryr.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ ! -d /etc/kuryr ]; then 4 | mkdir -p /etc/kuryr 5 | cat > /etc/kuryr/kuryr.conf << EOF 6 | [DEFAULT] 7 | 8 | bindir = /usr/libexec/kuryr 9 | capability_scope = $CAPABILITY_SCOPE 10 | log_dir = /var/log/kuryr 11 | log_file = kuryr.log 12 | 13 | [neutron] 14 | project_domain_name = $USER_DOMAIN_NAME 15 | project_name = $SERVICE_PROJECT_NAME 16 | user_domain_name = $SERVICE_DOMAIN_NAME 17 | password = $SERVICE_PASSWORD 18 | username = $SERVICE_USER 19 | auth_url = $IDENTITY_URL 20 | auth_type = password 21 | EOF 22 | 23 | fi 24 | 25 | /usr/sbin/uwsgi \ 26 | --plugin /usr/lib/uwsgi/python \ 27 | --http-socket $HTTP_SOCKET \ 28 | -w kuryr_libnetwork.server:app \ 29 | --master \ 30 | --processes "$PROCESSES" 31 | -------------------------------------------------------------------------------- /contrib/docker/v2plugin/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "Description": "kuryr-libnetwork plugin for Docker", 3 | "Documentation": "https://docs.openstack.org/kuryr-libnetwork/latest/", 4 | "Entrypoint": ["/opt/kuryr-libnetwork/contrib/docker/run_kuryr.sh"], 5 | "Interface" : { 6 | "Types": ["docker.networkdriver/1.0", "docker.ipamdriver/1.0"], 7 | "Socket": "kuryr-libnetwork.sock" 8 | }, 9 | "network": { 10 | "type": "host" 11 | }, 12 | "Env": [ 13 | { 14 | "Description": "Username", 15 | "Name": "SERVICE_USER", 16 | "Settable": [ 17 | "value" 18 | ], 19 | "Value": "admin" 20 | }, 21 | { 22 | "Description": "Project name to scope to", 23 | "Name": "SERVICE_PROJECT_NAME", 24 | "Settable": [ 25 | "value" 26 | ], 27 | "Value": "admin" 28 | }, 29 | { 30 | "Description": "User's password", 31 | "Name": "SERVICE_PASSWORD", 32 | "Settable": [ 33 | "value" 34 | ], 35 | "Value": "pass" 36 | }, 37 | { 38 | "Description": "Domain name containing project", 39 | "Name": "SERVICE_DOMAIN_NAME", 40 | "Settable": [ 41 | "value" 42 | ], 43 | "Value": "Default" 44 | }, 45 | { 46 | "Description": "User's domain name", 47 | "Name": "USER_DOMAIN_NAME", 48 | "Settable": [ 49 | "value" 50 | ], 51 | "Value": "Default" 52 | }, 53 | { 54 | "Description": "Authentication URL", 55 | "Name": "IDENTITY_URL", 56 | "Settable": [ 57 | "value" 58 | ], 59 | "Value": "http://127.0.0.1:5000/v3" 60 | }, 61 | { 62 | "Description": "Kuryr plugin scope reported to libnetwork", 63 | "Name": "CAPABILITY_SCOPE", 64 | "Settable": [ 65 | "value" 66 | ], 67 | "Value": "local" 68 | }, 69 | { 70 | "Description": "http-socket in uwsgi", 71 | "Name": "HTTP_SOCKET", 72 | "Settable": [ 73 | "value" 74 | ], 75 | "Value": "/run/docker/plugins/kuryr-libnetwork.sock" 76 | }, 77 | { 78 | "Description": "log level", 79 | "Name": "LOG_LEVEL", 80 | "Settable": [ 81 | "value" 82 | ], 83 | "Value": "INFO" 84 | }, 85 | { 86 | "Description": "uwsgi process number", 87 | "Name": "PROCESSES", 88 | "Settable": [ 89 | "value" 90 | ], 91 | "Value": "2" 92 | } 93 | ], 94 | "mounts": [ 95 | { 96 | "type": "bind", 97 | "options": ["rbind", "rw"], 98 | "source": "/var/run/openvswitch", 99 | "destination": "/var/run/openvswitch" 100 | }, 101 | { 102 | "type": "bind", 103 | "options": ["rbind", "rw"], 104 | "source": "/var/log/kuryr", 105 | "destination": "/var/log/kuryr" 106 | }, 107 | { 108 | "type": "bind", 109 | "options": ["rbind", "ro"], 110 | "source": "/etc/kuryr", 111 | "destination": "/etc/kuryr" 112 | } 113 | ], 114 | "Linux": { 115 | "Capabilities": ["CAP_NET_ADMIN"] 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /contrib/docker/v2plugin/v2plugin_rootfs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Script to create the kuryr-libnetwork docker v2 plugin 3 | # run this script from kuryr-libnetwork directory with contrib/docker/v2plugin/v2plugin_rootfs.sh 4 | 5 | echo "Copy kuryr-libentwork config.json" 6 | rm -rf ./config.json 7 | cp contrib/docker/v2plugin/config.json ./ 8 | echo "Creating rootfs for kuryr-libnetwork v2plugin" 9 | docker build -t kuryr-libnetwork-rootfs . 10 | id=$(docker create kuryr-libnetwork-rootfs true) 11 | echo "Deleting old rootfs" 12 | rm -rf rootfs 13 | echo "Creating new rootfs" 14 | mkdir -p rootfs 15 | docker export "${id}" | tar -x -C rootfs 16 | echo "Clean up" 17 | docker rm -vf "${id}" 18 | docker rmi kuryr-libnetwork-rootfs 19 | -------------------------------------------------------------------------------- /contrib/tls/kuryr.json: -------------------------------------------------------------------------------- 1 | { 2 | "Name": "kuryr", 3 | "Addr": "https://127.0.0.1:23750", 4 | "TLSConfig": { 5 | "InsecureSkipVerify": false, 6 | "CAFile": "/var/lib/kuryr/certs/ca.pem", 7 | "CertFile": "/var/lib/kuryr/certs/cert.pem", 8 | "KeyFile": "/var/lib/kuryr/certs/key.pem" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /contrib/vagrant/README.md: -------------------------------------------------------------------------------- 1 | vagrant-devstack-Kuryr-libnetwork 2 | ================================= 3 | 4 | Getting started 5 | --------------- 6 | 7 | A Vagrant based kuryr,neutron,keystone and experimental docker system. 8 | 9 | Steps to try vagrant image: 10 | 11 | 1. Install Vagrant on your local machine. Install one of the current 12 | providers supported: VirtualBox, Libvirt or Vagrant 13 | 2. Git clone kuryr-libnetwork repository. 14 | 3. Run `cd kuryr-libnetwork/contrib/vagrant` 15 | 4. Run `vagrant up` 16 | It will take from 10 to 60 minutes, depending on your internet speed. 17 | Vagrant-cachier can speed up the process [2]. 18 | 5. `vagrant ssh` 19 | You will get a VM with everything running. 20 | You will get vm shell with keystone and neutron already running. 21 | 22 | At this point you should have experimental docker, kuryr, neutron, keystone all 23 | up, running and pointing to each other. Any docker network related commands can 24 | be tried now as explained in [1]. 25 | 26 | References: 27 | 28 | [1] https://github.com/openstack/kuryr/blob/master/doc/source/devref/libnetwork_remote_driver_design.rst#L64 29 | [2] http://fgrehm.viewdocs.io/vagrant-cachier/ 30 | 31 | Vagrant Options available 32 | ------------------------- 33 | 34 | You can set the following environment variables before running `vagrant up` to modify 35 | the definition of the Virtual Machine spawned: 36 | 37 | * **VAGRANT\_KURYR\_VM\_BOX**: To change the Vagrant Box used. Should be available in 38 | [atlas](http://atlas.hashicorp.com). 39 | 40 | export VAGRANT_KURYR_VM_BOX=centos/7 41 | 42 | Could be an example of a rpm-based option. 43 | 44 | * **VAGRANT\_KURYR\_VM\_MEMORY**: To modify the RAM of the VM. Defaulted to: 4096 45 | * **VAGRANT\_KURYR\_VM\_CPU**: To modify the cpus of the VM. Defaulted to: 2 46 | * **VAGRANT\_KURYR\_RUN\_DEVSTACK**: Whether `vagrant up` should run devstack to 47 | have an environment ready to use. Set it to 'false' if you want to edit 48 | `local.conf` before run ./stack.sh manually in the VM. Defaulted to: true. 49 | See below for additional options for editing local.conf. 50 | 51 | Additional devstack configuration 52 | --------------------------------- 53 | 54 | To add additional configuration to local.conf before the VM is provisioned, you can 55 | create a file called "user_local.conf" in the contrib/vagrant directory of 56 | networking-kuryr. This file will be appended to the "local.conf" created during the 57 | Vagrant provisioning. 58 | 59 | For example, to use OVN as the Neutron plugin with Kuryr, you can create a 60 | "user_local.conf" with the following configuration: 61 | 62 | enable_plugin networking-ovn http://opendev.org/openstack/networking-ovn 63 | enable_service ovn-northd 64 | enable_service ovn-controller 65 | disable_service q-agt 66 | disable_service q-l3 67 | disable_service q-dhcp 68 | -------------------------------------------------------------------------------- /contrib/vagrant/Vagrantfile: -------------------------------------------------------------------------------- 1 | VAGRANTFILE_API_VERSION = "2" 2 | 3 | Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| 4 | 5 | VM_MEMORY = ENV.fetch('VAGRANT_KURYR_VM_MEMORY', 6144).to_i 6 | VM_CPUS = ENV.fetch('VAGRANT_KURYR_VM_CPUS', 2).to_i 7 | RUN_DEVSTACK = ENV.fetch('VAGRANT_KURYR_RUN_DEVSTACK', 'true') 8 | 9 | config.vm.hostname = 'devstack' 10 | 11 | config.vm.provider 'virtualbox' do |v, override| 12 | override.vm.box = ENV.fetch('VAGRANT_KURYR_VM_BOX', 'ubuntu/xenial64') 13 | v.memory = VM_MEMORY 14 | v.cpus = VM_CPUS 15 | end 16 | 17 | config.vm.provider 'parallels' do |v, override| 18 | override.vm.box = ENV.fetch('VAGRANT_KURYR_VM_BOX', 'parallels/ubuntu-16.04') 19 | v.memory = VM_MEMORY 20 | v.cpus = VM_CPUS 21 | v.customize ['set', :id, '--nested-virt', 'on'] 22 | end 23 | 24 | config.vm.provider 'libvirt' do |v, override| 25 | override.vm.box = ENV.fetch('VAGRANT_KURYR_VM_BOX', 'yk0/ubuntu-xenial') 26 | v.memory = VM_MEMORY 27 | v.cpus = VM_CPUS 28 | v.nested = true 29 | v.graphics_type = 'spice' 30 | v.video_type = 'qxl' 31 | end 32 | 33 | config.ssh.username = "ubuntu" 34 | config.vm.provision "shell", path: "add_vagrant_user.sh" 35 | 36 | config.vm.synced_folder '../../devstack/', '/devstack' 37 | # For CentOS machines it needs to be specified 38 | config.vm.synced_folder '.', '/vagrant' 39 | 40 | config.vm.provision :shell do |s| 41 | s.path = 'vagrant.sh' 42 | s.args = RUN_DEVSTACK 43 | end 44 | 45 | if Vagrant.has_plugin?('vagrant-cachier') 46 | config.cache.scope = :box 47 | end 48 | 49 | config.vm.network :forwarded_port, guest: 80, host_ip: "127.0.0.1", host: 8080 50 | end 51 | -------------------------------------------------------------------------------- /contrib/vagrant/add_vagrant_user.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo "create user vagrant" 4 | adduser --disabled-password --gecos "" vagrant 5 | echo 'vagrant:vagrant' | chpasswd 6 | ls -al /home/ 7 | echo "add sudo privilege to user vagrant" 8 | cp /etc/sudoers.d/90-cloud-init-users /etc/sudoers.d/admin 9 | chmod +w /etc/sudoers.d/admin 10 | ls -al /etc/sudoers.d/ 11 | sed -i 's/ubuntu/vagrant/g' /etc/sudoers.d/admin 12 | cat /etc/sudoers.d/admin 13 | echo "enable ssh access for user vagrant" 14 | mkdir /home/vagrant/.ssh 15 | cat /home/ubuntu/.ssh/authorized_keys > /home/vagrant/.ssh/authorized_keys 16 | chown vagrant:vagrant -R /home/vagrant/.ssh 17 | su - vagrant -c "cat /home/vagrant/.ssh/authorized_keys" 18 | chmod 600 /home/vagrant/.ssh/authorized_keys 19 | ls -al /home/vagrant/.ssh 20 | chmod 700 /home/vagrant/.ssh 21 | ls -al /home/vagrant 22 | -------------------------------------------------------------------------------- /contrib/vagrant/config/kuryr_rc: -------------------------------------------------------------------------------- 1 | export SERVICE_USER=admin 2 | export SERVICE_PASSWORD=pass 3 | export SERVICE_TENANT_NAME=admin 4 | export SERVICE_TOKEN=pass 5 | export IDENTITY_URL=http://127.0.0.1:5000/v2.0 6 | export DOCKER_HOST="tcp://0.0.0.0:2375" 7 | -------------------------------------------------------------------------------- /contrib/vagrant/devstack.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | BASHPATH=$(dirname "$0"\") 6 | RUN_DEVSTACK="$1" 7 | echo "Run script from $BASHPATH" 8 | 9 | # Copied shamelessly from Devstack 10 | function GetOSVersion { 11 | if [[ -x $(which lsb_release 2>/dev/null) ]]; then 12 | os_FAMILY='Debian' 13 | elif [[ -r /etc/redhat-release ]]; then 14 | os_FAMILY='RedHat' 15 | else 16 | echo "Unsupported distribution!" 17 | exit 1; 18 | fi 19 | } 20 | 21 | GetOSVersion 22 | 23 | if [[ "$os_FAMILY" == "Debian" ]]; then 24 | export DEBIAN_FRONTEND noninteractive 25 | sudo apt-get update 26 | sudo apt-get install -qqy git 27 | elif [[ "$os_FAMILY" == "RedHat" ]]; then 28 | sudo yum install -y -d 0 -e 0 git 29 | fi 30 | 31 | # determine checkout folder 32 | PWD=$(su "$OS_USER" -c "cd && pwd") 33 | DEVSTACK=$PWD/devstack 34 | 35 | # check if devstack is already there 36 | if [[ ! -d "$DEVSTACK" ]] 37 | then 38 | echo "Download devstack into $DEVSTACK" 39 | 40 | # clone devstack 41 | su "$OS_USER" -c "cd && git clone -b master https://github.com/openstack-dev/devstack.git $DEVSTACK" 42 | 43 | echo "Copy configuration" 44 | 45 | # copy local.conf.sample settings (source: kuryr/devstack/local.conf.sample) 46 | cp /devstack/local.conf.sample $DEVSTACK/local.conf 47 | # If local settings are present, append them 48 | if [ -f "/vagrant/user_local.conf" ]; then 49 | cat /vagrant/user_local.conf >> $DEVSTACK/local.conf 50 | fi 51 | chown "$OS_USER":"$OS_USER" "$DEVSTACK"/local.conf 52 | 53 | fi 54 | 55 | if $RUN_DEVSTACK; then 56 | echo "Start Devstack" 57 | su "$OS_USER" -c "cd $DEVSTACK && ./stack.sh" 58 | else 59 | echo "Virtual Machine ready. You can run devstack by executing '/home/vagrant/devstack/stack.sh'" 60 | fi 61 | -------------------------------------------------------------------------------- /contrib/vagrant/vagrant.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | export OS_USER=vagrant 4 | export HOST_IP=127.0.0.1 5 | 6 | # run script 7 | bash /vagrant/devstack.sh "$1" 8 | 9 | #set environment variables for kuryr 10 | su "$OS_USER" -c "echo 'source /vagrant/config/kuryr_rc' >> ~/.bash_profile" 11 | -------------------------------------------------------------------------------- /devstack/local.conf.sample: -------------------------------------------------------------------------------- 1 | [[local|localrc]] 2 | 3 | LOGFILE=stack.sh.log 4 | LOG_COLOR=False 5 | 6 | DATABASE_PASSWORD=pass 7 | RABBIT_PASSWORD=pass 8 | SERVICE_PASSWORD=pass 9 | SERVICE_TOKEN=pass 10 | ADMIN_PASSWORD=pass 11 | 12 | # If you want to try pluginv2 in devstack, set to True 13 | ENABLE_PLUGINV2=False 14 | 15 | # Install kuryr git master source code by default. 16 | # If you want to use stable kuryr lib, please comment out this line. 17 | LIBS_FROM_GIT=kuryr 18 | 19 | enable_plugin devstack-plugin-container https://github.com/openstack/devstack-plugin-container 20 | enable_plugin kuryr-libnetwork https://opendev.org/openstack/kuryr-libnetwork 21 | enable_plugin neutron https://opendev.org/openstack/neutron 22 | 23 | # Use Neutron instead of nova-network 24 | disable_service n-net 25 | enable_service q-svc 26 | enable_service q-dhcp 27 | enable_service q-l3 28 | disable_service heat 29 | enable_service q-agt 30 | enable_service q-qos 31 | disable_service tempest 32 | -------------------------------------------------------------------------------- /devstack/plugin.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 3 | # not use this file except in compliance with the License. You may obtain 4 | # a copy of the License at 5 | # 6 | # http://www.apache.org/licenses/LICENSE-2.0 7 | # 8 | # Unless required by applicable law or agreed to in writing, software 9 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 10 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 11 | # License for the specific language governing permissions and limitations 12 | # under the License. 13 | 14 | # Save trace setting 15 | XTRACE=$(set +o | grep xtrace) 16 | set +o xtrace 17 | 18 | echo_summary "kuryr-libnetwork's plugin.sh was called..." 19 | 20 | 21 | function check_docker { 22 | if is_ubuntu; then 23 | dpkg -s docker-engine > /dev/null 2>&1 24 | else 25 | rpm -q docker-engine > /dev/null 2>&1 || rpm -q docker > /dev/null 2>&1 26 | fi 27 | } 28 | 29 | function create_kuryr_cache_dir { 30 | # Create cache dir 31 | sudo install -d -o "$STACK_USER" "$KURYR_AUTH_CACHE_DIR" 32 | if [[ ! "$KURYR_AUTH_CACHE_DIR" == "" ]]; then 33 | rm -f "$KURYR_AUTH_CACHE_DIR"/* 34 | fi 35 | 36 | } 37 | 38 | function create_kuryr_account { 39 | if is_service_enabled kuryr-libnetwork; then 40 | create_service_user "kuryr" "admin" 41 | get_or_create_service "kuryr-libnetwork" "kuryr-libnetwork" \ 42 | "Kuryr-Libnetwork Service" 43 | fi 44 | } 45 | 46 | function configure_kuryr { 47 | local binding_path 48 | 49 | binding_path="$1" 50 | sudo install -d -o "$STACK_USER" "$KURYR_CONFIG_DIR" 51 | 52 | (cd "$KURYR_HOME" && exec ./tools/generate_config_file_samples.sh) 53 | 54 | cp "$KURYR_HOME/etc/kuryr.conf.sample" "$KURYR_CONFIG" 55 | 56 | create_kuryr_cache_dir 57 | 58 | if is_service_enabled kuryr-libnetwork; then 59 | configure_auth_token_middleware "$KURYR_CONFIG" kuryr \ 60 | "$KURYR_AUTH_CACHE_DIR" neutron 61 | iniset $KURYR_CONFIG DEFAULT capability_scope $KURYR_CAPABILITY_SCOPE 62 | iniset $KURYR_CONFIG DEFAULT process_external_connectivity $KURYR_PROCESS_EXTERNAL_CONNECTIVITY 63 | fi 64 | 65 | if [[ "$ENABLE_PLUGINV2" == "True" ]]; then 66 | # bindir is /user/libexec/kuryr in docker image 67 | iniset -sudo ${KURYR_CONFIG} DEFAULT bindir "/usr/libexec/kuryr" 68 | else 69 | iniset -sudo ${KURYR_CONFIG} DEFAULT bindir "$binding_path/libexec/kuryr" 70 | fi 71 | iniset -sudo ${KURYR_CONFIG} DEFAULT debug $ENABLE_DEBUG_LOG_LEVEL 72 | } 73 | 74 | 75 | # main loop 76 | if is_service_enabled kuryr-libnetwork; then 77 | DISTRO_DISTUTILS_DATA_PATH=$($PYTHON -c "import distutils.dist;import distutils.command.install;inst = distutils.command.install.install(distutils.dist.Distribution());inst.finalize_options();print(inst.install_data)") 78 | if [[ "$1" == "stack" && "$2" == "install" ]]; then 79 | # Install kuryr-lib from git so we make sure we're testing 80 | # the latest code. 81 | if use_library_from_git "kuryr"; then 82 | git_clone_by_name "kuryr" 83 | setup_dev_lib "kuryr" 84 | # Install bind scripts 85 | if [ ! -d "${DISTRO_DISTUTILS_DATA_PATH}/libexec/kuryr" ]; then 86 | sudo mkdir -p ${DISTRO_DISTUTILS_DATA_PATH}/libexec/kuryr 87 | fi 88 | sudo cp -rf ${DEST}/kuryr/usr/libexec/kuryr/* ${DISTRO_DISTUTILS_DATA_PATH}/libexec/kuryr 89 | fi 90 | if [[ ! -d "${KURYR_LOG_DIR}" ]]; then 91 | echo -n "${KURYR_LOG_DIR} directory is missing. Creating it... " 92 | sudo mkdir -p ${KURYR_LOG_DIR} 93 | echo "Done" 94 | fi 95 | setup_develop $KURYR_HOME 96 | 97 | elif [[ "$1" == "stack" && "$2" == "post-config" ]]; then 98 | 99 | # This is needed in legacy plugin 100 | if [[ "$ENABLE_PLUGINV2" != "True" ]]; then 101 | if [[ ! -d "${KURYR_ACTIVATOR_DIR}" ]]; then 102 | echo -n "${KURYR_ACTIVATOR_DIR} directory is missing. Creating it... " 103 | sudo mkdir -p ${KURYR_ACTIVATOR_DIR} 104 | echo "Done" 105 | fi 106 | 107 | if [[ ! -f "${KURYR_ACTIVATOR}" ]]; then 108 | echo -n "${KURYR_ACTIVATOR} is missing. Copying the default one... " 109 | sudo cp ${KURYR_DEFAULT_ACTIVATOR} ${KURYR_ACTIVATOR} 110 | echo "Done" 111 | fi 112 | fi 113 | 114 | create_kuryr_account 115 | configure_kuryr "${DISTRO_DISTUTILS_DATA_PATH}" 116 | fi 117 | 118 | if [[ "$1" == "stack" && "$2" == "extra" ]]; then 119 | echo "Build busybox docker image for fullstack and rally test" 120 | cd $DEST/kuryr-libnetwork/contrib/busybox 121 | sh build_image.sh 122 | 123 | # FIXME(limao): When Kuryr start up, it need to detect if neutron support tag plugin. 124 | # Kuryr will call neutron extension api to verify if neutron support tag. 125 | # So Kuryr need to start after neutron-server finish load tag plugin. 126 | # The process of devstack is: 127 | # ... 128 | # run_phase "stack" "post-config" 129 | # ... 130 | # start neutron-server 131 | # ... 132 | # run_phase "stack" "extra" 133 | # 134 | # If Kuryr start up in "post-config" phase, there is no way to make sure 135 | # Kuryr can start before neutron-server, so Kuryr start in "extra" phase. 136 | # Bug: https://bugs.launchpad.net/kuryr/+bug/1587522 137 | if [[ "$ENABLE_PLUGINV2" == "True" ]]; then 138 | # Build pluginv2 rootfs 139 | cd $DEST/kuryr-libnetwork/ 140 | sudo sh contrib/docker/v2plugin/v2plugin_rootfs.sh 141 | 142 | # Build and install pluginv2 image 143 | sudo docker plugin create kuryr/libnetwork2 ./ 144 | 145 | # Enable pluginv2 146 | sudo docker plugin enable kuryr/libnetwork2:latest 147 | else 148 | run_process kuryr-libnetwork "$KURYR_BIN_DIR/kuryr-server --config-file $KURYR_CONFIG" "" "root" 149 | fi 150 | 151 | openstack subnet pool create --default-prefix-length $KURYR_POOL_PREFIX_LEN --pool-prefix $KURYR_POOL_PREFIX kuryr 152 | 153 | fi 154 | 155 | if [[ "$1" == "unstack" ]]; then 156 | if [[ "$ENABLE_PLUGINV2" == "True" ]]; then 157 | sudo docker plugin disable kuryr/libnetwork2:latest 158 | else 159 | stop_process kuryr-libnetwork 160 | fi 161 | fi 162 | 163 | if [[ "$1" == "clean" ]]; then 164 | sudo rm -rf $KURYR_CONFIG_DIR 165 | fi 166 | fi 167 | 168 | # Restore xtrace 169 | $XTRACE 170 | 171 | -------------------------------------------------------------------------------- /devstack/settings: -------------------------------------------------------------------------------- 1 | 2 | KURYR_HOME=${KURYR_HOME:-$DEST/kuryr-libnetwork} 3 | KURYR_ACTIVATOR_FILENAME=${KURYR_ACTIVATOR_FILENAME:-kuryr.spec} 4 | KURYR_DEFAULT_ACTIVATOR=${KURYR_HOME}/etc/${KURYR_ACTIVATOR_FILENAME} 5 | 6 | # See libnetwork's plugin discovery mechanism: 7 | # https://github.com/docker/docker/blob/c4d45b6a29a91f2fb5d7a51ac36572f2a9b295c6/docs/extend/plugin_api.md#plugin-discovery 8 | KURYR_ACTIVATOR_DIR=${KURYR_ACTIVATOR_DIR:-/usr/lib/docker/plugins/kuryr} 9 | KURYR_ACTIVATOR=${KURYR_ACTIVATOR_DIR}/${KURYR_ACTIVATOR_FILENAME} 10 | 11 | KURYR_CONFIG_FILENAME=kuryr.conf 12 | KURYR_DEFAULT_CONFIG=${KURYR_HOME}/etc/${KURYR_CONFIG_FILENAME} 13 | KURYR_CONFIG_DIR=${KURYR_CONFIG_DIR:-/etc/kuryr} 14 | KURYR_CONFIG=${KURYR_CONFIG_DIR}/${KURYR_CONFIG_FILENAME} 15 | KURYR_AUTH_CACHE_DIR=${KURYR_AUTH_CACHE_DIR:-/var/cache/kuryr} 16 | KURYR_LOG_DIR=${KURYR_LOG_DIR:-/var/log/kuryr} 17 | KURYR_BIN_DIR=$(get_python_exec_prefix) 18 | 19 | KURYR_POOL_PREFIX=${KURYR_POOL_PREFIX:-10.10.0.0/16} 20 | KURYR_POOL_PREFIX_LEN=${KURYR_POOL_PREFIX_LEN:-24} 21 | 22 | KURYR_CAPABILITY_SCOPE=local 23 | KURYR_PROCESS_EXTERNAL_CONNECTIVITY=${KURYR_PROCESS_EXTERNAL_CONNECTIVITY:-True} 24 | 25 | KURYR_DOCKER_ENGINE_PORT=${KURYR_DOCKER_ENGINE_PORT:-2375} 26 | 27 | GITREPO["kuryr"]=${KURYR_REPO:-${GIT_BASE}/openstack/kuryr.git} 28 | GITBRANCH["kuryr"]=${KURYR_BRANCH:-$TARGET_BRANCH} 29 | GITDIR["kuryr"]=$DEST/kuryr 30 | 31 | enable_service kuryr-libnetwork docker-engine 32 | -------------------------------------------------------------------------------- /doc/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | PAPER = 8 | BUILDDIR = build 9 | 10 | # User-friendly check for sphinx-build 11 | ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) 12 | $(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) 13 | endif 14 | 15 | # Internal variables. 16 | PAPEROPT_a4 = -D latex_paper_size=a4 17 | PAPEROPT_letter = -D latex_paper_size=letter 18 | ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source 19 | # the i18n builder cannot share the environment and doctrees with the others 20 | I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source 21 | 22 | .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext 23 | 24 | help: 25 | @echo "Please use \`make ' where is one of" 26 | @echo " html to make standalone HTML files" 27 | @echo " dirhtml to make HTML files named index.html in directories" 28 | @echo " singlehtml to make a single large HTML file" 29 | @echo " pickle to make pickle files" 30 | @echo " json to make JSON files" 31 | @echo " htmlhelp to make HTML files and a HTML help project" 32 | @echo " qthelp to make HTML files and a qthelp project" 33 | @echo " devhelp to make HTML files and a Devhelp project" 34 | @echo " epub to make an epub" 35 | @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" 36 | @echo " latexpdf to make LaTeX files and run them through pdflatex" 37 | @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" 38 | @echo " text to make text files" 39 | @echo " man to make manual pages" 40 | @echo " texinfo to make Texinfo files" 41 | @echo " info to make Texinfo files and run them through makeinfo" 42 | @echo " gettext to make PO message catalogs" 43 | @echo " changes to make an overview of all changed/added/deprecated items" 44 | @echo " xml to make Docutils-native XML files" 45 | @echo " pseudoxml to make pseudoxml-XML files for display purposes" 46 | @echo " linkcheck to check all external links for integrity" 47 | @echo " doctest to run all doctests embedded in the documentation (if enabled)" 48 | 49 | clean: 50 | rm -rf $(BUILDDIR)/* 51 | 52 | html: 53 | $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html 54 | @echo 55 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." 56 | 57 | dirhtml: 58 | $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml 59 | @echo 60 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." 61 | 62 | singlehtml: 63 | $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml 64 | @echo 65 | @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." 66 | 67 | pickle: 68 | $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle 69 | @echo 70 | @echo "Build finished; now you can process the pickle files." 71 | 72 | json: 73 | $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json 74 | @echo 75 | @echo "Build finished; now you can process the JSON files." 76 | 77 | htmlhelp: 78 | $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp 79 | @echo 80 | @echo "Build finished; now you can run HTML Help Workshop with the" \ 81 | ".hhp project file in $(BUILDDIR)/htmlhelp." 82 | 83 | qthelp: 84 | $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp 85 | @echo 86 | @echo "Build finished; now you can run "qcollectiongenerator" with the" \ 87 | ".qhcp project file in $(BUILDDIR)/qthelp, like this:" 88 | @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/Together-Message.qhcp" 89 | @echo "To view the help file:" 90 | @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/Together-Message.qhc" 91 | 92 | devhelp: 93 | $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp 94 | @echo 95 | @echo "Build finished." 96 | @echo "To view the help file:" 97 | @echo "# mkdir -p $$HOME/.local/share/devhelp/Together-Message" 98 | @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/Together-Message" 99 | @echo "# devhelp" 100 | 101 | epub: 102 | $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub 103 | @echo 104 | @echo "Build finished. The epub file is in $(BUILDDIR)/epub." 105 | 106 | latex: 107 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 108 | @echo 109 | @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." 110 | @echo "Run \`make' in that directory to run these through (pdf)latex" \ 111 | "(use \`make latexpdf' here to do that automatically)." 112 | 113 | latexpdf: 114 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 115 | @echo "Running LaTeX files through pdflatex..." 116 | $(MAKE) -C $(BUILDDIR)/latex all-pdf 117 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 118 | 119 | latexpdfja: 120 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 121 | @echo "Running LaTeX files through platex and dvipdfmx..." 122 | $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja 123 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 124 | 125 | text: 126 | $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text 127 | @echo 128 | @echo "Build finished. The text files are in $(BUILDDIR)/text." 129 | 130 | man: 131 | $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man 132 | @echo 133 | @echo "Build finished. The manual pages are in $(BUILDDIR)/man." 134 | 135 | texinfo: 136 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 137 | @echo 138 | @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." 139 | @echo "Run \`make' in that directory to run these through makeinfo" \ 140 | "(use \`make info' here to do that automatically)." 141 | 142 | info: 143 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 144 | @echo "Running Texinfo files through makeinfo..." 145 | make -C $(BUILDDIR)/texinfo info 146 | @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." 147 | 148 | gettext: 149 | $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale 150 | @echo 151 | @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." 152 | 153 | changes: 154 | $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes 155 | @echo 156 | @echo "The overview file is in $(BUILDDIR)/changes." 157 | 158 | linkcheck: 159 | $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck 160 | @echo 161 | @echo "Link check complete; look for any errors in the above output " \ 162 | "or in $(BUILDDIR)/linkcheck/output.txt." 163 | 164 | doctest: 165 | $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest 166 | @echo "Testing of doctests in the sources finished, look at the " \ 167 | "results in $(BUILDDIR)/doctest/output.txt." 168 | 169 | xml: 170 | $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml 171 | @echo 172 | @echo "Build finished. The XML files are in $(BUILDDIR)/xml." 173 | 174 | pseudoxml: 175 | $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml 176 | @echo 177 | @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." 178 | -------------------------------------------------------------------------------- /doc/requirements.txt: -------------------------------------------------------------------------------- 1 | sphinx>=2.0.0,!=2.1.0 # BSD 2 | openstackdocstheme>=2.2.1 # Apache-2.0 3 | reno>=3.1.0 # Apache-2.0 4 | -------------------------------------------------------------------------------- /doc/source/conf.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # 6 | # http://www.apache.org/licenses/LICENSE-2.0 7 | # 8 | # Unless required by applicable law or agreed to in writing, software 9 | # distributed under the License is distributed on an "AS IS" BASIS, 10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 11 | # implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import os 16 | import sys 17 | 18 | sys.path.insert(0, os.path.abspath('../..')) 19 | # -- General configuration ---------------------------------------------------- 20 | 21 | # Add any Sphinx extension module names here, as strings. They can be 22 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones. 23 | extensions = [ 24 | 'sphinx.ext.autodoc', 25 | 'reno.sphinxext', 26 | 'openstackdocstheme', 27 | ] 28 | 29 | # autodoc generation is a bit aggressive and a nuisance when doing heavy 30 | # text edit cycles. 31 | # execute "export SPHINX_DEBUG=1" in your terminal to disable 32 | 33 | # The suffix of source filenames. 34 | source_suffix = '.rst' 35 | 36 | # The master toctree document. 37 | master_doc = 'index' 38 | 39 | # General information about the project. 40 | project = 'kuryr-libnetwork' 41 | copyright = '2013, OpenStack Foundation' 42 | 43 | # openstackdocstheme options 44 | openstackdocs_repo_name = 'openstack/kuryr-libnetwork' 45 | openstackdocs_auto_name = False 46 | openstackdocs_bug_project = 'kuryr-libnetwork' 47 | openstackdocs_bug_tag = '' 48 | 49 | # If true, '()' will be appended to :func: etc. cross-reference text. 50 | add_function_parentheses = True 51 | 52 | # If true, the current module name will be prepended to all description 53 | # unit titles (such as .. function::). 54 | add_module_names = True 55 | 56 | # The name of the Pygments (syntax highlighting) style to use. 57 | pygments_style = 'native' 58 | 59 | # -- Options for HTML output -------------------------------------------------- 60 | 61 | # The theme to use for HTML and HTML Help pages. Major themes that come with 62 | # Sphinx are currently 'default' and 'sphinxdoc'. 63 | # html_theme_path = ["."] 64 | html_theme = 'openstackdocs' 65 | # html_static_path = ['static'] 66 | 67 | # Output file base name for HTML help builder. 68 | htmlhelp_basename = '%sdoc' % project 69 | 70 | # Grouping the document tree into LaTeX files. List of tuples 71 | # (source start file, target name, title, author, documentclass 72 | # [howto/manual]). 73 | latex_documents = [ 74 | ('index', 75 | '%s.tex' % project, 76 | '%s Documentation' % project, 77 | 'OpenStack Foundation', 'manual'), 78 | ] 79 | 80 | # Example configuration for intersphinx: refer to the Python standard library. 81 | #intersphinx_mapping = {'http://docs.python.org/': None} 82 | -------------------------------------------------------------------------------- /doc/source/config-sriov.rst: -------------------------------------------------------------------------------- 1 | ====== 2 | SR-IOV 3 | ====== 4 | 5 | The purpose of this page is to describe how to enable SR-IOV functionality 6 | available in Kuryr-libnetwork. This page intends to serve as a guide for 7 | how to configure OpenStack Networking and Kuryr-libnetwork to create SR-IOV 8 | ports and leverage them for containers. 9 | 10 | The basics 11 | ~~~~~~~~~~ 12 | 13 | PCI-SIG Single Root I/O Virtualization and Sharing (SR-IOV) functionality is 14 | available in OpenStack since the Juno release. The SR-IOV specification 15 | defines a standardized mechanism to virtualize PCIe devices. This mechanism 16 | can virtualize a single PCIe Ethernet controller to appear as multiple PCIe 17 | devices. Each device can be directly assigned to an instance, bypassing the 18 | virtual switch layer. As a result, users are able to achieve low latency and 19 | near-line wire speed. 20 | 21 | The following terms are used throughout this document: 22 | 23 | .. list-table:: 24 | :header-rows: 1 25 | :widths: 10 90 26 | 27 | * - Term 28 | - Definition 29 | * - PF 30 | - Physical Function. The physical Ethernet controller that supports 31 | SR-IOV. 32 | * - VF 33 | - Virtual Function. The virtual PCIe device created from a physical 34 | Ethernet controller. 35 | 36 | Using SR-IOV interfaces 37 | ~~~~~~~~~~~~~~~~~~~~~~~ 38 | 39 | In order to enable SR-IOV, the following steps are required: 40 | 41 | #. Create Virtual Functions (Compute) 42 | #. Configure neutron-server (Controller) 43 | #. Enable neutron sriov-agent (Compute) 44 | #. Configure kuryr-libnetwork (Compute) 45 | 46 | Create Virtual Functions (Compute) 47 | ---------------------------------- 48 | 49 | Follow the session 'Create Virtual Functions' in the `networking guide 50 | `_. 51 | 52 | Configure neutron-server (Controller) 53 | ------------------------------------- 54 | 55 | Follow the session 'Configure neutron-server' in the `networking guide 56 | `_. 57 | 58 | Enable neutron sriov-agent (Compute) 59 | ------------------------------------- 60 | 61 | Follow the session 'Enable neutron sriov-agent' in the `networking guide 62 | `_. 63 | 64 | Configure kuryr-libnetwork (Compute) 65 | ------------------------------------ 66 | 67 | #. On every compute node running the ``kuryr-libnetwork`` service, 68 | edit kuryr-libnetwork config file (e.g. /etc/kuryr/kuryr.conf). Add 69 | ``kuryr_libnetwork.port_driver.drivers.sriov`` to 70 | ``enabled_port_drivers`` under ``[DEFAULT]`` and 71 | add ``kuryr.lib.binding.drivers.hw_veb`` to ``enabled_drivers`` 72 | under ``[binding]``. 73 | 74 | .. code-block:: ini 75 | 76 | [DEFAULT] 77 | enabled_port_drivers = kuryr_libnetwork.port_driver.drivers.veth, kuryr_libnetwork.port_driver.drivers.sriov 78 | 79 | [binding] 80 | enabled_drivers = kuryr.lib.binding.drivers.veth, kuryr.lib.binding.drivers.hw_veb 81 | 82 | #. Restart the ``kuryr-libnetwork`` service. 83 | 84 | Launching containers with SR-IOV ports 85 | -------------------------------------- 86 | 87 | Once configuration is complete, you can launch containers with SR-IOV ports. 88 | 89 | #. Get the ``id`` of the network where you want the SR-IOV port to be created: 90 | 91 | .. code-block:: console 92 | 93 | $ net_id=`neutron net-show net04 | grep "\ id\ " | awk '{ print $4 }'` 94 | 95 | #. Create a kuryr network by specifying the name of the neutron network. 96 | Replace ``10.10.0.0/24`` and ``10.10.0.1`` with the CIDR and gateway 97 | of the subnet where you want the SR-IOV port to be created: 98 | 99 | .. code-block:: console 100 | 101 | $ docker network create -d kuryr --ipam-driver=kuryr --subnet=10.10.0.0/24 --gateway=10.10.0.1 \ 102 | -o neutron.net.uuid=$net_id kuryr_net 103 | 104 | #. Create the SR-IOV port. ``vnic_type=direct`` is used here, but other options 105 | include ``normal``, ``direct-physical``, and ``macvtap``. 106 | The ``binding-profile`` is used by the Neutron SR-IOV driver [1]. 107 | Replace ``physnet2``, ``1137:0047``, and ``0000:0a:00.1`` 108 | with the correct value of the VF device: 109 | 110 | .. code-block:: console 111 | 112 | $ neutron port-create $net_id --name sriov_port --binding:vnic_type direct \ 113 | --binding-profile '{"physical_network": "physnet2", "pci_vendor_info": "1137:0047", "pci_slot": "0000:0a:00.1"}' 114 | 115 | #. Create the container. Specify the SR-IOV port's IP address created in step 116 | two: 117 | 118 | .. code-block:: console 119 | 120 | $ docker run -it --net=kuryr_net --ip=10.0.0.5 ubuntu 121 | 122 | Reference 123 | --------- 124 | [1] https://specs.openstack.org/openstack/neutron-specs/specs/juno/ml2-sriov-nic-switch.html 125 | -------------------------------------------------------------------------------- /doc/source/devref/index.rst: -------------------------------------------------------------------------------- 1 | .. 2 | Licensed under the Apache License, Version 2.0 (the "License"); you may 3 | not use this file except in compliance with the License. You may obtain 4 | a copy of the License at 5 | 6 | http://www.apache.org/licenses/LICENSE-2.0 7 | 8 | Unless required by applicable law or agreed to in writing, software 9 | distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 10 | WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 11 | License for the specific language governing permissions and limitations 12 | under the License. 13 | 14 | Convention for heading levels in Neutron devref: 15 | ======= Heading 0 (reserved for the title in a document) 16 | ------- Heading 1 17 | ~~~~~~~ Heading 2 18 | +++++++ Heading 3 19 | ''''''' Heading 4 20 | (Avoid deeper levels because they do not render well.) 21 | 22 | 23 | Design and Developer Docs 24 | ========================= 25 | 26 | Kuryr goal is to bring containers networking to Neutron core API 27 | and advanced networking services. 28 | This section contains detailed designs / project integration plans and low level 29 | use cases for the various parts inside Kuryr. 30 | 31 | 32 | Programming HowTos and Tutorials 33 | -------------------------------- 34 | .. toctree:: 35 | :maxdepth: 4 36 | 37 | libnetwork_remote_driver_design.rst 38 | 39 | Indices and tables 40 | ------------------ 41 | 42 | * :ref:`search` 43 | -------------------------------------------------------------------------------- /doc/source/fullstack-test.rst: -------------------------------------------------------------------------------- 1 | ============== 2 | Fullstack test 3 | ============== 4 | 5 | This is a guide for developers who want to run Fullstack tests in their local 6 | machine. 7 | 8 | Prerequisite 9 | ============ 10 | 11 | You need to deploy kuryr-libnetwork in a DevStack environment. 12 | 13 | Clone DevStack:: 14 | 15 | # Create a root directory for devstack if needed 16 | sudo mkdir -p /opt/stack 17 | sudo chown $USER /opt/stack 18 | 19 | git clone https://opendev.org/openstack/devstack /opt/stack/devstack 20 | 21 | We will run devstack with minimal local.conf settings required. You can use the 22 | sample local.conf as a quick-start:: 23 | 24 | git clone https://opendev.org/openstack/kuryr-libnetwork /opt/stack/kuryr-libnetwork 25 | cp /opt/stack/kuryr-libnetwork/devstack/local.conf.sample /opt/stack/devstack/local.conf 26 | 27 | Run DevStack:: 28 | 29 | cd /opt/stack/devstack 30 | ./stack.sh 31 | 32 | **NOTE:** This will take a while to setup the dev environment. 33 | 34 | 35 | Run the Fullstack test 36 | ====================== 37 | 38 | Navigate to kuryr-libnetwork directory:: 39 | 40 | cd /opt/stack/kuryr-libnetwork 41 | 42 | Run this command:: 43 | 44 | tox -e fullstack 45 | 46 | 47 | Also you can run *fullstack* test using credentials from openrc config file, 48 | this requires you source openrc file in your DevStack or production environment. 49 | In DevStack, you can using command "source openrc admin" in your devstack directory. 50 | For production environment, please refer "Create OpenStack client environment scripts" 51 | in OpenStack install guide. 52 | 53 | 54 | Source the credential of 'admin' user:: 55 | 56 | source /opt/stack/devstack/openrc admin 57 | 58 | Then run command:: 59 | 60 | tox -e fullstack 61 | -------------------------------------------------------------------------------- /doc/source/index.rst: -------------------------------------------------------------------------------- 1 | .. kuryr documentation master file, created by 2 | sphinx-quickstart on Tue Jul 9 22:26:36 2013. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | Welcome to kuryr-libnetwork's documentation! 7 | ======================================================== 8 | 9 | Contents: 10 | 11 | .. toctree:: 12 | :maxdepth: 2 13 | 14 | readme 15 | config-sriov.rst 16 | fullstack-test 17 | 18 | Design and Developer Docs 19 | ========================== 20 | 21 | .. toctree:: 22 | :maxdepth: 1 23 | 24 | devref/index 25 | 26 | Installation Guide 27 | ================== 28 | .. toctree:: 29 | :maxdepth: 1 30 | 31 | install/index 32 | 33 | Indices and tables 34 | ================== 35 | 36 | * :ref:`search` 37 | 38 | -------------------------------------------------------------------------------- /doc/source/install/compute-install-ubuntu.rst: -------------------------------------------------------------------------------- 1 | Install and configure a compute node for Ubuntu 2 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 3 | 4 | This section describes how to install and configure the Kuryr-libnetwork 5 | for Ubuntu 16.04 (LTS). 6 | 7 | Prerequisites 8 | ------------- 9 | 10 | This guide assumes Docker is already installed. Refer `Get Docker 11 | `_ 12 | for Docker installation. 13 | 14 | Install and configure components 15 | -------------------------------- 16 | 17 | #. Create kuryr user and necessary directories: 18 | 19 | * Create user: 20 | 21 | .. code-block:: console 22 | 23 | # groupadd --system kuryr 24 | # useradd --home-dir "/var/lib/kuryr" \ 25 | --create-home \ 26 | --system \ 27 | --shell /bin/false \ 28 | -g kuryr \ 29 | kuryr 30 | 31 | * Create directories: 32 | 33 | .. code-block:: console 34 | 35 | # mkdir -p /etc/kuryr 36 | # chown kuryr:kuryr /etc/kuryr 37 | 38 | #. Clone and install kuryr-libnetwork: 39 | 40 | .. code-block:: console 41 | 42 | # apt-get install python3-pip 43 | # cd /var/lib/kuryr 44 | # git clone -b master https://opendev.org/openstack/kuryr-libnetwork.git 45 | # chown -R kuryr:kuryr kuryr-libnetwork 46 | # cd kuryr-libnetwork 47 | # pip3 install -r requirements.txt 48 | # python3 setup.py install 49 | 50 | #. Generate a sample configuration file: 51 | 52 | .. code-block:: console 53 | 54 | # su -s /bin/sh -c "./tools/generate_config_file_samples.sh" kuryr 55 | # su -s /bin/sh -c "cp etc/kuryr.conf.sample \ 56 | /etc/kuryr/kuryr.conf" kuryr 57 | 58 | #. Edit the ``/etc/kuryr/kuryr.conf``: 59 | 60 | * In the ``[DEFAULT]`` section, configure the path for the Kuryr 61 | vif binding executables: 62 | 63 | .. code-block:: ini 64 | 65 | [DEFAULT] 66 | ... 67 | bindir = /usr/local/libexec/kuryr 68 | 69 | * In the ``[neutron]`` section, configure Identity service access: 70 | 71 | .. code-block:: ini 72 | 73 | [neutron] 74 | ... 75 | www_authenticate_uri = http://controller:5000 76 | auth_url = http://controller:5000 77 | username = kuryr 78 | user_domain_name = default 79 | password = KURYR_PASSWORD 80 | project_name = service 81 | project_domain_name = default 82 | auth_type = password 83 | 84 | Replace KURYR_PASSWORD with the password you chose for the kuryr user in the 85 | Identity service. 86 | 87 | #. Create an upstart config, it could be named as 88 | ``/etc/systemd/system/kuryr-libnetwork.service``: 89 | 90 | .. code-block:: ini 91 | 92 | [Unit] 93 | Description = Kuryr-libnetwork - Docker network plugin for Neutron 94 | 95 | [Service] 96 | ExecStart = /usr/local/bin/kuryr-server --config-file /etc/kuryr/kuryr.conf 97 | CapabilityBoundingSet = CAP_NET_ADMIN 98 | AmbientCapabilities = CAP_NET_ADMIN 99 | 100 | [Install] 101 | WantedBy = multi-user.target 102 | 103 | Finalize installation 104 | --------------------- 105 | 106 | #. Enable and start the kuryr-libnetwork service: 107 | 108 | .. code-block:: console 109 | 110 | # systemctl enable kuryr-libnetwork 111 | # systemctl start kuryr-libnetwork 112 | 113 | #. After Kuryr starts, please restart your Docker service: 114 | 115 | .. code-block:: console 116 | 117 | # systemctl restart docker 118 | -------------------------------------------------------------------------------- /doc/source/install/compute-install.rst: -------------------------------------------------------------------------------- 1 | Install and configure a compute node 2 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 3 | 4 | This section describes how to install and configure the 5 | Kuryr-libnetwork on the compute node. 6 | 7 | This section assumes that you already have a working OpenStack 8 | environment with at least the following components installed: 9 | Network, Identity. 10 | 11 | .. note:: 12 | 13 | The supported platforms are Ubuntu, openSUSE and SUSE Linux Enterprise, 14 | and Red Hat Enterprise Linux and CentOS. This guide currently provides 15 | installation stpes for Ubuntu. Other platforms will be introduced later. 16 | 17 | .. toctree:: 18 | 19 | compute-install-ubuntu.rst 20 | -------------------------------------------------------------------------------- /doc/source/install/controller-install.rst: -------------------------------------------------------------------------------- 1 | Install and configure controller node 2 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 3 | 4 | This section describes how to install and configure kuryr-libnetwork 5 | on the controller node. 6 | 7 | .. note:: 8 | 9 | The installation steps for Ubuntu, openSUSE and SUSE Linux Enterprise, 10 | and Red Hat Enterprise Linux and CentOS are all the same. 11 | 12 | #. Source the ``admin`` credentials to gain access to 13 | admin-only CLI commands: 14 | 15 | .. code-block:: console 16 | 17 | $ . admin-openrc 18 | 19 | #. To create the service credentials, complete these steps: 20 | 21 | * Create the ``kuryr`` user: 22 | 23 | .. code-block:: console 24 | 25 | $ openstack user create --domain default --password-prompt kuryr 26 | User Password: 27 | Repeat User Password: 28 | +-----------+----------------------------------+ 29 | | Field | Value | 30 | +-----------+----------------------------------+ 31 | | domain_id | e0353a670a9e496da891347c589539e9 | 32 | | enabled | True | 33 | | id | ca2e175b851943349be29a328cc5e360 | 34 | | name | kuryr | 35 | +-----------+----------------------------------+ 36 | 37 | * Add the ``admin`` role to the ``kuryr`` user: 38 | 39 | .. code-block:: console 40 | 41 | $ openstack role add --project service --user kuryr admin 42 | -------------------------------------------------------------------------------- /doc/source/install/get_started.rst: -------------------------------------------------------------------------------- 1 | ========================= 2 | Kuryr-libnetwork overview 3 | ========================= 4 | 5 | Kuryr-libnetwork is Kuryr's Docker libnetwork driver that uses Neutron to 6 | provide networking services. It provides containerised images for the common 7 | Neutron plugins. 8 | 9 | Features 10 | -------- 11 | 12 | * Docker libnetwork remote driver 13 | 14 | * Docker libnetwork IPAM driver 15 | 16 | * Support both IPv4 and IPv6 17 | 18 | * Support for Linux Bridge, Open vSwitch, Midonet, and IOvisor port bindings 19 | 20 | * Support for using existing Neutron networks. 21 | 22 | * Support for using existing Neutron ports. 23 | 24 | * Support for the Docker "expose" option. 25 | -------------------------------------------------------------------------------- /doc/source/install/index.rst: -------------------------------------------------------------------------------- 1 | =================================== 2 | Kuryr-libnetwork Installation Guide 3 | =================================== 4 | 5 | .. toctree:: 6 | 7 | get_started.rst 8 | controller-install.rst 9 | compute-install.rst 10 | verify.rst 11 | next-steps.rst 12 | 13 | This chapter assumes a working setup of OpenStack following the 14 | `OpenStack Installation Tutorial `_. 15 | -------------------------------------------------------------------------------- /doc/source/install/next-steps.rst: -------------------------------------------------------------------------------- 1 | .. _next-steps: 2 | 3 | Next steps 4 | ~~~~~~~~~~ 5 | 6 | Your kuryr-libnetwork is now running. 7 | 8 | To add more services, see the 9 | `additional documentation on installing OpenStack `_ . 10 | 11 | To learn more about the kuryr-libnetwork, read the `Kuryr-libnetwork documentation 12 | `__. 13 | -------------------------------------------------------------------------------- /doc/source/install/verify.rst: -------------------------------------------------------------------------------- 1 | .. _verify: 2 | 3 | Verify operation 4 | ~~~~~~~~~~~~~~~~ 5 | 6 | Verify operation of the kuryr-libnetwork. 7 | 8 | #. Create a IPv4 network: 9 | 10 | .. code-block:: console 11 | 12 | # docker network create --driver kuryr --ipam-driver kuryr \ 13 | --subnet 10.10.0.0/16 --gateway=10.10.0.1 test_net 14 | 785f8c1b5ae480c4ebcb54c1c48ab875754e4680d915b270279e4f6a1aa52283 15 | # docker network ls 16 | NETWORK ID NAME DRIVER SCOPE 17 | ... 18 | e13c98aa096b test_net kuryr local 19 | # docker run --net test_net cirros ifconfig 20 | eth0 Link encap:Ethernet HWaddr FA:16:3E:D5:BB:5F 21 | inet addr:10.10.0.9 Bcast:0.0.0.0 Mask:255.255.0.0 22 | UP BROADCAST RUNNING MULTICAST MTU:1450 Metric:1 23 | RX packets:9 errors:0 dropped:0 overruns:0 frame:0 24 | TX packets:2 errors:0 dropped:0 overruns:0 carrier:0 25 | collisions:0 txqueuelen:1000 26 | RX bytes:894 (894.0 B) TX bytes:188 (188.0 B) 27 | 28 | lo Link encap:Local Loopback 29 | inet addr:127.0.0.1 Mask:255.0.0.0 30 | UP LOOPBACK RUNNING MTU:65536 Metric:1 31 | RX packets:0 errors:0 dropped:0 overruns:0 frame:0 32 | TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 33 | collisions:0 txqueuelen:1 34 | RX bytes:0 (0.0 B) TX bytes:0 (0.0 B) 35 | -------------------------------------------------------------------------------- /doc/source/readme.rst: -------------------------------------------------------------------------------- 1 | .. include:: ../../README.rst 2 | -------------------------------------------------------------------------------- /etc/README-config.txt: -------------------------------------------------------------------------------- 1 | To generate the sample kuryr.conf file, run the following 2 | command from the top level of the kuryr directory: 3 | 4 | tox -egenconfig 5 | 6 | The sample file will be generated at etc/kuryr.conf.sample 7 | -------------------------------------------------------------------------------- /etc/kuryr.json: -------------------------------------------------------------------------------- 1 | { 2 | "Name": "kuryr", 3 | "Addr": "http://127.0.0.1:23750" 4 | } 5 | -------------------------------------------------------------------------------- /etc/kuryr.spec: -------------------------------------------------------------------------------- 1 | http://127.0.0.1:23750 2 | -------------------------------------------------------------------------------- /etc/oslo-config-generator/kuryr.conf: -------------------------------------------------------------------------------- 1 | [DEFAULT] 2 | output_file = etc/kuryr.conf.sample 3 | wrap_width = 79 4 | namespace = kuryr_libnetwork 5 | -------------------------------------------------------------------------------- /init/kuryr.conf: -------------------------------------------------------------------------------- 1 | description "Kuryr libnetwork driver" 2 | author "Antoni Segura Puimedon " 3 | 4 | start on (net-device-up 5 | and local-filesystems 6 | and runlevel [2345]) 7 | stop on runlevel [016] 8 | 9 | respawn 10 | respawn limit 10 5 11 | 12 | script 13 | exec start-stop-daemon --start --exec /usr/bin/kuryr-server -- --config-file /etc/kuryr/kuryr.conf 14 | end script 15 | -------------------------------------------------------------------------------- /kuryr_libnetwork/__init__.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | import pbr.version 13 | 14 | from kuryr_libnetwork import utils 15 | 16 | 17 | __version__ = pbr.version.VersionInfo( 18 | 'kuryr-libnetwork').version_string() 19 | 20 | 21 | app = utils.make_json_app(__name__) 22 | -------------------------------------------------------------------------------- /kuryr_libnetwork/config.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | 13 | """ 14 | Routines for configuring Kuryr 15 | """ 16 | 17 | import os 18 | 19 | from oslo_config import cfg 20 | from oslo_log import log 21 | import pbr.version 22 | 23 | from kuryr.lib._i18n import _ 24 | from kuryr.lib import config as lib_config 25 | 26 | core_opts = [ 27 | cfg.StrOpt('pybasedir', 28 | default=os.path.abspath(os.path.join(os.path.dirname(__file__), 29 | '../')), 30 | help=_('Directory where Kuryr python module is installed.')), 31 | cfg.StrOpt('kuryr_uri', 32 | default=os.environ.get('OS_KURYR_URI', 33 | 'http://127.0.0.1:23750'), 34 | help=_('Kuryr URL for accessing Kuryr through json rpc.')), 35 | cfg.StrOpt('capability_scope', 36 | default=os.environ.get('CAPABILITY_SCOPE', 'local'), 37 | choices=['local', 'global'], 38 | help=_('Kuryr plugin scope reported to libnetwork.')), 39 | cfg.StrOpt('local_default_address_space', 40 | default='no_address_space', 41 | help=_('There is no address-space by default in neutron')), 42 | cfg.StrOpt('global_default_address_space', 43 | default='no_address_space', 44 | help=_('There is no address-space by default in neutron')), 45 | cfg.StrOpt('port_driver', 46 | default='kuryr_libnetwork.port_driver.drivers.veth', 47 | deprecated_for_removal=True, 48 | help=_('Default driver for the desired deployment model')), 49 | cfg.StrOpt('default_port_driver', 50 | default='kuryr_libnetwork.port_driver.drivers.veth', 51 | help=_('Default driver for the desired deployment model')), 52 | cfg.ListOpt('enabled_port_drivers', 53 | default=['kuryr_libnetwork.port_driver.drivers.veth'], 54 | help=_('Available port drivers')), 55 | cfg.BoolOpt('process_external_connectivity', 56 | default=True, 57 | help=_('Do processing external connectivity')), 58 | cfg.StrOpt('ssl_cert_file', 59 | default='/var/lib/kuryr/certs/cert.pem', 60 | help=_('This option allows setting absolute path' 61 | 'to the SSL certificate')), 62 | cfg.StrOpt('ssl_key_file', 63 | default='/var/lib/kuryr/certs/key.pem', 64 | help=_('This option allows setting absolute path' 65 | 'to the SSL private key')), 66 | cfg.BoolOpt('enable_ssl', 67 | default=False, 68 | help=_('Enable SSL for Kuryr')) 69 | ] 70 | 71 | CONF = cfg.CONF 72 | CONF.register_opts(core_opts) 73 | 74 | CONF.register_opts(lib_config.core_opts) 75 | CONF.register_opts(lib_config.binding_opts, 'binding') 76 | lib_config.register_neutron_opts(CONF) 77 | 78 | # Setting oslo.log options for logging. 79 | log.register_options(CONF) 80 | 81 | 82 | def init(args, **kwargs): 83 | cfg.CONF( 84 | args=args, 85 | project='kuryr', 86 | version=pbr.version.VersionInfo('kuryr-libnetwork').version_string(), 87 | **kwargs) 88 | -------------------------------------------------------------------------------- /kuryr_libnetwork/constants.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | 13 | 14 | SCHEMA = { 15 | "PLUGIN_ACTIVATE": {"Implements": ["NetworkDriver", "IpamDriver"]}, 16 | "SUCCESS": {} 17 | } 18 | 19 | # Routes are given a RouteType of 0 and a value for NextHop; 20 | ROUTE_TYPE = { 21 | "NEXTHOP": 0 22 | } 23 | 24 | PROTOCOLS = { 25 | 1: 'icmp', 26 | 6: 'tcp', 27 | 17: 'udp' 28 | } 29 | 30 | NET_NAME_PREFIX = 'kuryr-net-' 31 | SUBNET_NAME_PREFIX = 'kuryr-subnet-' 32 | NEUTRON_ID_LH_OPTION = 'kuryr.net.uuid.lh' 33 | NEUTRON_ID_UH_OPTION = 'kuryr.net.uuid.uh' 34 | 35 | DOCKER_EXPOSED_PORTS_OPTION = 'com.docker.network.endpoint.exposedports' 36 | DOCKER_MAC_ADDRESS_OPTION = 'com.docker.network.endpoint.macaddress' 37 | KURYR_EXISTING_NEUTRON_NET = 'kuryr.net.existing' 38 | KURYR_EXISTING_NEUTRON_SUBNETPOOL = 'kuryr.subnetpool.existing' 39 | KURYR_EXISTING_NEUTRON_PORT = 'kuryr.port.existing' 40 | NETWORK_GATEWAY_OPTIONS = 'com.docker.network.gateway' 41 | NETWORK_GENERIC_OPTIONS = 'com.docker.network.generic' 42 | NEUTRON_NAME_OPTION = 'neutron.net.name' 43 | NEUTRON_SHARED_OPTION = 'neutron.net.shared' 44 | NEUTRON_SUBNET_NAME_OPTION = 'neutron.subnet.name' 45 | NEUTRON_SUBNET_UUID_OPTION = 'neutron.subnet.uuid' 46 | NEUTRON_V6_SUBNET_NAME_OPTION = 'neutron.subnet.v6.name' 47 | NEUTRON_V6_SUBNET_UUID_OPTION = 'neutron.subnet.v6.uuid' 48 | NEUTRON_POOL_NAME_OPTION = 'neutron.pool.name' 49 | NEUTRON_POOL_UUID_OPTION = 'neutron.pool.uuid' 50 | NEUTRON_V6_POOL_NAME_OPTION = 'neutron.pool.v6.name' 51 | NEUTRON_V6_POOL_UUID_OPTION = 'neutron.pool.v6.uuid' 52 | NEUTRON_UUID_OPTION = 'neutron.net.uuid' 53 | REQUEST_ADDRESS_TYPE = 'RequestAddressType' 54 | KURYR_UNBOUND_PORT = 'kuryr-unbound-port' 55 | NEUTRON_UNBOUND_PORT = 'neutron-unbound-port' 56 | BINDING_PROFILE = 'binding:profile' 57 | 58 | # Define supported virtual NIC types. 59 | VNIC_TYPE_NORMAL = 'normal' 60 | VNIC_TYPE_DIRECT = 'direct' 61 | VNIC_TYPE_MACVTAP = 'macvtap' 62 | VNIC_TYPE_DIRECT_PHYSICAL = 'direct-physical' 63 | 64 | # Define list of virtual NIC types. 65 | VNIC_TYPES_SRIOV = (VNIC_TYPE_DIRECT, VNIC_TYPE_MACVTAP, 66 | VNIC_TYPE_DIRECT_PHYSICAL) 67 | -------------------------------------------------------------------------------- /kuryr_libnetwork/opts.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | 13 | __all__ = [ 14 | 'list_kuryr_libnetwork_opts', 15 | ] 16 | 17 | import copy 18 | import itertools 19 | 20 | from oslo_log import _options 21 | 22 | from kuryr.lib import opts as lib_opts 23 | from kuryr_libnetwork import config 24 | 25 | 26 | _core_opts_with_logging = config.core_opts 27 | _core_opts_with_logging += _options.common_cli_opts 28 | _core_opts_with_logging += _options.logging_cli_opts 29 | _core_opts_with_logging += _options.generic_log_opts 30 | 31 | _kuryr_libnetwork_opts = [ 32 | (None, list(itertools.chain(_core_opts_with_logging))), 33 | ] 34 | 35 | 36 | def list_kuryr_libnetwork_opts(): 37 | """Return a list of oslo_config options available in kuryr-libnetwork service. 38 | 39 | Each element of the list is a tuple. The first element is the name of the 40 | group under which the list of elements in the second element will be 41 | registered. A group name of None corresponds to the [DEFAULT] group in 42 | config files. 43 | 44 | This function is also discoverable via the 'kuryr_libnetwork' entry point 45 | under the 'oslo_config.opts' namespace. 46 | 47 | The purpose of this is to allow tools like the Oslo sample config file 48 | generator to discover the options exposed to users by kuryr-libnetwork. 49 | 50 | :returns: a list of (group_name, opts) tuples 51 | """ 52 | 53 | return ([(k, copy.deepcopy(o)) for k, o in _kuryr_libnetwork_opts] + 54 | lib_opts.list_kuryr_opts()) 55 | -------------------------------------------------------------------------------- /kuryr_libnetwork/port_driver/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openstack/kuryr-libnetwork/70676593993a8c370be3fc27a8fecc4e84661e24/kuryr_libnetwork/port_driver/__init__.py -------------------------------------------------------------------------------- /kuryr_libnetwork/port_driver/base.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | 13 | import abc 14 | 15 | from kuryr.lib.binding.drivers import utils 16 | from kuryr.lib import exceptions 17 | from kuryr_libnetwork import app 18 | from kuryr_libnetwork import config 19 | from kuryr_libnetwork.port_driver import driver 20 | 21 | 22 | class BaseNestedDriver(driver.Driver, metaclass=abc.ABCMeta): 23 | """Driver for container-in-VM deployments with MACVLAN and IPVLAN.""" 24 | 25 | def __init__(self): 26 | self.link_iface = config.CONF.binding.link_iface 27 | 28 | def _get_port_from_host_iface(self, ifname): 29 | """Returns the Neutron port associated to ifname or raises otherwise. 30 | 31 | Returns the Neutron port associated to ifname if such port exists, a 32 | exceptions.KuryrException if it does not, 33 | n_exceptions.NeutronClientException on errors. 34 | 35 | :returns: a Neutron port dictionary as returned by 36 | python-neutronclient or None 37 | :raises: exceptions.KuryrException 38 | neutronclient.common.exceptions.NeutronClientException 39 | """ 40 | ip = utils.get_ipdb() 41 | 42 | mac_address = ip.interfaces.get(ifname, {}).get('address', None) 43 | if mac_address: 44 | ports = app.neutron.list_ports(mac_address=mac_address) 45 | if ports['ports']: 46 | return ports['ports'][0] 47 | 48 | raise exceptions.KuryrException("Cannot find a Neutron port " 49 | "associated to interface name {0}".format(ifname)) 50 | 51 | def get_container_iface_name(self, neutron_port): 52 | """Returns interface name of a container in the default namespace. 53 | 54 | :param neutron_port: The neutron port 55 | :returns: interface name as string. 56 | """ 57 | _, container_iface_name = utils.get_veth_pair_names(neutron_port['id']) 58 | return container_iface_name 59 | -------------------------------------------------------------------------------- /kuryr_libnetwork/port_driver/drivers/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openstack/kuryr-libnetwork/70676593993a8c370be3fc27a8fecc4e84661e24/kuryr_libnetwork/port_driver/drivers/__init__.py -------------------------------------------------------------------------------- /kuryr_libnetwork/port_driver/drivers/nested.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | 13 | from neutronclient.common import exceptions as n_exceptions 14 | from oslo_log import log 15 | 16 | from kuryr.lib import binding 17 | from kuryr.lib import exceptions 18 | 19 | from kuryr_libnetwork import app 20 | from kuryr_libnetwork.port_driver import base 21 | 22 | LOG = log.getLogger(__name__) 23 | 24 | 25 | class NestedDriver(base.BaseNestedDriver): 26 | """Driver for container-in-VM deployments with MACVLAN and IPVLAN.""" 27 | 28 | BINDING_DRIVERS = ('macvlan', 'ipvlan') 29 | 30 | def __init__(self): 31 | super(NestedDriver, self).__init__() 32 | 33 | def get_supported_bindings(self): 34 | """Returns a tuple of supported binding driver names for the driver. 35 | 36 | :returns: a tuple of strings 37 | """ 38 | return self.BINDING_DRIVERS 39 | 40 | def get_default_network_id(self): 41 | """Returns a Neutron network ID as per driver logic, if any. 42 | 43 | Nested Endpoints need to join the same network as their Master 44 | interface, this function will return its Neutron network UUID for the 45 | Endpoint to join or throw in case of failure. 46 | 47 | :returns: the Neutron network UUID as a string 48 | :raises: exceptions.KuryrException 49 | """ 50 | vm_port = self._get_port_from_host_iface(self.link_iface) 51 | 52 | return vm_port['network_id'] 53 | 54 | def create_host_iface(self, endpoint_id, neutron_port, subnets, 55 | network=None): 56 | """Instantiates a host interface and binds it to the host. 57 | 58 | A host linked interface will be created for the specific Neutron port 59 | by delegating to the pre-selected kuryr-lib driver. 60 | This driver will also add the IP and MAC address pairs of the Endpoint 61 | to the allowed_address_pairs list of the Neutron port associated to the 62 | underlying host interface. 63 | 64 | :param endpoint_id: the ID of the endpoint as string 65 | :param neutron_port: the container Neutron port dictionary as returned 66 | by python-neutronclient 67 | :param subnets: an iterable of all the Neutron subnets which the 68 | endpoint is trying to join 69 | :param network: the Neutron network which the endpoint is trying 70 | to join 71 | :returns: the tuple of stdout and stderr returned by 72 | processutils.execute invoked 73 | with the executable script for binding 74 | :raises: exceptions.VethCreationFailure, 75 | exceptions.KuryrException, 76 | n_exceptions.NeutronClientException, 77 | processutils.ProcessExecutionError 78 | """ 79 | container_mac = neutron_port['mac_address'] 80 | container_ips = neutron_port['fixed_ips'] 81 | 82 | if not container_ips: # The MAC address should be mandatory, no check 83 | raise exceptions.KuryrException( 84 | "Neutron port {0} does not have fixed_ips." 85 | .format(neutron_port['id'])) 86 | 87 | vm_port = self._get_port_from_host_iface(self.link_iface) 88 | 89 | _, _, (stdout, stderr) = binding.port_bind( 90 | endpoint_id, neutron_port, subnets, network, vm_port) 91 | self._add_to_allowed_address_pairs(vm_port, container_ips, 92 | container_mac) 93 | 94 | return (stdout, stderr) 95 | 96 | def delete_host_iface(self, endpoint_id, neutron_port): 97 | """Deletes a host interface after unbinding it from the host. 98 | 99 | The host Slave interface associated to the Neutron port will be deleted 100 | by delegating to the selected kuryr-lib driver. 101 | This driver will also remove the IP and MAC address pairs of the 102 | Endpoint to the allowed_address_pairs list of the Neutron port 103 | associated to the underlying host interface. 104 | 105 | :param endpoint_id: the ID of the endpoint as string 106 | :param neutron_port: a port dictionary returned from 107 | python-neutronclient 108 | :returns: the tuple of stdout and stderr returned 109 | by processutils.execute invoked with the executable script 110 | for unbinding 111 | :raises: exceptions.VethDeletionFailure, 112 | exceptions.KuryrException, 113 | n_exceptions.NeutronClientException, 114 | processutils.ProcessExecutionError, 115 | """ 116 | vm_port = self._get_port_from_host_iface(self.link_iface) 117 | container_ips = neutron_port['fixed_ips'] 118 | 119 | self._remove_from_allowed_address_pairs(vm_port, container_ips) 120 | return binding.port_unbind(endpoint_id, neutron_port) 121 | 122 | def _add_to_allowed_address_pairs(self, port, ip_addresses, 123 | mac_address=None): 124 | address_pairs = port['allowed_address_pairs'] 125 | for ip_entry in ip_addresses: 126 | pair = {'ip_address': ip_entry['ip_address']} 127 | if mac_address: 128 | pair['mac_address'] = mac_address 129 | address_pairs.append(pair) 130 | 131 | self._update_port_address_pairs(port['id'], address_pairs) 132 | 133 | def _remove_from_allowed_address_pairs(self, port, ip_addresses): 134 | address_pairs = port['allowed_address_pairs'] 135 | filter = frozenset(ip_entry['ip_address'] for ip_entry in ip_addresses) 136 | updated_address_pairs = [] 137 | 138 | # filter allowed IPs by copying 139 | for address_pair in address_pairs: 140 | if address_pair['ip_address'] in filter: 141 | continue 142 | updated_address_pairs.append(address_pair) 143 | 144 | self._update_port_address_pairs(port['id'], updated_address_pairs) 145 | 146 | def _update_port_address_pairs(self, port_id, address_pairs): 147 | try: 148 | app.neutron.update_port( 149 | port_id, 150 | { 151 | 'port': { 152 | 'allowed_address_pairs': address_pairs 153 | } 154 | }) 155 | except n_exceptions.NeutronClientException as ex: 156 | LOG.error("Error happened during updating Neutron " 157 | "port %(port_id)s: %(ex)s", port_id, ex) 158 | raise 159 | -------------------------------------------------------------------------------- /kuryr_libnetwork/port_driver/drivers/sriov.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | 13 | import glob 14 | import os 15 | import re 16 | 17 | from kuryr.lib import binding 18 | from kuryr.lib import exceptions 19 | 20 | from kuryr_libnetwork import constants as const 21 | from kuryr_libnetwork.port_driver import driver 22 | 23 | 24 | def get_ifname_by_pci_address(pci_addr, pf_interface=False): 25 | """Get the interface name based on a VF's pci address. 26 | 27 | The returned interface name is either the parent PF's or that of the VF 28 | itself based on the argument of pf_interface. 29 | """ 30 | dev_path = _get_sysfs_netdev_path(pci_addr, pf_interface) 31 | try: 32 | dev_info = os.listdir(dev_path) 33 | return dev_info.pop() 34 | except Exception: 35 | raise exceptions.KuryrException( 36 | "PCI device %s not found" % pci_addr) 37 | 38 | 39 | def _get_sysfs_netdev_path(pci_addr, pf_interface): 40 | """Get the sysfs path based on the PCI address of the device. 41 | 42 | Assumes a networking device - will not check for the existence of the path. 43 | """ 44 | if pf_interface: 45 | return "/sys/bus/pci/devices/%s/physfn/net" % pci_addr 46 | return "/sys/bus/pci/devices/%s/net" % pci_addr 47 | 48 | 49 | def get_vf_num_by_pci_address(pci_addr): 50 | """Get the VF number based on a VF's pci address 51 | 52 | A VF is associated with an VF number, which ip link command uses to 53 | configure it. This number can be obtained from the PCI device filesystem. 54 | """ 55 | VIRTFN_RE = re.compile(r"virtfn(\d+)") 56 | virtfns_path = "/sys/bus/pci/devices/%s/physfn/virtfn*" % (pci_addr) 57 | vf_num = None 58 | try: 59 | for vf_path in glob.iglob(virtfns_path): 60 | if re.search(pci_addr, os.readlink(vf_path)): 61 | t = VIRTFN_RE.search(vf_path) 62 | vf_num = t.group(1) 63 | break 64 | except Exception: 65 | pass 66 | if vf_num is None: 67 | raise exceptions.KuryrException( 68 | "PCI device %s not found" % pci_addr) 69 | return vf_num 70 | 71 | 72 | class SriovDriver(driver.Driver): 73 | """Driver supporting SR-IOV on Bare Metal""" 74 | 75 | BINDING_DRIVERS = ('hw_veb',) 76 | 77 | def get_supported_bindings(self): 78 | """Returns a tuple of supported binding driver names for the driver. 79 | 80 | :returns: a tuple of strings 81 | """ 82 | return self.BINDING_DRIVERS 83 | 84 | def get_default_network_id(self): 85 | """Returns a Neutron network ID as per driver logic, if any. 86 | 87 | This driver does not make use of any specific network and will thus 88 | return None. 89 | 90 | :returns: None 91 | """ 92 | return None 93 | 94 | def create_host_iface(self, endpoint_id, neutron_port, subnets, 95 | network=None): 96 | """Instantiates a host interface and bind it to the host. 97 | 98 | :param endpoint_id: the ID of the endpoint as string 99 | :param neutron_port: the container Neutron port dictionary as returned 100 | by python-neutronclient 101 | :param subnets: an iterable of all the Neutron subnets which the 102 | endpoint is trying to join 103 | :param network: the Neutron network which the endpoint is trying 104 | to join 105 | :returns: the tuple of stdout and stderr returned by 106 | processutils.execute invoked with the executable script for 107 | unbinding 108 | :raises: kuryr.lib.exceptions.BindingNotSupportedFailure 109 | processutils.ProcessExecutionError 110 | """ 111 | binding_driver = 'kuryr.lib.binding.drivers.hw_veb' 112 | pci_addr = neutron_port[const.BINDING_PROFILE]['pci_slot'] 113 | pf_ifname = get_ifname_by_pci_address(pci_addr, 114 | pf_interface=True) 115 | vf_num = get_vf_num_by_pci_address(pci_addr) 116 | _, _, (stdout, stderr) = binding.port_bind( 117 | endpoint_id, neutron_port, subnets, pf_ifname=pf_ifname, 118 | vf_num=vf_num, driver=binding_driver) 119 | return (stdout, stderr) 120 | 121 | def delete_host_iface(self, endpoint_id, neutron_port): 122 | """Deletes a host interface after unbinding it from the host. 123 | 124 | The host veth interface associated to the Neutron port will be unbound 125 | from its vitual bridge and deleted by delegating to the selected 126 | kuryr-lib driver. 127 | 128 | :param endpoint_id: the ID of the Docker container as string 129 | :param neutron_port: a port dictionary returned from 130 | python-neutronclient 131 | :returns: the tuple of stdout and stderr returned by 132 | processutils.execute invoked with the executable script for 133 | unbinding 134 | :raises: processutils.ProcessExecutionError 135 | """ 136 | binding_driver = 'kuryr.lib.binding.drivers.hw_veb' 137 | pci_addr = neutron_port[const.BINDING_PROFILE]['pci_slot'] 138 | pf_ifname = get_ifname_by_pci_address(pci_addr, 139 | pf_interface=True) 140 | vf_num = get_vf_num_by_pci_address(pci_addr) 141 | return binding.port_unbind(endpoint_id, neutron_port, 142 | pf_ifname=pf_ifname, 143 | vf_num=vf_num, driver=binding_driver) 144 | 145 | def get_container_iface_name(self, neutron_port): 146 | """Returns interface name of a container in the default namespace. 147 | 148 | :param neutron_port_id: The ID of a neutron port as string 149 | :returns: interface name as string 150 | """ 151 | pci_addr = neutron_port[const.BINDING_PROFILE]['pci_slot'] 152 | vf_ifname = get_ifname_by_pci_address(pci_addr) 153 | return vf_ifname 154 | -------------------------------------------------------------------------------- /kuryr_libnetwork/port_driver/drivers/veth.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | 13 | from kuryr.lib import binding 14 | from kuryr.lib.binding.drivers import utils 15 | 16 | from kuryr_libnetwork.port_driver import driver 17 | 18 | 19 | class VethDriver(driver.Driver): 20 | """Driver supporting veth on Bare Metal""" 21 | 22 | BINDING_DRIVERS = ('veth',) 23 | 24 | def get_supported_bindings(self): 25 | """Returns a tuple of supported binding driver names for the driver. 26 | 27 | :returns: a tuple of strings 28 | """ 29 | return self.BINDING_DRIVERS 30 | 31 | def get_default_network_id(self): 32 | """Returns a Neutron network ID as per driver logic, if any. 33 | 34 | This driver does not make use of any specific network and will thus 35 | return None. 36 | 37 | :returns: None 38 | """ 39 | return None 40 | 41 | def create_host_iface(self, endpoint_id, neutron_port, subnets, 42 | network=None): 43 | """Instantiates a host interface and bind it to the host. 44 | 45 | The interface type will be veth and bound to a virtual bridge. 46 | 47 | :param endpoint_id: the ID of the endpoint as string 48 | :param neutron_port: the container Neutron port dictionary as returned 49 | by python-neutronclient 50 | :param subnets: an iterable of all the Neutron subnets which the 51 | endpoint is trying to join 52 | :param network: the Neutron network which the endpoint is trying 53 | to join 54 | :returns: the tuple of stdout and stderr returned by 55 | processutils.execute invoked with the executable script for 56 | unbinding 57 | :raises: kuryr.lib.exceptions.VethCreationFailure, 58 | kuryr.lib.exceptions.BindingNotSupportedFailure 59 | processutils.ProcessExecutionError 60 | """ 61 | _, _, (stdout, stderr) = binding.port_bind( 62 | endpoint_id, neutron_port, subnets, network) 63 | return (stdout, stderr) 64 | 65 | def delete_host_iface(self, endpoint_id, neutron_port): 66 | """Deletes a host interface after unbinding it from the host. 67 | 68 | The host veth interface associated to the Neutron port will be unbound 69 | from its vitual bridge and deleted by delegating to the selected 70 | kuryr-lib driver. 71 | 72 | :param endpoint_id: the ID of the endpoint as string 73 | :param neutron_port: a port dictionary returned from 74 | python-neutronclient 75 | :returns: the tuple of stdout and stderr returned by 76 | processutils.execute invoked with the executable script for 77 | unbinding 78 | :raises: kuryr.lib.exceptions.VethDeletionFailure, 79 | processutils.ProcessExecutionError 80 | """ 81 | return binding.port_unbind(endpoint_id, neutron_port) 82 | 83 | def get_container_iface_name(self, neutron_port): 84 | """Returns interface name of a container in the default namespace. 85 | 86 | :param neutron_port_id: The neutron port 87 | :returns: interface name as string 88 | """ 89 | _, container_iface_name = utils.get_veth_pair_names(neutron_port['id']) 90 | return container_iface_name 91 | -------------------------------------------------------------------------------- /kuryr_libnetwork/schemata/__init__.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | 13 | from kuryr_libnetwork.schemata import endpoint_create 14 | from kuryr_libnetwork.schemata import endpoint_delete 15 | from kuryr_libnetwork.schemata import endpoint_info 16 | from kuryr_libnetwork.schemata import join 17 | from kuryr_libnetwork.schemata import leave 18 | from kuryr_libnetwork.schemata import network_create 19 | from kuryr_libnetwork.schemata import network_delete 20 | from kuryr_libnetwork.schemata import release_address 21 | from kuryr_libnetwork.schemata import release_pool 22 | from kuryr_libnetwork.schemata import request_address 23 | from kuryr_libnetwork.schemata import request_pool 24 | 25 | 26 | # Aliases for schemata in each module 27 | ENDPOINT_CREATE_SCHEMA = endpoint_create.ENDPOINT_CREATE_SCHEMA 28 | ENDPOINT_DELETE_SCHEMA = endpoint_delete.ENDPOINT_DELETE_SCHEMA 29 | ENDPOINT_INFO_SCHEMA = endpoint_info.ENDPOINT_INFO_SCHEMA 30 | JOIN_SCHEMA = join.JOIN_SCHEMA 31 | LEAVE_SCHEMA = leave.LEAVE_SCHEMA 32 | NETWORK_CREATE_SCHEMA = network_create.NETWORK_CREATE_SCHEMA 33 | NETWORK_DELETE_SCHEMA = network_delete.NETWORK_DELETE_SCHEMA 34 | RELEASE_ADDRESS_SCHEMA = release_address.RELEASE_ADDRESS_SCHEMA 35 | RELEASE_POOL_SCHEMA = release_pool.RELEASE_POOL_SCHEMA 36 | REQUEST_ADDRESS_SCHEMA = request_address.REQUEST_ADDRESS_SCHEMA 37 | REQUEST_POOL_SCHEMA = request_pool.REQUEST_POOL_SCHEMA 38 | -------------------------------------------------------------------------------- /kuryr_libnetwork/schemata/endpoint_create.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | 13 | from kuryr_libnetwork.schemata import commons 14 | 15 | ENDPOINT_CREATE_SCHEMA = { 16 | u'links': [{ 17 | u'method': u'POST', 18 | u'href': u'/NetworkDriver.CreateEndpoint', 19 | u'description': u'Create an Endpoint', 20 | u'rel': u'self', 21 | u'title': u'Create' 22 | }], 23 | u'title': u'Create endpoint', 24 | u'required': [u'NetworkID', u'EndpointID', u'Options', u'Interface'], 25 | u'definitions': {u'commons': {}}, 26 | u'$schema': u'http://json-schema.org/draft-04/hyper-schema', 27 | u'type': u'object', 28 | u'properties': { 29 | u'NetworkID': { 30 | u'description': u'Network ID', 31 | u'$ref': u'#/definitions/commons/definitions/id' 32 | }, 33 | u'Interface': { 34 | u'$ref': u'#/definitions/commons/definitions/interface', 35 | u'description': u'Interface information' 36 | }, 37 | u'Options': { 38 | u'description': u'Options', 39 | u'$ref': u'#/definitions/commons/definitions/options' 40 | }, 41 | u'EndpointID': { 42 | u'description': u'Endpoint ID', 43 | u'$ref': u'#/definitions/commons/definitions/id' 44 | } 45 | } 46 | } 47 | 48 | ENDPOINT_CREATE_SCHEMA[u'definitions'][u'commons'] = commons.COMMONS 49 | -------------------------------------------------------------------------------- /kuryr_libnetwork/schemata/endpoint_delete.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | 13 | from kuryr_libnetwork.schemata import commons 14 | 15 | ENDPOINT_DELETE_SCHEMA = { 16 | u'links': [{ 17 | u'method': u'POST', 18 | u'href': u'/NetworkDriver.DeleteEndpoint', 19 | u'description': u'Delete an Endpoint', 20 | u'rel': u'self', 21 | u'title': u'Delete' 22 | }], 23 | u'title': u'Delete endpoint', 24 | u'required': [u'NetworkID', u'EndpointID'], 25 | u'definitions': {u'commons': {}}, 26 | u'$schema': u'http://json-schema.org/draft-04/hyper-schema', 27 | u'type': u'object', 28 | u'properties': { 29 | u'NetworkID': { 30 | u'description': u'Network ID', 31 | u'$ref': u'#/definitions/commons/definitions/id' 32 | }, 33 | u'EndpointID': { 34 | u'description': u'Endpoint ID', 35 | u'$ref': u'#/definitions/commons/definitions/id' 36 | } 37 | } 38 | } 39 | 40 | ENDPOINT_DELETE_SCHEMA[u'definitions'][u'commons'] = commons.COMMONS 41 | -------------------------------------------------------------------------------- /kuryr_libnetwork/schemata/endpoint_info.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | 13 | from kuryr_libnetwork.schemata import commons 14 | 15 | ENDPOINT_INFO_SCHEMA = { 16 | u'links': [{ 17 | u'method': u'POST', 18 | u'href': u'/NetworkDriver.EndpointOperInfo', 19 | u'description': u'Show an Endpoint operational info', 20 | u'rel': u'self', 21 | u'title': u'Show' 22 | }], 23 | u'title': u'Show endpoint operational info', 24 | u'required': [u'NetworkID', u'EndpointID'], 25 | u'definitions': {u'commons': {}}, 26 | u'$schema': u'http://json-schema.org/draft-04/hyper-schema', 27 | u'type': u'object', 28 | u'properties': { 29 | u'NetworkID': { 30 | u'description': u'Network ID', 31 | u'$ref': u'#/definitions/commons/definitions/id' 32 | }, 33 | u'EndpointID': { 34 | u'description': u'Endpoint ID', 35 | u'$ref': u'#/definitions/commons/definitions/id' 36 | } 37 | } 38 | } 39 | 40 | ENDPOINT_INFO_SCHEMA[u'definitions'][u'commons'] = commons.COMMONS 41 | -------------------------------------------------------------------------------- /kuryr_libnetwork/schemata/join.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | 13 | from kuryr_libnetwork.schemata.commons import COMMONS 14 | 15 | 16 | JOIN_SCHEMA = { 17 | u'links': [{ 18 | u'method': u'POST', 19 | u'href': u'/NetworkDriver.Join', 20 | u'description': u'Join the network', 21 | u'rel': u'self', 22 | u'title': u'Create' 23 | }], 24 | u'title': u'Join endpoint', 25 | u'required': [ 26 | u'NetworkID', 27 | u'EndpointID', 28 | u'SandboxKey' 29 | ], 30 | u'properties': { 31 | u'NetworkID': { 32 | u'description': u'Network ID', 33 | u'$ref': u'#/definitions/commons/definitions/id' 34 | }, 35 | u'SandboxKey': { 36 | u'description': u'Sandbox Key', 37 | u'$ref': u'#/definitions/commons/definitions/sandbox_key' 38 | }, 39 | u'Options': { 40 | u'$ref': u'#/definitions/commons/definitions/options' 41 | }, 42 | u'EndpointID': { 43 | u'description': u'Endpoint ID', 44 | u'$ref': u'#/definitions/commons/definitions/id' 45 | } 46 | }, 47 | u'definitions': {u'commons': {}}, 48 | u'$schema': u'http://json-schema.org/draft-04/hyper-schema', 49 | u'type': u'object', 50 | } 51 | 52 | JOIN_SCHEMA[u'definitions'][u'commons'] = COMMONS 53 | -------------------------------------------------------------------------------- /kuryr_libnetwork/schemata/leave.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | 13 | from kuryr_libnetwork.schemata import endpoint_delete 14 | 15 | 16 | LEAVE_SCHEMA = endpoint_delete.ENDPOINT_DELETE_SCHEMA 17 | LEAVE_SCHEMA[u'title'] = u'Leave endpoint' 18 | LEAVE_SCHEMA[u'links'] = [{ 19 | u'method': u'POST', 20 | u'href': u'/NetworkDriver.Leave', 21 | u'description': u'Unbinds the endpoint from the container.', 22 | u'rel': u'self', 23 | u'title': u'Leave' 24 | }] 25 | -------------------------------------------------------------------------------- /kuryr_libnetwork/schemata/network_create.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | 13 | from kuryr_libnetwork.schemata import commons 14 | 15 | NETWORK_CREATE_SCHEMA = { 16 | u'links': [{ 17 | u'method': u'POST', 18 | u'href': u'/NetworkDriver.CreateNetwork', 19 | u'description': u'Create a Network', 20 | u'rel': u'self', 21 | u'title': u'Create' 22 | }], 23 | u'title': u'Create network', 24 | u'required': [u'NetworkID', u'IPv4Data', u'IPv6Data'], 25 | u'definitions': {u'commons': {}}, 26 | u'$schema': u'http://json-schema.org/draft-04/hyper-schema', 27 | u'type': u'object', 28 | u'properties': { 29 | u'NetworkID': { 30 | u'description': u'ID of a Network to be created', 31 | u'$ref': u'#/definitions/commons/definitions/id' 32 | }, 33 | u'IPv4Data': { 34 | u'description': u'IPv4 data for the network', 35 | u'type': u'array', 36 | u'items': { 37 | u'$ref': u'#/definitions/commons/definitions/ipv4datum' 38 | } 39 | }, 40 | u'IPv6Data': { 41 | u'description': u'IPv6 data for the network', 42 | u'type': u'array', 43 | u'items': { 44 | u'$ref': u'#/definitions/commons/definitions/ipv6datum' 45 | } 46 | }, 47 | u'Options': { 48 | u'type': [u'object', u'null'], 49 | u'description': u'Options', 50 | u'example': {} 51 | } 52 | } 53 | } 54 | 55 | NETWORK_CREATE_SCHEMA[u'definitions'][u'commons'] = commons.COMMONS 56 | -------------------------------------------------------------------------------- /kuryr_libnetwork/schemata/network_delete.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | 13 | from kuryr_libnetwork.schemata import commons 14 | 15 | NETWORK_DELETE_SCHEMA = { 16 | u'links': [{ 17 | u'method': u'POST', 18 | u'href': u'/NetworkDriver.DeleteNetwork', 19 | u'description': u'Delete a Network', 20 | u'rel': u'self', 21 | u'title': u'Delete' 22 | }], 23 | u'title': u'Delete network', 24 | u'required': [u'NetworkID'], 25 | u'definitions': {u'commons': {}}, 26 | u'$schema': u'http://json-schema.org/draft-04/hyper-schema', 27 | u'type': u'object', 28 | u'properties': { 29 | u'NetworkID': { 30 | u'description': u'ID of the Network ID to be deleted', 31 | u'$ref': u'#/definitions/commons/definitions/id' 32 | } 33 | } 34 | } 35 | 36 | NETWORK_DELETE_SCHEMA[u'definitions'][u'commons'] = commons.COMMONS 37 | -------------------------------------------------------------------------------- /kuryr_libnetwork/schemata/release_address.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | 13 | from kuryr_libnetwork.schemata import commons 14 | 15 | RELEASE_ADDRESS_SCHEMA = { 16 | u'links': [{ 17 | u'method': u'POST', 18 | u'href': u'/IpamDriver.ReleaseAddress', 19 | u'description': u'Release an ip address', 20 | u'rel': u'self', 21 | u'title': u'Release' 22 | }], 23 | u'title': u'Release an IP', 24 | u'required': [u'PoolID', u'Address'], 25 | u'definitions': {u'commons': {}}, 26 | u'$schema': u'http://json-schema.org/draft-04/hyper-schema', 27 | u'type': u'object', 28 | u'properties': { 29 | u'PoolID': { 30 | u'description': u'neutron uuid of allocated subnetpool', 31 | u'$ref': u'#/definitions/commons/definitions/uuid' 32 | }, 33 | u'Address': { 34 | u'description': u'Address in IP(v4 or v6) form', 35 | u'$ref': u'#/definitions/commons/definitions/ipv4_or_ipv6' 36 | } 37 | } 38 | 39 | } 40 | 41 | RELEASE_ADDRESS_SCHEMA[u'definitions'][u'commons'] = commons.COMMONS 42 | -------------------------------------------------------------------------------- /kuryr_libnetwork/schemata/release_pool.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | 13 | from kuryr_libnetwork.schemata import commons 14 | 15 | RELEASE_POOL_SCHEMA = { 16 | u'links': [{ 17 | u'method': u'POST', 18 | u'href': u'/IpamDriver.ReleasePool', 19 | u'description': u'Release an ip pool', 20 | u'rel': u'self', 21 | u'title': u'Release' 22 | }], 23 | u'title': u'Release an IP pool', 24 | u'required': [u'PoolID'], 25 | u'definitions': {u'commons': {}}, 26 | u'$schema': u'http://json-schema.org/draft-04/hyper-schema', 27 | u'type': u'object', 28 | u'properties': { 29 | u'PoolID': { 30 | u'description': u'neutron ID of allocated subnetpool', 31 | u'$ref': u'#/definitions/commons/definitions/uuid' 32 | } 33 | } 34 | } 35 | 36 | RELEASE_POOL_SCHEMA[u'definitions'][u'commons'] = commons.COMMONS 37 | -------------------------------------------------------------------------------- /kuryr_libnetwork/schemata/request_address.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | 13 | from kuryr_libnetwork.schemata import commons 14 | 15 | REQUEST_ADDRESS_SCHEMA = { 16 | u'links': [{ 17 | u'method': u'POST', 18 | u'href': u'/IpamDriver.RequestAddress', 19 | u'description': u'Allocate an ip addresses', 20 | u'rel': u'self', 21 | u'title': u'Create' 22 | }], 23 | u'title': u'Create an IP', 24 | u'required': [u'PoolID', u'Address', u'Options'], 25 | u'definitions': {u'commons': {}}, 26 | u'$schema': u'http://json-schema.org/draft-04/hyper-schema', 27 | u'type': u'object', 28 | u'properties': { 29 | u'PoolID': { 30 | u'description': u'neutron uuid of allocated subnetpool', 31 | u'$ref': u'#/definitions/commons/definitions/uuid' 32 | }, 33 | u'Address': { 34 | u'description': u'Preferred address in regular IP form.', 35 | u'example': u'10.0.0.1', 36 | u'$ref': u'#/definitions/commons/definitions/ipv4_or_ipv6' 37 | }, 38 | u'Options': { 39 | u'type': [u'object', u'null'], 40 | u'description': u'Options', 41 | u'example': {} 42 | } 43 | } 44 | 45 | } 46 | 47 | REQUEST_ADDRESS_SCHEMA[u'definitions'][u'commons'] = commons.COMMONS 48 | -------------------------------------------------------------------------------- /kuryr_libnetwork/schemata/request_pool.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | 13 | from kuryr_libnetwork.schemata import commons 14 | 15 | REQUEST_POOL_SCHEMA = { 16 | u'links': [{ 17 | u'method': u'POST', 18 | u'href': u'/IpamDriver.RequestPool', 19 | u'description': u'Allocate pool of ip addresses', 20 | u'rel': u'self', 21 | u'title': u'Create' 22 | }], 23 | u'title': u'Create pool', 24 | u'required': [u'AddressSpace', u'Pool', u'SubPool', u'V6'], 25 | u'definitions': {u'commons': {}}, 26 | u'$schema': u'http://json-schema.org/draft-04/hyper-schema', 27 | u'type': u'object', 28 | u'properties': { 29 | u'AddressSpace': { 30 | u'description': u'The name of the address space.', 31 | u'type': u'string', 32 | u'example': u'foo', 33 | }, 34 | u'Pool': { 35 | u'description': u'A range of IP Addresses represented in ' 36 | u'CIDR format address/mask.', 37 | u'$ref': u'#/definitions/commons/definitions/cidrv4_or_cidrv6' 38 | }, 39 | u'SubPool': { 40 | u'description': u'A subset of IP range from Pool in' 41 | u'CIDR format address/mask.', 42 | u'$ref': u'#/definitions/commons/definitions/cidrv4_or_cidrv6' 43 | }, 44 | u'Options': { 45 | u'type': [u'object', u'null'], 46 | u'description': u'Options', 47 | u'example': {}, 48 | }, 49 | u'V6': { 50 | u'description': u'If set to "True", requesting IPv6 pool and ' 51 | u'vice-versa.', 52 | u'type': u'boolean', 53 | u'example': False 54 | } 55 | } 56 | } 57 | 58 | REQUEST_POOL_SCHEMA[u'definitions'][u'commons'] = commons.COMMONS 59 | -------------------------------------------------------------------------------- /kuryr_libnetwork/server.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | import os 13 | import sys 14 | 15 | from oslo_log import log 16 | from urllib import parse 17 | 18 | from kuryr.lib._i18n import _ 19 | from kuryr_libnetwork import app 20 | from kuryr_libnetwork import config 21 | from kuryr_libnetwork import controllers 22 | 23 | 24 | def configure_app(): 25 | config.init(sys.argv[1:]) 26 | log.setup(config.CONF, 'kuryr') 27 | controllers.neutron_client() 28 | controllers.check_for_neutron_ext_support() 29 | controllers.check_for_neutron_tag_support() 30 | controllers.load_default_subnet_pools() 31 | controllers.load_port_driver() 32 | 33 | 34 | def _get_ssl_configs(use_ssl): 35 | if use_ssl: 36 | cert_file = config.CONF.ssl_cert_file 37 | key_file = config.CONF.ssl_key_file 38 | 39 | if not os.path.exists(cert_file): 40 | raise RuntimeError( 41 | _("Unable to find cert_file : %s") % cert_file) 42 | 43 | if not os.path.exists(key_file): 44 | raise RuntimeError( 45 | _("Unable to find key_file : %s") % key_file) 46 | 47 | return cert_file, key_file 48 | else: 49 | return None 50 | 51 | 52 | def start(): 53 | configure_app() 54 | kuryr_uri = parse.urlparse(config.CONF.kuryr_uri) 55 | 56 | # SSL configuration 57 | use_ssl = config.CONF.enable_ssl 58 | 59 | app.run(kuryr_uri.hostname, kuryr_uri.port, 60 | ssl_context=_get_ssl_configs(use_ssl)) 61 | 62 | 63 | if __name__ == '__main__': 64 | sys.exit(start()) 65 | elif 'UWSGI_ORIGINAL_PROC_NAME' in os.environ: 66 | # The module is being loaded by uWSGI to get the Flask app running under 67 | # it. This allows Neutron to be set, since uWSGI does not run 'start', 68 | # which would trigger the embedded Flask wsgi development server. 69 | configure_app() 70 | -------------------------------------------------------------------------------- /kuryr_libnetwork/tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openstack/kuryr-libnetwork/70676593993a8c370be3fc27a8fecc4e84661e24/kuryr_libnetwork/tests/__init__.py -------------------------------------------------------------------------------- /kuryr_libnetwork/tests/contrib/gate_hook.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -ex 4 | 5 | VENV=${1:-"fullstack"} 6 | 7 | GATE_DEST=$BASE/new 8 | DEVSTACK_PATH=$GATE_DEST/devstack 9 | 10 | export DEVSTACK_LOCAL_CONFIG+=$'\n'"enable_plugin devstack-plugin-container https://github.com/openstack/devstack-plugin-container" 11 | export DEVSTACK_LOCAL_CONFIG+=$'\n'"KURYR_CONFIG_DIR=/etc/kuryr-libnetwork" 12 | 13 | $BASE/new/devstack-gate/devstack-vm-gate.sh 14 | -------------------------------------------------------------------------------- /kuryr_libnetwork/tests/contrib/post_test_hook.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -xe 4 | 5 | KURYR_LIBNETWORK_DIR="$BASE/new/kuryr-libnetwork" 6 | TEMPEST_DIR="$BASE/new/tempest" 7 | SCRIPTS_DIR="/usr/os-testr-env/bin/" 8 | 9 | venv=${1:-"fullstack"} 10 | 11 | function generate_test_logs { 12 | local path="$1" 13 | # Compress all $path/*.txt files and move the directories holding those 14 | # files to /opt/stack/logs. Files with .log suffix have their 15 | # suffix changed to .txt (so browsers will know to open the compressed 16 | # files and not download them). 17 | if [[ -d "$path" ]] ; then 18 | sudo find "$path" -iname "*.log" -type f -exec mv {} {}.txt \; -exec gzip -9 {}.txt \; 19 | sudo mv "$path/*" /opt/stack/logs/ 20 | fi 21 | } 22 | 23 | function generate_testr_results { 24 | # Give job user rights to access tox logs 25 | sudo -H -u "$owner" chmod o+rw . 26 | sudo -H -u "$owner" chmod o+rw -R .stestr 27 | if [[ -f ".stestr/0" ]] ; then 28 | ".tox/$venv/bin/subunit-1to2" < .stestr/0 > ./stestr.subunit 29 | $SCRIPTS_DIR/subunit2html ./stestr.subunit testr_results.html 30 | gzip -9 ./stestr.subunit 31 | gzip -9 ./testr_results.html 32 | sudo mv ./*.gz /opt/stack/logs/ 33 | fi 34 | 35 | if [[ "$venv" == fullstack* ]] ; then 36 | generate_test_logs "/tmp/${venv}-logs" 37 | fi 38 | } 39 | 40 | #owner=tempest 41 | # Configure the api tests to use the tempest.conf set by devstack. 42 | #sudo_env="TEMPEST_CONFIG_DIR=$TEMPEST_DIR/etc" 43 | 44 | owner=stack 45 | sudo_env= 46 | 47 | # Set owner permissions according to job's requirements. 48 | cd "$KURYR_LIBNETWORK_DIR" 49 | sudo chown -R $owner:stack "$KURYR_LIBNETWORK_DIR" 50 | 51 | # Run tests 52 | echo "Running Kuryr $venv tests" 53 | set +e 54 | sudo pip install tox 55 | sudo -H -u "$owner" tox -e "$venv" 56 | testr_exit_code=$? 57 | set -e 58 | 59 | # Collect and parse results 60 | generate_testr_results 61 | exit $testr_exit_code 62 | -------------------------------------------------------------------------------- /kuryr_libnetwork/tests/fullstack/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openstack/kuryr-libnetwork/70676593993a8c370be3fc27a8fecc4e84661e24/kuryr_libnetwork/tests/fullstack/__init__.py -------------------------------------------------------------------------------- /kuryr_libnetwork/tests/fullstack/kuryr_base.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | 13 | import docker 14 | import os 15 | 16 | from keystoneauth1 import identity 17 | from keystoneauth1 import session as ks 18 | from neutronclient.v2_0 import client 19 | import os_client_config 20 | from oslo_log import log 21 | from oslotest import base 22 | 23 | 24 | LOG = log.getLogger(__name__) 25 | 26 | 27 | def get_neutron_client_from_env(): 28 | # We should catch KeyError exception with the purpose of 29 | # source or configure openrc file. 30 | auth_url = os.environ['OS_AUTH_URL'] 31 | username = os.environ['OS_USERNAME'] 32 | password = os.environ['OS_PASSWORD'] 33 | project_name = os.environ['OS_PROJECT_NAME'] 34 | 35 | # Either project(user)_domain_name or project(user)_domain_id 36 | # would be acceptable. 37 | project_domain_name = os.environ.get("OS_PROJECT_DOMAIN_NAME") 38 | project_domain_id = os.environ.get("OS_PROJECT_DOMAIN_ID") 39 | user_domain_name = os.environ.get("OS_USER_DOMAIN_NAME") 40 | user_domain_id = os.environ.get("OS_USER_DOMAIN_ID") 41 | 42 | auth = identity.Password(auth_url=auth_url, 43 | username=username, 44 | password=password, 45 | project_name=project_name, 46 | project_domain_id=project_domain_id, 47 | project_domain_name=project_domain_name, 48 | user_domain_id=user_domain_id, 49 | user_domain_name=user_domain_name) 50 | session = ks.Session(auth=auth) 51 | return client.Client(session=session) 52 | 53 | 54 | def _get_cloud_config_auth_data(cloud='devstack-admin'): 55 | """Retrieves Keystone auth data to run functional tests 56 | 57 | Credentials are either read via os-client-config from the environment 58 | or from a config file ('clouds.yaml'). Environment variables override 59 | those from the config file. 60 | 61 | devstack produces a clouds.yaml with two named clouds - one named 62 | 'devstack' which has user privs and one named 'devstack-admin' which 63 | has admin privs. This function will default to getting the devstack-admin 64 | cloud as that is the current expected behavior. 65 | """ 66 | cloud_config = os_client_config.OpenStackConfig().get_one_cloud(cloud) 67 | return cloud_config.get_auth(), cloud_config.get_session() 68 | 69 | 70 | def get_neutron_client_from_creds(): 71 | auth_plugin, session = _get_cloud_config_auth_data() 72 | return client.Client(session=session, auth=auth_plugin) 73 | 74 | 75 | class KuryrBaseTest(base.BaseTestCase): 76 | """Basic class for Kuryr fullstack testing 77 | 78 | This class has common code shared for Kuryr fullstack testing 79 | including the various clients (docker, neutron) and common 80 | setup/cleanup code. 81 | """ 82 | def setUp(self): 83 | super(KuryrBaseTest, self).setUp() 84 | self.docker_client = docker.APIClient( 85 | base_url='tcp://0.0.0.0:2375') 86 | try: 87 | self.neutron_client = get_neutron_client_from_env() 88 | except Exception as e: 89 | # We may missing or didn't source configured openrc file. 90 | message = ("Missing environment variable %s in your local." 91 | "Please add it and also check other missing " 92 | "environment variables. After that please source " 93 | "the openrc file. " 94 | "Trying credentials from DevStack cloud.yaml ...") 95 | LOG.warning(message, e.args[0]) 96 | self.neutron_client = get_neutron_client_from_creds() 97 | -------------------------------------------------------------------------------- /kuryr_libnetwork/tests/fullstack/test_container.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | 13 | from kuryr.lib import utils as lib_utils 14 | from kuryr_libnetwork.tests.fullstack import kuryr_base 15 | from kuryr_libnetwork import utils 16 | 17 | 18 | class ContainerTest(kuryr_base.KuryrBaseTest): 19 | """Test Container related operations 20 | 21 | Test container connect/disconnect from docker to Neutron 22 | """ 23 | def setUp(self): 24 | super(ContainerTest, self).setUp() 25 | 26 | fake_ipam = { 27 | "Driver": "kuryr", 28 | "Options": {}, 29 | "Config": [ 30 | { 31 | "Subnet": "10.3.0.0/16", 32 | "IPRange": "10.3.0.0/24", 33 | "Gateway": "10.3.0.1" 34 | } 35 | ] 36 | } 37 | net_name = lib_utils.get_random_string(8) 38 | res = self.docker_client.create_network(name=net_name, 39 | driver='kuryr', 40 | ipam=fake_ipam) 41 | self.net_id = res.get('Id') 42 | 43 | try: 44 | networks = self.neutron_client.list_networks( 45 | tags=utils.make_net_tags(self.net_id)) 46 | except Exception as e: 47 | self.docker_client.remove_network(self.net_id) 48 | message = ("Failed to list neutron networks: %s") 49 | self.fail(message % e.args[0]) 50 | self.assertEqual(1, len(networks['networks'])) 51 | self.neutron_net_id = networks['networks'][0]['id'] 52 | 53 | def tearDown(self): 54 | self.docker_client.remove_network(self.net_id) 55 | networks = self.neutron_client.list_networks( 56 | tags=utils.make_net_tags(self.net_id)) 57 | self.assertEqual(0, len(networks['networks'])) 58 | super(ContainerTest, self).tearDown() 59 | 60 | def test_connect_disconnect_container(self): 61 | # Test if support connect/disconnect operations 62 | container_name = lib_utils.get_random_string(8) 63 | container = self.docker_client.create_container( 64 | image='kuryr/busybox', 65 | command='/bin/sleep 600', 66 | hostname='kuryr_test_container', 67 | name=container_name) 68 | warn_msg = container.get('Warning') 69 | container_id = container.get('Id') 70 | self.assertIsNone(warn_msg, 'Warn in creating container') 71 | self.assertIsNotNone(container_id, 'Create container id must not ' 72 | 'be None') 73 | self.docker_client.start(container=container_id) 74 | self.docker_client.connect_container_to_network(container_id, 75 | self.net_id) 76 | try: 77 | ports = self.neutron_client.list_ports( 78 | network_id=self.neutron_net_id) 79 | except Exception as e: 80 | self.docker_client.disconnect_container_from_network( 81 | container_id, 82 | self.net_id) 83 | message = ("Failed to list neutron ports: %s") 84 | self.fail(message % e.args[0]) 85 | # A dhcp port gets created as well; dhcp is enabled by default 86 | self.assertEqual(2, len(ports['ports'])) 87 | self.docker_client.disconnect_container_from_network(container_id, 88 | self.net_id) 89 | ports = self.neutron_client.list_ports( 90 | network_id=self.neutron_net_id) 91 | self.assertEqual(1, len(ports['ports'])) 92 | self.docker_client.stop(container=container_id) 93 | 94 | # TODO(banix) Stopping the container is enough for the 95 | # container to get disconnected from the network. Therefore, 96 | # the following is not necessary for this test. The problem 97 | # with removing container is not related to the networking 98 | # but we should find out how the container can be removed. 99 | # self.docker_client.remove_container(container=container_id, 100 | # force=True) 101 | -------------------------------------------------------------------------------- /kuryr_libnetwork/tests/fullstack/test_network.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | 13 | 14 | from kuryr.lib import utils as lib_utils 15 | from kuryr_libnetwork import constants 16 | from kuryr_libnetwork.tests.fullstack import kuryr_base 17 | from kuryr_libnetwork import utils 18 | 19 | 20 | class NetworkTest(kuryr_base.KuryrBaseTest): 21 | """Test Networks operation 22 | 23 | Test networks creation/deletion from docker to Neutron 24 | """ 25 | def test_create_delete_network_with_kuryr_driver(self): 26 | """Create and Delete docker network with Kuryr 27 | 28 | This method creates a docker network with Kuryr driver 29 | and tests it was created in Neutron. 30 | It then deletes the docker network and tests that it was 31 | deleted from Neutron. 32 | """ 33 | fake_ipam = { 34 | "Driver": "kuryr", 35 | "Options": {}, 36 | "Config": [ 37 | { 38 | "Subnet": "10.0.0.0/16", 39 | "IPRange": "10.0.0.0/24", 40 | "Gateway": "10.0.0.1" 41 | } 42 | ] 43 | } 44 | net_name = lib_utils.get_random_string(8) 45 | res = self.docker_client.create_network(name=net_name, driver='kuryr', 46 | ipam=fake_ipam) 47 | net_id = res['Id'] 48 | try: 49 | network = self.neutron_client.list_networks( 50 | tags=utils.make_net_tags(net_id)) 51 | except Exception as e: 52 | self.docker_client.remove_network(net_id) 53 | message = ("Failed to list neutron networks: %s") 54 | self.fail(message % e.args[0]) 55 | self.assertEqual(1, len(network['networks'])) 56 | self.docker_client.remove_network(net_id) 57 | network = self.neutron_client.list_networks( 58 | tags=utils.make_net_tags(net_id)) 59 | self.assertEqual(0, len(network['networks'])) 60 | 61 | def test_create_delete_dualstack_network_with_kuryr_driver(self): 62 | """Create and Delete docker dual-stack network with Kuryr 63 | 64 | This method creates a docker network with Kuryr driver 65 | and tests it was created in Neutron. 66 | It then deletes the docker network and tests that it was 67 | deleted from Neutron. 68 | """ 69 | fake_ipam = { 70 | "Driver": "kuryr", 71 | "Options": {}, 72 | "Config": [ 73 | { 74 | "Subnet": "10.4.0.0/16", 75 | "IPRange": "10.4.0.0/24", 76 | "Gateway": "10.4.0.1" 77 | }, 78 | { 79 | "Subnet": "2001:db8:a0b:12f0::/64", 80 | "IPRange": "2001:db8:a0b:12f0::/64", 81 | "Gateway": "2001:db8:a0b:12f0::1" 82 | } 83 | ] 84 | } 85 | net_name = lib_utils.get_random_string(8) 86 | res = self.docker_client.create_network(name=net_name, 87 | driver='kuryr', 88 | enable_ipv6=True, 89 | ipam=fake_ipam) 90 | net_id = res['Id'] 91 | try: 92 | network = self.neutron_client.list_networks( 93 | tags=utils.make_net_tags(net_id)) 94 | except Exception as e: 95 | self.docker_client.remove_network(net_id) 96 | message = ("Failed to list neutron networks: %s") 97 | self.fail(message % e.args[0]) 98 | self.assertEqual(1, len(network['networks'])) 99 | neutron_netid = network['networks'][0]['id'] 100 | subnets = self.neutron_client.list_subnets( 101 | network_id=neutron_netid) 102 | self.assertEqual(2, len(subnets['subnets'])) 103 | subnet_version = [] 104 | subnet_name = [] 105 | for subnet in subnets['subnets']: 106 | subnet_version.append(subnet['ip_version']) 107 | subnet_name.append(subnet['name']) 108 | self.assertIn(4, subnet_version) 109 | self.assertIn(6, subnet_version) 110 | self.assertIn( 111 | constants.SUBNET_NAME_PREFIX + '10.4.0.0/24', 112 | subnet_name) 113 | self.assertIn( 114 | constants.SUBNET_NAME_PREFIX + '2001:db8:a0b:12f0::/64', 115 | subnet_name) 116 | self.docker_client.remove_network(net_id) 117 | network = self.neutron_client.list_networks( 118 | tags=utils.make_net_tags(net_id)) 119 | self.assertEqual(0, len(network['networks'])) 120 | subnets = self.neutron_client.list_subnets( 121 | network_id=neutron_netid) 122 | self.assertEqual(0, len(subnets['subnets'])) 123 | 124 | def test_create_delete_network_without_kuryr_driver(self): 125 | """Create and Delete docker network without Kuryr 126 | 127 | This method create a docker network with the default 128 | docker driver, It tests that it was created correctly, but 129 | not added to Neutron 130 | """ 131 | net_name = lib_utils.get_random_string(8) 132 | res = self.docker_client.create_network(name=net_name) 133 | net_id = res['Id'] 134 | network = self.neutron_client.list_networks( 135 | tags=utils.make_net_tags(net_id)) 136 | self.assertEqual(0, len(network['networks'])) 137 | docker_networks = self.docker_client.networks() 138 | network_found = False 139 | for docker_net in docker_networks: 140 | if docker_net['Id'] == net_id: 141 | network_found = True 142 | self.assertTrue(network_found) 143 | self.docker_client.remove_network(net_id) 144 | -------------------------------------------------------------------------------- /kuryr_libnetwork/tests/unit/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openstack/kuryr-libnetwork/70676593993a8c370be3fc27a8fecc4e84661e24/kuryr_libnetwork/tests/unit/__init__.py -------------------------------------------------------------------------------- /kuryr_libnetwork/tests/unit/port_driver/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openstack/kuryr-libnetwork/70676593993a8c370be3fc27a8fecc4e84661e24/kuryr_libnetwork/tests/unit/port_driver/__init__.py -------------------------------------------------------------------------------- /kuryr_libnetwork/tests/unit/port_driver/drivers/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openstack/kuryr-libnetwork/70676593993a8c370be3fc27a8fecc4e84661e24/kuryr_libnetwork/tests/unit/port_driver/drivers/__init__.py -------------------------------------------------------------------------------- /kuryr_libnetwork/tests/unit/port_driver/test_base.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | 13 | from unittest import mock 14 | 15 | import ddt 16 | 17 | from kuryr.lib import exceptions 18 | from kuryr_libnetwork.port_driver import base as d_base 19 | from kuryr_libnetwork.tests.unit import base 20 | 21 | 22 | class TestBaseDriver(d_base.BaseNestedDriver): 23 | def get_default_network_id(self): 24 | pass 25 | 26 | def create_host_iface(self, endpoint_id, neutron_port, subnets, 27 | network=None): 28 | pass 29 | 30 | def delete_host_iface(self, endpoint_id, neutron_port): 31 | pass 32 | 33 | def get_container_iface_name(self, neutron_port): 34 | pass 35 | 36 | def get_supported_bindings(self): 37 | pass 38 | 39 | def update_port(self, neutron_port_id, endpoint_id): 40 | pass 41 | 42 | 43 | @ddt.ddt 44 | class TestBaseNestedDriver(base.TestKuryrBase): 45 | """Unit tests for the BaseNestedDriver port driver""" 46 | 47 | @mock.patch('kuryr_libnetwork.app.neutron.list_ports') 48 | @mock.patch('kuryr.lib.binding.drivers.utils.get_ipdb') 49 | @ddt.data(('fa:16:3e:20:57:c3'), (None)) 50 | def test__get_port_from_host_iface(self, addr, m_get_ipdb, m_list_ports): 51 | m_ip = mock.MagicMock() 52 | m_iface = mock.MagicMock() 53 | port = mock.sentinel.port 54 | ports = {'ports': [port]} 55 | 56 | m_get_ipdb.return_value = m_ip 57 | m_ip.interfaces.get.return_value = m_iface 58 | m_iface.get.return_value = addr 59 | m_list_ports.return_value = ports 60 | 61 | base_driver = TestBaseDriver() 62 | if addr: 63 | response = base_driver._get_port_from_host_iface('iface') 64 | self.assertEqual(port, response) 65 | m_list_ports.assert_called_with(mac_address=addr) 66 | else: 67 | self.assertRaises(exceptions.KuryrException, 68 | base_driver._get_port_from_host_iface, 'iface') 69 | 70 | 71 | class TestBaseNestedDriverFailures(base.TestKuryrFailures): 72 | """Unit tests for the BaseNestedDriver port driver failures""" 73 | 74 | @mock.patch('kuryr.lib.binding.drivers.utils.get_ipdb') 75 | def test__get_port_from_host_iface(self, m_get_ipdb): 76 | m_ip = mock.MagicMock() 77 | m_get_ipdb.return_value = m_ip 78 | m_ip.interfaces.get.return_value = {} 79 | 80 | base_driver = TestBaseDriver() 81 | self.assertRaises(exceptions.KuryrException, 82 | base_driver._get_port_from_host_iface, '') 83 | -------------------------------------------------------------------------------- /kuryr_libnetwork/tests/unit/port_driver/test_driver.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | 13 | from unittest import mock 14 | 15 | import ddt 16 | 17 | from oslo_utils import importutils 18 | 19 | from kuryr.lib import exceptions 20 | from kuryr_libnetwork.port_driver import driver 21 | from kuryr_libnetwork.tests.unit import base 22 | 23 | 24 | @ddt.ddt 25 | class TestDriver(base.TestKuryrBase): 26 | """Unit tests for driver loading""" 27 | 28 | @mock.patch.object(driver, '_verify_binding_driver_compatibility') 29 | @mock.patch.object(driver, '_verify_port_driver_compliancy') 30 | @mock.patch.object(importutils, 'import_object') 31 | @mock.patch.object(driver, '_parse_port_driver_config') 32 | def test_get_driver_instance( 33 | self, mock_parse_config, mock_import_object, 34 | mock_verify_compliancy, mock_verify_compatibility): 35 | module = 'kuryr_libnetwork.port_driver.drivers.veth' 36 | mock_parse_config.return_value = (module, 'veth', 'VethDriver') 37 | fake_driver = mock.Mock(spec=driver.Driver) 38 | mock_import_object.return_value = fake_driver 39 | 40 | response_driver = driver.get_driver_instance() 41 | mock_parse_config.assert_called_once() 42 | mock_import_object.assert_called_once_with(module + '.VethDriver') 43 | mock_verify_compliancy.assert_called_once_with(fake_driver, 'veth') 44 | mock_verify_compatibility.assert_called_once_with(fake_driver, 'veth') 45 | self.assertEqual(response_driver, fake_driver) 46 | 47 | @mock.patch('kuryr_libnetwork.config.CONF') 48 | @ddt.data('kuryr_libnetwork.port_driver.drivers.veth', 'veth') 49 | def test__parse_port_driver_config(self, port_driver_value, mock_conf): 50 | mock_conf.default_port_driver = port_driver_value 51 | 52 | module, name, classname = driver._parse_port_driver_config() 53 | self.assertEqual(module, 'kuryr_libnetwork.port_driver.drivers.veth') 54 | self.assertEqual(name, 'veth') 55 | self.assertEqual(classname, 'VethDriver') 56 | 57 | def test__verify_port_driver_compliancy(self): 58 | fake_driver = mock.Mock(spec=driver.Driver) 59 | ret = driver._verify_port_driver_compliancy(fake_driver, 'driver') 60 | self.assertIsNone(ret) 61 | 62 | @mock.patch('kuryr_libnetwork.config.CONF') 63 | def test__verify_binding_driver_compatibility(self, mock_conf): 64 | mock_conf.binding.enabled_drivers = ['veth'] 65 | fake_driver = mock.Mock(spec=driver.Driver) 66 | fake_driver.get_supported_bindings.return_value = ('veth',) 67 | 68 | ret = driver._verify_binding_driver_compatibility(fake_driver, 'veth') 69 | fake_driver.get_supported_bindings.assert_called_once() 70 | self.assertIsNone(ret) 71 | 72 | @mock.patch('kuryr_libnetwork.config.CONF') 73 | def test__verify_binding_driver_compatibility_multi_drivers( 74 | self, mock_conf): 75 | mock_conf.binding.enabled_drivers = ['veth', 'sriov'] 76 | fake_driver = mock.Mock(spec=driver.Driver) 77 | fake_driver.get_supported_bindings.return_value = ('sriov',) 78 | 79 | ret = driver._verify_binding_driver_compatibility(fake_driver, 'sriov') 80 | fake_driver.get_supported_bindings.assert_called_once() 81 | self.assertIsNone(ret) 82 | 83 | 84 | class TestNestedDriverFailures(base.TestKuryrFailures): 85 | """Unit tests for driver loading failures""" 86 | 87 | @mock.patch('kuryr_libnetwork.config.CONF') 88 | def test__parse_port_driver_config_empty(self, mock_conf): 89 | mock_conf.default_port_driver = '' 90 | 91 | self.assertRaisesRegex(exceptions.KuryrException, 92 | "No port driver provided", driver._parse_port_driver_config) 93 | 94 | @mock.patch.object(importutils, 'import_object', side_effect=ImportError) 95 | def test_get_driver_instance_import_error(self, mock_import_object): 96 | self.assertRaises(exceptions.KuryrException, 97 | driver.get_driver_instance) 98 | 99 | def test__verify_port_driver_compliancy(self): 100 | class InvalidDriver(object): 101 | pass 102 | 103 | self.assertRaises(exceptions.KuryrException, 104 | driver._verify_port_driver_compliancy, InvalidDriver(), 'invalid') 105 | 106 | @mock.patch('kuryr_libnetwork.config.CONF') 107 | def test__verify_binding_driver_compatibility_not_compatible(self, m_conf): 108 | m_conf.binding.enabled_drivers = ['macvlan'] 109 | message = r"Configuration file error: port driver 'veth' is not " \ 110 | r"compatible with binding driver '\['macvlan'\]'" 111 | 112 | fake_driver = mock.Mock(spec=driver.Driver) 113 | fake_driver.get_supported_bindings.return_value = ('veth',) 114 | self.assertRaisesRegex(exceptions.KuryrException, message, 115 | driver._verify_binding_driver_compatibility, fake_driver, 'veth') 116 | 117 | @mock.patch('kuryr_libnetwork.config.CONF') 118 | def test__verify_binding_driver_compatibility_not_compatible_multi_drivers( 119 | self, m_conf): 120 | m_conf.binding.enabled_drivers = ['macvlan', 'sriov'] 121 | message = r"Configuration file error: port driver 'veth' is not " \ 122 | r"compatible with binding driver '\['macvlan'\, 'sriov']'" 123 | 124 | fake_driver = mock.Mock(spec=driver.Driver) 125 | fake_driver.get_supported_bindings.return_value = ('veth',) 126 | self.assertRaisesRegex(exceptions.KuryrException, message, 127 | driver._verify_binding_driver_compatibility, fake_driver, 'veth') 128 | 129 | @mock.patch('kuryr_libnetwork.config.CONF') 130 | def test__verify_binding_driver_compatibility_not_supported(self, m_conf): 131 | m_conf.binding.enabled_drivers = ['ipvlan'] 132 | message = r"Configuration file error: binding driver " \ 133 | r"'\['ipvlan'\]' is currently not supported " \ 134 | r"with 'nested' port driver" 135 | 136 | fake_driver = mock.Mock(spec=driver.Driver) 137 | fake_driver.get_supported_bindings.return_value = ('ipvlan',) 138 | self.assertRaisesRegex(exceptions.KuryrException, message, 139 | driver._verify_binding_driver_compatibility, fake_driver, 'nested') 140 | -------------------------------------------------------------------------------- /kuryr_libnetwork/tests/unit/test_config.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | 13 | import ddt 14 | import os 15 | import sys 16 | from unittest import mock 17 | from urllib import parse 18 | 19 | from neutronclient.common import exceptions as n_exceptions 20 | 21 | from kuryr.lib import exceptions 22 | from kuryr_libnetwork import config 23 | from kuryr_libnetwork import controllers 24 | from kuryr_libnetwork.server import start 25 | from kuryr_libnetwork.tests.unit import base 26 | 27 | 28 | @ddt.ddt 29 | class ConfigurationTest(base.TestKuryrBase): 30 | 31 | def test_defaults(self): 32 | basepath = os.path.abspath(os.path.join(os.path.dirname(__file__), 33 | '../../..')) 34 | self.assertEqual(basepath, 35 | config.CONF.pybasedir) 36 | self.assertEqual('/usr/libexec/kuryr', 37 | config.CONF.bindir) 38 | self.assertEqual('http://127.0.0.1:23750', 39 | config.CONF.kuryr_uri) 40 | 41 | self.assertEqual('kuryr', 42 | config.CONF.neutron.default_subnetpool_v4) 43 | 44 | self.assertEqual('kuryr6', 45 | config.CONF.neutron.default_subnetpool_v6) 46 | 47 | self.assertEqual('kuryr_libnetwork.port_driver.drivers.veth', 48 | config.CONF.port_driver) 49 | 50 | @mock.patch('kuryr_libnetwork.controllers.check_for_neutron_tag_support') 51 | @mock.patch('kuryr_libnetwork.controllers.check_for_neutron_ext_support') 52 | @mock.patch('kuryr_libnetwork.controllers.neutron_client') 53 | @mock.patch('kuryr_libnetwork.app.run') 54 | def test_start(self, mock_run, mock_neutron_client, 55 | mock_check_neutron_ext_support, 56 | mock_check_for_neutron_tag_support): 57 | with mock.patch.object(sys, 'argv', ['prog']): 58 | start() 59 | kuryr_uri = parse.urlparse(config.CONF.kuryr_uri) 60 | mock_neutron_client.assert_called_once() 61 | mock_check_neutron_ext_support.assert_called_once() 62 | mock_check_for_neutron_tag_support.assert_called_once_with() 63 | mock_run.assert_called_once_with(kuryr_uri.hostname, 23750, 64 | ssl_context=None) 65 | 66 | def test_check_for_neutron_ext_support_with_ex(self): 67 | with mock.patch.object(controllers.app.neutron, 68 | 'show_extension') as mock_extension: 69 | ext_alias = "subnet_allocation" 70 | err = n_exceptions.NotFound.status_code 71 | ext_not_found_ex = n_exceptions.NeutronClientException( 72 | status_code=err, 73 | message="") 74 | mock_extension.side_effect = ext_not_found_ex 75 | ex = exceptions.MandatoryApiMissing 76 | self.assertRaises(ex, controllers.check_for_neutron_ext_support) 77 | mock_extension.assert_called_once_with(ext_alias) 78 | 79 | @mock.patch('kuryr_libnetwork.controllers.app.neutron.show_extension') 80 | def test_check_for_neutron_tag_support_with_modern_ext(self, 81 | mock_extension): 82 | controllers.check_for_neutron_tag_support() 83 | mock_extension.assert_called_once_with('standard-attr-tag') 84 | self.assertTrue(controllers.app.tag) 85 | self.assertTrue(controllers.app.tag_ext) 86 | 87 | @mock.patch('kuryr_libnetwork.controllers.app.neutron.show_extension') 88 | @ddt.data({'tag': True, 'tag-ext': True}, 89 | {'tag': True, 'tag-ext': False}, 90 | {'tag': False, 'tag-ext': True}, 91 | {'tag': False, 'tag-ext': False}) 92 | def test_check_for_neutron_tag_support_with_legacy_ext(self, ext_matrix, 93 | mock_extension): 94 | err = n_exceptions.NotFound.status_code 95 | ext_not_found_ex = n_exceptions.NeutronClientException( 96 | status_code=err, 97 | message="") 98 | 99 | def mock_fn(ext): 100 | if not ext_matrix.get(ext, False): 101 | raise ext_not_found_ex 102 | 103 | mock_extension.side_effect = mock_fn 104 | controllers.check_for_neutron_tag_support() 105 | mock_extension.assert_any_call('standard-attr-tag') 106 | mock_extension.assert_any_call('tag') 107 | mock_extension.assert_any_call('tag-ext') 108 | 109 | self.assertEqual(controllers.app.tag, ext_matrix['tag']) 110 | self.assertEqual(controllers.app.tag_ext, ext_matrix['tag-ext']) 111 | -------------------------------------------------------------------------------- /kuryr_libnetwork/tests/unit/test_ipam_pool.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | 13 | from unittest import mock 14 | 15 | import ddt 16 | from neutronclient.common import exceptions 17 | from oslo_serialization import jsonutils 18 | 19 | from kuryr.lib import utils as lib_utils 20 | from kuryr_libnetwork.tests.unit import base 21 | 22 | 23 | @ddt.ddt 24 | class TestIpamRequestPoolFailures(base.TestKuryrFailures): 25 | """Unit tests for testing request pool failures. 26 | 27 | This test covers error responses listed in the spec: 28 | https://docs.openstack.org/api-ref/network/v2/index.html#subnet-pools-extension-subnetpools # noqa 29 | """ 30 | def _invoke_create_request(self, pool): 31 | fake_request = { 32 | 'AddressSpace': '', 33 | 'Pool': pool, 34 | 'SubPool': '', # In the case --ip-range is not given 35 | 'Options': {}, 36 | 'V6': False 37 | } 38 | response = self.app.post('/IpamDriver.RequestPool', 39 | content_type='application/json', 40 | data=jsonutils.dumps(fake_request)) 41 | return response 42 | 43 | @mock.patch('kuryr_libnetwork.controllers.app.neutron.list_subnets') 44 | @mock.patch('kuryr_libnetwork.controllers.app.neutron.list_subnetpools') 45 | @mock.patch('kuryr_libnetwork.controllers.app.neutron.create_subnetpool') 46 | @ddt.data(exceptions.Unauthorized, exceptions.Forbidden, 47 | exceptions.NotFound) 48 | def test_request_pool_create_failures(self, GivenException, 49 | mock_create_subnetpool, mock_list_subnetpools, mock_list_subnets): 50 | pool_name = lib_utils.get_neutron_subnetpool_name("10.0.0.0/16") 51 | new_subnetpool = { 52 | 'name': pool_name, 53 | 'default_prefixlen': 16, 54 | 'prefixes': ['10.0.0.0/16'], 55 | 'shared': False} 56 | 57 | fake_subnet = {"subnets": []} 58 | mock_list_subnets.return_value = fake_subnet 59 | 60 | fake_subnet_pools = {'subnetpools': []} 61 | mock_list_subnetpools.return_value = fake_subnet_pools 62 | 63 | mock_create_subnetpool.side_effect = GivenException 64 | pool = '10.0.0.0/16' 65 | response = self._invoke_create_request(pool) 66 | 67 | self.assertEqual(GivenException.status_code, response.status_code) 68 | mock_list_subnets.assert_called_with(cidr='10.0.0.0/16') 69 | mock_list_subnetpools.assert_called_with(name=pool_name) 70 | mock_create_subnetpool.assert_called_with( 71 | {'subnetpool': new_subnetpool}) 72 | decoded_json = jsonutils.loads(response.data) 73 | self.assertIn('Err', decoded_json) 74 | self.assertEqual( 75 | {'Err': GivenException.message}, decoded_json) 76 | 77 | def test_request_pool_bad_request_failure(self): 78 | pool = 'pool-should-be-cidr' 79 | response = self._invoke_create_request(pool) 80 | 81 | self.assertEqual(400, response.status_code) 82 | decoded_json = jsonutils.loads(response.data) 83 | self.assertIn('Err', decoded_json) 84 | self.assertIn(pool, decoded_json['Err']) 85 | self.assertIn('Pool', decoded_json['Err']) 86 | 87 | @mock.patch('kuryr_libnetwork.controllers.app.neutron.list_subnets') 88 | @mock.patch('kuryr_libnetwork.controllers.app.neutron.list_subnetpools') 89 | def test_request_pool_list_subnetpool_failure(self, 90 | mock_list_subnetpools, mock_list_subnets): 91 | fake_subnet = {"subnets": []} 92 | fake_pool_name = lib_utils.get_neutron_subnetpool_name("10.0.0.0/16") 93 | mock_list_subnets.return_value = fake_subnet 94 | 95 | ex = exceptions.Unauthorized 96 | mock_list_subnetpools.side_effect = ex 97 | 98 | pool = '10.0.0.0/16' 99 | response = self._invoke_create_request(pool) 100 | mock_list_subnets.assert_called_with(cidr='10.0.0.0/16') 101 | mock_list_subnetpools.assert_called_with(name=fake_pool_name) 102 | self.assertEqual(ex.status_code, response.status_code) 103 | -------------------------------------------------------------------------------- /kuryr_libnetwork/tests/unit/test_join.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | 13 | import ddt 14 | from oslo_serialization import jsonutils 15 | from werkzeug import exceptions as w_exceptions 16 | 17 | from kuryr.lib import utils as lib_utils 18 | from kuryr_libnetwork.tests.unit import base 19 | from kuryr_libnetwork import utils 20 | 21 | 22 | @ddt.ddt 23 | class TestKuryrJoinFailures(base.TestKuryrFailures): 24 | """Unit tests for the failures for binding a Neutron port.""" 25 | def _invoke_join_request(self, docker_network_id, 26 | docker_endpoint_id, container_id): 27 | data = { 28 | 'NetworkID': docker_network_id, 29 | 'EndpointID': docker_endpoint_id, 30 | 'SandboxKey': utils.get_sandbox_key(container_id), 31 | 'Options': {}, 32 | } 33 | response = self.app.post('/NetworkDriver.Join', 34 | content_type='application/json', 35 | data=jsonutils.dumps(data)) 36 | 37 | return response 38 | 39 | def test_join_bad_request(self): 40 | fake_docker_network_id = lib_utils.get_hash() 41 | invalid_docker_endpoint_id = 'id-should-be-hexdigits' 42 | fake_container_id = lib_utils.get_hash() 43 | 44 | response = self._invoke_join_request( 45 | fake_docker_network_id, invalid_docker_endpoint_id, 46 | fake_container_id) 47 | 48 | self.assertEqual( 49 | w_exceptions.BadRequest.code, response.status_code) 50 | decoded_json = jsonutils.loads(response.data) 51 | self.assertIn('Err', decoded_json) 52 | # TODO(tfukushima): Add the better error message validation. 53 | self.assertIn(invalid_docker_endpoint_id, decoded_json['Err']) 54 | self.assertIn('Failed validating ', decoded_json['Err']) 55 | -------------------------------------------------------------------------------- /kuryr_libnetwork/tests/unit/test_leave.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | 13 | import ddt 14 | from oslo_serialization import jsonutils 15 | from werkzeug import exceptions as w_exceptions 16 | 17 | from kuryr.lib import utils as lib_utils 18 | from kuryr_libnetwork.tests.unit import base 19 | 20 | 21 | @ddt.ddt 22 | class TestKuryrLeaveFailures(base.TestKuryrFailures): 23 | """Unit tests for the failures for leaving the namespace.""" 24 | def _invoke_leave_request(self, docker_network_id, 25 | docker_endpoint_id): 26 | data = { 27 | 'NetworkID': docker_network_id, 28 | 'EndpointID': docker_endpoint_id, 29 | } 30 | response = self.app.post('/NetworkDriver.Leave', 31 | content_type='application/json', 32 | data=jsonutils.dumps(data)) 33 | 34 | return response 35 | 36 | def test_leave_bad_request(self): 37 | fake_docker_network_id = lib_utils.get_hash() 38 | invalid_docker_endpoint_id = 'id-should-be-hexdigits' 39 | 40 | response = self._invoke_leave_request( 41 | fake_docker_network_id, invalid_docker_endpoint_id) 42 | 43 | self.assertEqual(w_exceptions.BadRequest.code, response.status_code) 44 | decoded_json = jsonutils.loads(response.data) 45 | self.assertIn('Err', decoded_json) 46 | # TODO(tfukushima): Add the better error message validation. 47 | self.assertIn(invalid_docker_endpoint_id, decoded_json['Err']) 48 | self.assertIn('Failed validating ', decoded_json['Err']) 49 | -------------------------------------------------------------------------------- /kuryr_libnetwork/tests/unit/test_schema.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | 13 | import jsonschema 14 | from jsonschema.exceptions import ValidationError 15 | 16 | from kuryr_libnetwork import schemata 17 | from kuryr_libnetwork.schemata import commons 18 | from kuryr_libnetwork.tests.unit import base 19 | 20 | 21 | class TestKuryrSchema(base.TestKuryrBase): 22 | """Unit tests for Kuryr schema.""" 23 | 24 | def test_network_id_64_len(self): 25 | network_id = '51c75a2515d47edecc3f720bb541e287224416fb66715eb' \ 26 | '7802011d6ffd499f1' 27 | target_schema = commons.COMMONS[u'definitions'][u'id'] 28 | self._validate_schema(network_id, target_schema) 29 | 30 | def test_network_id_25_len(self): 31 | network_id = 'xqqzd9p112o4kvok38n3caxjm' 32 | target_schema = commons.COMMONS[u'definitions'][u'id'] 33 | self._validate_schema(network_id, target_schema) 34 | 35 | def test_network_id_invalid_charactor(self): 36 | network_id = '@#qzd9p112o4kvok38n3cax&%' 37 | target_schema = commons.COMMONS[u'definitions'][u'id'] 38 | self.assertRaises(ValidationError, jsonschema.validate, network_id, 39 | target_schema) 40 | 41 | def test_network_id_invalid_length(self): 42 | network_id = 'xqqzd9p112o4kvok38n3caxjmabcd' 43 | target_schema = commons.COMMONS[u'definitions'][u'id'] 44 | self.assertRaises(ValidationError, jsonschema.validate, network_id, 45 | target_schema) 46 | 47 | def test_network_create_schema(self): 48 | docker_network_id = '51c75a2515d47edecc3f720bb541e287224416fb66715eb' \ 49 | '7802011d6ffd499f1' 50 | network_request = { 51 | 'NetworkID': docker_network_id, 52 | 'IPv4Data': [{ 53 | 'AddressSpace': 'foo', 54 | 'Pool': '192.168.42.0/24', 55 | 'Gateway': '192.168.42.1/24', 56 | 'AuxAddresses': {} 57 | }], 58 | 'IPv6Data': [{ 59 | 'AddressSpace': 'bar', 60 | 'Pool': 'fe80::/64', 61 | 'Gateway': 'fe80::f816:3eff:fe20:57c3/64', 62 | 'AuxAddresses': {} 63 | }], 64 | 'Options': {} 65 | } 66 | self._validate_schema(network_request, schemata.NETWORK_CREATE_SCHEMA) 67 | 68 | def test_network_create_schema_missing_required(self): 69 | docker_network_id = '51c75a2515d47edecc3f720bb541e287224416fb66715eb' \ 70 | '7802011d6ffd499f1' 71 | net_request = { 72 | 'NetworkID': docker_network_id, 73 | 'IPv4Data': [{ 74 | 'AddressSpace': 'foo', 75 | 'Pool': '192.168.42.0/24', 76 | 'Gateway': '192.168.42.1/24', 77 | 'AuxAddresses': {} 78 | }], 79 | 'Options': {} 80 | } 81 | self.assertRaises(ValidationError, jsonschema.validate, net_request, 82 | schemata.NETWORK_CREATE_SCHEMA) 83 | 84 | @classmethod 85 | def _validate_schema(self, target, schema): 86 | try: 87 | jsonschema.validate(target, schema) 88 | except ValidationError: 89 | self.fail("Unexpected validation error raised!") 90 | -------------------------------------------------------------------------------- /kuryr_libnetwork/tests/unit/test_utils.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | 13 | 14 | import ddt 15 | 16 | from kuryr.lib import utils as lib_utils 17 | from kuryr_libnetwork.tests.unit import base 18 | from kuryr_libnetwork import utils 19 | 20 | 21 | @ddt.ddt 22 | class TestKuryrUtils(base.TestKuryrBase): 23 | """Unit tests for utilities.""" 24 | 25 | @ddt.data(lib_utils.get_hash(), '51c75a2515d4' '51c75a') 26 | def test_get_sandbox_key(self, fake_container_id): 27 | sandbox_key = utils.get_sandbox_key(fake_container_id) 28 | expected = '/'.join([lib_utils.DOCKER_NETNS_BASE, 29 | fake_container_id[:12]]) 30 | self.assertEqual(expected, sandbox_key) 31 | 32 | def test_get_port_name(self): 33 | fake_docker_endpoint_id = lib_utils.get_hash() 34 | generated_neutron_port_name = utils.get_neutron_port_name( 35 | fake_docker_endpoint_id) 36 | self.assertIn(lib_utils.PORT_POSTFIX, generated_neutron_port_name) 37 | self.assertIn(fake_docker_endpoint_id, generated_neutron_port_name) 38 | -------------------------------------------------------------------------------- /kuryr_libnetwork/utils.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | 13 | import os 14 | import sys 15 | import time 16 | import traceback 17 | 18 | import flask 19 | import jsonschema 20 | 21 | from neutronclient.common import exceptions as n_exceptions 22 | from oslo_concurrency import processutils 23 | from oslo_log import log 24 | from werkzeug import exceptions as w_exceptions 25 | 26 | from kuryr.lib import constants as lib_const 27 | from kuryr.lib import exceptions 28 | from kuryr.lib import utils as lib_utils 29 | from kuryr_libnetwork import constants as const 30 | 31 | 32 | LOG = log.getLogger(__name__) 33 | SG_POSTFIX = 'exposed_ports' 34 | 35 | 36 | # Return all errors as JSON. From http://flask.pocoo.org/snippets/83/ 37 | def make_json_app(import_name, **kwargs): 38 | """Creates a JSON-oriented Flask app. 39 | 40 | All error responses that you don't specifically manage yourself will have 41 | application/json content type, and will contain JSON that follows the 42 | libnetwork remote driver protocol. 43 | 44 | 45 | { "Err": "405: Method Not Allowed" } 46 | 47 | 48 | See: 49 | - https://github.com/docker/libnetwork/blob/3c8e06bc0580a2a1b2440fe0792fbfcd43a9feca/docs/remote.md#errors # noqa 50 | """ 51 | app = flask.Flask(import_name, **kwargs) 52 | 53 | @app.errorhandler(exceptions.KuryrException) 54 | @app.errorhandler(n_exceptions.NeutronClientException) 55 | @app.errorhandler(jsonschema.ValidationError) 56 | @app.errorhandler(processutils.ProcessExecutionError) 57 | def make_json_error(ex): 58 | LOG.error("Unexpected error happened: %s", ex) 59 | traceback.print_exc(file=sys.stderr) 60 | response = flask.jsonify({"Err": str(ex)}) 61 | response.status_code = w_exceptions.InternalServerError.code 62 | if isinstance(ex, w_exceptions.HTTPException): 63 | response.status_code = ex.code 64 | elif isinstance(ex, n_exceptions.NeutronClientException): 65 | response.status_code = ex.status_code 66 | elif isinstance(ex, jsonschema.ValidationError): 67 | response.status_code = w_exceptions.BadRequest.code 68 | content_type = 'application/vnd.docker.plugins.v1+json; charset=utf-8' 69 | response.headers['Content-Type'] = content_type 70 | return response 71 | 72 | for code in w_exceptions.default_exceptions: 73 | app.register_error_handler(code, make_json_error) 74 | 75 | return app 76 | 77 | 78 | def get_sandbox_key(container_id): 79 | """Returns a sandbox key constructed with the given container ID. 80 | 81 | :param container_id: the ID of the Docker container as string 82 | :returns: the constructed sandbox key as string 83 | """ 84 | return os.path.join(lib_utils.DOCKER_NETNS_BASE, container_id[:12]) 85 | 86 | 87 | def get_neutron_port_name(docker_endpoint_id): 88 | """Returns a Neutron port name. 89 | 90 | :param docker_endpoint_id: the EndpointID 91 | :returns: the Neutron port name formatted appropriately 92 | """ 93 | return '-'.join([docker_endpoint_id, lib_utils.PORT_POSTFIX]) 94 | 95 | 96 | def get_sg_expose_name(port_id): 97 | """Returns a Neutron security group name. 98 | 99 | :param port_id: The Neutron port id to create a security group for 100 | :returns: the Neutron security group name formatted appropriately 101 | """ 102 | return '-'.join([port_id, SG_POSTFIX]) 103 | 104 | 105 | def create_net_tags(tag): 106 | tags = [] 107 | tags.append(const.NEUTRON_ID_LH_OPTION + ':' + tag[:32]) 108 | if len(tag) > 32: 109 | tags.append(const.NEUTRON_ID_UH_OPTION + ':' + tag[32:64]) 110 | 111 | return tags 112 | 113 | 114 | def existing_net_tag(netid): 115 | return const.KURYR_EXISTING_NEUTRON_NET + ':' + netid[:12] 116 | 117 | 118 | def make_net_tags(tag): 119 | tags = create_net_tags(tag) 120 | return ','.join(map(str, tags)) 121 | 122 | 123 | def make_net_name(netid, tags=True): 124 | if tags: 125 | return const.NET_NAME_PREFIX + netid[:8] 126 | return netid 127 | 128 | 129 | def make_subnet_name(pool_cidr): 130 | return const.SUBNET_NAME_PREFIX + pool_cidr 131 | 132 | 133 | def create_port_tags(tag): 134 | tags = [] 135 | tags.append(const.NEUTRON_ID_LH_OPTION + ':' + tag[:32]) 136 | if len(tag) > 32: 137 | tags.append(const.NEUTRON_ID_UH_OPTION + ':' + tag[32:64]) 138 | 139 | return tags 140 | 141 | 142 | def make_port_tags(tag): 143 | tags = create_port_tags(tag) 144 | return ','.join(map(str, tags)) 145 | 146 | 147 | def wait_for_port_active(neutron_client, neutron_port_id, vif_plug_timeout): 148 | port_active = False 149 | tries = 0 150 | while True: 151 | try: 152 | port = neutron_client.show_port(neutron_port_id) 153 | except n_exceptions.NeutronClientException as ex: 154 | LOG.error('Could not get the port %s to check ' 155 | 'its status', ex) 156 | else: 157 | if port['port']['status'] == lib_const.PORT_STATUS_ACTIVE: 158 | port_active = True 159 | if port_active or (vif_plug_timeout > 0 and 160 | tries >= vif_plug_timeout): 161 | break 162 | LOG.debug('Waiting for port %s to become ACTIVE', neutron_port_id) 163 | tries += 1 164 | time.sleep(1) 165 | 166 | return port_active 167 | -------------------------------------------------------------------------------- /kuryr_libnetwork/version.py: -------------------------------------------------------------------------------- 1 | # Copyright 2015 OpenStack Foundation 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 4 | # not use this file except in compliance with the License. You may obtain 5 | # a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 | # License for the specific language governing permissions and limitations 13 | # under the License. 14 | 15 | import pbr.version 16 | 17 | version_info = pbr.version.VersionInfo('kuryr-libnetwork') 18 | -------------------------------------------------------------------------------- /playbooks/post_fullstack_job.yaml: -------------------------------------------------------------------------------- 1 | - hosts: all 2 | roles: 3 | - fetch-tox-output 4 | - fetch-subunit-output 5 | -------------------------------------------------------------------------------- /playbooks/run_fullstack_job.yaml: -------------------------------------------------------------------------------- 1 | - hosts: all 2 | roles: 3 | - run-devstack 4 | - ensure-tox 5 | - tox 6 | -------------------------------------------------------------------------------- /rally-jobs/README.rst: -------------------------------------------------------------------------------- 1 | Rally job related files 2 | ======================= 3 | 4 | This directory contains rally tasks and plugins that are run by OpenStack CI. 5 | 6 | Structure 7 | --------- 8 | 9 | * plugins - directory where you can add rally plugins. Almost everything in 10 | Rally is a plugin. Benchmark context, Benchmark scenario, SLA checks, Generic 11 | cleanup resources, .... 12 | 13 | * extra - all files from this directory will be copy pasted to gates, so you 14 | are able to use absolute paths in rally tasks. 15 | Files will be located in ~/.rally/extra/* 16 | 17 | * kuryr-libnetwork.yaml is a task that is run in gates against OpenStack with 18 | Kuryr and Neutron deployed 19 | 20 | Useful links 21 | ------------ 22 | 23 | * More about Rally: https://rally.readthedocs.org/en/latest/ 24 | 25 | * Rally release notes: https://rally.readthedocs.org/en/latest/release_notes.html 26 | 27 | * How to add rally-gates: https://rally.readthedocs.org/en/latest/gates.html 28 | 29 | * About plugins: https://rally.readthedocs.org/en/latest/plugins.html 30 | 31 | * Plugin samples: https://github.com/openstack/rally/tree/master/samples/plugins 32 | -------------------------------------------------------------------------------- /rally-jobs/extra/README.rst: -------------------------------------------------------------------------------- 1 | Extra files 2 | =========== 3 | 4 | All files from this directory will be copy pasted to gates, so you are able to 5 | use absolute path in rally tasks. Files will be in ~/.rally/extra/* 6 | 7 | -------------------------------------------------------------------------------- /rally-jobs/kuryr-libnetwork.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | Kuryr.list_networks: 3 | - 4 | runner: 5 | type: "constant" 6 | times: 20 7 | concurrency: 1 8 | sla: 9 | failure_rate: 10 | max: 0 11 | 12 | Kuryr.create_and_delete_networks_with_kuryr: 13 | - 14 | runner: 15 | type: "constant" 16 | times: 20 17 | concurrency: 1 18 | sla: 19 | failure_rate: 20 | max: 0 21 | 22 | Kuryr.create_and_delete_networks_without_kuryr: 23 | - 24 | runner: 25 | type: "constant" 26 | times: 20 27 | concurrency: 1 28 | sla: 29 | failure_rate: 30 | max: 0 31 | 32 | Kuryr.start_and_stop_containers: 33 | # Start/stop Containers with Kuryr Network 34 | - 35 | runner: 36 | type: "constant" 37 | times: 20 38 | concurrency: 1 39 | context: 40 | docker_network: 41 | is_kuryr: True 42 | Subnet: 50.0.0.0/24 43 | IPRange: 50.0.0.0/24 44 | Gateway: 50.0.0.1 45 | sla: 46 | failure_rate: 47 | max: 0 48 | - 49 | # Start/stop Containers with Default Network 50 | runner: 51 | type: "constant" 52 | times: 20 53 | concurrency: 1 54 | context: 55 | docker_network: 56 | is_kuryr: False 57 | sla: 58 | failure_rate: 59 | max: 0 60 | -------------------------------------------------------------------------------- /rally-jobs/plugins/README.rst: -------------------------------------------------------------------------------- 1 | Rally plugins 2 | ============= 3 | 4 | All *.py modules from this directory will be auto-loaded by Rally and all 5 | plugins will be discoverable. There is no need of any extra configuration 6 | and there is no difference between writing them here and in rally code base. 7 | 8 | Note that it is better to push all interesting and useful benchmarks to Rally 9 | code base, this simplifies administration for Operators. 10 | -------------------------------------------------------------------------------- /rally-jobs/plugins/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openstack/kuryr-libnetwork/70676593993a8c370be3fc27a8fecc4e84661e24/rally-jobs/plugins/__init__.py -------------------------------------------------------------------------------- /rally-jobs/plugins/context/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openstack/kuryr-libnetwork/70676593993a8c370be3fc27a8fecc4e84661e24/rally-jobs/plugins/context/__init__.py -------------------------------------------------------------------------------- /rally-jobs/plugins/context/docker_networks.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 2 | # not use this file except in compliance with the License. You may obtain 3 | # a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | # License for the specific language governing permissions and limitations 11 | # under the License. 12 | 13 | import docker 14 | 15 | from rally.common import logging 16 | from rally import consts 17 | from rally.task import context 18 | 19 | LOG = logging.getLogger(__name__) 20 | 21 | 22 | @context.configure(name="docker_network", order=1000) 23 | class DockerNetworkContext(context.Context): 24 | """Create a kuryr or non-kuryr docker network as context""" 25 | 26 | CONFIG_SCHEMA = { 27 | "type": "object", 28 | "$schema": consts.JSON_SCHEMA, 29 | "additionalProperties": False, 30 | "properties": { 31 | "is_kuryr": { 32 | "type": "boolean" 33 | }, 34 | "Subnet": { 35 | "type": "string" 36 | }, 37 | "IPRange": { 38 | "type": "string" 39 | }, 40 | "Gateway": { 41 | "type": "string" 42 | } 43 | } 44 | } 45 | DEFAULT_CONFIG = { 46 | "is_kuryr": True, 47 | "Subnet": "50.0.0.0/24", 48 | "IPRange": "50.0.0.0/24", 49 | "Gateway": "50.0.0.1" 50 | } 51 | 52 | def setup(self): 53 | """Create kuryr or non-kuryr docker network, and prepare image cache""" 54 | try: 55 | docker_client = docker.APIClient(base_url="tcp://0.0.0.0:2375") 56 | 57 | if self.config["is_kuryr"]: 58 | ipam = { 59 | "Driver": "kuryr", 60 | "Options": {}, 61 | "Config": [ 62 | { 63 | "Subnet": self.config.get("Subnet"), 64 | "IPRange": self.config.get("IPRange"), 65 | "Gateway": self.config.get("Gateway") 66 | } 67 | ] 68 | } 69 | res = docker_client.create_network(name="kuryr_network", 70 | driver="kuryr", 71 | ipam=ipam) 72 | self.context["netid"] = res.get("Id") 73 | self.context["netname"] = "kuryr_network" 74 | else: 75 | res = docker_client.create_network(name="docker_network") 76 | self.context["netid"] = res.get("Id") 77 | self.context["netname"] = "docker_network" 78 | LOG.debug("Container network id is '%s'" % self.context["netid"]) 79 | except Exception as e: 80 | msg = "Can't create docker network: %s" % e.message 81 | if logging.is_debug(): 82 | LOG.exception(msg) 83 | else: 84 | LOG.warning(msg) 85 | 86 | def cleanup(self): 87 | """Clean up network""" 88 | try: 89 | self.docker_client.remove_network(self.context["netid"]) 90 | LOG.debug("Docker network '%s' deleted" % self.context["netid"]) 91 | except Exception as e: 92 | msg = "Can't delete docker network: %s" % e.message 93 | if logging.is_debug(): 94 | LOG.exception(msg) 95 | else: 96 | LOG.warning(msg) 97 | -------------------------------------------------------------------------------- /rally-jobs/plugins/scenarios/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openstack/kuryr-libnetwork/70676593993a8c370be3fc27a8fecc4e84661e24/rally-jobs/plugins/scenarios/__init__.py -------------------------------------------------------------------------------- /rally-jobs/plugins/scenarios/kuryr.py: -------------------------------------------------------------------------------- 1 | # Copyright 2016: IBM Inc. 2 | # All Rights Reserved. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 5 | # not use this file except in compliance with the License. You may obtain 6 | # a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | # License for the specific language governing permissions and limitations 14 | # under the License. 15 | 16 | import docker 17 | import utils 18 | 19 | from rally_openstack import scenario 20 | 21 | 22 | @scenario.configure(name="Kuryr.list_networks") 23 | class KuryrListNetworks(utils.KuryrScenario): 24 | 25 | def run(self, network_list_args=None): 26 | """List the networks. 27 | 28 | Measure the "docker network ls" command performance under kuryr. 29 | 30 | This will call the docker client API to list networks 31 | 32 | TODO (baohua): 33 | 1. may support tenant/user in future. 34 | 2. validation.required_services add KURYR support 35 | 36 | :param network_list_args: dict: names, ids 37 | """ 38 | self.docker_client = docker.APIClient(base_url='tcp://0.0.0.0:2375') 39 | self._list_networks(network_list_args or {}) 40 | 41 | 42 | @scenario.configure(name="Kuryr.create_and_delete_networks_with_kuryr") 43 | class KuryrCreateDeleteNetworksWithKuryr(utils.KuryrScenario): 44 | 45 | def run(self, network_create_args=None): 46 | """Create and delete a network with kuryr. 47 | 48 | Measure the "docker network create" and "docker network rm" command 49 | performance with kuryr driver. 50 | 51 | :param network_create_args: dict as options to create the network 52 | """ 53 | self.docker_client = docker.APIClient(base_url='tcp://0.0.0.0:2375') 54 | network = self._create_network(is_kuryr=True, 55 | network_create_args=network_create_args or {}) 56 | self._delete_network(network) 57 | 58 | 59 | @scenario.configure(name="Kuryr.create_and_delete_networks_without_kuryr") 60 | class KuryrCreateDeleteNetworksWithoutKuryr(utils.KuryrScenario): 61 | 62 | def run(self, network_create_args=None): 63 | """Create and delete a network without kuryr. 64 | 65 | Measure the "docker network create" and "docker network rm" command 66 | performance with default driver. 67 | 68 | :param network_create_args: dict as options to create the network 69 | """ 70 | self.docker_client = docker.APIClient(base_url='tcp://0.0.0.0:2375') 71 | network = self._create_network(is_kuryr=False, 72 | network_create_args=network_create_args or {}) 73 | self._delete_network(network) 74 | 75 | 76 | @scenario.configure(name="Kuryr.start_and_stop_containers") 77 | class KuryrStartStopContainers(utils.KuryrScenario): 78 | 79 | def run(self, container_create_args=None): 80 | """Start and stop container on docker network. 81 | 82 | Measure the "docker run" , "docker stop", "docker rm" 83 | command performance. 84 | """ 85 | self.docker_client = docker.APIClient(base_url='tcp://0.0.0.0:2375') 86 | container_id = self._start_container(container_create_args or {}) 87 | self._stop_container(container_id) 88 | # TODO(yedongcan) We will hit the Docker bug: 89 | # "Unable to remove filesystem - device or resource busy" 90 | # Temporary workaround is disable remove_container here. 91 | # self._remove_container(container_id) 92 | -------------------------------------------------------------------------------- /rally-jobs/plugins/scenarios/utils.py: -------------------------------------------------------------------------------- 1 | # Copyright 2016: IBM Inc. 2 | # All Rights Reserved. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 5 | # not use this file except in compliance with the License. You may obtain 6 | # a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | # License for the specific language governing permissions and limitations 14 | # under the License. 15 | 16 | from rally.common import logging 17 | from rally.task import atomic 18 | from rally_openstack import scenario 19 | 20 | LOG = logging.getLogger(__name__) 21 | 22 | 23 | class KuryrScenario(scenario.OpenStackScenario): 24 | """Base class for Kuryr scenarios with basic atomic actions.""" 25 | 26 | @atomic.action_timer("kuryr.list_networks") 27 | def _list_networks(self, network_list_args): 28 | """Return user networks list. 29 | 30 | :param network_list_args: network list options 31 | """ 32 | LOG.debug("Running the list_networks scenario") 33 | names = network_list_args.get('names') 34 | ids = network_list_args.get('ids') 35 | return self.docker_client.networks(names, ids) 36 | 37 | @atomic.action_timer("kuryr.create_network") 38 | def _create_network(self, is_kuryr=True, network_create_args=None): 39 | """Create network with kuryr or without kuryr. 40 | 41 | :param network_create_args: dict: name, driver and others 42 | :returns: dict of the created network reference object 43 | """ 44 | name = self.generate_random_name() 45 | if is_kuryr: 46 | ipam = { 47 | "Driver": "kuryr", 48 | "Options": {}, 49 | "Config": [ 50 | { 51 | "Subnet": "20.0.0.0/24", 52 | "IPRange": "20.0.0.0/24", 53 | "Gateway": "20.0.0.1" 54 | } 55 | ] 56 | } 57 | return self.docker_client.create_network(name=name, 58 | driver='kuryr', 59 | ipam=ipam, 60 | options=network_create_args) 61 | else: 62 | return self.docker_client.create_network(name=name, 63 | options=network_create_args) 64 | 65 | @atomic.action_timer("kuryr.delete_network") 66 | def _delete_network(self, network): 67 | """Delete Kuryr network. 68 | 69 | :param network: Network object 70 | """ 71 | self.docker_client.remove_network(network['Id']) 72 | 73 | @atomic.action_timer("kuryr.start_container") 74 | def _start_container(self, container_create_args=None): 75 | """Start Container on docker network.""" 76 | network_config = self.docker_client.create_networking_config( 77 | {self.context.get("netname"): 78 | self.docker_client.create_endpoint_config()}) 79 | container = self.docker_client.create_container( 80 | image='kuryr/busybox', 81 | command='/bin/sleep 600', 82 | networking_config=network_config) 83 | container_id = container.get('Id') 84 | self.docker_client.start(container=container_id) 85 | return container_id 86 | 87 | @atomic.action_timer("kuryr.stop_container") 88 | def _stop_container(self, container_id): 89 | """Stop Container.""" 90 | self.docker_client.stop(container=container_id) 91 | 92 | @atomic.action_timer("kuryr.remove_container") 93 | def _remove_container(self, container_id): 94 | self.docker_client.remove_container(container=container_id, 95 | force=True) 96 | -------------------------------------------------------------------------------- /rally-jobs/tasks/scenarios/create_and_delete_networks_with_kuryr.json: -------------------------------------------------------------------------------- 1 | { 2 | "Kuryr.create_and_delete_networks_with_kuryr": [ 3 | { 4 | "runner": { 5 | "type": "constant", 6 | "concurrency": 2, 7 | "times": 20 8 | }, 9 | "args": { 10 | "network_create_args": {} 11 | }, 12 | "context": { 13 | "users": { 14 | "project_domain": "default", 15 | "users_per_tenant": 3, 16 | "tenants": 3, 17 | "resource_management_workers": 10, 18 | "user_domain": "default" 19 | }, 20 | "quotas": { 21 | "neutron": { 22 | "network": -1 23 | } 24 | } 25 | } 26 | } 27 | ] 28 | } 29 | -------------------------------------------------------------------------------- /rally-jobs/tasks/scenarios/create_and_delete_networks_without_kuryr.json: -------------------------------------------------------------------------------- 1 | { 2 | "Kuryr.create_and_delete_networks_without_kuryr": [ 3 | { 4 | "runner": { 5 | "type": "constant", 6 | "concurrency": 2, 7 | "times": 20 8 | }, 9 | "args": { 10 | "network_create_args": {} 11 | }, 12 | "context": { 13 | "users": { 14 | "project_domain": "default", 15 | "users_per_tenant": 3, 16 | "tenants": 3, 17 | "resource_management_workers": 10, 18 | "user_domain": "default" 19 | }, 20 | "quotas": { 21 | "neutron": { 22 | "network": -1 23 | } 24 | } 25 | } 26 | } 27 | ] 28 | } 29 | -------------------------------------------------------------------------------- /rally-jobs/tasks/scenarios/list_networks.json: -------------------------------------------------------------------------------- 1 | { 2 | "Kuryr.list_networks": [ 3 | { 4 | "runner": { 5 | "type": "constant", 6 | "concurrency": 2, 7 | "times": 20 8 | }, 9 | "args": { 10 | "network_list_args": {} 11 | }, 12 | "context": { 13 | "users": { 14 | "project_domain": "default", 15 | "users_per_tenant": 3, 16 | "tenants": 3, 17 | "resource_management_workers": 10, 18 | "user_domain": "default" 19 | }, 20 | "quotas": { 21 | "neutron": { 22 | "network": -1 23 | } 24 | } 25 | } 26 | } 27 | ] 28 | } 29 | -------------------------------------------------------------------------------- /releasenotes/notes/add_support_ipv6_subnet-a024ffd6f7acc883.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | features: 3 | - | 4 | Support creating an IPv6 subnet from Docker client. Users can pass --ipv6 and 5 | IPv6 subnet attribute in CLI. 6 | issues: 7 | - | 8 | Docker version 1.12 and 1.13 have problem to pass ipv6 tag [1], according to 9 | this limitation, current support is for dual-stack only. 10 | [1] https://github.com/docker/docker/issues/28055 11 | -------------------------------------------------------------------------------- /releasenotes/notes/bp-existing-subnetpool-aa454cf843cba47c.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | features: 3 | - | 4 | Support creating a Docker network with existing subnetpool. Users can use 5 | the option "neutron.pool.name" to specify the name of existing neutron 6 | subnetpool. 7 | upgrade: 8 | - | 9 | The semantic of the option "neutron.pool.name" is changed. This option was 10 | used to specify a custom name of the creating subnetpool, and now it is 11 | used to specify the name of a pre-existing subnetpool. As a result, 12 | subnetpools created with custom name in before are now treated as external 13 | resources and won't be cleanup on deletion. Users need to cleanup the 14 | resources manually. 15 | -------------------------------------------------------------------------------- /releasenotes/notes/bug-1668803-c39f746e38878239.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | fixes: 3 | - | 4 | In before, creating a container with an existing Neutron port that has both 5 | ipv4 and ipv6 would fail. For example: 6 | 7 | $ docker run --net=dualnet -itd --name=container --ip 10.2.0.4 \ 8 | --ip6 fe80::8 busybox 9 | 10 | ... 11 | docker: Error response from daemon: IpamDriver.RequestAddress: Requested ip address {'subnet_id': u'xxx', 'ip_address': u'fe80::8'} already belongs to a bound Neutron port: XXX. 12 | 13 | This was fixed in this release (Bug #1668803). 14 | -------------------------------------------------------------------------------- /releasenotes/notes/bug-1671222-9ea0cf3ab39f0abc.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | other: 3 | - | 4 | Tag existing subnetpool if tag extension is enabled in Neutron. 5 | This will ensure the subnetpool to deleted is the one kuryr created. 6 | -------------------------------------------------------------------------------- /releasenotes/notes/drop-py-2-7-033606554411d7c6.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | upgrade: 3 | - | 4 | Python 2.7 support has been dropped. Last release of kuryr-libnetwork 5 | to support python 2.7 is OpenStack Train. The minimum version of Python now 6 | supported by kuryr-libnetwork is Python 3.6. 7 | -------------------------------------------------------------------------------- /releasenotes/notes/started-using-reno-8411d91eb3fe9e6c.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | other: 3 | - Started using reno for release notes. 4 | -------------------------------------------------------------------------------- /releasenotes/notes/use-uwsgi-to-run-server-4f43e615fd277c73.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | features: 3 | - | 4 | scripts/run_kuryr.sh now defaults to running api server under uwsgi. This behaviour 5 | can be controlled by KURYR_USE_UWSGI env variable (default True). 6 | In case it is set to False or uwsgi is abscent api would be run as usual. 7 | -------------------------------------------------------------------------------- /releasenotes/source/2023.1.rst: -------------------------------------------------------------------------------- 1 | =========================== 2 | 2023.1 Series Release Notes 3 | =========================== 4 | 5 | .. release-notes:: 6 | :branch: unmaintained/2023.1 7 | -------------------------------------------------------------------------------- /releasenotes/source/2023.2.rst: -------------------------------------------------------------------------------- 1 | =========================== 2 | 2023.2 Series Release Notes 3 | =========================== 4 | 5 | .. release-notes:: 6 | :branch: stable/2023.2 7 | -------------------------------------------------------------------------------- /releasenotes/source/2024.1.rst: -------------------------------------------------------------------------------- 1 | =========================== 2 | 2024.1 Series Release Notes 3 | =========================== 4 | 5 | .. release-notes:: 6 | :branch: stable/2024.1 7 | -------------------------------------------------------------------------------- /releasenotes/source/2024.2.rst: -------------------------------------------------------------------------------- 1 | =========================== 2 | 2024.2 Series Release Notes 3 | =========================== 4 | 5 | .. release-notes:: 6 | :branch: stable/2024.2 7 | -------------------------------------------------------------------------------- /releasenotes/source/2025.1.rst: -------------------------------------------------------------------------------- 1 | =========================== 2 | 2025.1 Series Release Notes 3 | =========================== 4 | 5 | .. release-notes:: 6 | :branch: stable/2025.1 7 | -------------------------------------------------------------------------------- /releasenotes/source/_static/.placeholder: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openstack/kuryr-libnetwork/70676593993a8c370be3fc27a8fecc4e84661e24/releasenotes/source/_static/.placeholder -------------------------------------------------------------------------------- /releasenotes/source/_templates/.placeholder: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openstack/kuryr-libnetwork/70676593993a8c370be3fc27a8fecc4e84661e24/releasenotes/source/_templates/.placeholder -------------------------------------------------------------------------------- /releasenotes/source/conf.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Kuryr-Libnetwork documentation build configuration file, created by 4 | # sphinx-quickstart on Tue Jan 17 09:02:23 2017. 5 | # 6 | # This file is execfile()d with the current directory set to its 7 | # containing dir. 8 | # 9 | # Note that not all possible configuration values are present in this 10 | # autogenerated file. 11 | # 12 | # All configuration values have a default; values that are commented out 13 | # serve to show the default. 14 | 15 | # If extensions (or modules to document with autodoc) are in another directory, 16 | # add these directories to sys.path here. If the directory is relative to the 17 | # documentation root, use os.path.abspath to make it absolute, like shown here. 18 | # 19 | # import os 20 | # import sys 21 | # sys.path.insert(0, os.path.abspath('.')) 22 | 23 | 24 | # -- General configuration ------------------------------------------------ 25 | 26 | # If your documentation needs a minimal Sphinx version, state it here. 27 | # 28 | # needs_sphinx = '1.0' 29 | 30 | # Add any Sphinx extension module names here, as strings. They can be 31 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 32 | # ones. 33 | extensions = [ 34 | 'reno.sphinxext', 35 | 'openstackdocstheme', 36 | ] 37 | 38 | # Add any paths that contain templates here, relative to this directory. 39 | templates_path = ['_templates'] 40 | 41 | # The suffix(es) of source filenames. 42 | # You can specify multiple suffix as a list of string: 43 | # 44 | # source_suffix = ['.rst', '.md'] 45 | source_suffix = '.rst' 46 | 47 | # The master toctree document. 48 | master_doc = 'index' 49 | 50 | # General information about the project. 51 | project = u'Kuryr-Libnetwork' 52 | copyright = u'2017, Kuryr-Libnetwork Developers' 53 | author = u'Kuryr-Libnetwork Developers' 54 | 55 | # openstackdocstheme options 56 | openstackdocs_repo_name = 'openstack/kuryr-libnetwork' 57 | openstackdocs_auto_name = False 58 | openstackdocs_bug_project = 'kuryr-libnetwork' 59 | openstackdocs_bug_tag = '' 60 | 61 | # Release notes do not need a version number in the title, they 62 | # cover multiple releases. 63 | # The short X.Y version. 64 | version = '' 65 | # The full version, including alpha/beta/rc tags. 66 | release = '' 67 | 68 | # The language for content autogenerated by Sphinx. Refer to documentation 69 | # for a list of supported languages. 70 | # 71 | # This is also used if you do content translation via gettext catalogs. 72 | # Usually you set "language" from the command line for these cases. 73 | # language = None 74 | 75 | # List of patterns, relative to source directory, that match files and 76 | # directories to ignore when looking for source files. 77 | # This patterns also effect to html_static_path and html_extra_path 78 | exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] 79 | 80 | # The name of the Pygments (syntax highlighting) style to use. 81 | pygments_style = 'native' 82 | 83 | # If true, `todo` and `todoList` produce output, else they produce nothing. 84 | todo_include_todos = False 85 | 86 | # -- Options for HTML output ---------------------------------------------- 87 | 88 | # The theme to use for HTML and HTML Help pages. See the documentation for 89 | # a list of builtin themes. 90 | # 91 | html_theme = 'openstackdocs' 92 | 93 | 94 | # Theme options are theme-specific and customize the look and feel of a theme 95 | # further. For a list of options available for each theme, see the 96 | # documentation. 97 | # 98 | # html_theme_options = {} 99 | 100 | # Add any paths that contain custom static files (such as style sheets) here, 101 | # relative to this directory. They are copied after the builtin static files, 102 | # so a file named "default.css" will overwrite the builtin "default.css". 103 | html_static_path = ['_static'] 104 | 105 | 106 | # -- Options for HTMLHelp output ------------------------------------------ 107 | 108 | # Output file base name for HTML help builder. 109 | htmlhelp_basename = 'Kuryr-Libnetworkdoc' 110 | 111 | 112 | # -- Options for LaTeX output --------------------------------------------- 113 | 114 | latex_elements = { 115 | # The paper size ('letterpaper' or 'a4paper'). 116 | # 117 | # 'papersize': 'letterpaper', 118 | 119 | # The font size ('10pt', '11pt' or '12pt'). 120 | # 121 | # 'pointsize': '10pt', 122 | 123 | # Additional stuff for the LaTeX preamble. 124 | # 125 | # 'preamble': '', 126 | 127 | # Latex figure (float) alignment 128 | # 129 | # 'figure_align': 'htbp', 130 | } 131 | 132 | # Grouping the document tree into LaTeX files. List of tuples 133 | # (source start file, target name, title, 134 | # author, documentclass [howto, manual, or own class]). 135 | latex_documents = [ 136 | (master_doc, 'Kuryr-Libnetwork.tex', u'Kuryr-Libnetwork Documentation', 137 | u'Kuryr-Libnetwork Developers', 'manual'), 138 | ] 139 | 140 | 141 | # -- Options for manual page output --------------------------------------- 142 | 143 | # One entry per manual page. List of tuples 144 | # (source start file, name, description, authors, manual section). 145 | man_pages = [ 146 | (master_doc, 'kuryr-libnetwork', u'Kuryr-Libnetwork Documentation', 147 | [author], 1) 148 | ] 149 | 150 | 151 | # -- Options for Texinfo output ------------------------------------------- 152 | 153 | # Grouping the document tree into Texinfo files. List of tuples 154 | # (source start file, target name, title, author, 155 | # dir menu entry, description, category) 156 | texinfo_documents = [ 157 | (master_doc, 'Kuryr-Libnetwork', u'Kuryr-Libnetwork Documentation', 158 | author, 'Kuryr-Libnetwork', 'One line description of project.', 159 | 'Miscellaneous'), 160 | ] 161 | -------------------------------------------------------------------------------- /releasenotes/source/index.rst: -------------------------------------------------------------------------------- 1 | Welcome to Kuryr-Libnetwork's documentation! 2 | ============================================ 3 | 4 | .. toctree:: 5 | :maxdepth: 1 6 | 7 | unreleased 8 | 2025.1 9 | 2024.2 10 | 2024.1 11 | 2023.2 12 | 2023.1 13 | zed 14 | yoga 15 | xena 16 | wallaby 17 | victoria 18 | ussuri 19 | train 20 | stein 21 | rocky 22 | queens 23 | -------------------------------------------------------------------------------- /releasenotes/source/queens.rst: -------------------------------------------------------------------------------- 1 | =================================== 2 | Queens Series Release Notes 3 | =================================== 4 | 5 | .. release-notes:: 6 | :branch: stable/queens 7 | -------------------------------------------------------------------------------- /releasenotes/source/rocky.rst: -------------------------------------------------------------------------------- 1 | =================================== 2 | Rocky Series Release Notes 3 | =================================== 4 | 5 | .. release-notes:: 6 | :branch: stable/rocky 7 | -------------------------------------------------------------------------------- /releasenotes/source/stein.rst: -------------------------------------------------------------------------------- 1 | =================================== 2 | Stein Series Release Notes 3 | =================================== 4 | 5 | .. release-notes:: 6 | :branch: stable/stein 7 | -------------------------------------------------------------------------------- /releasenotes/source/train.rst: -------------------------------------------------------------------------------- 1 | ========================== 2 | Train Series Release Notes 3 | ========================== 4 | 5 | .. release-notes:: 6 | :branch: stable/train 7 | -------------------------------------------------------------------------------- /releasenotes/source/unreleased.rst: -------------------------------------------------------------------------------- 1 | ============================ 2 | Current Series Release Notes 3 | ============================ 4 | 5 | .. release-notes:: 6 | -------------------------------------------------------------------------------- /releasenotes/source/ussuri.rst: -------------------------------------------------------------------------------- 1 | =========================== 2 | Ussuri Series Release Notes 3 | =========================== 4 | 5 | .. release-notes:: 6 | :branch: stable/ussuri 7 | -------------------------------------------------------------------------------- /releasenotes/source/victoria.rst: -------------------------------------------------------------------------------- 1 | ============================= 2 | Victoria Series Release Notes 3 | ============================= 4 | 5 | .. release-notes:: 6 | :branch: unmaintained/victoria 7 | -------------------------------------------------------------------------------- /releasenotes/source/wallaby.rst: -------------------------------------------------------------------------------- 1 | ============================ 2 | Wallaby Series Release Notes 3 | ============================ 4 | 5 | .. release-notes:: 6 | :branch: unmaintained/wallaby 7 | -------------------------------------------------------------------------------- /releasenotes/source/xena.rst: -------------------------------------------------------------------------------- 1 | ========================= 2 | Xena Series Release Notes 3 | ========================= 4 | 5 | .. release-notes:: 6 | :branch: unmaintained/xena 7 | -------------------------------------------------------------------------------- /releasenotes/source/yoga.rst: -------------------------------------------------------------------------------- 1 | ========================= 2 | Yoga Series Release Notes 3 | ========================= 4 | 5 | .. release-notes:: 6 | :branch: unmaintained/yoga 7 | -------------------------------------------------------------------------------- /releasenotes/source/zed.rst: -------------------------------------------------------------------------------- 1 | ======================== 2 | Zed Series Release Notes 3 | ======================== 4 | 5 | .. release-notes:: 6 | :branch: unmaintained/zed 7 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | # Requirements lower bounds listed here are our best effort to keep them up to 2 | # date but we do not test them so no guarantee of having them all correct. If 3 | # you find any incorrect lower bounds, let us know or propose a fix. 4 | 5 | # The order of packages is significant, because pip processes them in the order 6 | # of appearance. Changing the order has an impact on the overall integration 7 | # process, which may cause wedges in the gate later. 8 | 9 | Babel!=2.4.0,>=2.3.4 # BSD 10 | Flask!=0.11,>=0.10 # BSD 11 | jsonschema>=3.2.0 # MIT 12 | kuryr-lib>=0.7.0 # Apache-2.0 13 | neutron-lib>=1.13.0 # Apache-2.0 14 | os-client-config>=1.28.0 # Apache-2.0 15 | oslo.concurrency>=3.25.0 # Apache-2.0 16 | oslo.config>=5.2.0 # Apache-2.0 17 | oslo.log>=3.36.0 # Apache-2.0 18 | oslo.utils>=3.33.0 # Apache-2.0 19 | pbr!=2.1.0,>=2.0.0 # Apache-2.0 20 | python-neutronclient>=6.7.0 # Apache-2.0 21 | -------------------------------------------------------------------------------- /scripts/run_kuryr.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 4 | # not use this file except in compliance with the License. You may obtain 5 | # a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 | # License for the specific language governing permissions and limitations 13 | # under the License. 14 | 15 | KURYR_HOME=${KURYR_HOME:-.} 16 | KURYR_JSON_FILENAME=kuryr.json 17 | KURYR_DEFAULT_JSON=${KURYR_HOME}/etc/${KURYR_JSON_FILENAME} 18 | # See libnetwork's plugin discovery mechanism: 19 | # https://github.com/docker/docker/blob/c4d45b6a29a91f2fb5d7a51ac36572f2a9b295c6/docs/extend/plugin_api.md#plugin-discovery 20 | KURYR_JSON_DIR=${KURYR_JSON_DIR:-/usr/lib/docker/plugins/kuryr} 21 | KURYR_JSON=${KURYR_JSON_DIR}/${KURYR_JSON_FILENAME} 22 | 23 | KURYR_CONFIG_FILENAME=kuryr.conf 24 | KURYR_DEFAULT_CONFIG=${KURYR_HOME}/etc/${KURYR_CONFIG_FILENAME} 25 | KURYR_CONFIG_DIR=${KURYR_CONFIG_DIR:-/etc/kuryr} 26 | KURYR_CONFIG=${KURYR_CONFIG_DIR}/${KURYR_CONFIG_FILENAME} 27 | 28 | SSL_ENABLED=${SSL_ENABLED:-False} 29 | KURYR_SSL_ENABLED_JSON=${KURYR_HOME}/contrib/tls/${KURYR_JSON_FILENAME} 30 | 31 | 32 | if [[ ! -d "${KURYR_JSON_DIR}" ]]; then 33 | echo -n "${KURYR_JSON_DIR} directory is missing. Creating it... " 34 | sudo mkdir -p ${KURYR_JSON_DIR} 35 | echo "Done" 36 | fi 37 | 38 | 39 | if [ "$SSL_ENABLED" == "True" ]; then 40 | echo -n "Copying ${KURYR_SSL_ENABLED_JSON} one... " 41 | sudo cp ${KURYR_SSL_ENABLED_JSON} ${KURYR_JSON} 42 | fi 43 | 44 | 45 | if [[ ! -f "${KURYR_JSON}" ]]; then 46 | echo -n "${KURYR_JSON} is missing. Copying the ssl enabled one... " 47 | sudo cp ${KURYR_DEFAULT_JSON} ${KURYR_JSON} 48 | echo "Done" 49 | fi 50 | 51 | if [[ ! -d "${KURYR_CONFIG_DIR}" ]]; then 52 | echo -n "${KURYR_CONFIG_DIR} directory is missing. Creating it... " 53 | sudo mkdir -p ${KURYR_CONFIG_DIR} 54 | echo "Done" 55 | fi 56 | 57 | if [[ ! -f "${KURYR_CONFIG}" ]]; then 58 | if [[ -f "${KURYR_DEFAULT_CONFIG}" ]]; then 59 | echo -n "${KURYR_CONFIG} is missing. Copying the default one... " 60 | sudo cp ${KURYR_DEFAULT_CONFIG} ${KURYR_CONFIG} 61 | else 62 | if [ "$SSL_ENABLED" == "True" ];then 63 | # To Avoid tls compatible Config file and json file mismatch it would be 64 | # better to raise an error than to continue with corrupt env. 65 | echo "Please check configuration for Tls.." 66 | echo "Aborting" 67 | exit 1 68 | else 69 | echo -n "${KURYR_CONFIG} and the default config missing. Auto generating and copying one... " 70 | cd ${KURYR_HOME} 71 | tox -egenconfig 72 | sudo cp ${KURYR_DEFAULT_CONFIG}.sample ${KURYR_DEFAULT_CONFIG} 73 | sudo cp ${KURYR_DEFAULT_CONFIG} ${KURYR_CONFIG} 74 | fi 75 | fi 76 | echo "Done" 77 | fi 78 | 79 | KURYR_USE_UWSGI=${KURYR_USE_UWSGI:-True} 80 | KURYR_UWSGI_PROCESSES=${KURYR_UWSGI_PROCESSES:-1} 81 | KURYR_UWSGI_THREADS=${KURYR_UWSGI_THREADS:-1} 82 | 83 | UWSGI_BIN=$(which uwsgi) 84 | if [[ -z "UWSGI_BIN" && $KURYR_USE_UWSGI == "True" ]]; then 85 | echo "Requested uwsgi usage, but no uwsgi executable is available. Falling back to run_server.py" 86 | echo "To suppress this message set KURYR_USE_UWSGI to False" 87 | KURYR_USE_UWSGI="False" 88 | fi 89 | 90 | UWSGI_ADDITIONAL_ARGS=() 91 | if [[ $KURYR_USE_UWSGI == "True" ]]; then 92 | if [[ "$VIRTUAL_ENV" ]]; then 93 | UWSGI_ADDITIONAL_ARGS=( --virtualenv $VIRTUAL_ENV ) 94 | fi 95 | echo "Starting uwsgi with ${KURYR_UWSGI_PROCESSES} processes and ${KURYR_UWSGI_THREADS} threads" 96 | $UWSGI_BIN \ 97 | --plugins python \ 98 | --http-socket :23750 \ 99 | --wsgi kuryr_libnetwork.server:app \ 100 | --python-path "${KURYR_HOME}" \ 101 | --pyargv "--config-file ${KURYR_CONFIG}" \ 102 | --master \ 103 | --need-app \ 104 | --processes "$KURYR_UWSGI_PROCESSES" \ 105 | --threads "$KURYR_UWSGI_THREADS" \ 106 | "${UWSGI_ADDITIONAL_ARGS[@]}" 107 | else 108 | PYTHONPATH="${KURYR_HOME}" python3 "${KURYR_HOME}/scripts/run_server.py" --config-file "${KURYR_CONFIG}" "$@" 109 | fi 110 | -------------------------------------------------------------------------------- /scripts/run_server.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 4 | # not use this file except in compliance with the License. You may obtain 5 | # a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 | # License for the specific language governing permissions and limitations 13 | # under the License. 14 | 15 | from kuryr_libnetwork import server 16 | 17 | server.start() 18 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [metadata] 2 | name = kuryr-libnetwork 3 | summary = Docker libnetwork driver for OpenStack Neutron 4 | description_file = 5 | README.rst 6 | author = OpenStack 7 | author_email = openstack-discuss@lists.openstack.org 8 | home_page = https://docs.openstack.org/kuryr-libnetwork/latest/ 9 | python_requires = >=3.8 10 | classifier = 11 | Environment :: OpenStack 12 | Intended Audience :: Information Technology 13 | Intended Audience :: System Administrators 14 | License :: OSI Approved :: Apache Software License 15 | Operating System :: POSIX :: Linux 16 | Programming Language :: Python 17 | Programming Language :: Python :: Implementation :: CPython 18 | Programming Language :: Python :: 3 :: Only 19 | Programming Language :: Python :: 3 20 | Programming Language :: Python :: 3.8 21 | Programming Language :: Python :: 3.9 22 | Programming Language :: Python :: 3.10 23 | Programming Language :: Python :: 3.11 24 | 25 | [entry_points] 26 | oslo.config.opts = 27 | kuryr_libnetwork = kuryr_libnetwork.opts:list_kuryr_libnetwork_opts 28 | 29 | console_scripts = 30 | kuryr-server = kuryr_libnetwork.server:start 31 | 32 | [files] 33 | packages = 34 | kuryr_libnetwork 35 | data_files = 36 | /usr/lib/docker/plugins/kuryr = etc/kuryr.spec 37 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2013 Hewlett-Packard Development Company, L.P. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 12 | # implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | import setuptools 17 | 18 | setuptools.setup( 19 | setup_requires=['pbr>=2.0.0'], 20 | pbr=True) 21 | -------------------------------------------------------------------------------- /test-requirements.txt: -------------------------------------------------------------------------------- 1 | # The order of packages is significant, because pip processes them in the order 2 | # of appearance. Changing the order has an impact on the overall integration 3 | # process, which may cause wedges in the gate later. 4 | 5 | hacking>=3.0.1,<3.1.0 # Apache-2.0 6 | 7 | coverage!=4.4,>=4.0 # Apache-2.0 8 | ddt>=1.0.1 # MIT 9 | docker>=2.4.2 # Apache-2.0 10 | stestr>=1.0.0 # Apache-2.0 11 | oslo.serialization!=2.19.1,>=2.18.0 # Apache-2.0 12 | oslotest>=3.2.0 # Apache-2.0 13 | python-subunit>=1.0.0 # Apache-2.0/BSD 14 | testscenarios>=0.4 # Apache-2.0/BSD 15 | testtools>=2.2.0 # MIT 16 | -------------------------------------------------------------------------------- /tools/generate_config_file_samples.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 | # License for the specific language governing permissions and limitations 13 | # under the License. 14 | 15 | set -e 16 | 17 | GEN_CMD=oslo-config-generator 18 | SCRIPT_PATH=$(dirname "$(readlink -f "$0")") 19 | DIST_PATH=$(dirname "$SCRIPT_PATH") 20 | 21 | prerequisites() ( 22 | if ! command -v "$GEN_CMD" > /dev/null; then 23 | echo "ERROR: $GEN_CMD not installed on the system." 24 | return 1 25 | fi 26 | 27 | if ! [ -f "${DIST_PATH}/kuryr_libnetwork.egg-info/entry_points.txt" ]; then 28 | curr_dir=$(pwd) 29 | cd "${DIST_PATH}" 30 | python3 setup.py egg_info # Generate entrypoints for config generation 31 | cd "${curr_dir}" 32 | fi 33 | 34 | return 0 35 | ) 36 | 37 | generate() ( 38 | curr_dir=$(pwd) 39 | cd "${DIST_PATH}" 40 | # Set PYTHONPATH so that it will use the generated egg-info 41 | PYTHONPATH=. find "etc/oslo-config-generator" -type f -exec "$GEN_CMD" --config-file="{}" \; 42 | cd "${curr_dir}" 43 | ) 44 | 45 | 46 | prerequisites 47 | rc=$? 48 | if [ $rc -ne 0 ]; then 49 | exit $rc 50 | fi 51 | 52 | generate 53 | 54 | set -x 55 | -------------------------------------------------------------------------------- /tox.ini: -------------------------------------------------------------------------------- 1 | [tox] 2 | minversion = 2.3.1 3 | envlist = py38,pep8 4 | 5 | [testenv] 6 | # Note the hash seed is set to 0 until neutron can be tested with a 7 | # random hash seed successfully. 8 | setenv = VIRTUAL_ENV={envdir} 9 | PYTHONHASHSEED=0 10 | PYTHONWARNINGS=default::DeprecationWarning 11 | usedevelop = True 12 | install_command = pip install {opts} {packages} 13 | deps = -c{env:TOX_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/master} 14 | -r{toxinidir}/requirements.txt 15 | -r{toxinidir}/test-requirements.txt 16 | 17 | allowlist_externals = sh 18 | find 19 | commands = find . -type f -name "*.py[c|o]" -delete 20 | stestr run {posargs} 21 | 22 | [testenv:fullstack] 23 | setenv = OS_TEST_PATH=./kuryr_libnetwork/tests/fullstack 24 | passenv = OS_* 25 | 26 | [testenv:debug] 27 | commands = oslo_debug_helper -t kuryr_libnetwork/tests {posargs} 28 | 29 | [testenv:pep8] 30 | commands = flake8 31 | 32 | [testenv:venv] 33 | commands = {posargs} 34 | 35 | [testenv:cover] 36 | setenv = 37 | VIRTUAL_ENV={envdir} 38 | PYTHON=coverage run --source kuryr_libnetwork --parallel-mode 39 | commands = 40 | stestr run {posargs} 41 | coverage combine 42 | coverage html -d cover 43 | coverage xml -o cover/coverage.xml 44 | coverage report 45 | 46 | [testenv:docs] 47 | deps = -c{env:TOX_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/master} 48 | -r{toxinidir}/doc/requirements.txt 49 | commands = 50 | sphinx-build -a -W -E -b html doc/source doc/build/html 51 | 52 | [flake8] 53 | # E128 continuation line under-indented for visual indent 54 | # W504 line break after binary operator 55 | ignore = E128,W504 56 | show-source = true 57 | 58 | exclude = .venv,.git,.tox,dist,doc,*lib/python*,*egg,build,tools,.ropeproject,rally-scenarios,releasenotes 59 | 60 | [testenv:pylint] 61 | deps = 62 | {[testenv]deps} 63 | pylint 64 | commands = 65 | pylint --rcfile=.pylintrc --output-format=colorized {posargs:neutron} 66 | 67 | [hacking] 68 | import_exceptions = kuryr.lib._i18n 69 | local-check-factory = neutron_lib.hacking.checks.factory 70 | 71 | [testenv:genconfig] 72 | commands = {toxinidir}/tools/generate_config_file_samples.sh 73 | 74 | [testenv:releasenotes] 75 | deps = {[testenv:docs]deps} 76 | commands = sphinx-build -a -W -E -d releasenotes/build/doctrees -b html releasenotes/source releasenotes/build/html 77 | --------------------------------------------------------------------------------