diff --git a/.gitignore b/.gitignore index 2778a65c89..956e13e21c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1,13 @@ *~ .*.sw? *.log -*.log.[1-9] +*-log +*.log.* +*-log.* *.pem +*.pyc .localrc.auto +.localrc.password .prereqs .tox .stackenv @@ -11,16 +15,26 @@ accrc doc/files doc/build files/*.gz +files/*.vmdk +files/*.rpm +files/*.rpm.* +files/*.deb +files/*.deb.* files/*.qcow2 files/*.img files/images files/pip-* files/get-pip.py* files/ir-deploy* -local.conf +files/ironic-inspector* +files/etcd* +^local.conf local.sh localrc proto shocco src stack-screenrc +userrc_early +AUTHORS +ChangeLog diff --git a/.zuul.yaml b/.zuul.yaml new file mode 100644 index 0000000000..9aafcdbb84 --- /dev/null +++ b/.zuul.yaml @@ -0,0 +1,700 @@ +- nodeset: + name: openstack-single-node + nodes: + - name: controller + label: ubuntu-xenial + groups: + - name: tempest + nodes: + - controller + +- nodeset: + name: openstack-single-node-bionic + nodes: + - name: controller + label: ubuntu-bionic + groups: + - name: tempest + nodes: + - controller + +- nodeset: + name: openstack-single-node-xenial + nodes: + - name: controller + label: ubuntu-xenial + groups: + - name: tempest + nodes: + - controller + +- nodeset: + name: devstack-single-node-centos-7 + nodes: + - name: controller + label: centos-7 + groups: + - name: tempest + nodes: + - controller + +- nodeset: + name: devstack-single-node-opensuse-150 + nodes: + - name: controller + label: opensuse-150 + groups: + - name: tempest + nodes: + - controller + +- nodeset: + name: devstack-single-node-fedora-latest + nodes: + - name: controller + label: fedora-28 + groups: + - name: tempest + nodes: + - controller + +- nodeset: + name: openstack-two-node + nodes: + - name: controller + label: ubuntu-xenial + - name: compute1 + label: ubuntu-xenial + groups: + # Node where tests are executed and test results collected + - name: tempest + nodes: + - controller + # Nodes running the compute service + - name: compute + nodes: + - controller + - compute1 + # Nodes that are not the controller + - name: subnode + nodes: + - compute1 + # Switch node for multinode networking setup + - name: switch + nodes: + - controller + # Peer nodes for multinode networking setup + - name: peers + nodes: + - compute1 + +- nodeset: + name: openstack-two-node-bionic + nodes: + - name: controller + label: ubuntu-bionic + - name: compute1 + label: ubuntu-bionic + groups: + # Node where tests are executed and test results collected + - name: tempest + nodes: + - controller + # Nodes running the compute service + - name: compute + nodes: + - controller + - compute1 + # Nodes that are not the controller + - name: subnode + nodes: + - compute1 + # Switch node for multinode networking setup + - name: switch + nodes: + - controller + # Peer nodes for multinode networking setup + - name: peers + nodes: + - compute1 + +- nodeset: + name: openstack-two-node-xenial + nodes: + - name: controller + label: ubuntu-xenial + - name: compute1 + label: ubuntu-xenial + groups: + # Node where tests are executed and test results collected + - name: tempest + nodes: + - controller + # Nodes running the compute service + - name: compute + nodes: + - controller + - compute1 + # Nodes that are not the controller + - name: subnode + nodes: + - compute1 + # Switch node for multinode networking setup + - name: switch + nodes: + - controller + # Peer nodes for multinode networking setup + - name: peers + nodes: + - compute1 + +- job: + name: devstack-base + parent: multinode + abstract: true + description: | + Base abstract Devstack job. + + Defines plays and base variables, but it does not include any project + and it does not run any service by default. This is a common base for + all single Devstack jobs, single or multinode. + Variables are defined in job.vars, which is what is then used by single + node jobs and by multi node jobs for the controller, as well as in + job.group-vars.peers, which is what is used by multi node jobs for subnode + nodes (everything but the controller). + required-projects: + - git.openstack.org/openstack-dev/devstack + roles: + - zuul: git.openstack.org/openstack-infra/devstack-gate + - zuul: git.openstack.org/openstack-infra/openstack-zuul-jobs + vars: + devstack_localrc: + DATABASE_PASSWORD: secretdatabase + RABBIT_PASSWORD: secretrabbit + ADMIN_PASSWORD: secretadmin + SERVICE_PASSWORD: secretservice + NETWORK_GATEWAY: 10.1.0.1 + FIXED_RANGE: 10.1.0.0/20 + IPV4_ADDRS_SAFE_TO_USE: 10.1.0.0/20 + FLOATING_RANGE: 172.24.5.0/24 + PUBLIC_NETWORK_GATEWAY: 172.24.5.1 + LOGFILE: /opt/stack/logs/devstacklog.txt + LOG_COLOR: false + VERBOSE: true + VERBOSE_NO_TIMESTAMP: true + NOVNC_FROM_PACKAGE: true + ERROR_ON_CLONE: true + # Gate jobs can't deal with nested virt. Disable it. + LIBVIRT_TYPE: qemu + devstack_services: + # Ignore any default set by devstack. Emit a "disable_all_services". + base: false + zuul_copy_output: + '{{ devstack_conf_dir }}/local.conf': logs + '{{ devstack_conf_dir }}/localrc': logs + '{{ devstack_conf_dir }}/.localrc.auto': logs + '{{ devstack_conf_dir }}/.stackenv': logs + '{{ devstack_log_dir }}/dstat-csv.log': logs + '{{ devstack_log_dir }}/devstacklog.txt': logs + '{{ devstack_log_dir }}/devstacklog.txt.summary': logs + '{{ devstack_full_log}}': logs + '{{ stage_dir }}/verify_tempest_conf.log': logs + '{{ stage_dir }}/apache': logs + '{{ stage_dir }}/apache_config': logs + '{{ stage_dir }}/etc': logs + /var/log/rabbitmq: logs + /var/log/postgresql: logs + /var/log/mysql.err: logs + /var/log/mysql.log: logs + /var/log/libvirt: logs + /etc/sudoers: logs + /etc/sudoers.d: logs + '{{ stage_dir }}/iptables.txt': logs + '{{ stage_dir }}/df.txt': logs + '{{ stage_dir }}/pip2-freeze.txt': logs + '{{ stage_dir }}/pip3-freeze.txt': logs + '{{ stage_dir }}/dpkg-l.txt': logs + '{{ stage_dir }}/rpm-qa.txt': logs + '{{ stage_dir }}/core': logs + '{{ stage_dir }}/listen53.txt': logs + '{{ stage_dir }}/deprecations.log': logs + /var/log/ceph: logs + /var/log/openvswitch: logs + /var/log/glusterfs: logs + /etc/glusterfs/glusterd.vol: logs + /etc/resolv.conf: logs + /var/log/unbound.log: logs + extensions_to_txt: + conf: true + log: true + localrc: true + stackenv: true + auto: true + group-vars: + subnode: + devstack_localrc: + DATABASE_PASSWORD: secretdatabase + RABBIT_PASSWORD: secretrabbit + ADMIN_PASSWORD: secretadmin + SERVICE_PASSWORD: secretservice + NETWORK_GATEWAY: 10.1.0.1 + FIXED_RANGE: 10.1.0.0/20 + IPV4_ADDRS_SAFE_TO_USE: 10.1.0.0/20 + FLOATING_RANGE: 172.24.5.0/24 + PUBLIC_NETWORK_GATEWAY: 172.24.5.1 + LOGFILE: /opt/stack/logs/devstacklog.txt + LOG_COLOR: false + VERBOSE: true + VERBOSE_NO_TIMESTAMP: true + NOVNC_FROM_PACKAGE: true + ERROR_ON_CLONE: true + LIBVIRT_TYPE: qemu + devstack_services: + base: false + pre-run: playbooks/pre.yaml + run: playbooks/devstack.yaml + post-run: playbooks/post.yaml + irrelevant-files: + # Documentation related + - ^.*\.rst$ + - ^api-ref/.*$ + - ^doc/.*$ + - ^releasenotes/.*$ + # Translations + - ^.*/locale/.*po$ + +- job: + name: devstack-minimal + parent: devstack-base + description: | + Minimal devstack base job, intended for use by jobs that need + less than the normal minimum set of required-projects. + nodeset: openstack-single-node-bionic + required-projects: + - git.openstack.org/openstack/requirements + vars: + devstack_localrc: + # Multinode specific settings + SERVICE_HOST: "{{ hostvars['controller']['nodepool']['private_ipv4'] }}" + HOST_IP: "{{ hostvars['controller']['nodepool']['private_ipv4'] }}" + PUBLIC_BRIDGE_MTU: '{{ external_bridge_mtu }}' + devstack_services: + # Shared services + dstat: true + etcd3: true + mysql: true + peakmem_tracker: true + rabbit: true + group-vars: + subnode: + devstack_services: + # Shared services + dstat: true + peakmem_tracker: true + devstack_localrc: + # Multinode specific settings + HOST_IP: "{{ hostvars[inventory_hostname]['nodepool']['private_ipv4'] }}" + SERVICE_HOST: "{{ hostvars['controller']['nodepool']['private_ipv4'] }}" + PUBLIC_BRIDGE_MTU: '{{ external_bridge_mtu }}' + # Subnode specific settings + DATABASE_TYPE: mysql + RABBIT_HOST: "{{ hostvars['controller']['nodepool']['private_ipv4'] }}" + DATABASE_HOST: "{{ hostvars['controller']['nodepool']['private_ipv4'] }}" + + +- job: + name: devstack + parent: devstack-minimal + description: | + Base devstack job for integration gate. + + This base job can be used for single node and multinode devstack jobs. + + With a single node nodeset, this job sets up an "all-in-one" (aio) + devstack with the seven OpenStack services included in the devstack tree: + keystone, glance, cinder, neutron, nova, placement, and swift. + + With a two node nodeset, this job sets up an aio + compute node. + The controller can be customised using host-vars.controller, the + sub-nodes can be customised using group-vars.subnode. + + Descendent jobs can enable / disable services, add devstack configuration + options, enable devstack plugins, configure log files or directories to be + transferred to the log server. + + The job assumes that there is only one controller node. The number of + subnodes can be scaled up seamlessly by setting a custom nodeset in + job.nodeset. + + The run playbook consists of a single role, so it can be easily rewritten + and extended. + required-projects: + - git.openstack.org/openstack/cinder + - git.openstack.org/openstack/glance + - git.openstack.org/openstack/keystone + - git.openstack.org/openstack/neutron + - git.openstack.org/openstack/nova + - git.openstack.org/openstack/placement + - git.openstack.org/openstack/swift + timeout: 7200 + vars: + devstack_localrc: + # Common OpenStack services settings + SWIFT_REPLICAS: 1 + SWIFT_START_ALL_SERVICES: false + SWIFT_HASH: 1234123412341234 + CINDER_PERIODIC_INTERVAL: 10 + DEBUG_LIBVIRT_COREDUMPS: true + NOVA_VNC_ENABLED: true + VNCSERVER_LISTEN: 0.0.0.0 + VNCSERVER_PROXYCLIENT_ADDRESS: $HOST_IP + devstack_local_conf: + post-config: + $NEUTRON_CONF: + DEFAULT: + global_physnet_mtu: '{{ external_bridge_mtu }}' + devstack_services: + # Core services enabled for this branch. + # This list replaces the test-matrix. + # Shared services + dstat: true + etcd3: true + mysql: true + peakmem_tracker: true + rabbit: true + tls-proxy: true + # Keystone services + key: true + # Glance services + g-api: true + g-reg: true + # Nova services + n-api: true + n-api-meta: true + n-cauth: true + n-cond: true + n-cpu: true + n-novnc: true + n-obj: true + n-sch: true + placement-api: true + # Neutron services + # We need to keep using the neutron-legacy based services for + # now until all issues with the new lib/neutron code are solved + q-agt: true + q-dhcp: true + q-l3: true + q-meta: true + q-metering: true + q-svc: true + # neutron-api: true + # neutron-agent: true + # neutron-dhcp: true + # neutron-l3: true + # neutron-metadata-agent: true + # neutron-metering: true + # Swift services + s-account: true + s-container: true + s-object: true + s-proxy: true + # Cinder services + c-api: true + c-bak: true + c-sch: true + c-vol: true + cinder: true + # Services we don't need. + # This section is not really needed, it's for readability. + horizon: false + tempest: false + # Test matrix emits ceilometer but ceilomenter is not installed in the + # integrated gate, so specifying the services has not effect. + # ceilometer-*: false + group-vars: + subnode: + devstack_services: + # Core services enabled for this branch. + # This list replaces the test-matrix. + # Shared services + dstat: true + peakmem_tracker: true + tls-proxy: true + # Nova services + n-cpu: true + placement-client: true + # Neutron services + neutron-agent: true + # Cinder services + c-bak: true + c-vol: true + # Services we don't run at all on subnode. + # This section is not really needed, it's for readability. + # keystone: false + # s-*: false + horizon: false + tempest: false + # Test matrix emits ceilometer but ceilomenter is not installed in the + # integrated gate, so specifying the services has not effect. + # ceilometer-*: false + devstack_localrc: + # Subnode specific settings + GLANCE_HOSTPORT: "{{ hostvars['controller']['nodepool']['private_ipv4'] }}:9292" + Q_HOST: "{{ hostvars['controller']['nodepool']['private_ipv4'] }}" + NOVA_VNC_ENABLED: true + VNCSERVER_LISTEN: 0.0.0.0 + VNCSERVER_PROXYCLIENT_ADDRESS: $HOST_IP + +- job: + name: devstack-ipv6 + parent: devstack + description: | + Devstack single node job for integration gate with IPv6. + vars: + devstack_localrc: + SERVICE_IP_VERSION: 6 + SERVICE_HOST: "" + # IPv6 and certificates known issue with python2 + # https://bugs.launchpad.net/devstack/+bug/1794929 + USE_PYTHON3: true + +- job: + name: devstack-xenial + parent: devstack + nodeset: openstack-single-node-xenial + description: | + Simple singlenode test to verify functionality on devstack + side running on Xenial. + +- job: + name: devstack-multinode + parent: devstack + nodeset: openstack-two-node-bionic + description: | + Simple multinode test to verify multinode functionality on devstack side. + This is not meant to be used as a parent job. + +- job: + name: devstack-multinode-xenial + parent: devstack + nodeset: openstack-two-node-xenial + description: | + Simple multinode test to verify multinode functionality on devstack + side running on Xenial. + This is not meant to be used as a parent job. + +# NOTE(ianw) Platform tests have traditionally been non-voting because +# we often have to rush things through devstack to stabilise the gate, +# and these platforms don't have the round-the-clock support to avoid +# becoming blockers in that situation. +- job: + name: devstack-platform-centos-7 + parent: tempest-full + description: Centos 7 platform test + nodeset: devstack-single-node-centos-7 + voting: false + +- job: + name: devstack-platform-opensuse-150 + parent: tempest-full + description: openSUSE 15.0 platform test + nodeset: devstack-single-node-opensuse-150 + voting: false + +- job: + name: devstack-platform-fedora-latest + parent: tempest-full + description: Fedora latest platform test + nodeset: devstack-single-node-fedora-latest + voting: false + +- job: + name: devstack-platform-xenial + parent: tempest-full + description: Ubuntu Xenial platform test + nodeset: openstack-single-node-xenial + voting: false + +- job: + name: devstack-tox-base + parent: devstack + description: | + Base job for devstack-based functional tests that use tox. + + This job is not intended to be run directly. It's just here + for organizational purposes for devstack-tox-functional and + devstack-tox-functional-consumer. + post-run: playbooks/tox/post.yaml + vars: + tox_envlist: functional + tox_install_siblings: false + +- job: + name: devstack-tox-functional + parent: devstack-tox-base + description: | + Base job for devstack-based functional tests that use tox. + + Runs devstack, then runs the tox ``functional`` environment, + then collects tox/testr build output like normal tox jobs. + + Turns off tox sibling installation. Projects may be involved + in the devstack deployment and so may be in the required-projects + list, but may not want to test against master of the other + projects in their tox env. Child jobs can set tox_install_siblings + to True to re-enable sibling processing. + run: playbooks/tox/run-both.yaml + +- job: + name: devstack-tox-functional-consumer + parent: devstack + description: | + Base job for devstack-based functional tests for projects that + consume the devstack cloud. + + This base job should only be used by projects that are not involved + in the devstack deployment step, but are instead projects that are using + devstack to get a cloud against which they can test things. + + Runs devstack in pre-run, then runs the tox ``functional`` environment, + then collects tox/testr build output like normal tox jobs. + + Turns off tox sibling installation. Projects may be involved + in the devstack deployment and so may be in the required-projects + list, but may not want to test against master of the other + projects in their tox env. Child jobs can set tox_install_siblings + to True to re-enable sibling processing. + pre-run: + - playbooks/devstack.yaml + - playbooks/tox/pre.yaml + run: playbooks/tox/run.yaml + +- job: + name: devstack-unit-tests + description: | + Runs unit tests on devstack project. + + It runs ``run_tests.sh``. + pre-run: playbooks/unit-tests/pre.yaml + run: playbooks/unit-tests/run.yaml + +- project: + templates: + - integrated-gate + - integrated-gate-py35 + - publish-openstack-docs-pti + check: + jobs: + - devstack + - devstack-xenial + - devstack-ipv6: + voting: false + - devstack-platform-centos-7 + - devstack-platform-opensuse-150 + - devstack-platform-fedora-latest + - devstack-platform-xenial + - devstack-multinode + - devstack-multinode-xenial + - devstack-unit-tests + - openstack-tox-bashate + - ironic-tempest-dsvm-ipa-wholedisk-bios-agent_ipmitool-tinyipa: + voting: false + - swift-dsvm-functional: + voting: false + irrelevant-files: + - ^.*\.rst$ + - ^doc/.*$ + - neutron-grenade: + irrelevant-files: + - ^.*\.rst$ + - ^doc/.*$ + - neutron-grenade-multinode: + irrelevant-files: + - ^.*\.rst$ + - ^doc/.*$ + - neutron-tempest-linuxbridge: + irrelevant-files: + - ^.*\.rst$ + - ^doc/.*$ + - tempest-multinode-full: + voting: false + irrelevant-files: + - ^.*\.rst$ + - ^doc/.*$ + gate: + jobs: + - devstack + - devstack-xenial + - devstack-multinode + - devstack-multinode-xenial + - devstack-unit-tests + - openstack-tox-bashate + - neutron-grenade-multinode: + irrelevant-files: + - ^.*\.rst$ + - ^doc/.*$ + - neutron-tempest-linuxbridge: + irrelevant-files: + - ^.*\.rst$ + - ^doc/.*$ + - neutron-grenade: + irrelevant-files: + - ^.*\.rst$ + - ^doc/.*$ + # Please add a note on each job and conditions for the job not + # being experimental any more, so we can keep this list somewhat + # pruned. + # + # * nova-cells-v1: maintained by nova for cells v1 (nova-cells service); + # it's in experimental here (and in nova) for testing cells v1 + # changes to devstack w/o gating on it for all devstack changes. + # * nova-next: maintained by nova for unreleased/undefaulted + # things like cellsv2 and placement-api + # * neutron-fullstack-with-uwsgi: maintained by neutron for fullstack test + # when neutron-api is served by uwsgi, it's in exprimental for testing. + # the next cycle we can remove this job if things turn out to be + # stable enough. + # * neutron-functional-with-uwsgi: maintained by neutron for functional + # test. Next cycle we can remove this one if things turn out to be + # stable engouh with uwsgi. + # * neutron-tempest-with-uwsgi: maintained by neutron for tempest test. + # Next cycle we can remove this if everything run out stable enough. + + experimental: + jobs: + - nova-cells-v1: + irrelevant-files: + - ^.*\.rst$ + - ^doc/.*$ + - nova-next + - neutron-fullstack-with-uwsgi + - neutron-functional-with-uwsgi + - neutron-tempest-with-uwsgi + - devstack-plugin-ceph-tempest: + irrelevant-files: + - ^.*\.rst$ + - ^doc/.*$ + - devstack-plugin-ceph-tempest-py3: + irrelevant-files: + - ^.*\.rst$ + - ^doc/.*$ + - neutron-tempest-dvr: + irrelevant-files: + - ^.*\.rst$ + - ^doc/.*$ + - legacy-tempest-dsvm-neutron-dvr-multinode-full: + irrelevant-files: + - ^.*\.rst$ + - ^doc/.*$ + - neutron-tempest-dvr-ha-multinode-full: + irrelevant-files: + - ^.*\.rst$ + - ^doc/.*$ + - legacy-tempest-dsvm-lvm-multibackend: + irrelevant-files: + - ^.*\.rst$ + - ^doc/.*$ + - tempest-pg-full: + irrelevant-files: + - ^.*\.rst$ + - ^doc/.*$ diff --git a/HACKING.rst b/HACKING.rst index a40af54b45..3853eed9a1 100644 --- a/HACKING.rst +++ b/HACKING.rst @@ -20,7 +20,7 @@ in `How To Contribute`__ in the OpenStack wiki. `DevStack's LaunchPad project`_ contains the usual links for blueprints, bugs, etc. __ contribute_ -.. _contribute: http://docs.openstack.org/infra/manual/developers.html +.. _contribute: https://docs.openstack.org/infra/manual/developers.html __ lp_ .. _lp: https://launchpad.net/~devstack @@ -47,12 +47,7 @@ The DevStack repo generally keeps all of the primary scripts at the root level. ``doc`` - Contains the Sphinx source for the documentation. -``tools/build_docs.sh`` is used to generate the HTML versions of the -DevStack scripts. A complete doc build can be run with ``tox -edocs``. - -``exercises`` - Contains the test scripts used to sanity-check and -demonstrate some OpenStack functions. These scripts know how to exit -early or skip services that are not enabled. +A complete doc build can be run with ``tox -edocs``. ``extras.d`` - Contains the dispatch scripts called by the hooks in ``stack.sh``, ``unstack.sh`` and ``clean.sh``. See :doc:`the plugins @@ -183,89 +178,6 @@ The complete docs build is also handled with tox -edocs per the OpenStack project standard. -Exercises ---------- - -The scripts in the exercises directory are meant to 1) perform basic operational -checks on certain aspects of OpenStack; and b) document the use of the -OpenStack command-line clients. - -In addition to the guidelines above, exercise scripts MUST follow the structure -outlined here. ``swift.sh`` is perhaps the clearest example of these guidelines. -These scripts are executed serially by ``exercise.sh`` in testing situations. - -* Begin and end with a banner that stands out in a sea of script logs to aid - in debugging failures, particularly in automated testing situations. If the - end banner is not displayed, the script ended prematurely and can be assumed - to have failed. - - :: - - echo "**************************************************" - echo "Begin DevStack Exercise: $0" - echo "**************************************************" - ... - set +o xtrace - echo "**************************************************" - echo "End DevStack Exercise: $0" - echo "**************************************************" - -* The scripts will generally have the shell ``xtrace`` attribute set to display - the actual commands being executed, and the ``errexit`` attribute set to exit - the script on non-zero exit codes:: - - # This script exits on an error so that errors don't compound and you see - # only the first error that occurred. - set -o errexit - - # Print the commands being run so that we can see the command that triggers - # an error. It is also useful for following allowing as the install occurs. - set -o xtrace - -* Settings and configuration are stored in ``exerciserc``, which must be - sourced after ``openrc`` or ``stackrc``:: - - # Import exercise configuration - source $TOP_DIR/exerciserc - -* There are a couple of helper functions in the common ``functions`` sub-script - that will check for non-zero exit codes and unset environment variables and - print a message and exit the script. These should be called after most client - commands that are not otherwise checked to short-circuit long timeouts - (instance boot failure, for example):: - - swift post $CONTAINER - die_if_error "Failure creating container $CONTAINER" - - FLOATING_IP=`euca-allocate-address | cut -f2` - die_if_not_set FLOATING_IP "Failure allocating floating IP" - -* If you want an exercise to be skipped when for example a service wasn't - enabled for the exercise to be run, you can exit your exercise with the - special exitcode 55 and it will be detected as skipped. - -* The exercise scripts should only use the various OpenStack client binaries to - interact with OpenStack. This specifically excludes any ``*-manage`` tools - as those assume direct access to configuration and databases, as well as direct - database access from the exercise itself. - -* If specific configuration needs to be present for the exercise to complete, - it should be staged in ``stack.sh``, or called from ``stack.sh`` (see - ``files/keystone_data.sh`` for an example of this). - -* The ``OS_*`` environment variables should be the only ones used for all - authentication to OpenStack clients as documented in the CLIAuth_ wiki page. - -.. _CLIAuth: http://wiki.openstack.org/CLIAuth - -* The exercise MUST clean up after itself if successful. If it is not successful, - it is assumed that state will be left behind; this allows a chance for developers - to look around and attempt to debug the problem. The exercise SHOULD clean up - or graciously handle possible artifacts left over from previous runs if executed - again. It is acceptable to require a reboot or even a re-install of DevStack - to restore a clean test environment. - - Bash Style Guidelines ~~~~~~~~~~~~~~~~~~~~~ DevStack defines a bash set of best practices for maintaining large @@ -323,13 +235,13 @@ Variables and Functions Review Criteria -=============== +--------------- There are some broad criteria that will be followed when reviewing your change * **Is it passing tests** -- your change will not be reviewed - throughly unless the official CI has run successfully against it. + thoroughly unless the official CI has run successfully against it. * **Does this belong in DevStack** -- DevStack reviewers have a default position of "no" but are ready to be convinced by your @@ -355,7 +267,7 @@ your change * **Should this be upstream** -- DevStack generally does not override default choices provided by projects and attempts to not - unexpectedly modify behaviour. + unexpectedly modify behavior. * **Context in commit messages** -- DevStack touches many different areas and reviewers need context around changes to make good @@ -365,3 +277,26 @@ your change * **Reviewers** -- please see ``MAINTAINERS.rst`` for a list of people that should be added to reviews of various sub-systems. + + +Making Changes, Testing, and CI +------------------------------- + +Changes to Devstack are tested by automated continuous integration jobs +that run on a variety of Linux Distros using a handful of common +configurations. What this means is that every change to Devstack is +self testing. One major benefit of this is that developers do not +typically need to add new non voting test jobs to add features to +Devstack. Instead the features can be added, then if testing passes +with the feature enabled the change is ready to merge (pending code +review). + +A concrete example of this was the switch from screen based service +management to systemd based service management. No new jobs were +created for this. Instead the features were added to devstack, tested +locally and in CI using a change that enabled the feature, then once +the enabling change was passing and the new behavior communicated and +documented it was merged. + +Using this process has been proven to be effective and leads to +quicker implementation of desired features. diff --git a/MAINTAINERS.rst b/MAINTAINERS.rst index d3e8c67487..d4968a6051 100644 --- a/MAINTAINERS.rst +++ b/MAINTAINERS.rst @@ -45,6 +45,13 @@ Fedora/CentOS/RHEL Neutron ~~~~~~~ +MidoNet +~~~~~~~ + +* Jaume Devesa +* Ryu Ishimoto +* YAMAMOTO Takashi + OpenDaylight ~~~~~~~~~~~~ @@ -56,11 +63,6 @@ OpenFlow Agent (ofagent) * YAMAMOTO Takashi * Fumihiko Kakuma -Sahara -~~~~~~ - -* Sergey Lukjanov - Swift ~~~~~ diff --git a/Makefile b/Makefile index 082aff21d2..970d8009eb 100644 --- a/Makefile +++ b/Makefile @@ -13,10 +13,9 @@ # Duplicated from stackrc for now DEST=/opt/stack -WHEELHOUSE=$(DEST)/.wheelhouse all: - echo "This just saved you from a terrible mistake!" + @echo "This just saved you from a terrible mistake!" # Do Some Work stack: @@ -25,9 +24,6 @@ stack: unstack: ./unstack.sh -wheels: - WHEELHOUSE=$(WHEELHOUSE) tools/build-wheels.sh - docs: tox -edocs @@ -57,7 +53,7 @@ clean: # Clean out the cache too realclean: clean - rm -rf files/cirros*.tar.gz files/Fedora*.qcow2 $(WHEELHOUSE) + rm -rf files/cirros*.tar.gz files/Fedora*.qcow2 # Repo stuffs diff --git a/README.md b/README.md deleted file mode 100644 index 455e1c69c6..0000000000 --- a/README.md +++ /dev/null @@ -1,436 +0,0 @@ -DevStack is a set of scripts and utilities to quickly deploy an OpenStack cloud. - -# Goals - -* To quickly build dev OpenStack environments in a clean Ubuntu or Fedora - environment -* To describe working configurations of OpenStack (which code branches - work together? what do config files look like for those branches?) -* To make it easier for developers to dive into OpenStack so that they can - productively contribute without having to understand every part of the - system at once -* To make it easy to prototype cross-project features -* To provide an environment for the OpenStack CI testing on every commit - to the projects - -Read more at http://devstack.org. - -IMPORTANT: Be sure to carefully read `stack.sh` and any other scripts you -execute before you run them, as they install software and will alter your -networking configuration. We strongly recommend that you run `stack.sh` -in a clean and disposable vm when you are first getting started. - -# Versions - -The DevStack master branch generally points to trunk versions of OpenStack -components. For older, stable versions, look for branches named -stable/[release] in the DevStack repo. For example, you can do the -following to create a juno OpenStack cloud: - - git checkout stable/juno - ./stack.sh - -You can also pick specific OpenStack project releases by setting the appropriate -`*_BRANCH` variables in the ``localrc`` section of `local.conf` (look in -`stackrc` for the default set). Usually just before a release there will be -milestone-proposed branches that need to be tested:: - - GLANCE_REPO=git://git.openstack.org/openstack/glance.git - GLANCE_BRANCH=milestone-proposed - -# Start A Dev Cloud - -Installing in a dedicated disposable VM is safer than installing on your -dev machine! Plus you can pick one of the supported Linux distros for -your VM. To start a dev cloud run the following NOT AS ROOT (see -**DevStack Execution Environment** below for more on user accounts): - - ./stack.sh - -When the script finishes executing, you should be able to access OpenStack -endpoints, like so: - -* Horizon: http://myhost/ -* Keystone: http://myhost:5000/v2.0/ - -We also provide an environment file that you can use to interact with your -cloud via CLI: - - # source openrc file to load your environment with OpenStack CLI creds - . openrc - # list instances - nova list - -If the EC2 API is your cup-o-tea, you can create credentials and use euca2ools: - - # source eucarc to generate EC2 credentials and set up the environment - . eucarc - # list instances using ec2 api - euca-describe-instances - -# DevStack Execution Environment - -DevStack runs rampant over the system it runs on, installing things and -uninstalling other things. Running this on a system you care about is a recipe -for disappointment, or worse. Alas, we're all in the virtualization business -here, so run it in a VM. And take advantage of the snapshot capabilities -of your hypervisor of choice to reduce testing cycle times. You might even save -enough time to write one more feature before the next feature freeze... - -``stack.sh`` needs to have root access for a lot of tasks, but uses ``sudo`` -for all of those tasks. However, it needs to be not-root for most of its -work and for all of the OpenStack services. ``stack.sh`` specifically -does not run if started as root. - -This is a recent change (Oct 2013) from the previous behaviour of -automatically creating a ``stack`` user. Automatically creating -user accounts is not the right response to running as root, so -that bit is now an explicit step using ``tools/create-stack-user.sh``. -Run that (as root!) or just check it out to see what DevStack's -expectations are for the account it runs under. Many people simply -use their usual login (the default 'ubuntu' login on a UEC image -for example). - -# Customizing - -You can override environment variables used in `stack.sh` by creating file -name `local.conf` with a ``localrc`` section as shown below. It is likely -that you will need to do this to tweak your networking configuration should -you need to access your cloud from a different host. - - [[local|localrc]] - VARIABLE=value - -See the **Local Configuration** section below for more details. - -# Database Backend - -Multiple database backends are available. The available databases are defined -in the lib/databases directory. -`mysql` is the default database, choose a different one by putting the -following in the `localrc` section: - - disable_service mysql - enable_service postgresql - -`mysql` is the default database. - -# RPC Backend - -Multiple RPC backends are available. Currently, this -includes RabbitMQ (default), Qpid, and ZeroMQ. Your backend of -choice may be selected via the `localrc` section. - -Note that selecting more than one RPC backend will result in a failure. - -Example (ZeroMQ): - - ENABLED_SERVICES="$ENABLED_SERVICES,-rabbit,-qpid,zeromq" - -Example (Qpid): - - ENABLED_SERVICES="$ENABLED_SERVICES,-rabbit,-zeromq,qpid" - -# Apache Frontend - -Apache web server can be enabled for wsgi services that support being deployed -under HTTPD + mod_wsgi. By default, services that recommend running under -HTTPD + mod_wsgi are deployed under Apache. To use an alternative deployment -strategy (e.g. eventlet) for services that support an alternative to HTTPD + -mod_wsgi set ``ENABLE_HTTPD_MOD_WSGI_SERVICES`` to ``False`` in your -``local.conf``. - -Each service that can be run under HTTPD + mod_wsgi also has an override -toggle available that can be set in your ``local.conf``. - -Keystone is run under HTTPD + mod_wsgi by default. - -Example (Keystone): - - KEYSTONE_USE_MOD_WSGI="True" - -Example (Nova): - - NOVA_USE_MOD_WSGI="True" - -Example (Swift): - - SWIFT_USE_MOD_WSGI="True" - -# Swift - -Swift is disabled by default. When enabled, it is configured with -only one replica to avoid being IO/memory intensive on a small -vm. When running with only one replica the account, container and -object services will run directly in screen. The others services like -replicator, updaters or auditor runs in background. - -If you would like to enable Swift you can add this to your `localrc` section: - - enable_service s-proxy s-object s-container s-account - -If you want a minimal Swift install with only Swift and Keystone you -can have this instead in your `localrc` section: - - disable_all_services - enable_service key mysql s-proxy s-object s-container s-account - -If you only want to do some testing of a real normal swift cluster -with multiple replicas you can do so by customizing the variable -`SWIFT_REPLICAS` in your `localrc` section (usually to 3). - -# Swift S3 - -If you are enabling `swift3` in `ENABLED_SERVICES` DevStack will -install the swift3 middleware emulation. Swift will be configured to -act as a S3 endpoint for Keystone so effectively replacing the -`nova-objectstore`. - -Only Swift proxy server is launched in the screen session all other -services are started in background and managed by `swift-init` tool. - -# Neutron - -Basic Setup - -In order to enable Neutron a single node setup, you'll need the -following settings in your `local.conf`: - - disable_service n-net - enable_service q-svc - enable_service q-agt - enable_service q-dhcp - enable_service q-l3 - enable_service q-meta - enable_service q-metering - # Optional, to enable tempest configuration as part of DevStack - enable_service tempest - -Then run `stack.sh` as normal. - -DevStack supports setting specific Neutron configuration flags to the -service, Open vSwitch plugin and LinuxBridge plugin configuration files. -To make use of this feature, the settings can be added to ``local.conf``. -The old ``Q_XXX_EXTRA_XXX_OPTS`` variables are deprecated and will be removed -in the near future. The ``local.conf`` headers for the replacements are: - -* ``Q_SRV_EXTRA_OPTS``: - - [[post-config|/$Q_PLUGIN_CONF_FILE]] - [linuxbridge] # or [ovs] - -Example extra config in `local.conf`: - - [[post-config|/$Q_PLUGIN_CONF_FILE]] - [agent] - tunnel_type=vxlan - vxlan_udp_port=8472 - - [[post-config|$NEUTRON_CONF]] - [DEFAULT] - tenant_network_type=vxlan - -DevStack also supports configuring the Neutron ML2 plugin. The ML2 plugin -can run with the OVS, LinuxBridge, or Hyper-V agents on compute hosts. This -is a simple way to configure the ml2 plugin: - - # VLAN configuration - Q_PLUGIN=ml2 - ENABLE_TENANT_VLANS=True - - # GRE tunnel configuration - Q_PLUGIN=ml2 - ENABLE_TENANT_TUNNELS=True - - # VXLAN tunnel configuration - Q_PLUGIN=ml2 - Q_ML2_TENANT_NETWORK_TYPE=vxlan - -The above will default in DevStack to using the OVS on each compute host. -To change this, set the `Q_AGENT` variable to the agent you want to run -(e.g. linuxbridge). - - Variable Name Notes - ---------------------------------------------------------------------------- - Q_AGENT This specifies which agent to run with the - ML2 Plugin (Typically either `openvswitch` - or `linuxbridge`). - Defaults to `openvswitch`. - Q_ML2_PLUGIN_MECHANISM_DRIVERS The ML2 MechanismDrivers to load. The default - is `openvswitch,linuxbridge`. - Q_ML2_PLUGIN_TYPE_DRIVERS The ML2 TypeDrivers to load. Defaults to - all available TypeDrivers. - Q_ML2_PLUGIN_GRE_TYPE_OPTIONS GRE TypeDriver options. Defaults to - `tunnel_id_ranges=1:1000'. - Q_ML2_PLUGIN_VXLAN_TYPE_OPTIONS VXLAN TypeDriver options. Defaults to - `vni_ranges=1001:2000` - Q_ML2_PLUGIN_VLAN_TYPE_OPTIONS VLAN TypeDriver options. Defaults to none. - -# Heat - -Heat is disabled by default (see `stackrc` file). To enable it explicitly -you'll need the following settings in your `localrc` section: - - enable_service heat h-api h-api-cfn h-api-cw h-eng - -Heat can also run in standalone mode, and be configured to orchestrate -on an external OpenStack cloud. To launch only Heat in standalone mode -you'll need the following settings in your `localrc` section: - - disable_all_services - enable_service rabbit mysql heat h-api h-api-cfn h-api-cw h-eng - HEAT_STANDALONE=True - KEYSTONE_SERVICE_HOST=... - KEYSTONE_AUTH_HOST=... - -# Tempest - -If tempest has been successfully configured, a basic set of smoke -tests can be run as follows: - - $ cd /opt/stack/tempest - $ tox -efull tempest.scenario.test_network_basic_ops - -By default tempest is downloaded and the config file is generated, but the -tempest package is not installed in the system's global site-packages (the -package install includes installing dependences). So tempest won't run -outside of tox. If you would like to install it add the following to your -``localrc`` section: - - INSTALL_TEMPEST=True - -# DevStack on Xenserver - -If you would like to use Xenserver as the hypervisor, please refer -to the instructions in `./tools/xen/README.md`. - -# Additional Projects - -DevStack has a hook mechanism to call out to a dispatch script at specific -points in the execution of `stack.sh`, `unstack.sh` and `clean.sh`. This -allows upper-layer projects, especially those that the lower layer projects -have no dependency on, to be added to DevStack without modifying the core -scripts. Tempest is built this way as an example of how to structure the -dispatch script, see `extras.d/80-tempest.sh`. See `extras.d/README.md` -for more information. - -# Multi-Node Setup - -A more interesting setup involves running multiple compute nodes, with Neutron -networks connecting VMs on different compute nodes. -You should run at least one "controller node", which should have a `stackrc` -that includes at least: - - disable_service n-net - enable_service q-svc - enable_service q-agt - enable_service q-dhcp - enable_service q-l3 - enable_service q-meta - enable_service neutron - -You likely want to change your `localrc` section to run a scheduler that -will balance VMs across hosts: - - SCHEDULER=nova.scheduler.filter_scheduler.FilterScheduler - -You can then run many compute nodes, each of which should have a `stackrc` -which includes the following, with the IP address of the above controller node: - - ENABLED_SERVICES=n-cpu,rabbit,neutron,q-agt - SERVICE_HOST=[IP of controller node] - MYSQL_HOST=$SERVICE_HOST - RABBIT_HOST=$SERVICE_HOST - Q_HOST=$SERVICE_HOST - MATCHMAKER_REDIS_HOST=$SERVICE_HOST - -# Multi-Region Setup - -We want to setup two devstack (RegionOne and RegionTwo) with shared keystone -(same users and services) and horizon. -Keystone and Horizon will be located in RegionOne. -Full spec is available at: -https://wiki.openstack.org/wiki/Heat/Blueprints/Multi_Region_Support_for_Heat. - -In RegionOne: - - REGION_NAME=RegionOne - -In RegionTwo: - - disable_service horizon - KEYSTONE_SERVICE_HOST= - KEYSTONE_AUTH_HOST= - REGION_NAME=RegionTwo - -# Cells - -Cells is a new scaling option with a full spec at: -http://wiki.openstack.org/blueprint-nova-compute-cells. - -To setup a cells environment add the following to your `localrc` section: - - enable_service n-cell - -Be aware that there are some features currently missing in cells, one notable -one being security groups. The exercises have been patched to disable -functionality not supported by cells. - - -# Local Configuration - -Historically DevStack has used ``localrc`` to contain all local configuration -and customizations. More and more of the configuration variables available for -DevStack are passed-through to the individual project configuration files. -The old mechanism for this required specific code for each file and did not -scale well. This is handled now by a master local configuration file. - -# local.conf - -The new config file ``local.conf`` is an extended-INI format that introduces -a new meta-section header that provides some additional information such -as a phase name and destination config filename: - - [[ | ]] - -where ```` is one of a set of phase names defined by ``stack.sh`` -and ```` is the configuration filename. The filename is -eval'ed in the ``stack.sh`` context so all environment variables are -available and may be used. Using the project config file variables in -the header is strongly suggested (see the ``NOVA_CONF`` example below). -If the path of the config file does not exist it is skipped. - -The defined phases are: - -* **local** - extracts ``localrc`` from ``local.conf`` before ``stackrc`` is sourced -* **post-config** - runs after the layer 2 services are configured - and before they are started -* **extra** - runs after services are started and before any files - in ``extra.d`` are executed -* **post-extra** - runs after files in ``extra.d`` are executed - -The file is processed strictly in sequence; meta-sections may be specified more -than once but if any settings are duplicated the last to appear in the file -will be used. - - [[post-config|$NOVA_CONF]] - [DEFAULT] - use_syslog = True - - [osapi_v3] - enabled = False - -A specific meta-section ``local|localrc`` is used to provide a default -``localrc`` file (actually ``.localrc.auto``). This allows all custom -settings for DevStack to be contained in a single file. If ``localrc`` -exists it will be used instead to preserve backward-compatibility. - - [[local|localrc]] - FIXED_RANGE=10.254.1.0/24 - ADMIN_PASSWORD=speciale - LOGFILE=$DEST/logs/stack.sh.log - -Note that ``Q_PLUGIN_CONF_FILE`` is unique in that it is assumed to *NOT* -start with a ``/`` (slash) character. A slash will need to be added: - - [[post-config|/$Q_PLUGIN_CONF_FILE]] diff --git a/README.rst b/README.rst new file mode 100644 index 0000000000..6885546c94 --- /dev/null +++ b/README.rst @@ -0,0 +1,97 @@ +DevStack is a set of scripts and utilities to quickly deploy an OpenStack cloud +from git source trees. + +Goals +===== + +* To quickly build dev OpenStack environments in a clean Ubuntu or Fedora + environment +* To describe working configurations of OpenStack (which code branches + work together? what do config files look like for those branches?) +* To make it easier for developers to dive into OpenStack so that they can + productively contribute without having to understand every part of the + system at once +* To make it easy to prototype cross-project features +* To provide an environment for the OpenStack CI testing on every commit + to the projects + +Read more at https://docs.openstack.org/devstack/latest + +IMPORTANT: Be sure to carefully read `stack.sh` and any other scripts you +execute before you run them, as they install software and will alter your +networking configuration. We strongly recommend that you run `stack.sh` +in a clean and disposable vm when you are first getting started. + +Versions +======== + +The DevStack master branch generally points to trunk versions of OpenStack +components. For older, stable versions, look for branches named +stable/[release] in the DevStack repo. For example, you can do the +following to create a Pike OpenStack cloud:: + + git checkout stable/pike + ./stack.sh + +You can also pick specific OpenStack project releases by setting the appropriate +`*_BRANCH` variables in the ``localrc`` section of `local.conf` (look in +`stackrc` for the default set). Usually just before a release there will be +milestone-proposed branches that need to be tested:: + + GLANCE_REPO=git://git.openstack.org/openstack/glance.git + GLANCE_BRANCH=milestone-proposed + +Start A Dev Cloud +================= + +Installing in a dedicated disposable VM is safer than installing on your +dev machine! Plus you can pick one of the supported Linux distros for +your VM. To start a dev cloud run the following NOT AS ROOT (see +**DevStack Execution Environment** below for more on user accounts): + + ./stack.sh + +When the script finishes executing, you should be able to access OpenStack +endpoints, like so: + +* Horizon: http://myhost/ +* Keystone: http://myhost/identity/v2.0/ + +We also provide an environment file that you can use to interact with your +cloud via CLI:: + + # source openrc file to load your environment with OpenStack CLI creds + . openrc + # list instances + openstack server list + +DevStack Execution Environment +============================== + +DevStack runs rampant over the system it runs on, installing things and +uninstalling other things. Running this on a system you care about is a recipe +for disappointment, or worse. Alas, we're all in the virtualization business +here, so run it in a VM. And take advantage of the snapshot capabilities +of your hypervisor of choice to reduce testing cycle times. You might even save +enough time to write one more feature before the next feature freeze... + +``stack.sh`` needs to have root access for a lot of tasks, but uses +``sudo`` for all of those tasks. However, it needs to be not-root for +most of its work and for all of the OpenStack services. ``stack.sh`` +specifically does not run if started as root. + +DevStack will not automatically create the user, but provides a helper +script in ``tools/create-stack-user.sh``. Run that (as root!) or just +check it out to see what DevStack's expectations are for the account +it runs under. Many people simply use their usual login (the default +'ubuntu' login on a UEC image for example). + +Customizing +=========== + +DevStack can be extensively configured via the configuration file +`local.conf`. It is likely that you will need to provide and modify +this file if you want anything other than the most basic setup. Start +by reading the `configuration guide +`_ +for details of the configuration file and the many available options. diff --git a/clean.sh b/clean.sh index c31a65fd40..a29ebd94f0 100755 --- a/clean.sh +++ b/clean.sh @@ -26,7 +26,7 @@ if [[ -r $TOP_DIR/.stackenv ]]; then fi # Determine what system we are running on. This provides ``os_VENDOR``, -# ``os_RELEASE``, ``os_UPDATE``, ``os_PACKAGE``, ``os_CODENAME`` +# ``os_RELEASE``, ``os_PACKAGE``, ``os_CODENAME`` # and ``DISTRO`` GetDistro @@ -41,17 +41,18 @@ source $TOP_DIR/lib/rpc_backend source $TOP_DIR/lib/tls source $TOP_DIR/lib/oslo +source $TOP_DIR/lib/lvm source $TOP_DIR/lib/horizon source $TOP_DIR/lib/keystone source $TOP_DIR/lib/glance source $TOP_DIR/lib/nova +source $TOP_DIR/lib/placement source $TOP_DIR/lib/cinder source $TOP_DIR/lib/swift -source $TOP_DIR/lib/ceilometer -source $TOP_DIR/lib/heat +source $TOP_DIR/lib/neutron source $TOP_DIR/lib/neutron-legacy -source $TOP_DIR/lib/ironic +set -o xtrace # Extras Source # -------------- @@ -63,13 +64,8 @@ if [[ -d $TOP_DIR/extras.d ]]; then done fi -# See if there is anything running... -# need to adapt when run_service is merged -SESSION=$(screen -ls | awk '/[0-9].stack/ { print $1 }') -if [[ -n "$SESSION" ]]; then - # Let unstack.sh do its thing first - $TOP_DIR/unstack.sh --all -fi +# Let unstack.sh do its thing first +$TOP_DIR/unstack.sh --all # Run extras # ========== @@ -92,8 +88,10 @@ cleanup_cinder || /bin/true cleanup_glance cleanup_keystone cleanup_nova +cleanup_placement cleanup_neutron cleanup_swift +cleanup_horizon if is_service_enabled ldap; then cleanup_ldap @@ -105,7 +103,7 @@ if is_service_enabled nova && [[ -r $NOVA_PLUGINS/hypervisor-$VIRT_DRIVER ]]; th fi # Clean out /etc -sudo rm -rf /etc/keystone /etc/glance /etc/nova /etc/cinder /etc/swift /etc/heat /etc/neutron +sudo rm -rf /etc/keystone /etc/glance /etc/nova /etc/cinder /etc/swift /etc/neutron /etc/openstack/ # Clean out tgt sudo rm -f /etc/tgt/conf.d/* @@ -124,19 +122,37 @@ fi if [[ -n "$LOGDIR" ]] && [[ -d "$LOGDIR" ]]; then sudo rm -rf $LOGDIR fi -if [[ -n "$SCREEN_LOGDIR" ]] && [[ -d "$SCREEN_LOGDIR" ]]; then - sudo rm -rf $SCREEN_LOGDIR + +# Clean out the sytemd user unit files if systemd was used. +if [[ "$USE_SYSTEMD" = "True" ]]; then + sudo find $SYSTEMD_DIR -type f -name '*devstack@*service' -delete + # Make systemd aware of the deletion. + $SYSTEMCTL daemon-reload fi # Clean up venvs -DIRS_TO_CLEAN="$WHEELHOUSE ${PROJECT_VENV[@]}" +DIRS_TO_CLEAN="$WHEELHOUSE ${PROJECT_VENV[@]} .config/openstack" rm -rf $DIRS_TO_CLEAN # Clean up files -FILES_TO_CLEAN=".localrc.auto docs/files docs/html shocco/ stack-screenrc test*.conf* test.ini*" +FILES_TO_CLEAN=".localrc.auto .localrc.password " +FILES_TO_CLEAN+="docs/files docs/html shocco/ " +FILES_TO_CLEAN+="stack-screenrc test*.conf* test.ini* " FILES_TO_CLEAN+=".stackenv .prereqs" for file in $FILES_TO_CLEAN; do rm -rf $TOP_DIR/$file done + +rm -rf ~/.config/openstack + +# Clean up all *.pyc files +if [[ -n "$DEST" ]] && [[ -d "$DEST" ]]; then + find_version=`find --version | awk '{ print $NF; exit}'` + if vercmp "$find_version" "<" "4.2.3" ; then + sudo find $DEST -name "*.pyc" -print0 | xargs -0 rm + else + sudo find $DEST -name "*.pyc" -delete + fi +fi diff --git a/data/devstack-plugins-registry.header b/data/devstack-plugins-registry.header new file mode 100644 index 0000000000..576dbbd35a --- /dev/null +++ b/data/devstack-plugins-registry.header @@ -0,0 +1,21 @@ +.. Note to patch submitters: + + # ============================= # + # THIS FILE IS AUTOGENERATED ! # + # ============================= # + + ** Plugins are found automatically and added to this list ** + + This file is created by a periodic proposal job. You should not + edit this file. + + You should edit the files data/devstack-plugins-registry.footer + data/devstack-plugins-registry.header to modify this text. + +========================== + DevStack Plugin Registry +========================== + +The following list is an automatically-generated collection of +available DevStack plugins. This includes, but is not limited to, +official OpenStack projects. diff --git a/doc/requirements.txt b/doc/requirements.txt new file mode 100644 index 0000000000..f65e9dfece --- /dev/null +++ b/doc/requirements.txt @@ -0,0 +1,11 @@ +pbr>=2.0.0,!=2.1.0 + +Pygments +docutils +sphinx>=1.6.2 +openstackdocstheme>=1.11.0 +nwdiag +blockdiag +sphinxcontrib-blockdiag +sphinxcontrib-nwdiag +zuul-sphinx>=0.2.0 diff --git a/doc/source/assets/images/screen_session_1.png b/doc/source/assets/images/screen_session_1.png new file mode 100644 index 0000000000..6ad6752bb1 Binary files /dev/null and b/doc/source/assets/images/screen_session_1.png differ diff --git a/doc/source/assets/local.conf b/doc/source/assets/local.conf new file mode 120000 index 0000000000..cfc2a4e9d8 --- /dev/null +++ b/doc/source/assets/local.conf @@ -0,0 +1 @@ +../../../samples/local.conf \ No newline at end of file diff --git a/doc/source/changes.rst b/doc/source/changes.rst deleted file mode 100644 index 19fce0fd52..0000000000 --- a/doc/source/changes.rst +++ /dev/null @@ -1,12 +0,0 @@ -======= -Changes -======= - -Recent Changes What's been happening? -===================================== - -These are the commits to DevStack for the last six months. For the -complete list see `the DevStack project in -Gerrit `__. - -%GIT_LOG% diff --git a/doc/source/conf.py b/doc/source/conf.py index 3e9aa45911..e9708fae1d 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -26,7 +26,13 @@ # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. -extensions = [ 'oslosphinx' ] +extensions = [ 'sphinx.ext.autodoc', 'zuul_sphinx', 'openstackdocstheme', 'sphinxcontrib.blockdiag', 'sphinxcontrib.nwdiag' ] + +# openstackdocstheme options +repository_name = 'openstack-dev/devstack' +bug_project = 'devstack' +bug_tag = '' +html_last_updated_fmt = '%Y-%m-%d %H:%M' todo_include_todos = True @@ -87,7 +93,7 @@ # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. -html_theme = 'nature' +html_theme = 'openstackdocs' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the diff --git a/doc/source/configuration.rst b/doc/source/configuration.rst index 1cc7083bb4..022e6ba529 100644 --- a/doc/source/configuration.rst +++ b/doc/source/configuration.rst @@ -2,40 +2,28 @@ Configuration ============= -DevStack has always tried to be mostly-functional with a minimal amount -of configuration. The number of options has ballooned as projects add -features, new projects added and more combinations need to be tested. -Historically DevStack obtained all local configuration and -customizations from a ``localrc`` file. The number of configuration -variables that are simply passed-through to the individual project -configuration files is also increasing. The old mechanism for this -(``EXTRAS_OPTS`` and friends) required specific code for each file and -did not scale well. - -In Oct 2013 a new configuration method was introduced (in `review -46768 `__) to hopefully -simplify this process and meet the following goals: - -- contain all non-default local configuration in a single file -- be backward-compatible with ``localrc`` to smooth the transition - process -- allow settings in arbitrary configuration files to be changed +.. contents:: + :local: + :depth: 1 local.conf ========== -The new configuration file is ``local.conf`` and resides in the root -DevStack directory like the old ``localrc`` file. It is a modified INI -format file that introduces a meta-section header to carry additional -information regarding the configuration files to be changed. +DevStack configuration is modified via the file ``local.conf``. It is +a modified INI format file that introduces a meta-section header to +carry additional information regarding the configuration files to be +changed. + +A sample is provided in ``devstack/samples`` The new header is similar to a normal INI section header but with double brackets (``[[ ... ]]``) and two internal fields separated by a pipe -(``|``): - +(``|``). Note that there are no spaces between the double brackets and the +internal fields. Likewise, there are no spaces between the pipe and the +internal fields: :: - [[ | ]] + '[[' '|' ']]' where ```` is one of a set of phase names defined by ``stack.sh`` and ```` is the configuration filename. The filename @@ -48,14 +36,12 @@ The defined phases are: - **local** - extracts ``localrc`` from ``local.conf`` before ``stackrc`` is sourced -- **pre-install** - runs after the system packages are installed but - before any of the source repositories are installed -- **install** - runs immediately after the repo installations are - complete - **post-config** - runs after the layer 2 services are configured and before they are started - **extra** - runs after services are started and before any files in ``extra.d`` are executed +- **post-extra** - runs after files in ``extra.d`` are executed +- **test-config** - runs after tempest (and plugins) are configured The file is processed strictly in sequence; meta-sections may be specified more than once but if any settings are duplicated the last to @@ -73,13 +59,12 @@ appear in the file will be used. A specific meta-section ``local|localrc`` is used to provide a default ``localrc`` file (actually ``.localrc.auto``). This allows all custom settings for DevStack to be contained in a single file. If ``localrc`` -exists it will be used instead to preserve backward-compatibility. More -details on the :doc:`contents of local.conf ` are available. +exists it will be used instead to preserve backward-compatibility. :: [[local|localrc]] - FIXED_RANGE=10.254.1.0/24 + IPV4_ADDRS_SAFE_TO_USE=10.254.1.0/24 ADMIN_PASSWORD=speciale LOGFILE=$DEST/logs/stack.sh.log @@ -95,6 +80,76 @@ Also note that the ``localrc`` section is sourced as a shell script fragment and MUST conform to the shell requirements, specifically no whitespace around ``=`` (equals). +openrc +====== + +``openrc`` configures login credentials suitable for use with the +OpenStack command-line tools. ``openrc`` sources ``stackrc`` at the +beginning (which in turn sources the ``localrc`` section of +``local.conf``) in order to pick up ``HOST_IP`` and/or ``SERVICE_HOST`` +to use in the endpoints. The values shown below are the default values. + +OS\_PROJECT\_NAME (OS\_TENANT\_NAME) + Keystone has + standardized the term *project* as the entity that owns resources. In + some places references still exist to the previous term + *tenant* for this use. Also, *project\_name* is preferred to + *project\_id*. OS\_TENANT\_NAME remains supported for compatibility + with older tools. + + :: + + OS_PROJECT_NAME=demo + +OS\_USERNAME + In addition to the owning entity (project), OpenStack calls the entity + performing the action *user*. + + :: + + OS_USERNAME=demo + +OS\_PASSWORD + Keystone's default authentication requires a password be provided. + The usual cautions about putting passwords in environment variables + apply, for most DevStack uses this may be an acceptable tradeoff. + + :: + + OS_PASSWORD=secret + +HOST\_IP, SERVICE\_HOST + Set API endpoint host using ``HOST_IP``. ``SERVICE_HOST`` may also + be used to specify the endpoint, which is convenient for some + ``local.conf`` configurations. Typically, ``HOST_IP`` is set in the + ``localrc`` section. + + :: + + HOST_IP=127.0.0.1 + SERVICE_HOST=$HOST_IP + +OS\_AUTH\_URL + Authenticating against an OpenStack cloud using Keystone returns a + *Token* and *Service Catalog*. The catalog contains the endpoints + for all services the user/tenant has access to - including Nova, + Glance, Keystone and Swift. + + :: + + OS_AUTH_URL=http://$SERVICE_HOST:5000/v3.0 + +KEYSTONECLIENT\_DEBUG, NOVACLIENT\_DEBUG + Set command-line client log level to ``DEBUG``. These are commented + out by default. + + :: + + # export KEYSTONECLIENT_DEBUG=1 + # export NOVACLIENT_DEBUG=1 + + + .. _minimal-configuration: Minimal Configuration @@ -107,20 +162,19 @@ values that most often need to be set. - no logging - pre-set the passwords to prevent interactive prompts -- move network ranges away from the local network (``FIXED_RANGE`` and - ``FLOATING_RANGE``, commented out below) +- move network ranges away from the local network (``IPV4_ADDRS_SAFE_TO_USE`` + and ``FLOATING_RANGE``, commented out below) - set the host IP if detection is unreliable (``HOST_IP``, commented out below) :: [[local|localrc]] - ADMIN_PASSWORD=secrete + ADMIN_PASSWORD=secret DATABASE_PASSWORD=$ADMIN_PASSWORD RABBIT_PASSWORD=$ADMIN_PASSWORD SERVICE_PASSWORD=$ADMIN_PASSWORD - SERVICE_TOKEN=a682f596-76f3-11e3-b3b2-e716f9080d50 - #FIXED_RANGE=172.31.1.0/24 + #IPV4_ADDRS_SAFE_TO_USE=172.31.1.0/24 #FLOATING_RANGE=192.168.20.0/25 #HOST_IP=10.3.4.5 @@ -137,137 +191,279 @@ Ethernet interface to a bridge on the host. Setting it here also makes it available for ``openrc`` to set ``OS_AUTH_URL``. ``HOST_IP`` is not set by default. -Common Configuration Variables -============================== +``HOST_IPV6`` is normally detected on the first run of ``stack.sh`` but +will not be set if there is no IPv6 address on the default Ethernet interface. +Setting it here also makes it available for ``openrc`` to set ``OS_AUTH_URL``. +``HOST_IPV6`` is not set by default. -Installation Directory ----------------------- +For architecture specific configurations which differ from the x86 default +here, see `arch-configuration`_. - | *Default: ``DEST=/opt/stack``* - | The DevStack install directory is set by the ``DEST`` variable. - | By setting it early in the ``localrc`` section you can reference it - in later variables. It can be useful to set it even though it is not - changed from the default value. - | +Historical Notes +================ + +Historically DevStack obtained all local configuration and +customizations from a ``localrc`` file. In Oct 2013 the +``local.conf`` configuration method was introduced (in `review 46768 +`__) to simplify this +process. + +Configuration Notes +=================== + +.. contents:: + :local: + +Service Repos +------------- + +The Git repositories used to check out the source for each service are +controlled by a pair of variables set for each service. ``*_REPO`` +points to the repository and ``*_BRANCH`` selects which branch to +check out. These may be overridden in ``local.conf`` to pull source +from a different repo for testing, such as a Gerrit branch +proposal. ``GIT_BASE`` points to the primary repository server. :: - DEST=/opt/stack + NOVA_REPO=$GIT_BASE/openstack/nova.git + NOVA_BRANCH=master -Libraries from Git ------------------- +To pull a branch directly from Gerrit, get the repo and branch from +the Gerrit review page: - | *Default: ``LIBS_FROM_GIT=""``* + :: - | By default devstack installs OpenStack server components from - git, however it installs client libraries from released versions - on pypi. This is appropriate if you are working on server - development, but if you want to see how an unreleased version of - the client affects the system you can have devstack install it - from upstream, or from local git trees. - | Multiple libraries can be specified as a comma separated list. - | + git fetch https://review.openstack.org/p/openstack/nova refs/changes/50/5050/1 && git checkout FETCH_HEAD - :: + The repo is the stanza following ``fetch`` and the branch is the + stanza following that: - LIBS_FROM_GIT=python-keystoneclient,oslo.config + :: -Virtual Environments --------------------- + NOVA_REPO=https://review.openstack.org/p/openstack/nova + NOVA_BRANCH=refs/changes/50/5050/1 - | *Default: ``USE_VENV=False``* - | Enable the use of Python virtual environments by setting ``USE_VENV`` - to ``True``. This will enable the creation of venvs for each project - that is defined in the ``PROJECT_VENV`` array. - | *Default: ``PROJECT_VENV['']='.venv'* - | Each entry in the ``PROJECT_VENV`` array contains the directory name - of a venv to be used for the project. The array index is the project - name. Multiple projects can use the same venv if desired. +Installation Directory +---------------------- - :: +The DevStack install directory is set by the ``DEST`` variable. By +default it is ``/opt/stack``. - PROJECT_VENV["glance"]=${GLANCE_DIR}.venv +By setting it early in the ``localrc`` section you can reference it in +later variables. It can be useful to set it even though it is not +changed from the default value. - | *Default: ``ADDITIONAL_VENV_PACKAGES=""``* - | A comma-separated list of additional packages to be installed into each - venv. Often projects will not have certain packages listed in its - ``requirements.txt`` file because they are 'optional' requirements, - i.e. only needed for certain configurations. By default, the enabled - databases will have their Python bindings added when they are enabled. + :: + + DEST=/opt/stack + +Logging +------- Enable Logging --------------- +~~~~~~~~~~~~~~ - | *Defaults: ``LOGFILE="" LOGDAYS=7 LOG_COLOR=True``* - | By default ``stack.sh`` output is only written to the console - where is runs. It can be sent to a file in addition to the console - by setting ``LOGFILE`` to the fully-qualified name of the - destination log file. A timestamp will be appended to the given - filename for each run of ``stack.sh``. - | +By default ``stack.sh`` output is only written to the console where it +runs. It can be sent to a file in addition to the console by setting +``LOGFILE`` to the fully-qualified name of the destination log file. A +timestamp will be appended to the given filename for each run of +``stack.sh``. :: LOGFILE=$DEST/logs/stack.sh.log - Old log files are cleaned automatically if ``LOGDAYS`` is set to the - number of days of old log files to keep. +Old log files are cleaned automatically if ``LOGDAYS`` is set to the +number of days of old log files to keep. :: LOGDAYS=1 - The some of the project logs (Nova, Cinder, etc) will be colorized - by default (if ``SYSLOG`` is not set below); this can be turned off - by setting ``LOG_COLOR`` False. - - :: +Some coloring is used during the DevStack runs to make it easier to +see what is going on. This can be disabled with:: LOG_COLOR=False +When using the logfile, by default logs are sent to the console and +the file. You can set ``VERBOSE`` to ``false`` if you only wish the +logs to be sent to the file (this may avoid having double-logging in +some cases where you are capturing the script output and the log +files). If ``VERBOSE`` is ``true`` you can additionally set +``VERBOSE_NO_TIMESTAMP`` to avoid timestamps being added to each +output line sent to the console. This can be useful in some +situations where the console output is being captured by a runner or +framework (e.g. Ansible) that adds its own timestamps. Note that the +log lines sent to the ``LOGFILE`` will still be prefixed with a +timestamp. + Logging the Service Output --------------------------- +~~~~~~~~~~~~~~~~~~~~~~~~~~ - | *Default: ``LOGDIR=""``* - | DevStack will log the stdout output of the services it starts. - When using ``screen`` this logs the output in the screen windows - to a file. Without ``screen`` this simply redirects stdout of - the service process to a file in ``LOGDIR``. - | +By default, services run under ``systemd`` and are natively logging to +the systemd journal. - :: +To query the logs use the ``journalctl`` command, such as:: + + sudo journalctl --unit devstack@* + +More examples can be found in :ref:`journalctl-examples`. + +Example Logging Configuration +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +For example, non-interactive installs probably wish to save output to +a file, keep service logs and disable color in the stored files. + + :: + + [[local|localrc]] + DEST=/opt/stack/ + LOGFILE=$LOGDIR/stack.sh.log + LOG_COLOR=False + +Database Backend +---------------- + +Multiple database backends are available. The available databases are defined +in the lib/databases directory. +``mysql`` is the default database, choose a different one by putting the +following in the ``localrc`` section: + + :: + + disable_service mysql + enable_service postgresql + +``mysql`` is the default database. + +RPC Backend +----------- + +Support for a RabbitMQ RPC backend is included. Additional RPC +backends may be available via external plugins. Enabling or disabling +RabbitMQ is handled via the usual service functions and +``ENABLED_SERVICES``. + +Example disabling RabbitMQ in ``local.conf``: + +:: - LOGDIR=$DEST/logs + disable_service rabbit - *Note the use of ``DEST`` to locate the main install directory; this - is why we suggest setting it in ``local.conf``.* -Enabling Syslog +Apache Frontend --------------- - | *Default: ``SYSLOG=False SYSLOG_HOST=$HOST_IP SYSLOG_PORT=516``* - | Logging all services to a single syslog can be convenient. Enable - syslogging by setting ``SYSLOG`` to ``True``. If the destination log - host is not localhost ``SYSLOG_HOST`` and ``SYSLOG_PORT`` can be - used to direct the message stream to the log host. - | +The Apache web server can be enabled for wsgi services that support +being deployed under HTTPD + mod_wsgi. By default, services that +recommend running under HTTPD + mod_wsgi are deployed under Apache. To +use an alternative deployment strategy (e.g. eventlet) for services +that support an alternative to HTTPD + mod_wsgi set +``ENABLE_HTTPD_MOD_WSGI_SERVICES`` to ``False`` in your +``local.conf``. - :: +Each service that can be run under HTTPD + mod_wsgi also has an +override toggle available that can be set in your ``local.conf``. + +Keystone is run under Apache with ``mod_wsgi`` by default. + +Example (Keystone) + +:: + + KEYSTONE_USE_MOD_WSGI="True" + +Example (Nova): + +:: + + NOVA_USE_MOD_WSGI="True" + +Example (Swift): + +:: - SYSLOG=True - SYSLOG_HOST=$HOST_IP - SYSLOG_PORT=516 + SWIFT_USE_MOD_WSGI="True" + +Example (Heat): + +:: + + HEAT_USE_MOD_WSGI="True" + + +Example (Cinder): + +:: + + CINDER_USE_MOD_WSGI="True" + + +Libraries from Git +------------------ + +By default devstack installs OpenStack server components from git, +however it installs client libraries from released versions on pypi. +This is appropriate if you are working on server development, but if +you want to see how an unreleased version of the client affects the +system you can have devstack install it from upstream, or from local +git trees by specifying it in ``LIBS_FROM_GIT``. Multiple libraries +can be specified as a comma separated list. + + :: + + LIBS_FROM_GIT=python-keystoneclient,oslo.config + +Setting the variable to ``ALL`` will activate the download for all +libraries. + +Virtual Environments +-------------------- + +Enable the use of Python virtual environments by setting ``USE_VENV`` +to ``True``. This will enable the creation of venvs for each project +that is defined in the ``PROJECT_VENV`` array. + +Each entry in the ``PROJECT_VENV`` array contains the directory name +of a venv to be used for the project. The array index is the project +name. Multiple projects can use the same venv if desired. + + :: + + PROJECT_VENV["glance"]=${GLANCE_DIR}.venv + +``ADDITIONAL_VENV_PACKAGES`` is a comma-separated list of additional +packages to be installed into each venv. Often projects will not have +certain packages listed in its ``requirements.txt`` file because they +are 'optional' requirements, i.e. only needed for certain +configurations. By default, the enabled databases will have their +Python bindings added when they are enabled. + + :: + + ADDITIONAL_VENV_PACKAGES="python-foo, python-bar" + +Use python3 +------------ + +By default ``stack.sh`` uses python2 (the exact version set by the +``PYTHON2_VERSION``). This can be overriden so devstack will run +python3 (the exact version set by ``PYTHON3_VERSION``). + + :: + + USE_PYTHON3=True A clean install every time -------------------------- - | *Default: ``RECLONE=""``* - | By default ``stack.sh`` only clones the project repos if they do - not exist in ``$DEST``. ``stack.sh`` will freshen each repo on each - run if ``RECLONE`` is set to ``yes``. This avoids having to manually - remove repos in order to get the current branch from ``$GIT_BASE``. - | +By default ``stack.sh`` only clones the project repos if they do not +exist in ``$DEST``. ``stack.sh`` will freshen each repo on each run if +``RECLONE`` is set to ``yes``. This avoids having to manually remove +repos in order to get the current branch from ``$GIT_BASE``. :: @@ -276,172 +472,333 @@ A clean install every time Upgrade packages installed by pip --------------------------------- - | *Default: ``PIP_UPGRADE=""``* - | By default ``stack.sh`` only installs Python packages if no version - is currently installed or the current version does not match a specified - requirement. If ``PIP_UPGRADE`` is set to ``True`` then existing required - Python packages will be upgraded to the most recent version that - matches requirements. - | +By default ``stack.sh`` only installs Python packages if no version is +currently installed or the current version does not match a specified +requirement. If ``PIP_UPGRADE`` is set to ``True`` then existing +required Python packages will be upgraded to the most recent version +that matches requirements. :: PIP_UPGRADE=True -Swift ------ +Guest Images +------------ + +Images provided in URLS via the comma-separated ``IMAGE_URLS`` +variable will be downloaded and uploaded to glance by DevStack. + +Default guest-images are predefined for each type of hypervisor and +their testing-requirements in ``stack.sh``. Setting +``DOWNLOAD_DEFAULT_IMAGES=False`` will prevent DevStack downloading +these default images; in that case, you will want to populate +``IMAGE_URLS`` with sufficient images to satisfy testing-requirements. - | Default: SWIFT_HASH="" - | SWIFT_REPLICAS=1 - | SWIFT_DATA_DIR=$DEST/data/swift + :: + + DOWNLOAD_DEFAULT_IMAGES=False + IMAGE_URLS="http://foo.bar.com/image.qcow," + IMAGE_URLS+="http://foo.bar.com/image2.qcow" + + +Instance Type +------------- - | Swift is now used as the back-end for the S3-like object store. - When enabled Nova's objectstore (n-obj in ENABLED_SERVICES) is - automatically disabled. Enable Swift by adding it services to - ENABLED_SERVICES: enable_service s-proxy s-object s-container - s-account +``DEFAULT_INSTANCE_TYPE`` can be used to configure the default instance +type. When this parameter is not specified, Devstack creates additional +micro & nano flavors for really small instances to run Tempest tests. - Setting Swift's hash value is required and you will be prompted for - it if Swift is enabled so just set it to something already: +For guests with larger memory requirements, ``DEFAULT_INSTANCE_TYPE`` +should be specified in the configuration file so Tempest selects the +default flavors instead. + +KVM on Power with QEMU 2.4 requires 512 MB to load the firmware - +`QEMU 2.4 - PowerPC `__ so users +running instances on ppc64/ppc64le can choose one of the default +created flavors as follows: :: - SWIFT_HASH=66a3d6b56c1f479c8b4e70ab5c2000f5 + DEFAULT_INSTANCE_TYPE=m1.tiny + + +IP Version +---------- - For development purposes the default number of replicas is set to - ``1`` to reduce the overhead required. To better simulate a - production deployment set this to ``3`` or more. +``IP_VERSION`` can be used to configure Neutron to create either an +IPv4, IPv6, or dual-stack self-service project data-network by with +either ``IP_VERSION=4``, ``IP_VERSION=6``, or ``IP_VERSION=4+6`` +respectively. :: - SWIFT_REPLICAS=3 + IP_VERSION=4+6 - The data for Swift is stored in the source tree by default (in - ``$DEST/swift/data``) and can be moved by setting - ``SWIFT_DATA_DIR``. The specified directory will be created if it - does not exist. +The following optional variables can be used to alter the default IPv6 +behavior: :: - SWIFT_DATA_DIR=$DEST/data/swift + IPV6_RA_MODE=slaac + IPV6_ADDRESS_MODE=slaac + IPV6_ADDRS_SAFE_TO_USE=fd$IPV6_GLOBAL_ID::/56 + IPV6_PRIVATE_NETWORK_GATEWAY=fd$IPV6_GLOBAL_ID::1 + +*Note*: ``IPV6_ADDRS_SAFE_TO_USE`` and ``IPV6_PRIVATE_NETWORK_GATEWAY`` +can be configured with any valid IPv6 prefix. The default values make +use of an auto-generated ``IPV6_GLOBAL_ID`` to comply with RFC4193. + +Service Version +~~~~~~~~~~~~~~~ + +DevStack can enable service operation over either IPv4 or IPv6 by +setting ``SERVICE_IP_VERSION`` to either ``SERVICE_IP_VERSION=4`` or +``SERVICE_IP_VERSION=6`` respectively. - *Note: Previously just enabling ``swift`` was sufficient to start - the Swift services. That does not provide proper service - granularity, particularly in multi-host configurations, and is - considered deprecated. Some service combination tests now check for - specific Swift services and the old blanket acceptance will longer - work correctly.* +When set to ``4`` devstack services will open listen sockets on +``0.0.0.0`` and service endpoints will be registered using ``HOST_IP`` +as the address. -Service Catalog Backend ------------------------ +When set to ``6`` devstack services will open listen sockets on ``::`` +and service endpoints will be registered using ``HOST_IPV6`` as the +address. - | *Default: ``KEYSTONE_CATALOG_BACKEND=sql``* - | DevStack uses Keystone's ``sql`` service catalog backend. An - alternate ``template`` backend is also available. However, it does - not support the ``service-*`` and ``endpoint-*`` commands of the - ``keystone`` CLI. To do so requires the ``sql`` backend be enabled: - | +The default value for this setting is ``4``. Dual-mode support, for +example ``4+6`` is not currently supported. ``HOST_IPV6`` can +optionally be used to alter the default IPv6 address :: - KEYSTONE_CATALOG_BACKEND=template + HOST_IPV6=${some_local_ipv6_address} + +Multi-node setup +~~~~~~~~~~~~~~~~ + +See the :doc:`multi-node lab guide` + +Projects +-------- + +Neutron +~~~~~~~ + +See the :doc:`neutron configuration guide` for +details on configuration of Neutron + + +Swift +~~~~~ + +Swift is disabled by default. When enabled, it is configured with +only one replica to avoid being IO/memory intensive on a small +VM. + +If you would like to enable Swift you can add this to your ``localrc`` +section: + +:: + + enable_service s-proxy s-object s-container s-account - DevStack's default configuration in ``sql`` mode is set in - ``files/keystone_data.sh`` +If you want a minimal Swift install with only Swift and Keystone you +can have this instead in your ``localrc`` section: + +:: + + disable_all_services + enable_service key mysql s-proxy s-object s-container s-account + +If you only want to do some testing of a real normal swift cluster +with multiple replicas you can do so by customizing the variable +``SWIFT_REPLICAS`` in your ``localrc`` section (usually to 3). + +You can manually override the ring building to use specific storage +nodes, for example when you want to test a multinode environment. In +this case you have to set a space-separated list of IPs in +``SWIFT_STORAGE_IPS`` in your ``localrc`` section that should be used +as Swift storage nodes. +Please note that this does not create a multinode setup, it is only +used when adding nodes to the Swift rings. + +:: + + SWIFT_STORAGE_IPS="192.168.1.10 192.168.1.11 192.168.1.12" + +Swift S3 +++++++++ + +If you are enabling ``swift3`` in ``ENABLED_SERVICES`` DevStack will +install the swift3 middleware emulation. Swift will be configured to +act as a S3 endpoint for Keystone so effectively replacing the +``nova-objectstore``. + +Only Swift proxy server is launched in the systemd system all other +services are started in background and managed by ``swift-init`` tool. + +Tempest +~~~~~~~ + +If tempest has been successfully configured, a basic set of smoke +tests can be run as follows: + +:: + + $ cd /opt/stack/tempest + $ tox -efull tempest.scenario.test_network_basic_ops + +By default tempest is downloaded and the config file is generated, but the +tempest package is not installed in the system's global site-packages (the +package install includes installing dependences). So tempest won't run +outside of tox. If you would like to install it add the following to your +``localrc`` section: + +:: + + INSTALL_TEMPEST=True + + +Xenserver +~~~~~~~~~ + +If you would like to use Xenserver as the hypervisor, please refer to +the instructions in ``./tools/xen/README.md``. + +Cells +~~~~~ + +`Cells `__ is +an alternative scaling option. To setup a cells environment add the +following to your ``localrc`` section: + +:: + + enable_service n-cell + +Be aware that there are some features currently missing in cells, one +notable one being security groups. Cinder ------- +~~~~~~ - | Default: - | VOLUME_GROUP="stack-volumes" VOLUME_NAME_PREFIX="volume-" VOLUME_BACKING_FILE_SIZE=10250M - | The logical volume group used to hold the Cinder-managed volumes - is set by ``VOLUME_GROUP``, the logical volume name prefix is set - with ``VOLUME_NAME_PREFIX`` and the size of the volume backing file - is set with ``VOLUME_BACKING_FILE_SIZE``. - | +The logical volume group used to hold the Cinder-managed volumes is +set by ``VOLUME_GROUP_NAME``, the logical volume name prefix is set with +``VOLUME_NAME_PREFIX`` and the size of the volume backing file is set +with ``VOLUME_BACKING_FILE_SIZE``. :: - VOLUME_GROUP="stack-volumes" + VOLUME_GROUP_NAME="stack-volumes" VOLUME_NAME_PREFIX="volume-" - VOLUME_BACKING_FILE_SIZE=10250M + VOLUME_BACKING_FILE_SIZE=24G -Multi-host DevStack -------------------- - | *Default: ``MULTI_HOST=False``* - | Running DevStack with multiple hosts requires a custom - ``local.conf`` section for each host. The master is the same as a - single host installation with ``MULTI_HOST=True``. The slaves have - fewer services enabled and a couple of host variables pointing to - the master. - | **Master** +Keystone +~~~~~~~~ - :: +Multi-Region Setup +++++++++++++++++++ - MULTI_HOST=True +We want to setup two devstack (RegionOne and RegionTwo) with shared +keystone (same users and services) and horizon. Keystone and Horizon +will be located in RegionOne. Full spec is available at: +``__. - **Slave** +In RegionOne: - :: +:: - MYSQL_HOST=w.x.y.z - RABBIT_HOST=w.x.y.z - GLANCE_HOSTPORT=w.x.y.z:9292 - ENABLED_SERVICES=n-vol,n-cpu,n-net,n-api + REGION_NAME=RegionOne -IP Version - | Default: ``IP_VERSION=4`` - | This setting can be used to configure DevStack to create either an IPv4, - IPv6, or dual stack tenant data network by setting ``IP_VERSION`` to - either ``IP_VERSION=4``, ``IP_VERSION=6``, or ``IP_VERSION=4+6`` - respectively. This functionality requires that the Neutron networking - service is enabled by setting the following options: - | +In RegionTwo: - :: +:: - disable_service n-net - enable_service q-svc q-agt q-dhcp q-l3 + disable_service horizon + KEYSTONE_SERVICE_HOST= + KEYSTONE_AUTH_HOST= + REGION_NAME=RegionTwo + KEYSTONE_REGION_NAME=RegionOne - | The following optional variables can be used to alter the default IPv6 - behavior: - | +In the devstack for RegionOne, we set REGION_NAME as RegionOne, so region of +the services started in this devstack are registered as RegionOne. In devstack +for RegionTwo, similarly, we set REGION_NAME as RegionTwo since we want +services started in this devstack to be registered in RegionTwo. But Keystone +service is started and registered in RegionOne, not RegionTwo, so we use +KEYSTONE_REGION_NAME to specify the region of Keystone service. +KEYSTONE_REGION_NAME has a default value the same as REGION_NAME thus we omit +it in the configuration of RegionOne. - :: +Disabling Identity API v2 ++++++++++++++++++++++++++ - IPV6_RA_MODE=slaac - IPV6_ADDRESS_MODE=slaac - FIXED_RANGE_V6=fd$IPV6_GLOBAL_ID::/64 - IPV6_PRIVATE_NETWORK_GATEWAY=fd$IPV6_GLOBAL_ID::1 +The Identity API v2 is deprecated as of Mitaka and it is recommended to only +use the v3 API. It is possible to setup keystone without v2 API, by doing: - | *Note: ``FIXED_RANGE_V6`` and ``IPV6_PRIVATE_NETWORK_GATEWAY`` - can be configured with any valid IPv6 prefix. The default values make - use of an auto-generated ``IPV6_GLOBAL_ID`` to comply with RFC 4193.* +:: -Examples -======== + ENABLE_IDENTITY_V2=False -- Eliminate a Cinder pass-through (``CINDER_PERIODIC_INTERVAL``): +.. _arch-configuration: - :: +Architectures +------------- - [[post-config|$CINDER_CONF]] - [DEFAULT] - periodic_interval = 60 +The upstream CI runs exclusively on nodes with x86 architectures, but +OpenStack supports even more architectures. Some of them need to configure +Devstack in a certain way. -- Sample ``local.conf`` with screen logging enabled: +KVM on s390x (IBM z Systems) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - :: +KVM on s390x (IBM z Systems) is supported since the *Kilo* release. For +an all-in-one setup, these minimal settings in the ``local.conf`` file +are needed:: - [[local|localrc]] - FIXED_RANGE=10.254.1.0/24 - NETWORK_GATEWAY=10.254.1.1 - LOGDAYS=1 - LOGDIR=$DEST/logs - LOGFILE=$LOGDIR/stack.sh.log - ADMIN_PASSWORD=quiet - DATABASE_PASSWORD=$ADMIN_PASSWORD - RABBIT_PASSWORD=$ADMIN_PASSWORD - SERVICE_PASSWORD=$ADMIN_PASSWORD - SERVICE_TOKEN=a682f596-76f3-11e3-b3b2-e716f9080d50 + [[local|localrc]] + ADMIN_PASSWORD=secret + DATABASE_PASSWORD=$ADMIN_PASSWORD + RABBIT_PASSWORD=$ADMIN_PASSWORD + SERVICE_PASSWORD=$ADMIN_PASSWORD + + DOWNLOAD_DEFAULT_IMAGES=False + IMAGE_URLS="https://cloud-images.ubuntu.com/xenial/current/xenial-server-cloudimg-s390x-disk1.img" + + # Provide a custom etcd3 binary download URL and ints sha256. + # The binary must be located under '//etcd--linux-s390x.tar.gz' + # on this URL. + # Build instructions for etcd3: https://github.com/linux-on-ibm-z/docs/wiki/Building-etcd + ETCD_DOWNLOAD_URL= + ETCD_SHA256= + + enable_service n-sproxy + disable_service n-novnc + + [[post-config|$NOVA_CONF]] + + [serial_console] + base_url=ws://$HOST_IP:6083/ # optional + +Reasoning: + +* The default image of Devstack is x86 only, so we deactivate the download + with ``DOWNLOAD_DEFAULT_IMAGES``. The referenced guest image + in the code above (``IMAGE_URLS``) serves as an example. The list of + possible s390x guest images is not limited to that. + +* This platform doesn't support a graphical console like VNC or SPICE. + The technical reason is the missing framebuffer on the platform. This + means we rely on the substitute feature *serial console* which needs the + proxy service ``n-sproxy``. We also disable VNC's proxy ``n-novnc`` for + that reason . The configuration in the ``post-config`` section is only + needed if you want to use the *serial console* outside of the all-in-one + setup. + +* A link to an etcd3 binary and its sha256 needs to be provided as the + binary for s390x is not hosted on github like it is for other + architectures. For more details see + https://bugs.launchpad.net/devstack/+bug/1693192. Etcd3 can easily be + built along https://github.com/linux-on-ibm-z/docs/wiki/Building-etcd. + +.. note:: To run *Tempest* against this *Devstack* all-in-one, you'll need + to use a guest image which is smaller than 1GB when uncompressed. + The example image from above is bigger than that! diff --git a/doc/source/development.rst b/doc/source/development.rst new file mode 100644 index 0000000000..957de9b0e1 --- /dev/null +++ b/doc/source/development.rst @@ -0,0 +1,117 @@ +========================== + Developing with Devstack +========================== + +Now that you have your nifty DevStack up and running, what can you do +with it? + +Inspecting Services +=================== + +By default most services in DevStack are running as `systemd` units +named `devstack@$servicename.service`. You can see running services +with. + +.. code-block:: bash + + sudo systemctl status "devstack@*" + +To learn more about the basics of systemd, see :doc:`/systemd` + +Patching a Service +================== + +If you want to make a quick change to a running service the easiest +way to do that is to change the code directly in /opt/stack/$service +and then restart the affected daemons. + +.. code-block:: bash + + sudo systemctl restart devstack@n-cpu.service + +If your change impacts more than one daemon you can restart by +wildcard as well. + +.. code-block:: bash + + sudo systemctl restart "devstack@n-*" + +.. warning:: + + All changes you are making are in checked out git trees that + DevStack thinks it has full control over. Uncommitted work, or + work committed to the master branch, may be overwritten during + subsequent DevStack runs. + +Testing a Patch Series +====================== + +When testing a larger set of patches, or patches that will impact more +than one service within a project, it is often less confusing to use +custom git locations, and make all your changes in a dedicated git +tree. + +In your ``local.conf`` you can add ``**_REPO``, ``**_BRANCH`` for most projects +to use a custom git tree instead of the default upstream ones. + +For instance: + +.. code-block:: bash + + [[local|localrc]] + NOVA_REPO=/home/sdague/nova + NOVA_BRANCH=fold_disk_config + +Will use a custom git tree and branch when doing any devstack +operations, such as ``stack.sh``. + +When testing complicated changes committing to these trees, then doing +``./unstack.sh && ./stack.sh`` is often a valuable way to +iterate. This does take longer per iteration than direct patching, as +the whole devstack needs to rebuild. + +You can use this same approach to test patches that are up for review +in gerrit by using the ref name that gerrit assigns to each change. + +.. code-block:: bash + + [[local|localrc]] + NOVA_BRANCH=refs/changes/10/353710/1 + + +Testing Changes to Libraries +============================ + +When testing changes to libraries consumed by OpenStack services (such +as oslo or any of the python-fooclient libraries) things are a little +more complicated. By default we only test with released versions of +these libraries that are on pypi. + +You must first override this with the setting ``LIBS_FROM_GIT``. This +will enable your DevStack with the git version of that library instead +of the released version. + +After that point you can also specify ``**_REPO``, ``**_BRANCH`` to use +your changes instead of just upstream master. + +.. code-block:: bash + + [[local|localrc]] + LIBS_FROM_GIT=oslo.policy + OSLOPOLICY_REPO=/home/sdague/oslo.policy + OSLOPOLICY_BRANCH=better_exception + +As libraries are not installed `editable` by pip, after you make any +local changes you will need to: + +* cd to top of library path +* sudo pip install -U . +* restart all services you want to use the new library + +You can do that with wildcards such as + +.. code-block:: bash + + sudo systemctl restart "devstack@n-*" + +which will restart all nova services. diff --git a/doc/source/eucarc.rst b/doc/source/eucarc.rst deleted file mode 100644 index c2ecbc6732..0000000000 --- a/doc/source/eucarc.rst +++ /dev/null @@ -1,45 +0,0 @@ -===================== -eucarc - EC2 Settings -===================== - -``eucarc`` creates EC2 credentials for the current user as defined by -``OS_TENANT_NAME:OS_USERNAME``. ``eucarc`` sources ``openrc`` at the -beginning (which in turn sources ``stackrc`` and ``localrc``) in order -to set credentials to create EC2 credentials in Keystone. - -EC2\_URL - Set the EC2 url for euca2ools. The endpoint is extracted from the - service catalog for ``OS_TENANT_NAME:OS_USERNAME``. - - :: - - EC2_URL=$(openstack catalog show ec2 | awk '/ publicURL: / { print $4 }') - -S3\_URL - Set the S3 endpoint for euca2ools. The endpoint is extracted from - the service catalog for ``OS_TENANT_NAME:OS_USERNAME``. - - :: - - export S3_URL=$(openstack catalog show s3 | awk '/ publicURL: / { print $4 }') - -EC2\_ACCESS\_KEY, EC2\_SECRET\_KEY - Create EC2 credentials for the current tenant:user in Keystone. - - :: - - CREDS=$(openstack ec2 credentials create) - export EC2_ACCESS_KEY=$(echo "$CREDS" | awk '/ access / { print $4 }') - export EC2_SECRET_KEY=$(echo "$CREDS" | awk '/ secret / { print $4 }') - -Certificates for Bundling - Euca2ools requires certificate files to enable bundle uploading. The - exercise script ``exercises/bundle.sh`` demonstrated retrieving - certificates using the Nova CLI. - - :: - - EC2_PRIVATE_KEY=pk.pem - EC2_CERT=cert.pem - NOVA_CERT=cacert.pem - EUCALYPTUS_CERT=${NOVA_CERT} diff --git a/doc/source/exerciserc.rst b/doc/source/exerciserc.rst deleted file mode 100644 index dacae2ecf2..0000000000 --- a/doc/source/exerciserc.rst +++ /dev/null @@ -1,42 +0,0 @@ -============================== -exerciserc - Exercise Settings -============================== - -``exerciserc`` is used to configure settings for the exercise scripts. -The values shown below are the default values. These can all be -overridden by setting them in the ``localrc`` section. - -ACTIVE\_TIMEOUT - Max time to wait while vm goes from build to active state - - :: - - ACTIVE_TIMEOUT==30 - -ASSOCIATE\_TIMEOUT - Max time to wait for proper IP association and dis-association. - - :: - - ASSOCIATE_TIMEOUT=15 - -BOOT\_TIMEOUT - Max time till the vm is bootable - - :: - - BOOT_TIMEOUT=30 - -RUNNING\_TIMEOUT - Max time from run instance command until it is running - - :: - - RUNNING_TIMEOUT=$(($BOOT_TIMEOUT + $ACTIVE_TIMEOUT)) - -TERMINATE\_TIMEOUT - Max time to wait for a vm to terminate - - :: - - TERMINATE_TIMEOUT=30 diff --git a/doc/source/faq.rst b/doc/source/faq.rst index d3b491fdac..efb315cbee 100644 --- a/doc/source/faq.rst +++ b/doc/source/faq.rst @@ -2,176 +2,233 @@ FAQ === -- `General Questions <#general>`__ -- `Operation and Configuration <#ops_conf>`__ -- `Miscellaneous <#misc>`__ +.. contents:: + :local: General Questions ================= -Q: Can I use DevStack for production? - A: No. We mean it. Really. DevStack makes some implementation - choices that are not appropriate for production deployments. We - warned you! -Q: Then why selinux in enforcing mode? - A: That is the default on current Fedora and RHEL releases. DevStack - has (rightly so) a bad reputation for its security practices; it has - always been meant as a development tool first and system integration - later. This is changing as the security issues around OpenStack's - use of root (for example) have been tightened and developers need to - be better equipped to work in these environments. ``stack.sh``'s use - of root is primarily to support the activities that would be handled - by packaging in "real" deployments. To remove additional protections - that will be desired/required in production would be a step - backward. -Q: But selinux is disabled in RHEL! - A: Today it is, yes. That is a specific exception that certain - DevStack contributors fought strongly against. The primary reason it - was allowed was to support using RHEL6 as the Python 2.6 test - platform and that took priority time-wise. This will not be the case - with RHEL 7. -Q: Why a shell script, why not chef/puppet/... - A: The script is meant to be read by humans (as well as ran by - computers); it is the primary documentation after all. Using a - recipe system requires everyone to agree and understand chef or - puppet. -Q: Why not use Crowbar? - A: DevStack is optimized for documentation & developers. As some of - us use `Crowbar `__ for - production deployments, we hope developers documenting how they - setup systems for new features supports projects like Crowbar. -Q: I'd like to help! - A: That isn't a question, but please do! The source for DevStack is - at - `git.openstack.org `__ - and bug reports go to - `LaunchPad `__. Contributions - follow the usual process as described in the `developer - guide `__. This Sphinx - documentation is housed in the doc directory. -Q: Why not use packages? - A: Unlike packages, DevStack leaves your cloud ready to develop - - checkouts of the code and services running in screen. However, many - people are doing the hard work of packaging and recipes for - production deployments. We hope this script serves as a way to - communicate configuration changes between developers and packagers. -Q: Why isn't $MY\_FAVORITE\_DISTRO supported? - A: DevStack is meant for developers and those who want to see how - OpenStack really works. DevStack is known to run on the - distro/release combinations listed in ``README.md``. DevStack is - only supported on releases other than those documented in - ``README.md`` on a best-effort basis. -Q: What about Fedora/RHEL/CentOS? - A: Fedora and CentOS/RHEL are supported via rpm dependency files and - specific checks in ``stack.sh``. Support will follow the pattern set - with the Ubuntu testing, i.e. only a single release of the distro - will receive regular testing, others will be handled on a - best-effort basis. -Q: Are there any differences between Ubuntu and Fedora support? - A: Neutron is not fully supported prior to Fedora 18 due lack of - OpenVSwitch packages. -Q: Why can't I use another shell? - A: DevStack now uses some specific bash-ism that require Bash 4, such - as associative arrays. Simple compatibility patches have been accepted - in the past when they are not complex, at this point no additional - compatibility patches will be considered except for shells matching - the array functionality as it is very ingrained in the repo and project - management. -Q: But, but, can't I test on OS/X? - A: Yes, even you, core developer who complained about this, needs to - install bash 4 via homebrew to keep running tests on OS/X. Get a Real - Operating System. (For most of you who don't know, I am referring to - myself.) +Can I use DevStack for production? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +DevStack is targeted at developers and CI systems to use the raw +upstream code. It makes many choices that are not appropriate for +production systems. + +Your best choice is probably to choose a `distribution of OpenStack +`__. + +Can I use DevStack as a development environment? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Sure, you can. That said, there are a couple of things you should note before +doing so: + +- DevStack makes a lot of configuration changes to your system and should not + be run in your main development environment. + +- All the repositories that DevStack clones when deploying are considered + volatile by default and thus are subject to hard resets. This is necessary to + keep you in sync with the latest upstream, which is what you want in a CI + situation, but it can result in branches being overwritten and files being + removed. + + The corollary of this is that if you are working on a specific project, using + the DevStack project repository (defaulted to ``/opt/stack/``) as + the single master repository for storing all your work is not recommended. + This behavior can be overridden by setting the ``RECLONE`` config option to + ``no``. Alternatively, you can avoid running ``stack.sh`` to redeploy by + restarting services manually. In any case, you should generally ensure work + in progress is pushed to Gerrit or otherwise backed up before running + ``stack.sh``. + +- If you use DevStack within a VM, you may wish to mount a local OpenStack + directory, such as ``~/src/openstack``, inside the VM and configure DevStack + to use this as the clone location using the ``{PROJECT}_REPO`` config + variables. For example, assuming you're using Vagrant and sharing your home + directory, you should place the following in ``local.conf``: + + .. code-block:: shell + + NEUTRON_REPO=/home/vagrant/src/neutron + NOVA_REPO=/home/vagrant/src/nova + KEYSTONE_REPO=/home/vagrant/src/keystone + GLANCE_REPO=/home/vagrant/src/glance + SWIFT_REPO=/home/vagrant/src/swift + HORIZON_REPO=/home/vagrant/src/horizon + CINDER_REPO=/home/vagrant/src/cinder + HEAT_REPO=/home/vagrant/src/heat + TEMPEST_REPO=/home/vagrant/src/tempest + HEATCLIENT_REPO=/home/vagrant/src/python-heatclient + GLANCECLIENT_REPO=/home/vagrant/src/python-glanceclient + NOVACLIENT_REPO=/home/vagrant/src/python-novaclient + NEUTRONCLIENT_REPO=/home/vagrant/src/python-neutronclient + OPENSTACKCLIENT_REPO=/home/vagrant/src/python-openstackclient + HEAT_CFNTOOLS_REPO=/home/vagrant/src/heat-cfntools + HEAT_TEMPLATES_REPO=/home/vagrant/src/heat-templates + NEUTRON_FWAAS_REPO=/home/vagrant/src/neutron-fwaas + # ... + +Why a shell script, why not chef/puppet/... +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The script is meant to be read by humans (as well as ran by +computers); it is the primary documentation after all. Using a recipe +system requires everyone to agree and understand chef or puppet. + +I'd like to help! +~~~~~~~~~~~~~~~~~ + +That isn't a question, but please do! The source for DevStack is at +`git.openstack.org +`__ and bug +reports go to `LaunchPad +`__. Contributions follow the +usual process as described in the `developer guide +`__. This +Sphinx documentation is housed in the doc directory. + +Why not use packages? +~~~~~~~~~~~~~~~~~~~~~ + +Unlike packages, DevStack leaves your cloud ready to develop - +checkouts of the code and services running locally under systemd, +making it easy to hack on and test new patches. However, many people +are doing the hard work of packaging and recipes for production +deployments. + +Why isn't $MY\_FAVORITE\_DISTRO supported? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +DevStack is meant for developers and those who want to see how +OpenStack really works. DevStack is known to run on the distro/release +combinations listed in ``README.md``. DevStack is only supported on +releases other than those documented in ``README.md`` on a best-effort +basis. + +Are there any differences between Ubuntu and CentOS/Fedora support? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Both should work well and are tested by DevStack CI. + +Why can't I use another shell? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +DevStack now uses some specific bash-ism that require Bash 4, such as +associative arrays. Simple compatibility patches have been accepted in +the past when they are not complex, at this point no additional +compatibility patches will be considered except for shells matching +the array functionality as it is very ingrained in the repo and +project management. + +Can I test on OS/X? +~~~~~~~~~~~~~~~~~~~ + +Some people have success with bash 4 installed via homebrew to keep +running tests on OS/X. + +Can I at least source ``openrc`` with ``zsh``? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +People have reported success with a special function to run ``openrc`` +through bash for this + +.. code-block:: bash + + function sourceopenrc { + pushd ~/devstack >/dev/null + eval $(bash -c ". openrc $1 $2 >/dev/null;env|sed -n '/OS_/ { s/^/export /;p}'") + popd >/dev/null + } + Operation and Configuration =========================== -Q: Can DevStack handle a multi-node installation? - A: Indirectly, yes. You run DevStack on each node with the - appropriate configuration in ``local.conf``. The primary - considerations are turning off the services not required on the - secondary nodes, making sure the passwords match and setting the - various API URLs to the right place. -Q: How can I document the environment that DevStack is using? - A: DevStack includes a script (``tools/info.sh``) that gathers the - versions of the relevant installed apt packages, pip packages and - git repos. This is a good way to verify what Python modules are - installed. -Q: How do I turn off a service that is enabled by default? - A: Services can be turned off by adding ``disable_service xxx`` to - ``local.conf`` (using ``n-vol`` in this example): +Can DevStack handle a multi-node installation? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - :: +Yes, see :doc:`multinode lab guide ` + +How can I document the environment that DevStack is using? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +DevStack includes a script (``tools/info.sh``) that gathers the +versions of the relevant installed apt packages, pip packages and git +repos. This is a good way to verify what Python modules are +installed. - disable_service n-vol +How do I turn off a service that is enabled by default? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Q: Is enabling a service that defaults to off done with the reverse of the above? - A: Of course! +Services can be turned off by adding ``disable_service xxx`` to +``local.conf`` (using ``c-vol`` in this example): :: - enable_service qpid + disable_service c-vol -Q: How do I run a specific OpenStack milestone? - A: OpenStack milestones have tags set in the git repo. Set the appropriate tag in the ``*_BRANCH`` variables in ``local.conf``. Swift is on its own release schedule so pick a tag in the Swift repo that is just before the milestone release. For example: +Is enabling a service that defaults to off done with the reverse of the above? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Of course! :: - [[local|localrc]] - GLANCE_BRANCH=stable/juno - HORIZON_BRANCH=stable/juno - KEYSTONE_BRANCH=stable/juno - NOVA_BRANCH=stable/juno - GLANCE_BRANCH=stable/juno - NEUTRON_BRANCH=stable/juno - SWIFT_BRANCH=2.2.1 - -Q: Why not use [STRIKEOUT:``tools/pip-requires``]\ ``requirements.txt`` to grab project dependencies? - [STRIKEOUT:The majority of deployments will use packages to install - OpenStack that will have distro-based packages as dependencies. - DevStack installs as many of these Python packages as possible to - mimic the expected production environment.] Certain Linux - distributions have a 'lack of workaround' in their Python - configurations that installs vendor packaged Python modules and - pip-installed modules to the SAME DIRECTORY TREE. This is causing - heartache and moving us in the direction of installing more modules - from PyPI than vendor packages. However, that is only being done as - necessary as the packaging needs to catch up to the development - cycle anyway so this is kept to a minimum. -Q: What can I do about RabbitMQ not wanting to start on my fresh new VM? - A: This is often caused by ``erlang`` not being happy with the - hostname resolving to a reachable IP address. Make sure your - hostname resolves to a working IP address; setting it to 127.0.0.1 - in ``/etc/hosts`` is often good enough for a single-node - installation. And in an extreme case, use ``clean.sh`` to eradicate - it and try again. -Q: How can I set up Heat in stand-alone configuration? - A: Configure ``local.conf`` thusly: + enable_service q-svc - :: +How do I run a specific OpenStack release? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +DevStack master tracks the upstream master of all the projects. If you +would like to run a stable branch of OpenStack, you should use the +corresponding stable branch of DevStack as well. For instance the +``stable/ocata`` version of DevStack will already default to all the +projects running at ``stable/ocata`` levels. + +Note: it's also possible to manually adjust the ``*_BRANCH`` variables +further if you would like to test specific milestones, or even custom +out of tree branches. This is done with entries like the following in +your ``local.conf`` + +:: [[local|localrc]] - HEAT_STANDALONE=True - ENABLED_SERVICES=rabbit,mysql,heat,h-api,h-api-cfn,h-api-cw,h-eng - KEYSTONE_SERVICE_HOST= - KEYSTONE_AUTH_HOST= - -Q: Why are my configuration changes ignored? - A: You may have run into the package prerequisite installation - timeout. ``tools/install_prereqs.sh`` has a timer that skips the - package installation checks if it was run within the last - ``PREREQ_RERUN_HOURS`` hours (default is 2). To override this, set - ``FORCE_PREREQ=1`` and the package checks will never be skipped. + GLANCE_BRANCH=11.0.0.0rc1 + NOVA_BRANCH=12.0.0.0.rc1 + + +Upstream DevStack is only tested with master and stable +branches. Setting custom BRANCH definitions is not guaranteed to +produce working results. + +What can I do about RabbitMQ not wanting to start on my fresh new VM? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This is often caused by ``erlang`` not being happy with the hostname +resolving to a reachable IP address. Make sure your hostname resolves +to a working IP address; setting it to 127.0.0.1 in ``/etc/hosts`` is +often good enough for a single-node installation. And in an extreme +case, use ``clean.sh`` to eradicate it and try again. + +Why are my configuration changes ignored? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +You may have run into the package prerequisite installation +timeout. ``tools/install_prereqs.sh`` has a timer that skips the +package installation checks if it was run within the last +``PREREQ_RERUN_HOURS`` hours (default is 2). To override this, set +``FORCE_PREREQ=1`` and the package checks will never be skipped. Miscellaneous ============= -Q: ``tools/fixup_stuff.sh`` is broken and shouldn't 'fix' just one version of packages. - A: [Another not-a-question] No it isn't. Stuff in there is to - correct problems in an environment that need to be fixed elsewhere - or may/will be fixed in a future release. In the case of - ``httplib2`` and ``prettytable`` specific problems with specific - versions are being worked around. If later releases have those - problems than we'll add them to the script. Knowing about the broken - future releases is valuable rather than polling to see if it has - been fixed. +``tools/fixup_stuff.sh`` is broken and shouldn't 'fix' just one version of packages. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Stuff in there is to correct problems in an environment that need to +be fixed elsewhere or may/will be fixed in a future release. In the +case of ``httplib2`` and ``prettytable`` specific problems with +specific versions are being worked around. If later releases have +those problems than we'll add them to the script. Knowing about the +broken future releases is valuable rather than polling to see if it +has been fixed. diff --git a/doc/source/guides.rst b/doc/source/guides.rst new file mode 100644 index 0000000000..82e0dd6ac6 --- /dev/null +++ b/doc/source/guides.rst @@ -0,0 +1,74 @@ +Guides +====== + +.. warning:: + + The guides are point in time contributions, and may not always be + up to date with the latest work in devstack. + +Walk through various setups used by stackers + +.. toctree:: + :glob: + :maxdepth: 1 + + guides/single-vm + guides/single-machine + guides/lxc + guides/multinode-lab + guides/neutron + guides/devstack-with-nested-kvm + guides/nova + guides/devstack-with-lbaas-v2 + guides/devstack-with-ldap + +All-In-One Single VM +-------------------- + +Run :doc:`OpenStack in a VM `. The VMs launched in your cloud will be slow as +they are running in QEMU (emulation), but it is useful if you don't have +spare hardware laying around. :doc:`[Read] ` + +All-In-One Single Machine +------------------------- + +Run :doc:`OpenStack on dedicated hardware ` This can include a +server-class machine or a laptop at home. +:doc:`[Read] ` + +All-In-One LXC Container +------------------------- + +Run :doc:`OpenStack in a LXC container `. Beneficial for intermediate +and advanced users. The VMs launched in this cloud will be fully accelerated but +not all OpenStack features are supported. :doc:`[Read] ` + +Multi-Node Lab +-------------- + +Setup a :doc:`multi-node cluster ` with dedicated VLANs for VMs & Management. +:doc:`[Read] ` + +DevStack with Neutron Networking +-------------------------------- + +Building a DevStack cluster with :doc:`Neutron Networking `. +This guide is meant for building lab environments with a dedicated +control node and multiple compute nodes. + +DevStack with KVM-based Nested Virtualization +--------------------------------------------- + +Procedure to setup :doc:`DevStack with KVM-based Nested Virtualization +`. With this setup, Nova instances +will be more performant than with plain QEMU emulation. + +Nova and devstack +-------------------------------- + +Guide to working with nova features :doc:`Nova and devstack `. + +Deploying DevStack with LDAP +---------------------------- + +Guide to setting up :doc:`DevStack with LDAP `. diff --git a/doc/source/guides/devstack-with-lbaas-v2.rst b/doc/source/guides/devstack-with-lbaas-v2.rst index f67978310d..df3c7ce2ac 100644 --- a/doc/source/guides/devstack-with-lbaas-v2.rst +++ b/doc/source/guides/devstack-with-lbaas-v2.rst @@ -1,54 +1,57 @@ -Configure Load-Balancer in Kilo +Configure Load-Balancer Version 2 ================================= -The Kilo release of OpenStack will support Version 2 of the neutron load balancer. Until now, using OpenStack `LBaaS V2 `_ has required a good understanding of neutron and LBaaS architecture and several manual steps. +Starting in the OpenStack Liberty release, the +`neutron LBaaS v2 API `_ +is now stable while the LBaaS v1 API has been deprecated. The LBaaS v2 reference +driver is based on Octavia. Phase 1: Create DevStack + 2 nova instances -------------------------------------------- -First, set up a vm of your choice with at least 8 GB RAM and 16 GB disk space, make sure it is updated. Install git and any other developer tools you find useful. +First, set up a vm of your choice with at least 8 GB RAM and 16 GB disk space, +make sure it is updated. Install git and any other developer tools you find useful. Install devstack - :: +:: git clone https://git.openstack.org/openstack-dev/devstack cd devstack -Edit your `local.conf` to look like +Edit your ``local.conf`` to look like - :: +:: [[local|localrc]] # Load the external LBaaS plugin. enable_plugin neutron-lbaas https://git.openstack.org/openstack/neutron-lbaas + enable_plugin octavia https://git.openstack.org/openstack/octavia # ===== BEGIN localrc ===== DATABASE_PASSWORD=password ADMIN_PASSWORD=password SERVICE_PASSWORD=password - SERVICE_TOKEN=password RABBIT_PASSWORD=password # Enable Logging LOGFILE=$DEST/logs/stack.sh.log VERBOSE=True LOG_COLOR=True - SCREEN_LOGDIR=$DEST/logs # Pre-requisite ENABLED_SERVICES=rabbit,mysql,key # Horizon ENABLED_SERVICES+=,horizon # Nova - ENABLED_SERVICES+=,n-api,n-crt,n-obj,n-cpu,n-cond,n-sch - IMAGE_URLS+=",https://launchpad.net/cirros/trunk/0.3.0/+download/cirros-0.3.0-x86_64-disk.img" + ENABLED_SERVICES+=,n-api,n-cpu,n-cond,n-sch # Glance ENABLED_SERVICES+=,g-api,g-reg # Neutron ENABLED_SERVICES+=,q-svc,q-agt,q-dhcp,q-l3,q-meta - # Enable LBaaS V2 + # Enable LBaaS v2 ENABLED_SERVICES+=,q-lbaasv2 + ENABLED_SERVICES+=,octavia,o-cw,o-hk,o-hm,o-api # Cinder ENABLED_SERVICES+=,c-api,c-vol,c-sch # Tempest @@ -57,30 +60,30 @@ Edit your `local.conf` to look like Run stack.sh and do some sanity checks - :: +:: ./stack.sh . ./openrc - neutron net-list # should show public and private networks + openstack network list # should show public and private networks Create two nova instances that we can use as test http servers: - :: +:: #create nova instances on private network - nova boot --image $(nova image-list | awk '/ cirros-0.3.0-x86_64-disk / {print $2}') --flavor 1 --nic net-id=$(neutron net-list | awk '/ private / {print $2}') node1 - nova boot --image $(nova image-list | awk '/ cirros-0.3.0-x86_64-disk / {print $2}') --flavor 1 --nic net-id=$(neutron net-list | awk '/ private / {print $2}') node2 + nova boot --image $(nova image-list | awk '/ cirros-.*-x86_64-uec / {print $2}') --flavor 1 --nic net-id=$(openstack network list | awk '/ private / {print $2}') node1 + nova boot --image $(nova image-list | awk '/ cirros-.*-x86_64-uec / {print $2}') --flavor 1 --nic net-id=$(openstack network list | awk '/ private / {print $2}') node2 nova list # should show the nova instances just created - #add secgroup rule to allow ssh etc.. - neutron security-group-rule-create default --protocol icmp - neutron security-group-rule-create default --protocol tcp --port-range-min 22 --port-range-max 22 - neutron security-group-rule-create default --protocol tcp --port-range-min 80 --port-range-max 80 + #add secgroup rules to allow ssh etc.. + openstack security group rule create default --protocol icmp + openstack security group rule create default --protocol tcp --dst-port 22:22 + openstack security group rule create default --protocol tcp --dst-port 80:80 Set up a simple web server on each of these instances. ssh into each instance (username 'cirros', password 'cubswin:)') and run - :: +:: MYIP=$(ifconfig eth0|grep 'inet addr'|awk -F: '{print $2}'| awk '{print $1}') while true; do echo -e "HTTP/1.0 200 OK\r\n\r\nWelcome to $MYIP" | sudo nc -l -p 80 ; done& @@ -88,12 +91,19 @@ Set up a simple web server on each of these instances. ssh into each instance (u Phase 2: Create your load balancers ------------------------------------ - :: +:: neutron lbaas-loadbalancer-create --name lb1 private-subnet + neutron lbaas-loadbalancer-show lb1 # Wait for the provisioning_status to be ACTIVE. neutron lbaas-listener-create --loadbalancer lb1 --protocol HTTP --protocol-port 80 --name listener1 + sleep 10 # Sleep since LBaaS actions can take a few seconds depending on the environment. neutron lbaas-pool-create --lb-algorithm ROUND_ROBIN --listener listener1 --protocol HTTP --name pool1 + sleep 10 neutron lbaas-member-create --subnet private-subnet --address 10.0.0.3 --protocol-port 80 pool1 + sleep 10 neutron lbaas-member-create --subnet private-subnet --address 10.0.0.5 --protocol-port 80 pool1 -Please note here that the "10.0.0.3" and "10.0.0.5" in the above commands are the IPs of the nodes (in my test run-thru, they were actually 10.2 and 10.4), and the address of the created LB will be reported as "vip_address" from the lbaas-loadbalancer-create, and a quick test of that LB is "curl that-lb-ip", which should alternate between showing the IPs of the two nodes. +Please note here that the "10.0.0.3" and "10.0.0.5" in the above commands are the IPs of the nodes +(in my test run-thru, they were actually 10.2 and 10.4), and the address of the created LB will be +reported as "vip_address" from the lbaas-loadbalancer-create, and a quick test of that LB is +"curl that-lb-ip", which should alternate between showing the IPs of the two nodes. diff --git a/doc/source/guides/devstack-with-ldap.rst b/doc/source/guides/devstack-with-ldap.rst new file mode 100644 index 0000000000..ec411419b5 --- /dev/null +++ b/doc/source/guides/devstack-with-ldap.rst @@ -0,0 +1,174 @@ +============================ +Deploying DevStack with LDAP +============================ + +The OpenStack Identity service has the ability to integrate with LDAP. The goal +of this guide is to walk you through setting up an LDAP-backed OpenStack +development environment. + +Introduction +============ + +LDAP support in keystone is read-only. You can use it to back an entire +OpenStack deployment to a single LDAP server, or you can use it to back +separate LDAP servers to specific keystone domains. Users within those domains +will can authenticate against keystone, assume role assignments, and interact +with other OpenStack services. + +Configuration +============= + +To deploy an OpenLDAP server, make sure ``ldap`` is added to the list of +``ENABLED_SERVICES``:: + + enable_service ldap + +Devstack will require a password to set up an LDAP administrator. This +administrative user is also the bind user specified in keystone's configuration +files, similar to a ``keystone`` user for MySQL databases. + +Devstack will prompt you for a password when running ``stack.sh`` if +``LDAP_PASSWORD`` is not set. You can add the following to your +``local.conf``:: + + LDAP_PASSWORD=super_secret_password + +At this point, devstack should have everything it needs to deploy OpenLDAP, +bootstrap it with a minimal set of users, and configure it to back to a domain +in keystone:: + + ./stack.sh + +Once ``stack.sh`` completes, you should have a running keystone deployment with +a basic set of users. It is important to note that not all users will live +within LDAP. Instead, keystone will back different domains to different +identity sources. For example, the ``default`` domain will be backed by MySQL. +This is usually where you'll find your administrative and services users. If +you query keystone for a list of domains, you should see a domain called +``Users``. This domain is set up by devstack and points to OpenLDAP. + +User Management +=============== + +Initially, there will only be two users in the LDAP server. The ``Manager`` +user is used by keystone to talk to OpenLDAP. The ``demo`` user is a generic +user that you should be able to see if you query keystone for users within the +``Users`` domain. Both of these users were added to LDAP using basic LDAP +utilities installed by devstack (e.g. ``ldap-utils``) and LDIFs. The LDIFs used +to create these users can be found in ``devstack/files/ldap/``. + +Listing Users +------------- + +To list all users in LDAP directly, you can use ``ldapsearch`` with the LDAP +user bootstrapped by devstack:: + + ldapsearch -x -w LDAP_PASSWORD -D cn=Manager,dc=openstack,dc=org \ + -H ldap://localhost -b dc=openstack,dc=org + +As you can see, devstack creates an OpenStack domain called ``openstack.org`` +as a container for the ``Manager`` and ``demo`` users. + +Creating Users +-------------- + +Since keystone's LDAP integration is read-only, users must be added directly to +LDAP. Users added directly to OpenLDAP will automatically be placed into the +``Users`` domain. + +LDIFs can be used to add users via the command line. The following is an +example LDIF that can be used to create a new LDAP user, let's call it +``peter.ldif.in``:: + + dn: cn=peter,ou=Users,dc=openstack,dc=org + cn: peter + displayName: Peter Quill + givenName: Peter Quill + mail: starlord@openstack.org + objectClass: inetOrgPerson + objectClass: top + sn: peter + uid: peter + userPassword: im-a-better-pilot-than-rocket + +Now, we use the ``Manager`` user to create a user for Peter in LDAP:: + + ldapadd -x -w LDAP_PASSWORD -D cn=Manager,dc=openstack,dc=org \ + -H ldap://localhost -c -f peter.ldif.in + +We should be able to assign Peter roles on projects. After Peter has some level +of authorization, he should be able to login to Horizon by specifying the +``Users`` domain and using his ``peter`` username and password. Authorization +can be given to Peter by creating a project within the ``Users`` domain and +giving him a role assignment on that project:: + + $ openstack project create --domain Users awesome-mix-vol-1 + +-------------+----------------------------------+ + | Field | Value | + +-------------+----------------------------------+ + | description | | + | domain_id | 61a2de23107c46bea2d758167af707b9 | + | enabled | True | + | id | 7d422396d54945cdac8fe1e8e32baec4 | + | is_domain | False | + | name | awesome-mix-vol-1 | + | parent_id | 61a2de23107c46bea2d758167af707b9 | + | tags | [] | + +-------------+----------------------------------+ + $ openstack role add --user peter --user-domain Users \ + --project awesome-mix-vol-1 --project-domain Users admin + + +Deleting Users +-------------- + +We can use the same basic steps to remove users from LDAP, but instead of using +LDIFs, we can just pass the ``dn`` of the user we want to delete:: + + ldapdelete -x -w LDAP_PASSWORD -D cn=Manager,dc=openstack,dc=org \ + -H ldap://localhost cn=peter,ou=Users,dc=openstack,dc=org + +Group Management +================ + +Like users, groups are considered specific identities. This means that groups +also fall under the same read-only constraints as users and they can be managed +directly with LDAP in the same way users are with LDIFs. + +Adding Groups +------------- + +Let's define a specific group with the following LDIF:: + + dn: cn=guardians,ou=UserGroups,dc=openstack,dc=org + objectClass: groupOfNames + cn: guardians + description: Guardians of the Galaxy + member: cn=peter,dc=openstack,dc=org + member: cn=gamora,dc=openstack,dc=org + member: cn=drax,dc=openstack,dc=org + member: cn=rocket,dc=openstack,dc=org + member: cn=groot,dc=openstack,dc=org + +We can create the group using the same ``ldapadd`` command as we did with +users:: + + ldapadd -x -w LDAP_PASSWORD -D cn=Manager,dc=openstack,dc=org \ + -H ldap://localhost -c -f guardian-group.ldif.in + +If we check the group membership in Horizon, we'll see that only Peter is a +member of the ``guardians`` group, despite the whole crew being specified in +the LDIF. Once those accounts are created in LDAP, they will automatically be +added to the ``guardians`` group. They will also assume any role assignments +given to the ``guardians`` group. + +Deleting Groups +--------------- + +Just like users, groups can be deleted using the ``dn``:: + + ldapdelete -x -w LDAP_PASSWORD -D cn=Manager,dc=openstack,dc=org \ + -H ldap://localhost cn=guardians,ou=UserGroups,dc=openstack,dc=org + +Note that this operation will not remove users within that group. It will only +remove the group itself and the memberships any users had with that group. diff --git a/doc/source/guides/devstack-with-nested-kvm.rst b/doc/source/guides/devstack-with-nested-kvm.rst index b35492ea17..3732f06fd8 100644 --- a/doc/source/guides/devstack-with-nested-kvm.rst +++ b/doc/source/guides/devstack-with-nested-kvm.rst @@ -50,7 +50,7 @@ the host: parm: nested:bool Start your VM, now it should have KVM capabilities -- you can verify -that by ensuring `/dev/kvm` character device is present. +that by ensuring ``/dev/kvm`` character device is present. Configure Nested KVM for AMD-based Machines @@ -73,7 +73,7 @@ back: :: sudo rmmod kvm-amd - sudo sh -c "echo 'options amd nested=1' >> /etc/modprobe.d/dist.conf" + sudo sh -c "echo 'options kvm-amd nested=1' >> /etc/modprobe.d/dist.conf" sudo modprobe kvm-amd Ensure the Nested KVM Kernel module parameter for AMD is enabled on the @@ -88,7 +88,7 @@ host: parm: nested:int To make the above value persistent across reboots, add an entry in -/etc/modprobe.ddist.conf so it looks as below:: +/etc/modprobe.d/dist.conf so it looks as below:: cat /etc/modprobe.d/dist.conf options kvm-amd nested=y @@ -97,7 +97,7 @@ To make the above value persistent across reboots, add an entry in Expose Virtualization Extensions to DevStack VM ----------------------------------------------- -Edit the VM's libvirt XML configuration via `virsh` utility: +Edit the VM's libvirt XML configuration via ``virsh`` utility: :: @@ -115,10 +115,10 @@ Ensure DevStack VM is Using KVM ------------------------------- Before invoking ``stack.sh`` in the VM, ensure that KVM is enabled. This -can be verified by checking for the presence of the file `/dev/kvm` in +can be verified by checking for the presence of the file ``/dev/kvm`` in your VM. If it is present, DevStack will default to using the config -attribute `virt_type = kvm` in `/etc/nova.conf`; otherwise, it'll fall -back to `virt_type=qemu`, i.e. plain QEMU emulation. +attribute ``virt_type = kvm`` in ``/etc/nova.conf``; otherwise, it'll fall +back to ``virt_type=qemu``, i.e. plain QEMU emulation. Optionally, to explicitly set the type of virtualization, to KVM, by the libvirt driver in nova, the below config attribute can be used in @@ -131,7 +131,7 @@ DevStack's ``local.conf``: Once DevStack is configured successfully, verify if the Nova instances are using KVM by noticing the QEMU CLI invoked by Nova is using the -parameter `accel=kvm`, e.g.: +parameter ``accel=kvm``, e.g.: :: diff --git a/doc/source/guides/lxc.rst b/doc/source/guides/lxc.rst new file mode 100644 index 0000000000..9549ed2974 --- /dev/null +++ b/doc/source/guides/lxc.rst @@ -0,0 +1,164 @@ +================================ +All-In-One Single LXC Container +================================ + +This guide walks you through the process of deploying OpenStack using devstack +in an LXC container instead of a VM. + +The primary benefits to running devstack inside a container instead of a VM is +faster performance and lower memory overhead while still providing a suitable +level of isolation. This can be particularly useful when you want to simulate +running OpenStack on multiple nodes. + +.. Warning:: Containers do not provide the same level of isolation as a virtual + machine. + +.. Note:: Not all OpenStack features support running inside of a container. See + `Limitations`_ section below for details. :doc:`OpenStack in a VM ` + is recommended for beginners. + +Prerequisites +============== + +This guide is written for Ubuntu 14.04 but should be adaptable for any modern +Linux distribution. + +Install the LXC package:: + + sudo apt-get install lxc + +You can verify support for containerization features in your currently running +kernel using the ``lxc-checkconfig`` command. + +Container Setup +=============== + +Configuration +--------------- + +For a successful run of ``stack.sh`` and to permit use of KVM to run the VMs you +launch inside your container, we need to use the following additional +configuration options. Place the following in a file called +``devstack-lxc.conf``:: + + # Permit access to /dev/loop* + lxc.cgroup.devices.allow = b 7:* rwm + + # Setup access to /dev/net/tun and /dev/kvm + lxc.mount.entry = /dev/net/tun dev/net/tun none bind,create=file 0 0 + lxc.mount.entry = /dev/kvm dev/kvm none bind,create=file 0 0 + + # Networking + lxc.network.type = veth + lxc.network.flags = up + lxc.network.link = lxcbr0 + + +Create Container +------------------- + +The configuration and rootfs for LXC containers are created using the +``lxc-create`` command. + +We will name our container ``devstack`` and use the ``ubuntu`` template which +will use ``debootstrap`` to build a Ubuntu rootfs. It will default to the same +release and architecture as the host system. We also install the additional +packages ``bsdmainutils`` and ``git`` as we'll need them to run devstack:: + + sudo lxc-create -n devstack -t ubuntu -f devstack-lxc.conf -- --packages=bsdmainutils,git + +The first time it builds the rootfs will take a few minutes to download, unpack, +and configure all the necessary packages for a minimal installation of Ubuntu. +LXC will cache this and subsequent containers will only take seconds to create. + +.. Note:: To speed up the initial rootfs creation, you can specify a mirror to + download the Ubuntu packages from by appending ``--mirror=`` and then the URL + of a Ubuntu mirror. To see other other template options, you can run + ``lxc-create -t ubuntu -h``. + +Start Container +---------------- + +To start the container, run:: + + sudo lxc-start -n devstack + +A moment later you should be presented with the login prompt for your container. +You can login using the username ``ubuntu`` and password ``ubuntu``. + +You can also ssh into your container. On your host, run +``sudo lxc-info -n devstack`` to get the IP address (e.g. +``ssh ubuntu@$(sudo lxc-info -n devstack | awk '/IP/ { print $2 }')``). + +Run Devstack +------------- + +You should now be logged into your container and almost ready to run devstack. +The commands in this section should all be run inside your container. + +.. Tip:: You can greatly reduce the runtime of your initial devstack setup by + ensuring you have your apt sources.list configured to use a fast mirror. + Check and update ``/etc/apt/sources.list`` if necessary and then run + ``apt-get update``. + +#. Download DevStack + + :: + + git clone https://git.openstack.org/openstack-dev/devstack + +#. Configure + + Refer to :ref:`minimal-configuration` if you wish to configure the behaviour + of devstack. + +#. Start the install + + :: + + cd devstack + ./stack.sh + +Cleanup +------- + +To stop the container:: + + lxc-stop -n devstack + +To delete the container:: + + lxc-destroy -n devstack + +Limitations +============ + +Not all OpenStack features may function correctly or at all when ran from within +a container. + +Cinder +------- + +Unable to create LVM backed volume +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + In our configuration, we have not whitelisted access to device-mapper or LVM + devices. Doing so will permit your container to have access and control of LVM + on the host system. To enable, add the following to your + ``devstack-lxc.conf`` before running ``lxc-create``:: + + lxc.cgroup.devices.allow = c 10:236 rwm + lxc.cgroup.devices.allow = b 252:* rwm + + Additionally you'll need to set ``udev_rules = 0`` in the ``activation`` + section of ``/etc/lvm/lvm.conf`` unless you mount devtmpfs in your container. + +Unable to attach volume to instance +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + It is not possible to attach cinder volumes to nova instances due to parts of + the Linux iSCSI implementation not being network namespace aware. This can be + worked around by using network pass-through instead of a separate network + namespace but such a setup significantly reduces the isolation of the + container (e.g. a ``halt`` command issued in the container will cause the host + system to shutdown). diff --git a/doc/source/guides/multinode-lab.rst b/doc/source/guides/multinode-lab.rst index b2617c9f17..b4e2891c10 100644 --- a/doc/source/guides/multinode-lab.rst +++ b/doc/source/guides/multinode-lab.rst @@ -73,8 +73,7 @@ Otherwise create the stack user: :: - groupadd stack - useradd -g stack -s /bin/bash -d /opt/stack -m stack + useradd -s /bin/bash -d /opt/stack -m stack This user will be making many changes to your system during installation and operation so it needs to have sudo privileges to root without a @@ -128,10 +127,9 @@ cluster controller's DevStack in ``local.conf``: MULTI_HOST=1 LOGFILE=/opt/stack/logs/stack.sh.log ADMIN_PASSWORD=labstack - MYSQL_PASSWORD=supersecret - RABBIT_PASSWORD=supersecrete - SERVICE_PASSWORD=supersecrete - SERVICE_TOKEN=xyzpdqlazydog + DATABASE_PASSWORD=supersecret + RABBIT_PASSWORD=supersecret + SERVICE_PASSWORD=supersecret In the multi-node configuration the first 10 or so IPs in the private subnet are usually reserved. Add this to ``local.sh`` to have it run @@ -169,21 +167,25 @@ machines, create a ``local.conf`` with: MULTI_HOST=1 LOGFILE=/opt/stack/logs/stack.sh.log ADMIN_PASSWORD=labstack - MYSQL_PASSWORD=supersecret - RABBIT_PASSWORD=supersecrete - SERVICE_PASSWORD=supersecrete - SERVICE_TOKEN=xyzpdqlazydog + DATABASE_PASSWORD=supersecret + RABBIT_PASSWORD=supersecret + SERVICE_PASSWORD=supersecret DATABASE_TYPE=mysql SERVICE_HOST=192.168.42.11 - MYSQL_HOST=192.168.42.11 - RABBIT_HOST=192.168.42.11 - GLANCE_HOSTPORT=192.168.42.11:9292 - ENABLED_SERVICES=n-cpu,n-net,n-api,c-sch,c-api,c-vol + MYSQL_HOST=$SERVICE_HOST + RABBIT_HOST=$SERVICE_HOST + GLANCE_HOSTPORT=$SERVICE_HOST:9292 + ENABLED_SERVICES=n-cpu,q-agt,n-api-meta,c-vol,placement-client NOVA_VNC_ENABLED=True - NOVNCPROXY_URL="http://192.168.42.11:6080/vnc_auto.html" + NOVNCPROXY_URL="http://$SERVICE_HOST:6080/vnc_auto.html" VNCSERVER_LISTEN=$HOST_IP VNCSERVER_PROXYCLIENT_ADDRESS=$VNCSERVER_LISTEN +**Note:** the ``n-api-meta`` service is a version of the api server +that only serves the metadata service. It's needed because the +computes created won't have a routing path to the metadata service on +the controller. + Fire up OpenStack: :: @@ -195,6 +197,22 @@ A stream of activity ensues. When complete you will see a summary of to poke at your shiny new OpenStack. The most recent log file is available in ``stack.sh.log``. +Starting in the Ocata release, Nova requires a `Cells v2`_ deployment. Compute +node services must be mapped to a cell before they can be used. + +After each compute node is stacked, verify it shows up in the +``nova service-list --binary nova-compute`` output. The compute service is +registered in the cell database asynchronously so this may require polling. + +Once the compute node services shows up, run the ``./tools/discover_hosts.sh`` +script from the control node to map compute hosts to the single cell. + +The compute service running on the primary control node will be +discovered automatically when the control node is stacked so this really +only needs to be performed for subnodes. + +.. _Cells v2: https://docs.openstack.org/nova/latest/user/cells.html + Cleaning Up After DevStack -------------------------- @@ -251,19 +269,19 @@ for scripting: # Add a user and project NAME=bob - PASSWORD=BigSecrete + PASSWORD=BigSecret PROJECT=$NAME openstack project create $PROJECT openstack user create $NAME --password=$PASSWORD --project $PROJECT openstack role add Member --user $NAME --project $PROJECT # The Member role is created by stack.sh - # openstack role list + # openstack role assignment list Swift ----- Swift, OpenStack Object Storage, requires a significant amount of resources -and is disabled by default in DevStack. The support in DevStack is geared +and is disabled by default in DevStack. The support in DevStack is geared toward a minimal installation but can be used for testing. To implement a true multi-node test of swift, additional steps will be required. Enabling it is as simple as enabling the ``swift`` service in ``local.conf``: @@ -291,10 +309,10 @@ created inside OpenStack. The size can be overridden by setting ``stack-volumes`` can be pre-created on any physical volume supported by Linux's LVM. The name of the volume group can be changed by setting -``VOLUME_GROUP`` in ``localrc``. ``stack.sh`` deletes all logical -volumes in ``VOLUME_GROUP`` that begin with ``VOLUME_NAME_PREFIX`` as +``VOLUME_GROUP_NAME`` in ``localrc``. ``stack.sh`` deletes all logical +volumes in ``VOLUME_GROUP_NAME`` that begin with ``VOLUME_NAME_PREFIX`` as part of cleaning up from previous runs. It is recommended to not use the -root volume group as ``VOLUME_GROUP``. +root volume group as ``VOLUME_GROUP_NAME``. The details of creating the volume group depends on the server hardware involved but looks something like this: @@ -370,3 +388,47 @@ If you forgot to set the root password you can do this: :: mysqladmin -u root -pnova password 'supersecret' + +Live Migration +-------------- + +In order for live migration to work with the default live migration URI:: + + [libvirt] + live_migration_uri = qemu+ssh://stack@%s/system + +SSH keys need to be exchanged between each compute node: + +1. The SOURCE root user's public RSA key (likely in /root/.ssh/id_rsa.pub) + needs to be in the DESTINATION stack user's authorized_keys file + (~stack/.ssh/authorized_keys). This can be accomplished by manually + copying the contents from the file on the SOURCE to the DESTINATION. If + you have a password configured for the stack user, then you can use the + following command to accomplish the same thing:: + + ssh-copy-id -i /root/.ssh/id_rsa.pub stack@DESTINATION + +2. The DESTINATION host's public ECDSA key (/etc/ssh/ssh_host_ecdsa_key.pub) + needs to be in the SOURCE root user's known_hosts file + (/root/.ssh/known_hosts). This can be accomplished by running the + following on the SOURCE machine (hostname must be used):: + + ssh-keyscan -H DEST_HOSTNAME | sudo tee -a /root/.ssh/known_hosts + +3. Verify that login via ssh works without a password:: + + ssh -i /root/.ssh/id_rsa.pub stack@DESTINATION + +In essence, this means that every compute node's root user's public RSA key +must exist in every other compute node's stack user's authorized_keys file and +every compute node's public ECDSA key needs to be in every other compute +node's root user's known_hosts file. Please note that if the root or stack +user does not have a SSH key, one can be generated using:: + + ssh-keygen -t rsa + +The above steps are necessary because libvirtd runs as root when the +live_migration_uri uses the "qemu:///system" family of URIs. For more +information, see the `libvirt documentation`_. + +.. _libvirt documentation: https://libvirt.org/drvqemu.html#securitydriver diff --git a/doc/source/guides/neutron.rst b/doc/source/guides/neutron.rst index 3030c7b5f2..12c6d6902d 100644 --- a/doc/source/guides/neutron.rst +++ b/doc/source/guides/neutron.rst @@ -5,131 +5,251 @@ Using DevStack with neutron Networking This guide will walk you through using OpenStack neutron with the ML2 plugin and the Open vSwitch mechanism driver. -Network Interface Configuration -=============================== -To use neutron, it is suggested that two network interfaces be present -in the host operating system. +.. _single-interface-ovs: -The first interface, eth0 is used for the OpenStack management (API, -message bus, etc) as well as for ssh for an administrator to access -the machine. +Using Neutron with a Single Interface +===================================== -:: +In some instances, like on a developer laptop, there is only one +network interface that is available. In this scenario, the physical +interface is added to the Open vSwitch bridge, and the IP address of +the laptop is migrated onto the bridge interface. That way, the +physical interface can be used to transmit self service project +network traffic, the OpenStack API traffic, and management traffic. - stack@compute:~$ ifconfig eth0 - eth0 Link encap:Ethernet HWaddr bc:16:65:20:af:fc - inet addr:192.168.1.18 -eth1 is manually configured at boot to not have an IP address. -Consult your operating system documentation for the appropriate -technique. For Ubuntu, the contents of `/etc/network/interfaces` -contains: +.. warning:: -:: + When using a single interface networking setup, there will be a + temporary network outage as your IP address is moved from the + physical NIC of your machine, to the OVS bridge. If you are SSH'd + into the machine from another computer, there is a risk of being + disconnected from your ssh session (due to arp cache + invalidation), which would stop the stack.sh or leave it in an + unfinished state. In these cases, start stack.sh inside its own + screen session so it can continue to run. - auto eth1 - iface eth1 inet manual - up ifconfig $IFACE 0.0.0.0 up - down ifconfig $IFACE 0.0.0.0 down -The second physical interface, eth1 is added to a bridge (in this case -named br-ex), which is used to forward network traffic from guest VMs. -Network traffic from eth1 on the compute nodes is then NAT'd by the -controller node that runs Neutron's `neutron-l3-agent` and provides L3 -connectivity. +Physical Network Setup +---------------------- -:: - - stack@compute:~$ sudo ovs-vsctl add-br br-ex - stack@compute:~$ sudo ovs-vsctl add-port br-ex eth1 - stack@compute:~$ sudo ovs-vsctl show - 9a25c837-32ab-45f6-b9f2-1dd888abcf0f - Bridge br-ex - Port br-ex - Interface br-ex - type: internal - Port phy-br-ex - Interface phy-br-ex - type: patch - options: {peer=int-br-ex} - Port "eth1" - Interface "eth1" +In most cases where DevStack is being deployed with a single +interface, there is a hardware router that is being used for external +connectivity and DHCP. The developer machine is connected to this +network and is on a shared subnet with other machines. The +`local.conf` exhibited here assumes that 1500 is a reasonable MTU to +use on that network. +.. nwdiag:: + nwdiag { + inet [ shape = cloud ]; + router; + inet -- router; + network hardware_network { + address = "172.18.161.0/24" + router [ address = "172.18.161.1" ]; + devstack-1 [ address = "172.18.161.6" ]; + } + } -Disabling Next Generation Firewall Tools -======================================== -DevStack does not properly operate with modern firewall tools. Specifically -it will appear as if the guest VM can access the external network via ICMP, -but UDP and TCP packets will not be delivered to the guest VM. The root cause -of the issue is that both ufw (Uncomplicated Firewall) and firewalld (Fedora's -firewall manager) apply firewall rules to all interfaces in the system, rather -then per-device. One solution to this problem is to revert to iptables -functionality. +DevStack Configuration +---------------------- -To get a functional firewall configuration for Fedora do the following: +The following is a complete `local.conf` for the host named +`devstack-1`. It will run all the API and services, as well as +serving as a hypervisor for guest instances. :: - sudo service iptables save - sudo systemctl disable firewalld - sudo systemctl enable iptables - sudo systemctl stop firewalld - sudo systemctl start iptables + [[local|localrc]] + HOST_IP=172.18.161.6 + SERVICE_HOST=172.18.161.6 + MYSQL_HOST=172.18.161.6 + RABBIT_HOST=172.18.161.6 + GLANCE_HOSTPORT=172.18.161.6:9292 + ADMIN_PASSWORD=secret + DATABASE_PASSWORD=secret + RABBIT_PASSWORD=secret + SERVICE_PASSWORD=secret + ## Neutron options + Q_USE_SECGROUP=True + FLOATING_RANGE="172.18.161.0/24" + IPV4_ADDRS_SAFE_TO_USE="10.0.0.0/22" + Q_FLOATING_ALLOCATION_POOL=start=172.18.161.250,end=172.18.161.254 + PUBLIC_NETWORK_GATEWAY="172.18.161.1" + PUBLIC_INTERFACE=eth0 + + # Open vSwitch provider networking configuration + Q_USE_PROVIDERNET_FOR_PUBLIC=True + OVS_PHYSICAL_BRIDGE=br-ex + PUBLIC_BRIDGE=br-ex + OVS_BRIDGE_MAPPINGS=public:br-ex -To get a functional firewall configuration for distributions containing ufw, -disable ufw. Note ufw is generally not enabled by default in Ubuntu. To -disable ufw if it was enabled, do the following: -:: +Adding Additional Compute Nodes +------------------------------- - sudo service iptables save - sudo ufw disable +Let's suppose that after installing DevStack on the first host, you +also want to do multinode testing and networking. +Physical Network Setup +~~~~~~~~~~~~~~~~~~~~~~ +.. nwdiag:: + nwdiag { + inet [ shape = cloud ]; + router; + inet -- router; -Neutron Networking with Open vSwitch -==================================== + network hardware_network { + address = "172.18.161.0/24" + router [ address = "172.18.161.1" ]; + devstack-1 [ address = "172.18.161.6" ]; + devstack-2 [ address = "172.18.161.7" ]; + } + } -Configuring neutron, OpenStack Networking in DevStack is very similar to -configuring `nova-network` - many of the same configuration variables -(like `FIXED_RANGE` and `FLOATING_RANGE`) used by `nova-network` are -used by neutron, which is intentional. -The only difference is the disabling of `nova-network` in your -local.conf, and the enabling of the neutron components. +After DevStack installs and configures Neutron, traffic from guest VMs +flows out of `devstack-2` (the compute node) and is encapsulated in a +VXLAN tunnel back to `devstack-1` (the control node) where the L3 +agent is running. +:: -Configuration -------------- + stack@devstack-2:~/devstack$ sudo ovs-vsctl show + 8992d965-0ba0-42fd-90e9-20ecc528bc29 + Bridge br-int + fail_mode: secure + Port br-int + Interface br-int + type: internal + Port patch-tun + Interface patch-tun + type: patch + options: {peer=patch-int} + Bridge br-tun + fail_mode: secure + Port "vxlan-c0a801f6" + Interface "vxlan-c0a801f6" + type: vxlan + options: {df_default="true", in_key=flow, local_ip="172.18.161.7", out_key=flow, remote_ip="172.18.161.6"} + Port patch-int + Interface patch-int + type: patch + options: {peer=patch-tun} + Port br-tun + Interface br-tun + type: internal + ovs_version: "2.0.2" + +Open vSwitch on the control node, where the L3 agent runs, is +configured to de-encapsulate traffic from compute nodes, then forward +it over the `br-ex` bridge, where `eth0` is attached. :: - FIXED_RANGE=10.0.0.0/24 - FLOATING_RANGE=192.168.27.0/24 - PUBLIC_NETWORK_GATEWAY=192.168.27.2 + stack@devstack-1:~/devstack$ sudo ovs-vsctl show + 422adeea-48d1-4a1f-98b1-8e7239077964 + Bridge br-tun + fail_mode: secure + Port br-tun + Interface br-tun + type: internal + Port patch-int + Interface patch-int + type: patch + options: {peer=patch-tun} + Port "vxlan-c0a801d8" + Interface "vxlan-c0a801d8" + type: vxlan + options: {df_default="true", in_key=flow, local_ip="172.18.161.6", out_key=flow, remote_ip="172.18.161.7"} + Bridge br-ex + Port phy-br-ex + Interface phy-br-ex + type: patch + options: {peer=int-br-ex} + Port "eth0" + Interface "eth0" + Port br-ex + Interface br-ex + type: internal + Bridge br-int + fail_mode: secure + Port "tapce66332d-ea" + tag: 1 + Interface "tapce66332d-ea" + type: internal + Port "qg-65e5a4b9-15" + tag: 2 + Interface "qg-65e5a4b9-15" + type: internal + Port "qr-33e5e471-88" + tag: 1 + Interface "qr-33e5e471-88" + type: internal + Port "qr-acbe9951-70" + tag: 1 + Interface "qr-acbe9951-70" + type: internal + Port br-int + Interface br-int + type: internal + Port patch-tun + Interface patch-tun + type: patch + options: {peer=patch-int} + Port int-br-ex + Interface int-br-ex + type: patch + options: {peer=phy-br-ex} + ovs_version: "2.0.2" + +`br-int` is a bridge that the Open vSwitch mechanism driver creates, +which is used as the "integration bridge" where ports are created, and +plugged into the virtual switching fabric. `br-ex` is an OVS bridge +that is used to connect physical ports (like `eth0`), so that floating +IP traffic for project networks can be received from the physical +network infrastructure (and the internet), and routed to self service +project network ports. `br-tun` is a tunnel bridge that is used to +connect OpenStack nodes (like `devstack-2`) together. This bridge is +used so that project network traffic, using the VXLAN tunneling +protocol, flows between each compute node where project instances run. + + + +DevStack Compute Configuration +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The host `devstack-2` has a very minimal `local.conf`. - disable_service n-net - enable_service q-svc - enable_service q-agt - enable_service q-dhcp - enable_service q-meta - enable_service q-l3 +:: - Q_USE_SECGROUP=True - ENABLE_TENANT_VLANS=True - TENANT_VLAN_RANGE=1000:1999 - PHYSICAL_NETWORK=default - OVS_PHYSICAL_BRIDGE=br-ex + [[local|localrc]] + HOST_IP=172.18.161.7 + SERVICE_HOST=172.18.161.6 + MYSQL_HOST=172.18.161.6 + RABBIT_HOST=172.18.161.6 + GLANCE_HOSTPORT=172.18.161.6:9292 + ADMIN_PASSWORD=secret + MYSQL_PASSWORD=secret + RABBIT_PASSWORD=secret + SERVICE_PASSWORD=secret + + ## Neutron options + PUBLIC_INTERFACE=eth0 + ENABLED_SERVICES=n-cpu,rabbit,q-agt,placement-client + +Network traffic from `eth0` on the compute nodes is then NAT'd by the +controller node that runs Neutron's `neutron-l3-agent` and provides L3 +connectivity. -In this configuration we are defining FLOATING_RANGE to be a -subnet that exists in the private RFC1918 address space - however in -in a real setup FLOATING_RANGE would be a public IP address range. Neutron Networking with Open vSwitch and Provider Networks ========================================================== @@ -145,6 +265,76 @@ given a VLAN tag and IP address range, so that instances created via DevStack will use the external router for L3 connectivity, as opposed to the neutron L3 service. +Physical Network Setup +---------------------- + +.. nwdiag:: + + nwdiag { + inet [ shape = cloud ]; + router; + inet -- router; + + network provider_net { + address = "203.0.113.0/24" + router [ address = "203.0.113.1" ]; + controller; + compute1; + compute2; + } + + network control_plane { + router [ address = "10.0.0.1" ] + address = "10.0.0.0/24" + controller [ address = "10.0.0.2" ] + compute1 [ address = "10.0.0.3" ] + compute2 [ address = "10.0.0.4" ] + } + } + + +On a compute node, the first interface, eth0 is used for the OpenStack +management (API, message bus, etc) as well as for ssh for an +administrator to access the machine. + +:: + + stack@compute:~$ ifconfig eth0 + eth0 Link encap:Ethernet HWaddr bc:16:65:20:af:fc + inet addr:10.0.0.3 + +eth1 is manually configured at boot to not have an IP address. +Consult your operating system documentation for the appropriate +technique. For Ubuntu, the contents of `/etc/network/interfaces` +contains: + +:: + + auto eth1 + iface eth1 inet manual + up ifconfig $IFACE 0.0.0.0 up + down ifconfig $IFACE 0.0.0.0 down + +The second physical interface, eth1 is added to a bridge (in this case +named br-ex), which is used to forward network traffic from guest VMs. + +:: + + stack@compute:~$ sudo ovs-vsctl add-br br-ex + stack@compute:~$ sudo ovs-vsctl add-port br-ex eth1 + stack@compute:~$ sudo ovs-vsctl show + 9a25c837-32ab-45f6-b9f2-1dd888abcf0f + Bridge br-ex + Port br-ex + Interface br-ex + type: internal + Port phy-br-ex + Interface phy-br-ex + type: patch + options: {peer=int-br-ex} + Port "eth1" + Interface "eth1" + Service Configuration --------------------- @@ -159,19 +349,31 @@ nova, neutron) **Compute Nodes** In this example, the nodes that will host guest instances will run -the `neutron-openvswitch-agent` for network connectivity, as well as -the compute service `nova-compute`. +the ``neutron-openvswitch-agent`` for network connectivity, as well as +the compute service ``nova-compute``. DevStack Configuration ---------------------- +.. _ovs-provider-network-controller: + The following is a snippet of the DevStack configuration on the controller node. :: + HOST_IP=10.0.0.2 + SERVICE_HOST=10.0.0.2 + MYSQL_HOST=10.0.0.2 + RABBIT_HOST=10.0.0.2 + GLANCE_HOSTPORT=10.0.0.2:9292 PUBLIC_INTERFACE=eth1 + ADMIN_PASSWORD=secret + MYSQL_PASSWORD=secret + RABBIT_PASSWORD=secret + SERVICE_PASSWORD=secret + ## Neutron options Q_USE_SECGROUP=True ENABLE_TENANT_VLANS=True @@ -180,50 +382,253 @@ controller node. OVS_PHYSICAL_BRIDGE=br-ex Q_USE_PROVIDER_NETWORKING=True - Q_L3_ENABLED=False - - # Do not use Nova-Network - disable_service n-net - # Neutron - ENABLED_SERVICES+=,q-svc,q-dhcp,q-meta,q-agt + disable_service q-l3 ## Neutron Networking options used to create Neutron Subnets - FIXED_RANGE="10.1.1.0/24" + IPV4_ADDRS_SAFE_TO_USE="203.0.113.0/24" + NETWORK_GATEWAY=203.0.113.1 PROVIDER_SUBNET_NAME="provider_net" PROVIDER_NETWORK_TYPE="vlan" SEGMENTATION_ID=2010 + USE_SUBNETPOOL=False -In this configuration we are defining FIXED_RANGE to be a -subnet that exists in the private RFC1918 address space - however -in a real setup FIXED_RANGE would be a public IP address range, so -that you could access your instances from the public internet. +In this configuration we are defining IPV4_ADDRS_SAFE_TO_USE to be a +publicly routed IPv4 subnet. In this specific instance we are using +the special TEST-NET-3 subnet defined in `RFC 5737 `_, +which is used for documentation. In your DevStack setup, IPV4_ADDRS_SAFE_TO_USE +would be a public IP address range that you or your organization has +allocated to you, so that you could access your instances from the +public internet. -The following is a snippet of the DevStack configuration on the -compute node. +The following is the DevStack configuration on +compute node 1. :: + HOST_IP=10.0.0.3 + SERVICE_HOST=10.0.0.2 + MYSQL_HOST=10.0.0.2 + RABBIT_HOST=10.0.0.2 + GLANCE_HOSTPORT=10.0.0.2:9292 + ADMIN_PASSWORD=secret + MYSQL_PASSWORD=secret + RABBIT_PASSWORD=secret + SERVICE_PASSWORD=secret + # Services that a compute node runs ENABLED_SERVICES=n-cpu,rabbit,q-agt - ## Neutron options - Q_USE_SECGROUP=True - ENABLE_TENANT_VLANS=True - TENANT_VLAN_RANGE=3001:4000 + ## Open vSwitch provider networking options PHYSICAL_NETWORK=default OVS_PHYSICAL_BRIDGE=br-ex PUBLIC_INTERFACE=eth1 Q_USE_PROVIDER_NETWORKING=True - Q_L3_ENABLED=False + +Compute node 2's configuration will be exactly the same, except +``HOST_IP`` will be ``10.0.0.4`` When DevStack is configured to use provider networking (via -`Q_USE_PROVIDER_NETWORKING` is True and `Q_L3_ENABLED` is False) - +``Q_USE_PROVIDER_NETWORKING`` is True) - DevStack will automatically add the network interface defined in -`PUBLIC_INTERFACE` to the `OVS_PHYSICAL_BRIDGE` +``PUBLIC_INTERFACE`` to the ``OVS_PHYSICAL_BRIDGE`` For example, with the above configuration, a bridge is -created, named `br-ex` which is managed by Open vSwitch, and the -second interface on the compute node, `eth1` is attached to the +created, named ``br-ex`` which is managed by Open vSwitch, and the +second interface on the compute node, ``eth1`` is attached to the bridge, to forward traffic sent by guest VMs. + +Miscellaneous Tips +================== + +Non-Standard MTU on the Physical Network +---------------------------------------- + +Neutron by default uses a MTU of 1500 bytes, which is +the standard MTU for Ethernet. + +A different MTU can be specified by adding the following to +the Neutron section of `local.conf`. For example, +if you have network equipment that supports jumbo frames, you could +set the MTU to 9000 bytes by adding the following + +:: + + [[post-config|/$Q_PLUGIN_CONF_FILE]] + global_physnet_mtu = 9000 + + +Disabling Next Generation Firewall Tools +---------------------------------------- + +DevStack does not properly operate with modern firewall tools. Specifically +it will appear as if the guest VM can access the external network via ICMP, +but UDP and TCP packets will not be delivered to the guest VM. The root cause +of the issue is that both ufw (Uncomplicated Firewall) and firewalld (Fedora's +firewall manager) apply firewall rules to all interfaces in the system, rather +then per-device. One solution to this problem is to revert to iptables +functionality. + +To get a functional firewall configuration for Fedora do the following: + +:: + + sudo service iptables save + sudo systemctl disable firewalld + sudo systemctl enable iptables + sudo systemctl stop firewalld + sudo systemctl start iptables + + +To get a functional firewall configuration for distributions containing ufw, +disable ufw. Note ufw is generally not enabled by default in Ubuntu. To +disable ufw if it was enabled, do the following: + +:: + + sudo service iptables save + sudo ufw disable + +Configuring Extension Drivers for the ML2 Plugin +------------------------------------------------ + +Extension drivers for the ML2 plugin are set with the variable +``Q_ML2_PLUGIN_EXT_DRIVERS``, and includes the 'port_security' extension +by default. If you want to remove all the extension drivers (even +'port_security'), set ``Q_ML2_PLUGIN_EXT_DRIVERS`` to blank. + + +Using Linux Bridge instead of Open vSwitch +------------------------------------------ + +The configuration for using the Linux Bridge ML2 driver is fairly +straight forward. The Linux Bridge configuration for DevStack is similar +to the :ref:`Open vSwitch based single interface ` +setup, with small modifications for the interface mappings. + + +:: + + [[local|localrc]] + HOST_IP=172.18.161.6 + SERVICE_HOST=172.18.161.6 + MYSQL_HOST=172.18.161.6 + RABBIT_HOST=172.18.161.6 + GLANCE_HOSTPORT=172.18.161.6:9292 + ADMIN_PASSWORD=secret + DATABASE_PASSWORD=secret + RABBIT_PASSWORD=secret + SERVICE_PASSWORD=secret + + ## Neutron options + Q_USE_SECGROUP=True + FLOATING_RANGE="172.18.161.0/24" + IPV4_ADDRS_SAFE_TO_USE="10.0.0.0/24" + Q_FLOATING_ALLOCATION_POOL=start=172.18.161.250,end=172.18.161.254 + PUBLIC_NETWORK_GATEWAY="172.18.161.1" + PUBLIC_INTERFACE=eth0 + + Q_USE_PROVIDERNET_FOR_PUBLIC=True + + # Linuxbridge Settings + Q_AGENT=linuxbridge + LB_PHYSICAL_INTERFACE=eth0 + PUBLIC_PHYSICAL_NETWORK=default + LB_INTERFACE_MAPPINGS=default:eth0 + +Using MacVTap instead of Open vSwitch +------------------------------------------ + +Security groups are not supported by the MacVTap agent. Due to that, devstack +configures the NoopFirewall driver on the compute node. + +MacVTap agent does not support l3, dhcp and metadata agent. Due to that you can +chose between the following deployment scenarios: + +Single node with provider networks using config drive and external l3, dhcp +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +This scenario applies, if l3 and dhcp services are provided externally, or if +you do not require them. + + +:: + + [[local|localrc]] + HOST_IP=10.0.0.2 + SERVICE_HOST=10.0.0.2 + MYSQL_HOST=10.0.0.2 + RABBIT_HOST=10.0.0.2 + ADMIN_PASSWORD=secret + MYSQL_PASSWORD=secret + RABBIT_PASSWORD=secret + SERVICE_PASSWORD=secret + + Q_ML2_PLUGIN_MECHANISM_DRIVERS=macvtap + Q_USE_PROVIDER_NETWORKING=True + + enable_plugin neutron git://git.openstack.org/openstack/neutron + + ## MacVTap agent options + Q_AGENT=macvtap + PHYSICAL_NETWORK=default + + IPV4_ADDRS_SAFE_TO_USE="203.0.113.0/24" + NETWORK_GATEWAY=203.0.113.1 + PROVIDER_SUBNET_NAME="provider_net" + PROVIDER_NETWORK_TYPE="vlan" + SEGMENTATION_ID=2010 + USE_SUBNETPOOL=False + + [[post-config|/$Q_PLUGIN_CONF_FILE]] + [macvtap] + physical_interface_mappings = $PHYSICAL_NETWORK:eth1 + + [[post-config|$NOVA_CONF]] + force_config_drive = True + + +Multi node with MacVTap compute node +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +This scenario applies, if you require OpenStack provided l3, dhcp or metadata +services. Those are hosted on a separate controller and network node, running +some other l2 agent technology (in this example Open vSwitch). This node needs +to be configured for VLAN tenant networks. + +For OVS, a similar configuration like described in the +:ref:`OVS Provider Network ` section can be +used. Just add the following line to this local.conf, which also loads +the MacVTap mechanism driver: + +:: + + [[local|localrc]] + ... + Q_ML2_PLUGIN_MECHANISM_DRIVERS=openvswitch,linuxbridge,macvtap + ... + +For the MacVTap compute node, use this local.conf: + +:: + + HOST_IP=10.0.0.3 + SERVICE_HOST=10.0.0.2 + MYSQL_HOST=10.0.0.2 + RABBIT_HOST=10.0.0.2 + ADMIN_PASSWORD=secret + MYSQL_PASSWORD=secret + RABBIT_PASSWORD=secret + SERVICE_PASSWORD=secret + + # Services that a compute node runs + disable_all_services + enable_plugin neutron git://git.openstack.org/openstack/neutron + ENABLED_SERVICES+=n-cpu,q-agt + + ## MacVTap agent options + Q_AGENT=macvtap + PHYSICAL_NETWORK=default + + [[post-config|/$Q_PLUGIN_CONF_FILE]] + [macvtap] + physical_interface_mappings = $PHYSICAL_NETWORK:eth1 diff --git a/doc/source/guides/nova.rst b/doc/source/guides/nova.rst index a91e0d194c..0f105d7c58 100644 --- a/doc/source/guides/nova.rst +++ b/doc/source/guides/nova.rst @@ -13,7 +13,7 @@ In Juno, nova implemented a `spec `_ to allow read/write access to the serial console of an instance via `nova-serialproxy -`_. +`_. The service can be enabled by adding ``n-sproxy`` to ``ENABLED_SERVICES``. Further options can be enabled via @@ -62,11 +62,9 @@ The service can be enabled by adding ``n-sproxy`` to Enabling the service is enough to be functional for a single machine DevStack. -These config options are defined in `nova.console.serial -`_ -and `nova.cmd.serialproxy -`_. +These config options are defined in `nova.conf.serial_console +`_. For more information on OpenStack configuration see the `OpenStack -Configuration Reference -`_ +Compute Service Configuration Reference +`_ diff --git a/doc/source/guides/single-machine.rst b/doc/source/guides/single-machine.rst index 236ece9c01..168172c630 100644 --- a/doc/source/guides/single-machine.rst +++ b/doc/source/guides/single-machine.rst @@ -45,31 +45,37 @@ We need to add a user to install DevStack. (if you created a user during install you can skip this step and just give the user sudo privileges below) -:: +.. code-block:: console - adduser stack + $ sudo useradd -s /bin/bash -d /opt/stack -m stack Since this user will be making many changes to your system, it will need to have sudo privileges: -:: +.. code-block:: console - apt-get install sudo -y || yum install -y sudo - echo "stack ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers + $ apt-get install sudo -y || yum install -y sudo + $ echo "stack ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers + +.. note:: On some systems you may need to use ``sudo visudo``. From here on you should use the user you created. **Logout** and -**login** as that user. +**login** as that user: + +.. code-block:: console + + $ sudo su stack && cd ~ Download DevStack ----------------- We'll grab the latest version of DevStack via https: -:: +.. code-block:: console - sudo apt-get install git -y || sudo yum install -y git - git clone https://git.openstack.org/openstack-dev/devstack - cd devstack + $ sudo apt-get install git -y || sudo yum install -y git + $ git clone https://git.openstack.org/openstack-dev/devstack + $ cd devstack Run DevStack ------------ @@ -97,7 +103,7 @@ do the following: ``local.conf`` should look something like this: -:: +.. code-block:: ini [[local|localrc]] FLOATING_RANGE=192.168.1.224/27 @@ -105,16 +111,18 @@ do the following: FIXED_NETWORK_SIZE=256 FLAT_INTERFACE=eth0 ADMIN_PASSWORD=supersecret - MYSQL_PASSWORD=iheartdatabases + DATABASE_PASSWORD=iheartdatabases RABBIT_PASSWORD=flopsymopsy SERVICE_PASSWORD=iheartksl - SERVICE_TOKEN=xyzpdqlazydog + +.. note:: There is a sample :download:`local.conf ` file + under the *samples* directory in the devstack repository. Run DevStack: -:: +.. code-block:: console - ./stack.sh + $ ./stack.sh A seemingly endless stream of activity ensues. When complete you will see a summary of ``stack.sh``'s work, including the relevant URLs, @@ -128,7 +136,3 @@ computers on the local network. In this example that would be http://192.168.1.201/ for the dashboard (aka Horizon). Launch VMs and if you give them floating IPs and security group access those VMs will be accessible from other machines on your network. - -Some examples of using the OpenStack command-line clients ``nova`` and -``glance`` are in the shakedown scripts in ``devstack/exercises``. -``exercise.sh`` will run all of those scripts and report on the results. diff --git a/doc/source/guides/single-vm.rst b/doc/source/guides/single-vm.rst index c2ce1a34a0..45b8f2dd89 100644 --- a/doc/source/guides/single-vm.rst +++ b/doc/source/guides/single-vm.rst @@ -64,10 +64,9 @@ passed as the user-data file when booting the VM. cd devstack echo '[[local|localrc]]' > local.conf echo ADMIN_PASSWORD=password >> local.conf - echo MYSQL_PASSWORD=password >> local.conf + echo DATABASE_PASSWORD=password >> local.conf echo RABBIT_PASSWORD=password >> local.conf echo SERVICE_PASSWORD=password >> local.conf - echo SERVICE_TOKEN=tokentoken >> local.conf ./stack.sh path: /home/stack/start.sh permissions: 0755 @@ -78,6 +77,11 @@ passed as the user-data file when booting the VM. As DevStack will refuse to run as root, this configures ``cloud-init`` to create a non-root user and run the ``start.sh`` script as that user. +If you are using cloud-init and you have not +`enabled custom logging <../configuration.html#enable-logging>`_ of the stack +output, then the stack output can be found in +``/var/log/cloud-init-output.log`` by default. + Launching By Hand ----------------- diff --git a/doc/source/index.rst b/doc/source/index.rst index e0c3f3a5d6..6c42a5b4e9 100644 --- a/doc/source/index.rst +++ b/doc/source/index.rst @@ -1,244 +1,162 @@ -DevStack - an OpenStack Community Production -============================================ +.. Documentation Architecture for the devstack docs. -.. image:: assets/images/logo-blue.png - -.. toctree:: - :glob: - :maxdepth: 1 - - overview - configuration - plugins - faq - changes - hacking - -Quick Start ------------ + It is really easy for online docs to meander over time as people + attempt to add the small bit of additional information they think + people need, into an existing information architecture. In order to + prevent that we need to be a bit strict as to what's on this front + page. -#. Select a Linux Distribution + This should *only* be the quick start narrative. Which should end + with 2 sections: what you can do with devstack once it's set up, + and how to go beyond this setup. Both should be a set of quick + links to other documents to let people explore from there. - Only Ubuntu 14.04 (Trusty), Fedora 20 and CentOS/RHEL 7 are - documented here. OpenStack also runs and is packaged on other flavors - of Linux such as OpenSUSE and Debian. +========== + DevStack +========== -#. Install Selected OS +.. image:: assets/images/logo-blue.png - In order to correctly install all the dependencies, we assume a - specific minimal version of the supported distributions to make it as - easy as possible. We recommend using a minimal install of Ubuntu or - Fedora server in a VM if this is your first time. +DevStack is a series of extensible scripts used to quickly bring up a +complete OpenStack environment based on the latest versions of +everything from git master. It is used interactively as a development +environment and as the basis for much of the OpenStack project's +functional testing. -#. Download DevStack +The source is available at +``__. - :: +.. warning:: - git clone https://git.openstack.org/openstack-dev/devstack + DevStack will make substantial changes to your system during + installation. Only run DevStack on servers or virtual machines that + are dedicated to this purpose. - The ``devstack`` repo contains a script that installs OpenStack and - templates for configuration files +Quick Start +=========== -#. Configure +Install Linux +------------- - We recommend at least a :ref:`minimal-configuration` be set up. +Start with a clean and minimal install of a Linux system. Devstack +attempts to support the two latest LTS releases of Ubuntu, the +latest/current Fedora version, CentOS/RHEL 7, as well as Debian and +OpenSUSE. -#. Start the install +If you do not have a preference, Ubuntu 16.04 is the most tested, and +will probably go the smoothest. - :: +Add Stack User +-------------- - cd devstack; ./stack.sh +Devstack should be run as a non-root user with sudo enabled +(standard logins to cloud images such as "ubuntu" or "cloud-user" +are usually fine). - It takes a few minutes, we recommend `reading the - script `__ while it is building. +You can quickly create a separate `stack` user to run DevStack with -Guides -====== +.. code-block:: console -Walk through various setups used by stackers + $ sudo useradd -s /bin/bash -d /opt/stack -m stack -.. toctree:: - :glob: - :maxdepth: 1 +Since this user will be making many changes to your system, it should +have sudo privileges: - guides/single-vm - guides/single-machine - guides/multinode-lab - guides/neutron - guides/devstack-with-nested-kvm - guides/nova - guides/devstack-with-lbaas-v2 +.. code-block:: console -All-In-One Single VM --------------------- + $ echo "stack ALL=(ALL) NOPASSWD: ALL" | sudo tee /etc/sudoers.d/stack + $ sudo su - stack -Run :doc:`OpenStack in a VM `. The VMs launched in your cloud will be slow as -they are running in QEMU (emulation), but it is useful if you don't have -spare hardware laying around. :doc:`[Read] ` +Download DevStack +----------------- -All-In-One Single Machine -------------------------- +.. code-block:: console -Run :doc:`OpenStack on dedicated hardware ` This can include a -server-class machine or a laptop at home. -:doc:`[Read] ` + $ git clone https://git.openstack.org/openstack-dev/devstack + $ cd devstack -Multi-Node Lab --------------- +The ``devstack`` repo contains a script that installs OpenStack and +templates for configuration files -Setup a :doc:`multi-node cluster ` with dedicated VLANs for VMs & Management. -:doc:`[Read] ` +Create a local.conf +------------------- -DevStack with Neutron Networking --------------------------------- +Create a ``local.conf`` file with 4 passwords preset at the root of the +devstack git repo. -Building a DevStack cluster with :doc:`Neutron Networking `. -This guide is meant for building lab environments with a dedicated -control node and multiple compute nodes. +.. code-block:: ini -DevStack with KVM-based Nested Virtualization ---------------------------------------------- + [[local|localrc]] + ADMIN_PASSWORD=secret + DATABASE_PASSWORD=$ADMIN_PASSWORD + RABBIT_PASSWORD=$ADMIN_PASSWORD + SERVICE_PASSWORD=$ADMIN_PASSWORD -Procedure to setup :doc:`DevStack with KVM-based Nested Virtualization -`. With this setup, Nova instances -will be more performant than with plain QEMU emulation. +This is the minimum required config to get started with DevStack. -Nova and devstack --------------------------------- +.. note:: There is a sample :download:`local.conf ` file + under the *samples* directory in the devstack repository. -Guide to working with nova features :doc:`Nova and devstack `. +Start the install +----------------- -DevStack Documentation -====================== +.. code-block:: console -Overview --------- + $ ./stack.sh -:doc:`An overview of DevStack goals and priorities ` +This will take a 15 - 20 minutes, largely depending on the speed of +your internet connection. Many git trees and packages will be +installed during this process. -Configuration -------------- +Profit! +------- -:doc:`Configuring and customizing the stack ` +You now have a working DevStack! Congrats! -Plugins -------- +Your devstack will have installed ``keystone``, ``glance``, ``nova``, +``cinder``, ``neutron``, and ``horizon``. Floating IPs will be +available, guests have access to the external world. -:doc:`Extending DevStack with new features ` +You can access horizon to experience the web interface to +OpenStack, and manage vms, networks, volumes, and images from +there. -Recent Changes --------------- +You can ``source openrc`` in your shell, and then use the +``openstack`` command line tool to manage your devstack. -:doc:`An incomplete summary of recent changes ` +You can ``cd /opt/stack/tempest`` and run tempest tests that have +been configured to work with your devstack. -FAQ ---- +You can :doc:`make code changes to OpenStack and validate them +`. -:doc:`The DevStack FAQ ` +Going further +------------- -Contributing ------------- +Learn more about our :doc:`configuration system ` to +customize devstack for your needs. Including making adjustments to the +default :doc:`networking `. -:doc:`Pitching in to make DevStack a better place ` +Read :doc:`guides ` for specific setups people have (note: +guides are point in time contributions, and may not always be kept +up to date to the latest devstack). -Code -==== +Enable :doc:`devstack plugins ` to support additional +services, features, and configuration not present in base devstack. -*A look at the bits that make it all go* +Use devstack in your CI with :doc:`Ansible roles ` and +:doc:`Jobs ` for Zuul V3. Migrate your devstack Zuul V2 jobs to Zuul +V3 with this full migration :doc:`how-to `. -Scripts -------- +Get :doc:`the big picture ` of what we are trying to do +with devstack, and help us by :doc:`contributing to the project +`. -* `stack.sh `__ - The main script -* `functions `__ - DevStack-specific functions -* `functions-common `__ - Functions shared with other projects -* `lib/apache `__ -* `lib/ceilometer `__ -* `lib/ceph `__ -* `lib/cinder `__ -* `lib/database `__ -* `lib/dstat `__ -* `lib/glance `__ -* `lib/heat `__ -* `lib/horizon `__ -* `lib/infra `__ -* `lib/ironic `__ -* `lib/keystone `__ -* `lib/ldap `__ -* `lib/neutron-legacy `__ -* `lib/nova `__ -* `lib/oslo `__ -* `lib/rpc\_backend `__ -* `lib/sahara `__ -* `lib/swift `__ -* `lib/tempest `__ -* `lib/tls `__ -* `lib/zaqar `__ -* `unstack.sh `__ -* `clean.sh `__ -* `run\_tests.sh `__ - -* `extras.d/50-ironic.sh `__ -* `extras.d/60-ceph.sh `__ -* `extras.d/70-sahara.sh `__ -* `extras.d/70-tuskar.sh `__ -* `extras.d/70-zaqar.sh `__ -* `extras.d/80-tempest.sh `__ - -* `inc/ini-config `__ -* `inc/meta-config `__ -* `inc/python `__ - -* `pkg/elasticsearch.sh `_ - -Configuration -------------- +Contents +-------- .. toctree:: :glob: - :maxdepth: 1 - - local.conf - stackrc - openrc - exerciserc - eucarc - -Tools ------ - -* `tools/build\_docs.sh `__ -* `tools/build\_venv.sh `__ -* `tools/build\_wheels.sh `__ -* `tools/create-stack-user.sh `__ -* `tools/create\_userrc.sh `__ -* `tools/fixup\_stuff.sh `__ -* `tools/info.sh `__ -* `tools/install\_pip.sh `__ -* `tools/install\_prereqs.sh `__ -* `tools/make\_cert.sh `__ -* `tools/upload\_image.sh `__ - -Samples -------- + :maxdepth: 2 -* `local.sh `__ - -Exercises ---------- - -* `exercise.sh `__ -* `exercises/aggregates.sh `__ -* `exercises/boot\_from\_volume.sh `__ -* `exercises/bundle.sh `__ -* `exercises/client-args.sh `__ -* `exercises/client-env.sh `__ -* `exercises/euca.sh `__ -* `exercises/floating\_ips.sh `__ -* `exercises/horizon.sh `__ -* `exercises/neutron-adv-test.sh `__ -* `exercises/sahara.sh `__ -* `exercises/sec\_groups.sh `__ -* `exercises/swift.sh `__ -* `exercises/volumes.sh `__ -* `exercises/zaqar.sh `__ + * diff --git a/doc/source/local.conf.rst b/doc/source/local.conf.rst deleted file mode 100644 index a1ca60a75d..0000000000 --- a/doc/source/local.conf.rst +++ /dev/null @@ -1,9 +0,0 @@ -========================== -local.conf - User Settings -========================== - -``local.conf`` is a user-maintained settings file that is sourced in -``stackrc``. It contains a section that replaces the historical -``localrc`` file. See the description of -:doc:`local.conf ` for more details about the mechanics -of the file. diff --git a/doc/source/networking.rst b/doc/source/networking.rst new file mode 100644 index 0000000000..74010cd01a --- /dev/null +++ b/doc/source/networking.rst @@ -0,0 +1,116 @@ +===================== + DevStack Networking +===================== + +An important part of the DevStack experience is networking that works +by default for created guests. This might not be optimal for your +particular testing environment, so this document tries its best to +explain what's going on. + +Defaults +======== + +If you don't specify any configuration you will get the following: + +* neutron (including l3 with openvswitch) +* private project networks for each openstack project +* a floating ip range of 172.24.4.0/24 with the gateway of 172.24.4.1 +* the demo project configured with fixed ips on a subnet allocated from + the 10.0.0.0/22 range +* a ``br-ex`` interface controlled by neutron for all its networking + (this is not connected to any physical interfaces). +* DNS resolution for guests based on the resolv.conf for your host +* an ip masq rule that allows created guests to route out + +This creates an environment which is isolated to the single +host. Guests can get to the external network for package +updates. Tempest tests will work in this environment. + +.. note:: + + By default all OpenStack environments have security group rules + which block all inbound packets to guests. If you want to be able + to ssh / ping your created guests you should run the following. + + .. code-block:: bash + + openstack security group rule create --proto icmp --dst-port 0 default + openstack security group rule create --proto tcp --dst-port 22 default + +Locally Accessible Guests +========================= + +If you want to make you guests accessible from other machines on your +network, we have to connect ``br-ex`` to a physical interface. + +Dedicated Guest Interface +------------------------- + +If you have 2 or more interfaces on your devstack server, you can +allocate an interface to neutron to fully manage. This **should not** +be the same interface you use to ssh into the devstack server itself. + +This is done by setting with the ``PUBLIC_INTERFACE`` attribute. + +.. code-block:: bash + + [[local|localrc]] + PUBLIC_INTERFACE=eth1 + +That will put all layer 2 traffic from your guests onto the main +network. When running in this mode the ip masq rule is **not** added +in your devstack, you are responsible for making routing work on your +local network. + +Shared Guest Interface +---------------------- + +.. warning:: + + This is not a recommended configuration. Because of interactions + between ovs and bridging, if you reboot your box with active + networking you may lose network connectivity to your system. + +If you need your guests accessible on the network, but only have 1 +interface (using something like a NUC), you can share your one +network. But in order for this to work you need to manually set a lot +of addresses, and have them all exactly correct. + +.. code-block:: bash + + [[local|localrc]] + PUBLIC_INTERFACE=eth0 + HOST_IP=10.42.0.52 + FLOATING_RANGE=10.42.0.52/24 + PUBLIC_NETWORK_GATEWAY=10.42.0.1 + Q_FLOATING_ALLOCATION_POOL=start=10.42.0.250,end=10.42.0.254 + +In order for this scenario to work the floating ip network must match +the default networking on your server. This breaks HOST_IP detection, +as we exclude the floating range by default, so you have to specify +that manually. + +The ``PUBLIC_NETWORK_GATEWAY`` is the gateway that server would normally +use to get off the network. ``Q_FLOATING_ALLOCATION_POOL`` controls +the range of floating ips that will be handed out. As we are sharing +your existing network, you'll want to give it a slice that your local +dhcp server is not allocating. Otherwise you could easily have +conflicting ip addresses, and cause havoc with your local network. + + +Private Network Addressing +========================== + +The private networks addresses are controlled by the ``IPV4_ADDRS_SAFE_TO_USE`` +and the ``IPV6_ADDRS_SAFE_TO_USE`` variables. This allows users to specify one +single variable of safe internal IPs to use that will be referenced whether or +not subnetpools are in use. + +For IPv4, ``FIXED_RANGE`` and ``SUBNETPOOL_PREFIX_V4`` will just default to +the value of ``IPV4_ADDRS_SAFE_TO_USE`` directly. + +For IPv6, ``FIXED_RANGE_V6`` will default to the first /64 of the value of +``IPV6_ADDRS_SAFE_TO_USE``. If ``IPV6_ADDRS_SAFE_TO_USE`` is /64 or smaller, +``FIXED_RANGE_V6`` will just use the value of that directly. +``SUBNETPOOL_PREFIX_V6`` will just default to the value of +``IPV6_ADDRS_SAFE_TO_USE`` directly. diff --git a/doc/source/openrc.rst b/doc/source/openrc.rst deleted file mode 100644 index 0b090c77b7..0000000000 --- a/doc/source/openrc.rst +++ /dev/null @@ -1,68 +0,0 @@ -===================================== -openrc - User Authentication Settings -===================================== - -``openrc`` configures login credentials suitable for use with the -OpenStack command-line tools. ``openrc`` sources ``stackrc`` at the -beginning (which in turn sources the ``localrc`` section of -``local.conf``) in order to pick up ``HOST_IP`` and/or ``SERVICE_HOST`` -to use in the endpoints. The values shown below are the default values. - -OS\_PROJECT\_NAME (OS\_TENANT\_NAME) - Keystone has - standardized the term *project* as the entity that owns resources. In - some places references still exist to the previous term - *tenant* for this use. Also, *project\_name* is preferred to - *project\_id*. OS\_TENANT\_NAME remains supported for compatibility - with older tools. - - :: - - OS_PROJECT_NAME=demo - -OS\_USERNAME - In addition to the owning entity (project), OpenStack calls the entity - performing the action *user*. - - :: - - OS_USERNAME=demo - -OS\_PASSWORD - Keystone's default authentication requires a password be provided. - The usual cautions about putting passwords in environment variables - apply, for most DevStack uses this may be an acceptable tradeoff. - - :: - - OS_PASSWORD=secrete - -HOST\_IP, SERVICE\_HOST - Set API endpoint host using ``HOST_IP``. ``SERVICE_HOST`` may also - be used to specify the endpoint, which is convenient for some - ``local.conf`` configurations. Typically, ``HOST_IP`` is set in the - ``localrc`` section. - - :: - - HOST_IP=127.0.0.1 - SERVICE_HOST=$HOST_IP - -OS\_AUTH\_URL - Authenticating against an OpenStack cloud using Keystone returns a - *Token* and *Service Catalog*. The catalog contains the endpoints - for all services the user/tenant has access to - including Nova, - Glance, Keystone and Swift. - - :: - - OS_AUTH_URL=http://$SERVICE_HOST:5000/v2.0 - -KEYSTONECLIENT\_DEBUG, NOVACLIENT\_DEBUG - Set command-line client log level to ``DEBUG``. These are commented - out by default. - - :: - - # export KEYSTONECLIENT_DEBUG=1 - # export NOVACLIENT_DEBUG=1 diff --git a/doc/source/overview.rst b/doc/source/overview.rst index d245035a1a..2479cd0bc8 100644 --- a/doc/source/overview.rst +++ b/doc/source/overview.rst @@ -20,11 +20,11 @@ Base OS *The OpenStack Technical Committee (TC) has defined the current CI strategy to include the latest Ubuntu release and the latest RHEL -release (for Python 2.6 testing).* +release.* - Ubuntu: current LTS release plus current development release - Fedora: current release plus previous release -- RHEL: current major release +- RHEL/CentOS: current major release - Other OS platforms may continue to be included but the maintenance of those platforms shall not be assumed simply due to their presence. Having a listed point-of-contact for each additional OS will greatly @@ -38,7 +38,6 @@ Databases *As packaged by the host OS* - MySQL -- PostgreSQL Queues ------ @@ -46,7 +45,6 @@ Queues *As packaged by the host OS* - Rabbit -- Qpid Web Server ---------- @@ -58,9 +56,6 @@ Web Server OpenStack Network ----------------- -*Defaults to nova network, optionally use neutron* - -- Nova Network: FlatDHCP - Neutron: A basic configuration approximating the original FlatDHCP mode using linuxbridge or OpenVSwitch. @@ -68,9 +63,8 @@ Services -------- The default services configured by DevStack are Identity (keystone), -Object Storage (swift), Image Service (glance), Block Storage (cinder), -Compute (nova), Networking (nova), Dashboard (horizon), Orchestration -(heat) +Object Storage (swift), Image Service (glance), Block Storage +(cinder), Compute (nova), Networking (neutron), Dashboard (horizon) Additional services not included directly in DevStack can be tied in to ``stack.sh`` using the :doc:`plugin mechanism ` to call @@ -80,13 +74,4 @@ Node Configurations ------------------- - single node -- multi-node is not tested regularly by the core team, and even then - only minimal configurations are reviewed - -Exercises ---------- - -The DevStack exercise scripts are no longer used as integration and gate -testing as that job has transitioned to Tempest. They are still -maintained as a demonstrations of using OpenStack from the command line -and for quick operational testing. +- multi-node configurations as are tested by the gate diff --git a/doc/source/plugin-registry.rst b/doc/source/plugin-registry.rst new file mode 100644 index 0000000000..02d6911d4b --- /dev/null +++ b/doc/source/plugin-registry.rst @@ -0,0 +1,202 @@ +.. Note to patch submitters: + + # ============================= # + # THIS FILE IS AUTOGENERATED ! # + # ============================= # + + ** Plugins are found automatically and added to this list ** + + This file is created by a periodic proposal job. You should not + edit this file. + + You should edit the files data/devstack-plugins-registry.footer + data/devstack-plugins-registry.header to modify this text. + +========================== + DevStack Plugin Registry +========================== + +The following list is an automatically-generated collection of +available DevStack plugins. This includes, but is not limited to, +official OpenStack projects. + + +====================================== === +Plugin Name URL +====================================== === +almanach `git://git.openstack.org/openstack/almanach `__ +aodh `git://git.openstack.org/openstack/aodh `__ +apmec `git://git.openstack.org/openstack/apmec `__ +barbican `git://git.openstack.org/openstack/barbican `__ +bilean `git://git.openstack.org/openstack/bilean `__ +blazar `git://git.openstack.org/openstack/blazar `__ +broadview-collector `git://git.openstack.org/openstack/broadview-collector `__ +castellan-ui `git://git.openstack.org/openstack/castellan-ui `__ +ceilometer `git://git.openstack.org/openstack/ceilometer `__ +ceilometer-powervm `git://git.openstack.org/openstack/ceilometer-powervm `__ +cloudkitty `git://git.openstack.org/openstack/cloudkitty `__ +collectd-openstack-plugins `git://git.openstack.org/openstack/collectd-openstack-plugins `__ +congress `git://git.openstack.org/openstack/congress `__ +cyborg `git://git.openstack.org/openstack/cyborg `__ +designate `git://git.openstack.org/openstack/designate `__ +devstack-plugin-additional-pkg-repos `git://git.openstack.org/openstack/devstack-plugin-additional-pkg-repos `__ +devstack-plugin-amqp1 `git://git.openstack.org/openstack/devstack-plugin-amqp1 `__ +devstack-plugin-bdd `git://git.openstack.org/openstack/devstack-plugin-bdd `__ +devstack-plugin-ceph `git://git.openstack.org/openstack/devstack-plugin-ceph `__ +devstack-plugin-container `git://git.openstack.org/openstack/devstack-plugin-container `__ +devstack-plugin-glusterfs `git://git.openstack.org/openstack/devstack-plugin-glusterfs `__ +devstack-plugin-hdfs `git://git.openstack.org/openstack/devstack-plugin-hdfs `__ +devstack-plugin-kafka `git://git.openstack.org/openstack/devstack-plugin-kafka `__ +devstack-plugin-libvirt-qemu `git://git.openstack.org/openstack/devstack-plugin-libvirt-qemu `__ +devstack-plugin-mariadb `git://git.openstack.org/openstack/devstack-plugin-mariadb `__ +devstack-plugin-nfs `git://git.openstack.org/openstack/devstack-plugin-nfs `__ +devstack-plugin-pika `git://git.openstack.org/openstack/devstack-plugin-pika `__ +devstack-plugin-sheepdog `git://git.openstack.org/openstack/devstack-plugin-sheepdog `__ +devstack-plugin-vmax `git://git.openstack.org/openstack/devstack-plugin-vmax `__ +devstack-plugin-zmq `git://git.openstack.org/openstack/devstack-plugin-zmq `__ +dragonflow `git://git.openstack.org/openstack/dragonflow `__ +drbd-devstack `git://git.openstack.org/openstack/drbd-devstack `__ +ec2-api `git://git.openstack.org/openstack/ec2-api `__ +freezer `git://git.openstack.org/openstack/freezer `__ +freezer-api `git://git.openstack.org/openstack/freezer-api `__ +freezer-tempest-plugin `git://git.openstack.org/openstack/freezer-tempest-plugin `__ +freezer-web-ui `git://git.openstack.org/openstack/freezer-web-ui `__ +gce-api `git://git.openstack.org/openstack/gce-api `__ +glare `git://git.openstack.org/openstack/glare `__ +group-based-policy `git://git.openstack.org/openstack/group-based-policy `__ +gyan `git://git.openstack.org/openstack/gyan `__ +heat `git://git.openstack.org/openstack/heat `__ +heat-dashboard `git://git.openstack.org/openstack/heat-dashboard `__ +horizon-mellanox `git://git.openstack.org/openstack/horizon-mellanox `__ +ironic `git://git.openstack.org/openstack/ironic `__ +ironic-inspector `git://git.openstack.org/openstack/ironic-inspector `__ +ironic-staging-drivers `git://git.openstack.org/openstack/ironic-staging-drivers `__ +ironic-ui `git://git.openstack.org/openstack/ironic-ui `__ +karbor `git://git.openstack.org/openstack/karbor `__ +karbor-dashboard `git://git.openstack.org/openstack/karbor-dashboard `__ +keystone `git://git.openstack.org/openstack/keystone `__ +kingbird `git://git.openstack.org/openstack/kingbird `__ +kuryr-kubernetes `git://git.openstack.org/openstack/kuryr-kubernetes `__ +kuryr-libnetwork `git://git.openstack.org/openstack/kuryr-libnetwork `__ +kuryr-tempest-plugin `git://git.openstack.org/openstack/kuryr-tempest-plugin `__ +magnum `git://git.openstack.org/openstack/magnum `__ +magnum-ui `git://git.openstack.org/openstack/magnum-ui `__ +manila `git://git.openstack.org/openstack/manila `__ +manila-ui `git://git.openstack.org/openstack/manila-ui `__ +masakari `git://git.openstack.org/openstack/masakari `__ +meteos `git://git.openstack.org/openstack/meteos `__ +meteos-ui `git://git.openstack.org/openstack/meteos-ui `__ +mistral `git://git.openstack.org/openstack/mistral `__ +mixmatch `git://git.openstack.org/openstack/mixmatch `__ +mogan `git://git.openstack.org/openstack/mogan `__ +mogan-ui `git://git.openstack.org/openstack/mogan-ui `__ +monasca-analytics `git://git.openstack.org/openstack/monasca-analytics `__ +monasca-api `git://git.openstack.org/openstack/monasca-api `__ +monasca-ceilometer `git://git.openstack.org/openstack/monasca-ceilometer `__ +monasca-events-api `git://git.openstack.org/openstack/monasca-events-api `__ +monasca-log-api `git://git.openstack.org/openstack/monasca-log-api `__ +monasca-tempest-plugin `git://git.openstack.org/openstack/monasca-tempest-plugin `__ +monasca-transform `git://git.openstack.org/openstack/monasca-transform `__ +murano `git://git.openstack.org/openstack/murano `__ +networking-6wind `git://git.openstack.org/openstack/networking-6wind `__ +networking-ansible `git://git.openstack.org/openstack/networking-ansible `__ +networking-arista `git://git.openstack.org/openstack/networking-arista `__ +networking-bagpipe `git://git.openstack.org/openstack/networking-bagpipe `__ +networking-baremetal `git://git.openstack.org/openstack/networking-baremetal `__ +networking-bgpvpn `git://git.openstack.org/openstack/networking-bgpvpn `__ +networking-brocade `git://git.openstack.org/openstack/networking-brocade `__ +networking-calico `git://git.openstack.org/openstack/networking-calico `__ +networking-cisco `git://git.openstack.org/openstack/networking-cisco `__ +networking-cumulus `git://git.openstack.org/openstack/networking-cumulus `__ +networking-dpm `git://git.openstack.org/openstack/networking-dpm `__ +networking-fortinet `git://git.openstack.org/openstack/networking-fortinet `__ +networking-generic-switch `git://git.openstack.org/openstack/networking-generic-switch `__ +networking-hpe `git://git.openstack.org/openstack/networking-hpe `__ +networking-huawei `git://git.openstack.org/openstack/networking-huawei `__ +networking-hyperv `git://git.openstack.org/openstack/networking-hyperv `__ +networking-infoblox `git://git.openstack.org/openstack/networking-infoblox `__ +networking-l2gw `git://git.openstack.org/openstack/networking-l2gw `__ +networking-lagopus `git://git.openstack.org/openstack/networking-lagopus `__ +networking-midonet `git://git.openstack.org/openstack/networking-midonet `__ +networking-mlnx `git://git.openstack.org/openstack/networking-mlnx `__ +networking-nec `git://git.openstack.org/openstack/networking-nec `__ +networking-odl `git://git.openstack.org/openstack/networking-odl `__ +networking-onos `git://git.openstack.org/openstack/networking-onos `__ +networking-opencontrail `git://git.openstack.org/openstack/networking-opencontrail `__ +networking-ovn `git://git.openstack.org/openstack/networking-ovn `__ +networking-ovs-dpdk `git://git.openstack.org/openstack/networking-ovs-dpdk `__ +networking-plumgrid `git://git.openstack.org/openstack/networking-plumgrid `__ +networking-powervm `git://git.openstack.org/openstack/networking-powervm `__ +networking-sfc `git://git.openstack.org/openstack/networking-sfc `__ +networking-spp `git://git.openstack.org/openstack/networking-spp `__ +networking-vpp `git://git.openstack.org/openstack/networking-vpp `__ +networking-vsphere `git://git.openstack.org/openstack/networking-vsphere `__ +neutron `git://git.openstack.org/openstack/neutron `__ +neutron-classifier `git://git.openstack.org/openstack/neutron-classifier `__ +neutron-dynamic-routing `git://git.openstack.org/openstack/neutron-dynamic-routing `__ +neutron-fwaas `git://git.openstack.org/openstack/neutron-fwaas `__ +neutron-fwaas-dashboard `git://git.openstack.org/openstack/neutron-fwaas-dashboard `__ +neutron-lbaas `git://git.openstack.org/openstack/neutron-lbaas `__ +neutron-lbaas-dashboard `git://git.openstack.org/openstack/neutron-lbaas-dashboard `__ +neutron-tempest-plugin `git://git.openstack.org/openstack/neutron-tempest-plugin `__ +neutron-vpnaas `git://git.openstack.org/openstack/neutron-vpnaas `__ +neutron-vpnaas-dashboard `git://git.openstack.org/openstack/neutron-vpnaas-dashboard `__ +nova-dpm `git://git.openstack.org/openstack/nova-dpm `__ +nova-lxd `git://git.openstack.org/openstack/nova-lxd `__ +nova-mksproxy `git://git.openstack.org/openstack/nova-mksproxy `__ +nova-powervm `git://git.openstack.org/openstack/nova-powervm `__ +oaktree `git://git.openstack.org/openstack/oaktree `__ +octavia `git://git.openstack.org/openstack/octavia `__ +octavia-dashboard `git://git.openstack.org/openstack/octavia-dashboard `__ +omni `git://git.openstack.org/openstack/omni `__ +openstacksdk `git://git.openstack.org/openstack/openstacksdk `__ +os-xenapi `git://git.openstack.org/openstack/os-xenapi `__ +osprofiler `git://git.openstack.org/openstack/osprofiler `__ +oswin-tempest-plugin `git://git.openstack.org/openstack/oswin-tempest-plugin `__ +panko `git://git.openstack.org/openstack/panko `__ +patrole `git://git.openstack.org/openstack/patrole `__ +picasso `git://git.openstack.org/openstack/picasso `__ +qinling `git://git.openstack.org/openstack/qinling `__ +qinling-dashboard `git://git.openstack.org/openstack/qinling-dashboard `__ +rally `git://git.openstack.org/openstack/rally `__ +rally-openstack `git://git.openstack.org/openstack/rally-openstack `__ +sahara `git://git.openstack.org/openstack/sahara `__ +sahara-dashboard `git://git.openstack.org/openstack/sahara-dashboard `__ +scalpels `git://git.openstack.org/openstack/scalpels `__ +searchlight `git://git.openstack.org/openstack/searchlight `__ +searchlight-ui `git://git.openstack.org/openstack/searchlight-ui `__ +senlin `git://git.openstack.org/openstack/senlin `__ +slogging `git://git.openstack.org/openstack/slogging `__ +solum `git://git.openstack.org/openstack/solum `__ +stackube `git://git.openstack.org/openstack/stackube `__ +storlets `git://git.openstack.org/openstack/storlets `__ +stx-config `git://git.openstack.org/openstack/stx-config `__ +stx-fault `git://git.openstack.org/openstack/stx-fault `__ +stx-integ `git://git.openstack.org/openstack/stx-integ `__ +stx-nfv `git://git.openstack.org/openstack/stx-nfv `__ +stx-update `git://git.openstack.org/openstack/stx-update `__ +tacker `git://git.openstack.org/openstack/tacker `__ +tap-as-a-service `git://git.openstack.org/openstack/tap-as-a-service `__ +tap-as-a-service-dashboard `git://git.openstack.org/openstack/tap-as-a-service-dashboard `__ +tatu `git://git.openstack.org/openstack/tatu `__ +telemetry-tempest-plugin `git://git.openstack.org/openstack/telemetry-tempest-plugin `__ +tobiko `git://git.openstack.org/openstack/tobiko `__ +tricircle `git://git.openstack.org/openstack/tricircle `__ +trio2o `git://git.openstack.org/openstack/trio2o `__ +trove `git://git.openstack.org/openstack/trove `__ +trove-dashboard `git://git.openstack.org/openstack/trove-dashboard `__ +valet `git://git.openstack.org/openstack/valet `__ +vitrage `git://git.openstack.org/openstack/vitrage `__ +vitrage-dashboard `git://git.openstack.org/openstack/vitrage-dashboard `__ +vitrage-tempest-plugin `git://git.openstack.org/openstack/vitrage-tempest-plugin `__ +vmware-nsx `git://git.openstack.org/openstack/vmware-nsx `__ +vmware-vspc `git://git.openstack.org/openstack/vmware-vspc `__ +watcher `git://git.openstack.org/openstack/watcher `__ +watcher-dashboard `git://git.openstack.org/openstack/watcher-dashboard `__ +zaqar `git://git.openstack.org/openstack/zaqar `__ +zaqar-ui `git://git.openstack.org/openstack/zaqar-ui `__ +zun `git://git.openstack.org/openstack/zun `__ +zun-ui `git://git.openstack.org/openstack/zun-ui `__ +====================================== === + + diff --git a/doc/source/plugins.rst b/doc/source/plugins.rst index c4ed2285cb..89b9381813 100644 --- a/doc/source/plugins.rst +++ b/doc/source/plugins.rst @@ -2,78 +2,126 @@ Plugins ======= -DevStack has a couple of plugin mechanisms to allow easily adding -support for additional projects and features. +The OpenStack ecosystem is wide and deep, and only growing more so +every day. The value of DevStack is that it's simple enough to +understand what it's doing clearly. And yet we'd like to support as +much of the OpenStack Ecosystem as possible. We do that with plugins. -Extras.d Hooks -============== +DevStack plugins are bits of bash code that live outside the DevStack +tree. They are called through a strong contract, so these plugins can +be sure that they will continue to work in the future as DevStack +evolves. -These hooks are an extension of the service calls in -``stack.sh`` at specific points in its run, plus ``unstack.sh`` and -``clean.sh``. A number of the higher-layer projects are implemented in -DevStack using this mechanism. +Prerequisites +============= -The script in ``extras.d`` is expected to be mostly a dispatcher to -functions in a ``lib/*`` script. The scripts are named with a -zero-padded two digits sequence number prefix to control the order that -the scripts are called, and with a suffix of ``.sh``. DevStack reserves -for itself the sequence numbers 00 through 09 and 90 through 99. +If you are planning to create a plugin that is going to host a service in the +service catalog (that is, your plugin will use the command +``get_or_create_service``) please make sure that you apply to the `service +types authority`_ to reserve a valid service-type. This will help to make sure +that all deployments of your service use the same service-type. -Below is a template that shows handlers for the possible command-line -arguments: +Plugin Interface +================ -:: +DevStack supports a standard mechanism for including plugins from +external repositories. The plugin interface assumes the following: - # template.sh - DevStack extras.d dispatch script template +An external git repository that includes a ``devstack/`` top level +directory. Inside this directory there can be 3 files. - # check for service enabled - if is_service_enabled template; then +- ``override-defaults`` - a file containing global variables that + will be sourced before the lib/* files. This allows the plugin + to override the defaults that are otherwise set in the lib/* + files. - if [[ "$1" == "source" ]]; then - # Initial source of lib script - source $TOP_DIR/lib/template - fi + For example, override-defaults may export CINDER_ENABLED_BACKENDS + to include the plugin-specific storage backend and thus be able + to override the default lvm only storage backend for Cinder. - if [[ "$1" == "stack" && "$2" == "pre-install" ]]; then - # Set up system services - echo_summary "Configuring system services Template" - install_package cowsay +- ``settings`` - a file containing global variables that will be + sourced very early in the process. This is helpful if other plugins + might depend on this one, and need access to global variables to do + their work. - elif [[ "$1" == "stack" && "$2" == "install" ]]; then - # Perform installation of service source - echo_summary "Installing Template" - install_template + Your settings should include any ``enable_service`` lines required + by your plugin. This is especially important if you are kicking off + services using ``run_process`` as it only works with enabled + services. - elif [[ "$1" == "stack" && "$2" == "post-config" ]]; then - # Configure after the other layer 1 and 2 services have been configured - echo_summary "Configuring Template" - configure_template + Be careful to allow users to override global-variables for + customizing their environment. Usually it is best to provide a + default value only if the variable is unset or empty; e.g. in bash + syntax ``FOO=${FOO:-default}``. - elif [[ "$1" == "stack" && "$2" == "extra" ]]; then - # Initialize and start the template service - echo_summary "Initializing Template" - ##init_template - fi + The file should include a ``define_plugin`` line to indicate the + plugin's name, which is the name that should be used by users on + "enable_plugin" lines. It should generally be the last component of + the git repo path (e.g., if the plugin's repo is + openstack/devstack-foo, then the name here should be "foo") :: - if [[ "$1" == "unstack" ]]; then - # Shut down template services - # no-op - : - fi + define_plugin - if [[ "$1" == "clean" ]]; then - # Remove state and transient data - # Remember clean.sh first calls unstack.sh - # no-op - : - fi - fi + If your plugin depends on another plugin, indicate it in this file + with one or more lines like the following:: + + plugin_requires + + For a complete example, if the plugin "foo" depends on "bar", the + ``settings`` file should include:: + + define_plugin foo + plugin_requires foo bar + + Devstack does not currently use this dependency information, so it's + important that users continue to add enable_plugin lines in the + correct order in ``local.conf``, however adding this information + allows other tools to consider dependency information when + automatically generating ``local.conf`` files. + +- ``plugin.sh`` - the actual plugin. It is executed by devstack at + well defined points during a ``stack.sh`` run. The plugin.sh + internal structure is discussed below. + + +Plugins are registered by adding the following to the localrc section +of ``local.conf``. + +They are added in the following format:: + + [[local|localrc]] + enable_plugin [GITREF] + +- ``name`` - an arbitrary name. (ex: glusterfs, docker, zaqar, congress) +- ``giturl`` - a valid git url that can be cloned +- ``gitref`` - an optional git ref (branch / ref / tag) that will be + cloned. Defaults to master. + +An example would be as follows:: + + enable_plugin ec2-api git://git.openstack.org/openstack/ec2-api + +plugin.sh contract +================== + +``plugin.sh`` is a bash script that will be called at specific points +during ``stack.sh``, ``unstack.sh``, and ``clean.sh``. It will be +called in the following way:: + + source $PATH/TO/plugin.sh [phase] -The arguments are: +``mode`` can be thought of as the major mode being called, currently +one of: ``stack``, ``unstack``, ``clean``. ``phase`` is used by modes +which have multiple points during their run where it's necessary to +be able to execute code. All existing ``mode`` and ``phase`` points +are considered **strong contracts** and won't be removed without a +reasonable deprecation period. Additional new ``mode`` or ``phase`` +points may be added at any time if we discover we need them to support +additional kinds of plugins in devstack. -- **source** - Called by each script that utilizes ``extras.d`` hooks; - this replaces directly sourcing the ``lib/*`` script. -- **stack** - Called by ``stack.sh`` three times for different phases +The current full list of ``mode`` and ``phase`` are: + +- **stack** - Called by ``stack.sh`` four times for different phases of its run: - **pre-install** - Called after system (OS) setup is complete and @@ -84,112 +132,98 @@ The arguments are: been configured. All configuration files for enabled services should exist at this point. - **extra** - Called near the end after layer 1 and 2 services have - been started. This is the existing hook and has not otherwise - changed. + been started. + - **test-config** - Called at the end of devstack used to configure tempest + or any other test environments - **unstack** - Called by ``unstack.sh`` before other services are shut down. - **clean** - Called by ``clean.sh`` before other services are cleaned, but after ``unstack.sh`` has been called. +Example plugin +==================== -Externally Hosted Plugins -========================= - -Based on the extras.d hooks, DevStack supports a standard mechansim -for including plugins from external repositories. The plugin interface -assumes the following: +An example plugin would look something as follows. -An external git repository that includes a ``devstack/`` top level -directory. Inside this directory there can be 2 files. +``devstack/settings``:: -- ``settings`` - a file containing global variables that will be - sourced very early in the process. This is helpful if other plugins - might depend on this one, and need access to global variables to do - their work. - - Your settings should include any ``enable_service`` lines required - by your plugin. This is especially important if you are kicking off - services using ``run_process`` as it only works with enabled - services. - - Be careful to allow users to override global-variables for - customizing their environment. Usually it is best to provide a - default value only if the variable is unset or empty; e.g. in bash - syntax ``FOO=${FOO:-default}``. + # settings file for template + enable_service template -- ``plugin.sh`` - the actual plugin. It will be executed by devstack - during it's run. The run order will be done in the registration - order for these plugins, and will occur immediately after all in - tree extras.d dispatch at the phase in question. The plugin.sh - looks like the extras.d dispatcher above. -Plugins are registered by adding the following to the localrc section -of ``local.conf``. +``devstack/plugin.sh``:: -They are added in the following format:: + # plugin.sh - DevStack plugin.sh dispatch script template - [[local|localrc]] - enable_plugin [GITREF] + function install_template { + ... + } -- ``name`` - an arbitrary name. (ex: glustfs, docker, zaqar, congress) -- ``giturl`` - a valid git url that can be cloned -- ``gitref`` - an optional git ref (branch / ref / tag) that will be - cloned. Defaults to master. + function init_template { + ... + } -An example would be as follows:: + function configure_template { + ... + } - enable_plugin ec2api git://git.openstack.org/stackforge/ec2api + # check for service enabled + if is_service_enabled template; then -Plugins for gate jobs ---------------------- + if [[ "$1" == "stack" && "$2" == "pre-install" ]]; then + # Set up system services + echo_summary "Configuring system services Template" + install_package cowsay -All OpenStack plugins that wish to be used as gate jobs need to exist -in OpenStack's gerrit. Both ``openstack`` namespace and ``stackforge`` -namespace are fine. This allows testing of the plugin as well as -provides network isolation against upstream git repository failures -(which we see often enough to be an issue). + elif [[ "$1" == "stack" && "$2" == "install" ]]; then + # Perform installation of service source + echo_summary "Installing Template" + install_template -Ideally plugins will be implemented as ``devstack`` directory inside -the project they are testing. For example, the stackforge/ec2-api -project has it's pluggin support in it's tree. + elif [[ "$1" == "stack" && "$2" == "post-config" ]]; then + # Configure after the other layer 1 and 2 services have been configured + echo_summary "Configuring Template" + configure_template -In the cases where there is no "project tree" per say (like -integrating a backend storage configuration such as ceph or glusterfs) -it's also allowed to build a dedicated -``stackforge/devstack-plugin-FOO`` project to house the plugin. + elif [[ "$1" == "stack" && "$2" == "extra" ]]; then + # Initialize and start the template service + echo_summary "Initializing Template" + init_template + fi -Note jobs must not require cloning of repositories during tests. -Tests must list their repository in the ``PROJECTS`` variable for -`devstack-gate -`_ -for the repository to be available to the test. Further information -is provided in the project creator's guide. + if [[ "$1" == "unstack" ]]; then + # Shut down template services + # no-op + : + fi -Hypervisor -========== + if [[ "$1" == "clean" ]]; then + # Remove state and transient data + # Remember clean.sh first calls unstack.sh + # no-op + : + fi + fi -Hypervisor plugins are fairly new and condense most hypervisor -configuration into one place. +Plugin Execution Order +====================== -The initial plugin implemented was for Docker support and is a useful -template for the required support. Plugins are placed in -``lib/nova_plugins`` and named ``hypervisor-`` where ```` is -the value of ``VIRT_DRIVER``. Plugins must define the following -functions: +Plugins are run after in tree services at each of the stages +above. For example, if you need something to happen before Keystone +starts, you should do that at the ``post-config`` phase. -- ``install_nova_hypervisor`` - install any external requirements -- ``configure_nova_hypervisor`` - make configuration changes, including - those to other services -- ``start_nova_hypervisor`` - start any external services -- ``stop_nova_hypervisor`` - stop any external services -- ``cleanup_nova_hypervisor`` - remove transient data and cache +Multiple plugins can be specified in your ``local.conf``. When that +happens the plugins will be executed **in order** at each phase. This +allows plugins to conceptually depend on each other through +documenting to the user the order they must be declared. A formal +dependency mechanism is beyond the scope of the current work. System Packages =============== Devstack provides a framework for getting packages installed at an early -phase of its execution. This packages may be defined in a plugin as files +phase of its execution. These packages may be defined in a plugin as files that contain new-line separated lists of packages required by the plugin Supported packaging systems include apt and yum across multiple distributions. @@ -205,3 +239,50 @@ repository: - ``./devstack/files/rpms-suse/$plugin_name`` - Packages to install when running on SUSE Linux or openSUSE. + + +Using Plugins in the OpenStack Gate +=================================== + +For everyday use, DevStack plugins can exist in any git tree that's +accessible on the internet. However, when using DevStack plugins in +the OpenStack gate, they must live in projects in OpenStack's +gerrit. This allows testing of the plugin as well as provides network +isolation against upstream git repository failures (which we see often +enough to be an issue). + +Ideally a plugin will be included within the ``devstack`` directory of +the project they are being tested. For example, the openstack/ec2-api +project has its plugin support in its own tree. + +However, some times a DevStack plugin might be used solely to +configure a backend service that will be used by the rest of +OpenStack, so there is no "project tree" per say. Good examples +include: integration of back end storage (e.g. ceph or glusterfs), +integration of SDN controllers (e.g. ovn, OpenDayLight), or +integration of alternate RPC systems (e.g. zmq, qpid). In these cases +the best practice is to build a dedicated +``openstack/devstack-plugin-FOO`` project. + +To enable a plugin to be used in a gate job, the following lines will +be needed in your ``jenkins/jobs/.yaml`` definition in +`project-config +`_:: + + # Because we are testing a non standard project, add the + # our project repository. This makes zuul do the right + # reference magic for testing changes. + export PROJECTS="openstack/ec2-api $PROJECTS" + + # note the actual url here is somewhat irrelevant because it + # caches in nodepool, however make it a valid url for + # documentation purposes. + export DEVSTACK_LOCAL_CONFIG="enable_plugin ec2-api git://git.openstack.org/openstack/ec2-api" + +See Also +======== + +For additional inspiration on devstack plugins you can check out the +`Plugin Registry `_. + +.. _service types authority: https://specs.openstack.org/openstack/service-types-authority/ diff --git a/doc/source/stackrc.rst b/doc/source/stackrc.rst deleted file mode 100644 index b21f74f761..0000000000 --- a/doc/source/stackrc.rst +++ /dev/null @@ -1,66 +0,0 @@ -=========================== -stackrc - DevStack Settings -=========================== - -``stackrc`` is the primary configuration file for DevStack. It contains -all of the settings that control the services started and the -repositories used to download the source for those services. ``stackrc`` -sources the ``localrc`` section of ``local.conf`` to perform the default -overrides. - -DATABASE\_TYPE - Select the database backend to use. The default is ``mysql``, - ``postgresql`` is also available. -ENABLED\_SERVICES - Specify which services to launch. These generally correspond to - screen tabs. The default includes: Glance (API and Registry), - Keystone, Nova (API, Certificate, Object Store, Compute, Network, - Scheduler, Certificate Authentication), Cinder - (Scheduler, API, Volume), Horizon, MySQL, RabbitMQ, Tempest. - - :: - - ENABLED_SERVICES=g-api,g-reg,key,n-api,n-crt,n-obj,n-cpu,n-net,n-cond,c-sch,c-api,c-vol,n-sch,n-cauth,horizon,rabbit,tempest,$DATABASE_TYPE - - Other services that are not enabled by default can be enabled in - ``localrc``. For example, to add Swift, use the following service - names: - - :: - - enable_service s-proxy s-object s-container s-account - - A service can similarly be disabled: - - :: - - disable_service horizon - -Service Repos - The Git repositories used to check out the source for each service - are controlled by a pair of variables set for each service. - ``*_REPO`` points to the repository and ``*_BRANCH`` selects which - branch to check out. These may be overridden in ``local.conf`` to - pull source from a different repo for testing, such as a Gerrit - branch proposal. ``GIT_BASE`` points to the primary repository - server. - - :: - - NOVA_REPO=$GIT_BASE/openstack/nova.git - NOVA_BRANCH=master - - To pull a branch directly from Gerrit, get the repo and branch from - the Gerrit review page: - - :: - - git fetch https://review.openstack.org/p/openstack/nova refs/changes/50/5050/1 && git checkout FETCH_HEAD - - The repo is the stanza following ``fetch`` and the branch is the - stanza following that: - - :: - - NOVA_REPO=https://review.openstack.org/p/openstack/nova - NOVA_BRANCH=refs/changes/50/5050/1 diff --git a/doc/source/systemd.rst b/doc/source/systemd.rst new file mode 100644 index 0000000000..1bc9911879 --- /dev/null +++ b/doc/source/systemd.rst @@ -0,0 +1,246 @@ +=========================== + Using Systemd in DevStack +=========================== + +By default DevStack is run with all the services as systemd unit +files. Systemd is now the default init system for nearly every Linux +distro, and systemd encodes and solves many of the problems related to +poorly running processes. + +Why this instead of screen? +=========================== + +The screen model for DevStack was invented when the number of services +that a DevStack user was going to run was typically < 10. This made +screen hot keys to jump around very easy. However, the landscape has +changed (not all services are stoppable in screen as some are under +Apache, there are typically at least 20 items) + +There is also a common developer workflow of changing code in more +than one service, and needing to restart a bunch of services for that +to take effect. + +Unit Structure +============== + +.. note:: + + Originally we actually wanted to do this as user units, however + there are issues with running this under non interactive + shells. For now, we'll be running as system units. Some user unit + code is left in place in case we can switch back later. + +All DevStack user units are created as a part of the DevStack slice +given the name ``devstack@$servicename.service``. This makes it easy +to understand which services are part of the devstack run, and lets us +disable / stop them in a single command. + +Manipulating Units +================== + +Assuming the unit ``n-cpu`` to make the examples more clear. + +Enable a unit (allows it to be started):: + + sudo systemctl enable devstack@n-cpu.service + +Disable a unit:: + + sudo systemctl disable devstack@n-cpu.service + +Start a unit:: + + sudo systemctl start devstack@n-cpu.service + +Stop a unit:: + + sudo systemctl stop devstack@n-cpu.service + +Restart a unit:: + + sudo systemctl restart devstack@n-cpu.service + +See status of a unit:: + + sudo systemctl status devstack@n-cpu.service + +Operating on more than one unit at a time +----------------------------------------- + +Systemd supports wildcarding for unit operations. To restart every +service in devstack you can do that following:: + + sudo systemctl restart devstack@* + +Or to see the status of all Nova processes you can do:: + + sudo systemctl status devstack@n-* + +We'll eventually make the unit names a bit more meaningful so that +it's easier to understand what you are restarting. + +.. _journalctl-examples: + +Querying Logs +============= + +One of the other major things that comes with systemd is journald, a +consolidated way to access logs (including querying through structured +metadata). This is accessed by the user via ``journalctl`` command. + + +Logs can be accessed through ``journalctl``. journalctl has powerful +query facilities. We'll start with some common options. + +Follow logs for a specific service:: + + sudo journalctl -f --unit devstack@n-cpu.service + +Following logs for multiple services simultaneously:: + + sudo journalctl -f --unit devstack@n-cpu.service --unit devstack@n-cond.service + +or you can even do wild cards to follow all the nova services:: + + sudo journalctl -f --unit devstack@n-* + +Use higher precision time stamps:: + + sudo journalctl -f -o short-precise --unit devstack@n-cpu.service + +By default, journalctl strips out "unprintable" characters, including +ASCII color codes. To keep the color codes (which can be interpreted by +an appropriate terminal/pager - e.g. ``less``, the default):: + + sudo journalctl -a --unit devstack@n-cpu.service + +When outputting to the terminal using the default pager, long lines +will be truncated, but horizontal scrolling is supported via the +left/right arrow keys. You can override this by setting the +``SYSTEMD_LESS`` environment variable to e.g. ``FRXM``. + +You can pipe the output to another tool, such as ``grep``. For +example, to find a server instance UUID in the nova logs:: + + sudo journalctl -a --unit devstack@n-* | grep 58391b5c-036f-44d5-bd68-21d3c26349e6 + +See ``man 1 journalctl`` for more. + +Debugging +========= + +Using pdb +--------- + +In order to break into a regular pdb session on a systemd-controlled +service, you need to invoke the process manually - that is, take it out +of systemd's control. + +Discover the command systemd is using to run the service:: + + systemctl show devstack@n-sch.service -p ExecStart --no-pager + +Stop the systemd service:: + + sudo systemctl stop devstack@n-sch.service + +Inject your breakpoint in the source, e.g.:: + + import pdb; pdb.set_trace() + +Invoke the command manually:: + + /usr/local/bin/nova-scheduler --config-file /etc/nova/nova.conf + +Some executables, such as :program:`nova-compute`, will need to be executed +with a particular group. This will be shown in the systemd unit file:: + + sudo systemctl cat devstack@n-cpu.service | grep Group + +:: + + Group = libvirt + +Use the :program:`sg` tool to execute the command as this group:: + + sg libvirt -c '/usr/local/bin/nova-compute --config-file /etc/nova/nova-cpu.conf' + +Using remote-pdb +---------------- + +`remote-pdb`_ works while the process is under systemd control. + +Make sure you have remote-pdb installed:: + + sudo pip install remote-pdb + +Inject your breakpoint in the source, e.g.:: + + import remote_pdb; remote_pdb.set_trace() + +Restart the relevant service:: + + sudo systemctl restart devstack@n-api.service + +The remote-pdb code configures the telnet port when ``set_trace()`` is +invoked. Do whatever it takes to hit the instrumented code path, and +inspect the logs for a message displaying the listening port:: + + Sep 07 16:36:12 p8-100-neo devstack@n-api.service[772]: RemotePdb session open at 127.0.0.1:46771, waiting for connection ... + +Telnet to that port to enter the pdb session:: + + telnet 127.0.0.1 46771 + +See the `remote-pdb`_ home page for more options. + +.. _`remote-pdb`: https://pypi.python.org/pypi/remote-pdb + +Known Issues +============ + +Be careful about systemd python libraries. There are 3 of them on +pypi, and they are all very different. They unfortunately all install +into the ``systemd`` namespace, which can cause some issues. + +- ``systemd-python`` - this is the upstream maintained library, it has + a version number like systemd itself (currently ``234``). This is + the one you want. +- ``systemd`` - a python 3 only library, not what you want. +- ``python-systemd`` - another library you don't want. Installing it + on a system will break ansible's ability to run. + + +If we were using user units, the ``[Service]`` - ``Group=`` parameter +doesn't seem to work with user units, even though the documentation +says that it should. This means that we will need to do an explicit +``/usr/bin/sg``. This has the downside of making the SYSLOG_IDENTIFIER +be ``sg``. We can explicitly set that with ``SyslogIdentifier=``, but +it's really unfortunate that we're going to need this work +around. This is currently not a problem because we're only using +system units. + +Future Work +=========== + +user units +---------- + +It would be great if we could do services as user units, so that there +is a clear separation of code being run as not root, to ensure running +as root never accidentally gets baked in as an assumption to +services. However, user units interact poorly with devstack-gate and +the way that commands are run as users with ansible and su. + +Maybe someday we can figure that out. + +References +========== + +- Arch Linux Wiki - https://wiki.archlinux.org/index.php/Systemd/User +- Python interface to journald - + https://www.freedesktop.org/software/systemd/python-systemd/journal.html +- Systemd documentation on service files - + https://www.freedesktop.org/software/systemd/man/systemd.service.html +- Systemd documentation on exec (can be used to impact service runs) - + https://www.freedesktop.org/software/systemd/man/systemd.exec.html diff --git a/doc/source/zuul_ci_jobs_migration.rst b/doc/source/zuul_ci_jobs_migration.rst new file mode 100644 index 0000000000..c00f06e41a --- /dev/null +++ b/doc/source/zuul_ci_jobs_migration.rst @@ -0,0 +1,301 @@ +=============================== +Migrating Zuul V2 CI jobs to V3 +=============================== + +The OpenStack CI system moved from Zuul v2 to Zuul v3, and all CI jobs moved to +the new CI system. All jobs have been migrated automatically to a format +compatible with Zuul v3; the jobs produced in this way however are suboptimal +and do not use the capabilities introduced by Zuul v3, which allow for re-use of +job parts, in the form of Ansible roles, as well as inheritance between jobs. + +DevStack hosts a set of roles, plays and jobs that can be used by other +repositories to define their DevStack based jobs. To benefit from them, jobs +must be migrated from the legacy v2 ones into v3 native format. + +This document provides guidance and examples to make the migration process as +painless and smooth as possible. + +Where to host the job definitions. +================================== + +In Zuul V3 jobs can be defined in the repository that contains the code they +excercise. If you are writing CI jobs for an OpenStack service you can define +your DevStack based CI jobs in one of the repositories that host the code for +your service. If you have a branchless repo, like a Tempest plugin, that is +a convenient choice to host the job definitions since job changes do not have +to be backported. For example, see the beginning of the ``.zuul.yaml`` from the +sahara Tempest plugin repo: + +.. code:: yaml + + # In http://git.openstack.org/cgit/openstack/sahara-tests/tree/.zuul.yaml: + - job: + name: sahara-tests-tempest + description: | + Run Tempest tests from the Sahara plugin. + parent: devstack-tempest + +Which base job to start from +============================ + +If your job needs an OpenStack cloud deployed via DevStack, but you don't plan +on running Tempest tests, you can start from one of the base +:doc:`jobs ` defined in the DevStack repo. + +The ``devstack`` job can be used for both single-node jobs and multi-node jobs, +and it includes the list of services used in the integrated gate (keystone, +glance, nova, cinder, neutron and swift). Different topologies can be achieved +by switching the nodeset used in the child job. + +The ``devstack-base`` job is similar to ``devstack`` but it does not specify any +required repo or service to be run in DevStack. It can be useful to setup +children jobs that use a very narrow DevStack setup. + +If your job needs an OpenStack cloud deployed via DevStack, and you do plan +on running Tempest tests, you can start from one of the base jobs defined in the +Tempest repo. + +The ``devstack-tempest`` job can be used for both single-node jobs and +multi-node jobs. Different topologies can be achieved by switching the nodeset +used in the child job. + +Jobs can be customized as follows without writing any Ansible code: + +- add and/or remove DevStack services +- add or modify DevStack and services configuration +- install DevStack plugins +- extend the number of sub-nodes (multinode only) +- define extra log files and/or directories to be uploaded on logs.o.o +- define extra log file extensions to be rewritten to .txt for ease of access + +Tempest jobs can be further customized as follows: + +- define the Tempest tox environment to be used +- define the test concurrency +- define the test regular expression + +Writing Ansible code, or importing existing custom roles, jobs can be further +extended by: + +- adding pre and/or post playbooks +- overriding the run playbook, add custom roles + +The (partial) example below extends a Tempest single node base job +"devstack-tempest" in the Kuryr repository. The parent job name is defined in +job.parent. + +.. code:: yaml + + # https://git.openstack.org/cgit/openstack/kuryr-kubernetes/tree/.zuul.yaml: + - job: + name: kuryr-kubernetes-tempest-base + parent: devstack-tempest + description: Base kuryr-kubernetes-job + required-projects: + - openstack/devstack-plugin-container + - openstack/kuryr + - openstack/kuryr-kubernetes + - openstack/kuryr-tempest-plugin + - openstack/neutron-lbaas + vars: + tempest_test_regex: '^(kuryr_tempest_plugin.tests.)' + tox_envlist: 'all' + devstack_localrc: + KURYR_K8S_API_PORT: 8080 + TEMPEST_PLUGINS: '/opt/stack/kuryr-tempest-plugin' + devstack_services: + kubernetes-api: true + kubernetes-controller-manager: true + kubernetes-scheduler: true + kubelet: true + kuryr-kubernetes: true + (...) + devstack_plugins: + kuryr-kubernetes: https://git.openstack.org/openstack/kuryr + devstack-plugin-container: https://git.openstack.org/openstack/devstack-plugin-container + neutron-lbaas: https://git.openstack.org/openstack/neutron-lbaas + (...) + +Job variables +============= + +Variables can be added to the job in three different places: + +- job.vars: these are global variables available to all node in the nodeset +- job.host-vars.[HOST]: these are variables available only to the specified HOST +- job.group-vars.[GROUP]: these are variables available only to the specified + GROUP + +Zuul merges dict variables through job inheritance. Host and group variables +override variables with the same name defined as global variables. + +In the example below, for the sundaes job, hosts that are not part of the +subnode group will run vanilla and chocolate. Hosts in the subnode group will +run stracciatella and strawberry. + +.. code:: yaml + + - job: + name: ice-creams + vars: + devstack_service: + vanilla: true + chocolate: false + group-vars: + subnode: + devstack_service: + pistacchio: true + stracciatella: true + + - job: + name: sundaes + parent: ice-creams + vars: + devstack_service: + chocolate: true + group-vars: + subnode: + devstack_service: + strawberry: true + pistacchio: false + + +DevStack Gate Flags +=================== + +The old CI system worked using a combination of DevStack, Tempest and +devstack-gate to setup a test environment and run tests against it. With Zuul +V3, the logic that used to live in devstack-gate is moved into different repos, +including DevStack, Tempest and grenade. + +DevStack-gate exposes an interface for job definition based on a number of +DEVSTACK_GATE_* environment variables, or flags. This guide shows how to map +DEVSTACK_GATE flags into the new +system. + +The repo column indicates in which repository is hosted the code that replaces +the devstack-gate flag. The new implementation column explains how to reproduce +the same or a similar behaviour in Zuul v3 jobs. For localrc settings, +devstack-gate defined a default value. In ansible jobs the default is either the +value defined in the parent job, or the default from DevStack, if any. + +============================================== ============= ================== +DevStack gate flag Repo New implementation +============================================== ============= ================== +OVERRIDE_ZUUL_BRANCH zuul override-checkout: + [branch] + in the job definition. +DEVSTACK_GATE_NET_OVERLAY zuul-jobs A bridge called + br-infra is set up for + all jobs that inherit + from multinode with + a dedicated `bridge role `_. +DEVSTACK_GATE_FEATURE_MATRIX devstack-gate ``test_matrix_features`` + variable of the + test-matrix role in + devstack-gate. This + is a temporary + solution, feature + matrix will go away. + In the future services + will be defined in + jobs only. +DEVSTACK_CINDER_VOLUME_CLEAR devstack *CINDER_VOLUME_CLEAR: true/false* + in devstack_localrc + in the job vars. +DEVSTACK_GATE_NEUTRON devstack True by default. To + disable, disable all + neutron services in + devstack_services in + the job definition. +DEVSTACK_GATE_CONFIGDRIVE devstack *FORCE_CONFIG_DRIVE: true/false* + in devstack_localrc + in the job vars. +DEVSTACK_GATE_INSTALL_TESTONLY devstack *INSTALL_TESTONLY_PACKAGES: true/false* + in devstack_localrc + in the job vars. +DEVSTACK_GATE_VIRT_DRIVER devstack *VIRT_DRIVER: [virt driver]* + in devstack_localrc + in the job vars. +DEVSTACK_GATE_LIBVIRT_TYPE devstack *LIBVIRT_TYPE: [libvirt type]* + in devstack_localrc + in the job vars. +DEVSTACK_GATE_TEMPEST devstack Defined by the job + tempest that is used. The + ``devstack`` job only + runs devstack. + The ``devstack-tempest`` + one triggers a Tempest + run as well. +DEVSTACK_GATE_TEMPEST_FULL tempest *tox_envlist: full* + in the job vars. +DEVSTACK_GATE_TEMPEST_ALL tempest *tox_envlist: all* + in the job vars. +DEVSTACK_GATE_TEMPEST_ALL_PLUGINS tempest *tox_envlist: all-plugin* + in the job vars. +DEVSTACK_GATE_TEMPEST_SCENARIOS tempest *tox_envlist: scenario* + in the job vars. +TEMPEST_CONCURRENCY tempest *tempest_concurrency: [value]* + in the job vars. This + is available only on + jobs that inherit from + ``devstack-tempest`` + down. +DEVSTACK_GATE_TEMPEST_NOTESTS tempest *tox_envlist: venv-tempest* + in the job vars. This + will create Tempest + virtual environment + but run no tests. +DEVSTACK_GATE_SMOKE_SERIAL tempest *tox_envlist: smoke-serial* + in the job vars. +DEVSTACK_GATE_TEMPEST_DISABLE_TENANT_ISOLATION tempest *tox_envlist: full-serial* + in the job vars. + *TEMPEST_ALLOW_TENANT_ISOLATION: false* + in devstack_localrc in + the job vars. +============================================== ============= ================== + +The following flags have not been migrated yet or are legacy and won't be +migrated at all. + +===================================== ====== ========================== +DevStack gate flag Status Details +===================================== ====== ========================== +DEVSTACK_GATE_TOPOLOGY WIP The topology depends on the base + job that is used and more + specifically on the nodeset + attached to it. The new job + format allows project to define + the variables to be passed to + every node/node-group that exists + in the topology. Named topologies + that include the nodeset and the + matching variables can be defined + in the form of base jobs. +DEVSTACK_GATE_GRENADE TBD Grenade Zuul V3 jobs will be + hosted in the grenade repo. +GRENADE_BASE_BRANCH TBD Grenade Zuul V3 jobs will be + hosted in the grenade repo. +DEVSTACK_GATE_NEUTRON_DVR TBD Depends on multinode support. +DEVSTACK_GATE_EXERCISES TBD Can be done on request. +DEVSTACK_GATE_IRONIC TBD This will probably be implemented + on ironic side. +DEVSTACK_GATE_IRONIC_DRIVER TBD This will probably be implemented + on ironic side. +DEVSTACK_GATE_IRONIC_BUILD_RAMDISK TBD This will probably be implemented + on ironic side. +DEVSTACK_GATE_POSTGRES Legacy This flag exists in d-g but the + only thing that it does is + capture postgres logs. This is + already supported by the roles in + post, so the flag is useless in + the new jobs. postgres itself can + be enabled via the + devstack_service job variable. +DEVSTACK_GATE_ZEROMQ Legacy This has no effect in d-g. +DEVSTACK_GATE_MQ_DRIVER Legacy This has no effect in d-g. +DEVSTACK_GATE_TEMPEST_STRESS_ARGS Legacy Stress is not in Tempest anymore. +DEVSTACK_GATE_TEMPEST_HEAT_SLOW Legacy This is not used anywhere. +DEVSTACK_GATE_CELLS Legacy This has no effect in d-g. +DEVSTACK_GATE_NOVA_API_METADATA_SPLIT Legacy This has no effect in d-g. +===================================== ====== ========================== diff --git a/doc/source/zuul_jobs.rst b/doc/source/zuul_jobs.rst new file mode 100644 index 0000000000..cf203a8973 --- /dev/null +++ b/doc/source/zuul_jobs.rst @@ -0,0 +1,4 @@ +Zuul CI Jobs +============ + +.. zuul:autojobs:: diff --git a/doc/source/zuul_roles.rst b/doc/source/zuul_roles.rst new file mode 100644 index 0000000000..4939281057 --- /dev/null +++ b/doc/source/zuul_roles.rst @@ -0,0 +1,4 @@ +Zuul CI Roles +============= + +.. zuul:autoroles:: diff --git a/driver_certs/cinder_driver_cert.sh b/driver_certs/cinder_driver_cert.sh deleted file mode 100755 index d066e0667f..0000000000 --- a/driver_certs/cinder_driver_cert.sh +++ /dev/null @@ -1,106 +0,0 @@ -#!/usr/bin/env bash - -# **cinder_cert.sh** - -# This script is a simple wrapper around the tempest volume api tests -# It requires that you have a working and functional devstack install -# and that you've enabled your device driver by making the necessary -# modifications to /etc/cinder/cinder.conf - -# This script will refresh your openstack repo's and restart the cinder -# services to pick up your driver changes. -# please NOTE; this script assumes your devstack install is functional -# and includes tempest. A good first step is to make sure you can -# create volumes on your device before you even try and run this script. - -# It also assumes default install location (/opt/stack/xxx) -# to aid in debug, you should also verify that you've added -# an output directory for screen logs: -# -# SCREEN_LOGDIR=/opt/stack/screen-logs - -set -o pipefail - -CERT_DIR=$(cd $(dirname "$0") && pwd) -TOP_DIR=$(cd $CERT_DIR/..; pwd) - -source $TOP_DIR/functions -source $TOP_DIR/stackrc -source $TOP_DIR/openrc -source $TOP_DIR/lib/infra -source $TOP_DIR/lib/tempest -source $TOP_DIR/lib/cinder - -TEMPFILE=`mktemp` -RECLONE=True - -function log_message { - MESSAGE=$1 - STEP_HEADER=$2 - if [[ "$STEP_HEADER" = "True" ]]; then - echo -e "\n========================================================" | tee -a $TEMPFILE - fi - echo -e `date +%m/%d/%y/%T:`"${MESSAGE}" | tee -a $TEMPFILE - if [[ "$STEP_HEADER" = "True" ]]; then - echo -e "========================================================" | tee -a $TEMPFILE - fi -} - -if [[ "$OFFLINE" = "True" ]]; then - echo "ERROR: Driver cert requires fresh clone/pull from ${CINDER_BRANCH}" - echo " Please set OFFLINE=False and retry." - exit 1 -fi - -log_message "RUNNING CINDER DRIVER CERTIFICATION CHECK", True -log_message "Output is being logged to: $TEMPFILE" - -cd $CINDER_DIR -log_message "Cloning to ${CINDER_REPO}...", True -install_cinder - -log_message "Pull a fresh Clone of cinder repo...", True -git status | tee -a $TEMPFILE -git log --pretty=oneline -n 1 | tee -a $TEMPFILE - -log_message "Gathering copy of cinder.conf file (passwords will be scrubbed)...", True -cat /etc/cinder/cinder.conf | egrep -v "(^#.*|^$)" | tee -a $TEMPFILE -sed -i "s/\(.*password.*=\).*$/\1 xxx/i" $TEMPFILE -log_message "End of cinder.conf.", True - -cd $TOP_DIR -# Verify tempest is installed/enabled -if ! is_service_enabled tempest; then - log_message "ERROR!!! Cert requires tempest in enabled_services!", True - log_message" Please add tempest to enabled_services and retry." - exit 1 -fi - -cd $TEMPEST_DIR -install_tempest - -log_message "Verify tempest is current....", True -git status | tee -a $TEMPFILE -log_message "Check status and get latest commit..." -git log --pretty=oneline -n 1 | tee -a $TEMPFILE - - -#stop and restart cinder services -log_message "Restart Cinder services...", True -stop_cinder -sleep 1 -start_cinder -sleep 5 - -# run tempest api/volume/test_* -log_message "Run the actual tempest volume tests (./tools/pretty_tox.sh volume)...", True -./tools/pretty_tox.sh volume 2>&1 | tee -a $TEMPFILE -if [[ $? = 0 ]]; then - log_message "CONGRATULATIONS!!! Device driver PASSED!", True - log_message "Submit output: ($TEMPFILE)" - exit 0 -else - log_message "SORRY!!! Device driver FAILED!", True - log_message "Check output in $TEMPFILE" - exit 1 -fi diff --git a/eucarc b/eucarc deleted file mode 100644 index 1e672bd932..0000000000 --- a/eucarc +++ /dev/null @@ -1,40 +0,0 @@ -#!/usr/bin/env bash -# -# source eucarc [username] [tenantname] -# -# Create EC2 credentials for the current user as defined by OS_TENANT_NAME:OS_USERNAME -# Optionally set the tenant/username via openrc - -if [[ -n "$1" ]]; then - USERNAME=$1 -fi -if [[ -n "$2" ]]; then - TENANT=$2 -fi - -# Find the other rc files -RC_DIR=$(cd $(dirname "${BASH_SOURCE:-$0}") && pwd) - -# Get user configuration -source $RC_DIR/openrc - -# Set the ec2 url so euca2ools works -export EC2_URL=$(openstack catalog show ec2 | awk '/ publicURL: / { print $4 }') - -# Create EC2 credentials for the current user -CREDS=$(openstack ec2 credentials create) -export EC2_ACCESS_KEY=$(echo "$CREDS" | awk '/ access / { print $4 }') -export EC2_SECRET_KEY=$(echo "$CREDS" | awk '/ secret / { print $4 }') - -# Euca2ools Certificate stuff for uploading bundles -# See exercises/bundle.sh to see how to get certs using nova cli -NOVA_KEY_DIR=${NOVA_KEY_DIR:-$RC_DIR} -export S3_URL=$(openstack catalog show s3 | awk '/ publicURL: / { print $4 }') -export EC2_USER_ID=42 # nova does not use user id, but bundling requires it -export EC2_PRIVATE_KEY=${NOVA_KEY_DIR}/pk.pem -export EC2_CERT=${NOVA_KEY_DIR}/cert.pem -export NOVA_CERT=${NOVA_KEY_DIR}/cacert.pem -export EUCALYPTUS_CERT=${NOVA_CERT} # euca-bundle-image seems to require this set -alias ec2-bundle-image="ec2-bundle-image --cert ${EC2_CERT} --privatekey ${EC2_PRIVATE_KEY} --user ${EC2_USER_ID} --ec2cert ${NOVA_CERT}" -alias ec2-upload-bundle="ec2-upload-bundle -a ${EC2_ACCESS_KEY} -s ${EC2_SECRET_KEY} --url ${S3_URL} --ec2cert ${NOVA_CERT}" - diff --git a/exercise.sh b/exercise.sh deleted file mode 100755 index 19c9d80451..0000000000 --- a/exercise.sh +++ /dev/null @@ -1,74 +0,0 @@ -#!/usr/bin/env bash - -# **exercise.sh** - -# Keep track of the current DevStack directory. -TOP_DIR=$(cd $(dirname "$0") && pwd) - -# Import common functions -source $TOP_DIR/functions - -# Load local configuration -source $TOP_DIR/stackrc - -# Run everything in the exercises/ directory that isn't explicitly disabled - -# comma separated list of script basenames to skip -# to refrain from exercising euca.sh use ``SKIP_EXERCISES=euca`` -SKIP_EXERCISES=${SKIP_EXERCISES:-""} - -# comma separated list of script basenames to run -# to run only euca.sh use ``RUN_EXERCISES=euca`` -basenames=${RUN_EXERCISES:-""} - -EXERCISE_DIR=$TOP_DIR/exercises - -if [[ -z "${basenames}" ]]; then - # Locate the scripts we should run - basenames=$(for b in `ls $EXERCISE_DIR/*.sh`; do basename $b .sh; done) -else - # If ``RUN_EXERCISES`` was specified, ignore ``SKIP_EXERCISES``. - SKIP_EXERCISES= -fi - -# Track the state of each script -passes="" -failures="" -skips="" - -# Loop over each possible script (by basename) -for script in $basenames; do - if [[ ,$SKIP_EXERCISES, =~ ,$script, ]]; then - skips="$skips $script" - else - echo "=====================================================================" - echo Running $script - echo "=====================================================================" - $EXERCISE_DIR/$script.sh - exitcode=$? - if [[ $exitcode == 55 ]]; then - skips="$skips $script" - elif [[ $exitcode -ne 0 ]]; then - failures="$failures $script" - else - passes="$passes $script" - fi - fi -done - -# Output status of exercise run -echo "=====================================================================" -for script in $skips; do - echo SKIP $script -done -for script in $passes; do - echo PASS $script -done -for script in $failures; do - echo FAILED $script -done -echo "=====================================================================" - -if [[ -n "$failures" ]]; then - exit 1 -fi diff --git a/exerciserc b/exerciserc deleted file mode 100644 index 9105fe3331..0000000000 --- a/exerciserc +++ /dev/null @@ -1,32 +0,0 @@ -#!/usr/bin/env bash -# -# source exerciserc -# -# Configure the DevStack exercise scripts -# For best results, source this _after_ stackrc/localrc as it will set -# values only if they are not already set. - -# Max time to wait while vm goes from build to active state -export ACTIVE_TIMEOUT=${ACTIVE_TIMEOUT:-30} - -# Max time to wait for proper IP association and dis-association. -export ASSOCIATE_TIMEOUT=${ASSOCIATE_TIMEOUT:-15} - -# Max time till the vm is bootable -export BOOT_TIMEOUT=${BOOT_TIMEOUT:-30} - -# Max time from run instance command until it is running -export RUNNING_TIMEOUT=${RUNNING_TIMEOUT:-$(($BOOT_TIMEOUT + $ACTIVE_TIMEOUT))} - -# Max time to wait for a vm to terminate -export TERMINATE_TIMEOUT=${TERMINATE_TIMEOUT:-30} - -# Max time to wait for a euca-volume command to propagate -export VOLUME_TIMEOUT=${VOLUME_TIMEOUT:-30} - -# Max time to wait for a euca-delete command to propagate -export VOLUME_DELETE_TIMEOUT=${SNAPSHOT_DELETE_TIMEOUT:-60} - -# The size of the volume we want to boot from; some storage back-ends -# do not allow a disk resize, so it's important that this can be tuned -export DEFAULT_VOLUME_SIZE=${DEFAULT_VOLUME_SIZE:-1} diff --git a/exercises/aggregates.sh b/exercises/aggregates.sh deleted file mode 100755 index 01d548d1f2..0000000000 --- a/exercises/aggregates.sh +++ /dev/null @@ -1,155 +0,0 @@ -#!/usr/bin/env bash - -# **aggregates.sh** - -# This script demonstrates how to use host aggregates: -# -# * Create an Aggregate -# * Updating Aggregate details -# * Testing Aggregate metadata -# * Testing Aggregate delete -# * Testing General Aggregates (https://blueprints.launchpad.net/nova/+spec/general-host-aggregates) -# * Testing add/remove hosts (with one host) - -echo "**************************************************" -echo "Begin DevStack Exercise: $0" -echo "**************************************************" - -# This script exits on an error so that errors don't compound and you see -# only the first error that occurred. -set -o errexit - -# Print the commands being run so that we can see the command that triggers -# an error. It is also useful for following allowing as the install occurs. -set -o xtrace - - -# Settings -# ======== - -# Keep track of the current directory -EXERCISE_DIR=$(cd $(dirname "$0") && pwd) -TOP_DIR=$(cd $EXERCISE_DIR/..; pwd) - -# Import common functions -source $TOP_DIR/functions - -# Import configuration -source $TOP_DIR/openrc - -# Import exercise configuration -source $TOP_DIR/exerciserc - -# Test as the admin user -. $TOP_DIR/openrc admin admin - -# If nova api is not enabled we exit with exitcode 55 so that -# the exercise is skipped -is_service_enabled n-api || exit 55 - -# Cells does not support aggregates. -is_service_enabled n-cell && exit 55 - -# Create an aggregate -# =================== - -AGGREGATE_NAME=test_aggregate_$RANDOM -AGGREGATE2_NAME=test_aggregate_$RANDOM -AGGREGATE_A_ZONE=nova - -function exit_if_aggregate_present { - aggregate_name=$1 - - if [ $(nova aggregate-list | grep -c " $aggregate_name ") == 0 ]; then - echo "SUCCESS $aggregate_name not present" - else - die $LINENO "found aggregate: $aggregate_name" - exit -1 - fi -} - -exit_if_aggregate_present $AGGREGATE_NAME - -AGGREGATE_ID=$(nova aggregate-create $AGGREGATE_NAME $AGGREGATE_A_ZONE | grep " $AGGREGATE_NAME " | get_field 1) -die_if_not_set $LINENO AGGREGATE_ID "Failure creating AGGREGATE_ID for $AGGREGATE_NAME $AGGREGATE_A_ZONE" - -AGGREGATE2_ID=$(nova aggregate-create $AGGREGATE2_NAME $AGGREGATE_A_ZONE | grep " $AGGREGATE2_NAME " | get_field 1) -die_if_not_set $LINENO AGGREGATE2_ID "Fail creating AGGREGATE2_ID for $AGGREGATE2_NAME $AGGREGATE_A_ZONE" - -# check aggregate created -nova aggregate-list | grep -q " $AGGREGATE_NAME " || die $LINENO "Aggregate $AGGREGATE_NAME not created" - - -# Ensure creating a duplicate fails -# ================================= - -if nova aggregate-create $AGGREGATE_NAME $AGGREGATE_A_ZONE; then - die $LINENO "could create duplicate aggregate" -fi - - -# Test aggregate-update (and aggregate-details) -# ============================================= -AGGREGATE_NEW_NAME=test_aggregate_$RANDOM - -nova aggregate-update $AGGREGATE_ID $AGGREGATE_NEW_NAME -nova aggregate-details $AGGREGATE_ID | grep $AGGREGATE_NEW_NAME -nova aggregate-details $AGGREGATE_ID | grep $AGGREGATE_A_ZONE - -nova aggregate-update $AGGREGATE_ID $AGGREGATE_NAME $AGGREGATE_A_ZONE -nova aggregate-details $AGGREGATE_ID | grep $AGGREGATE_NAME -nova aggregate-details $AGGREGATE_ID | grep $AGGREGATE_A_ZONE - - -# Test aggregate-set-metadata -# =========================== -META_DATA_1_KEY=asdf -META_DATA_2_KEY=foo -META_DATA_3_KEY=bar - -#ensure no additional metadata is set -nova aggregate-details $AGGREGATE_ID | egrep "\|[{u ]*'availability_zone.+$AGGREGATE_A_ZONE'[ }]*\|" - -nova aggregate-set-metadata $AGGREGATE_ID ${META_DATA_1_KEY}=123 -nova aggregate-details $AGGREGATE_ID | grep $META_DATA_1_KEY -nova aggregate-details $AGGREGATE_ID | grep 123 - -nova aggregate-set-metadata $AGGREGATE_ID ${META_DATA_2_KEY}=456 -nova aggregate-details $AGGREGATE_ID | grep $META_DATA_1_KEY -nova aggregate-details $AGGREGATE_ID | grep $META_DATA_2_KEY - -nova aggregate-set-metadata $AGGREGATE_ID $META_DATA_2_KEY ${META_DATA_3_KEY}=789 -nova aggregate-details $AGGREGATE_ID | grep $META_DATA_1_KEY -nova aggregate-details $AGGREGATE_ID | grep $META_DATA_3_KEY - -nova aggregate-details $AGGREGATE_ID | grep $META_DATA_2_KEY && die $LINENO "ERROR metadata was not cleared" - -nova aggregate-set-metadata $AGGREGATE_ID $META_DATA_3_KEY $META_DATA_1_KEY -nova aggregate-details $AGGREGATE_ID | egrep "\|[{u ]*'availability_zone.+$AGGREGATE_A_ZONE'[ }]*\|" - - -# Test aggregate-add/remove-host -# ============================== -if [ "$VIRT_DRIVER" == "xenserver" ]; then - echo "TODO(johngarbutt) add tests for add/remove host from pool aggregate" -fi -FIRST_HOST=$(nova host-list | grep compute | get_field 1 | head -1) -# Make sure can add two aggregates to same host -nova aggregate-add-host $AGGREGATE_ID $FIRST_HOST -nova aggregate-add-host $AGGREGATE2_ID $FIRST_HOST -if nova aggregate-add-host $AGGREGATE2_ID $FIRST_HOST; then - die $LINENO "could add duplicate host to single aggregate" -fi -nova aggregate-remove-host $AGGREGATE2_ID $FIRST_HOST -nova aggregate-remove-host $AGGREGATE_ID $FIRST_HOST - -# Test aggregate-delete -# ===================== -nova aggregate-delete $AGGREGATE_ID -nova aggregate-delete $AGGREGATE2_ID -exit_if_aggregate_present $AGGREGATE_NAME - -set +o xtrace -echo "**************************************************" -echo "End DevStack Exercise: $0" -echo "**************************************************" diff --git a/exercises/boot_from_volume.sh b/exercises/boot_from_volume.sh deleted file mode 100755 index d520b9bbbf..0000000000 --- a/exercises/boot_from_volume.sh +++ /dev/null @@ -1,223 +0,0 @@ -#!/usr/bin/env bash - -# **boot_from_volume.sh** - -# This script demonstrates how to boot from a volume. It does the following: -# -# * Create a bootable volume -# * Boot a volume-backed instance - -echo "*********************************************************************" -echo "Begin DevStack Exercise: $0" -echo "*********************************************************************" - -# This script exits on an error so that errors don't compound and you see -# only the first error that occurred. -set -o errexit - -# Print the commands being run so that we can see the command that triggers -# an error. It is also useful for following allowing as the install occurs. -set -o xtrace - - -# Settings -# ======== - -# Keep track of the current directory -EXERCISE_DIR=$(cd $(dirname "$0") && pwd) -TOP_DIR=$(cd $EXERCISE_DIR/..; pwd) - -# Import common functions -source $TOP_DIR/functions - -# Import project functions -source $TOP_DIR/lib/cinder -source $TOP_DIR/lib/neutron-legacy - -# Import configuration -source $TOP_DIR/openrc - -# Import exercise configuration -source $TOP_DIR/exerciserc - -# If cinder is not enabled we exit with exitcode 55 so that -# the exercise is skipped -is_service_enabled cinder || exit 55 - -# Ironic does not support boot from volume. -[ "$VIRT_DRIVER" == "ironic" ] && exit 55 - -# Instance type to create -DEFAULT_INSTANCE_TYPE=${DEFAULT_INSTANCE_TYPE:-m1.tiny} - -# Boot this image, use first AMI image if unset -DEFAULT_IMAGE_NAME=${DEFAULT_IMAGE_NAME:-ami} - -# Security group name -SECGROUP=${SECGROUP:-boot_secgroup} - -# Instance and volume names -VM_NAME=${VM_NAME:-ex-bfv-inst} -VOL_NAME=${VOL_NAME:-ex-vol-bfv} - - -# Launching a server -# ================== - -# List servers for tenant: -nova list - -# Images -# ------ - -# List the images available -openstack image list - -# Grab the id of the image to launch -IMAGE=$(openstack image list | egrep " $DEFAULT_IMAGE_NAME " | get_field 1) -die_if_not_set $LINENO IMAGE "Failure getting image $DEFAULT_IMAGE_NAME" - -# Security Groups -# --------------- - -# List security groups -nova secgroup-list - -if is_service_enabled n-cell; then - # Cells does not support security groups, so force the use of "default" - SECGROUP="default" - echo "Using the default security group because of Cells." -else - # Create a secgroup - if ! nova secgroup-list | grep -q $SECGROUP; then - nova secgroup-create $SECGROUP "$SECGROUP description" - if ! timeout $ASSOCIATE_TIMEOUT sh -c "while ! nova secgroup-list | grep -q $SECGROUP; do sleep 1; done"; then - echo "Security group not created" - exit 1 - fi - fi -fi - -# Configure Security Group Rules -if ! nova secgroup-list-rules $SECGROUP | grep -q icmp; then - nova secgroup-add-rule $SECGROUP icmp -1 -1 0.0.0.0/0 -fi -if ! nova secgroup-list-rules $SECGROUP | grep -q " tcp .* 22 "; then - nova secgroup-add-rule $SECGROUP tcp 22 22 0.0.0.0/0 -fi - -# List secgroup rules -nova secgroup-list-rules $SECGROUP - -# Set up instance -# --------------- - -# List flavors -nova flavor-list - -# Select a flavor -INSTANCE_TYPE=$(nova flavor-list | grep $DEFAULT_INSTANCE_TYPE | get_field 1) -if [[ -z "$INSTANCE_TYPE" ]]; then - # grab the first flavor in the list to launch if default doesn't exist - INSTANCE_TYPE=$(nova flavor-list | head -n 4 | tail -n 1 | get_field 1) -fi - -# Clean-up from previous runs -nova delete $VM_NAME || true -if ! timeout $ACTIVE_TIMEOUT sh -c "while nova show $VM_NAME; do sleep 1; done"; then - echo "server didn't terminate!" - exit 1 -fi - -# Setup Keypair -KEY_NAME=test_key -KEY_FILE=key.pem -nova keypair-delete $KEY_NAME || true -nova keypair-add $KEY_NAME > $KEY_FILE -chmod 600 $KEY_FILE - -# Set up volume -# ------------- - -# Delete any old volume -cinder delete $VOL_NAME || true -if ! timeout $ACTIVE_TIMEOUT sh -c "while cinder list | grep $VOL_NAME; do sleep 1; done"; then - echo "Volume $VOL_NAME not deleted" - exit 1 -fi - -# Create the bootable volume -start_time=$(date +%s) -cinder create --image-id $IMAGE --display-name=$VOL_NAME --display-description "test bootable volume: $VOL_NAME" $DEFAULT_VOLUME_SIZE || \ - die $LINENO "Failure creating volume $VOL_NAME" -if ! timeout $ACTIVE_TIMEOUT sh -c "while ! cinder list | grep $VOL_NAME | grep available; do sleep 1; done"; then - echo "Volume $VOL_NAME not created" - exit 1 -fi -end_time=$(date +%s) -echo "Completed cinder create in $((end_time - start_time)) seconds" - -# Get volume ID -VOL_ID=$(cinder list | grep $VOL_NAME | get_field 1) -die_if_not_set $LINENO VOL_ID "Failure retrieving volume ID for $VOL_NAME" - -# Boot instance -# ------------- - -# Boot using the --block-device-mapping param. The format of mapping is: -# =::: -# Leaving the middle two fields blank appears to do-the-right-thing -VM_UUID=$(nova boot --flavor $INSTANCE_TYPE --image $IMAGE --block-device-mapping vda=$VOL_ID --security-groups=$SECGROUP --key-name $KEY_NAME $VM_NAME | grep ' id ' | get_field 2) -die_if_not_set $LINENO VM_UUID "Failure launching $VM_NAME" - -# Check that the status is active within ACTIVE_TIMEOUT seconds -if ! timeout $ACTIVE_TIMEOUT sh -c "while ! nova show $VM_UUID | grep status | grep -q ACTIVE; do sleep 1; done"; then - echo "server didn't become active!" - exit 1 -fi - -# Get the instance IP -IP=$(get_instance_ip $VM_UUID $PRIVATE_NETWORK_NAME) - -die_if_not_set $LINENO IP "Failure retrieving IP address" - -# Private IPs can be pinged in single node deployments -ping_check $IP $BOOT_TIMEOUT "$PRIVATE_NETWORK_NAME" - -# Clean up -# -------- - -# Delete volume backed instance -nova delete $VM_UUID || die $LINENO "Failure deleting instance $VM_NAME" -if ! timeout $TERMINATE_TIMEOUT sh -c "while nova list | grep -q $VM_UUID; do sleep 1; done"; then - echo "Server $VM_NAME not deleted" - exit 1 -fi - -# Wait for volume to be released -if ! timeout $ACTIVE_TIMEOUT sh -c "while ! cinder list | grep $VOL_NAME | grep available; do sleep 1; done"; then - echo "Volume $VOL_NAME not released" - exit 1 -fi - -# Delete volume -start_time=$(date +%s) -cinder delete $VOL_ID || die $LINENO "Failure deleting volume $VOLUME_NAME" -if ! timeout $ACTIVE_TIMEOUT sh -c "while cinder list | grep $VOL_NAME; do sleep 1; done"; then - echo "Volume $VOL_NAME not deleted" - exit 1 -fi -end_time=$(date +%s) -echo "Completed cinder delete in $((end_time - start_time)) seconds" - -if [[ $SECGROUP = "default" ]] ; then - echo "Skipping deleting default security group" -else - # Delete secgroup - nova secgroup-delete $SECGROUP || die $LINENO "Failure deleting security group $SECGROUP" -fi - -set +o xtrace -echo "*********************************************************************" -echo "SUCCESS: End DevStack Exercise: $0" -echo "*********************************************************************" diff --git a/exercises/bundle.sh b/exercises/bundle.sh deleted file mode 100755 index 5470960b91..0000000000 --- a/exercises/bundle.sh +++ /dev/null @@ -1,74 +0,0 @@ -#!/usr/bin/env bash - -# **bundle.sh** - -# we will use the ``euca2ools`` cli tool that wraps the python boto -# library to test ec2 bundle upload compatibility - -echo "*********************************************************************" -echo "Begin DevStack Exercise: $0" -echo "*********************************************************************" - -# This script exits on an error so that errors don't compound and you see -# only the first error that occurred. -set -o errexit - -# Print the commands being run so that we can see the command that triggers -# an error. It is also useful for following allowing as the install occurs. -set -o xtrace - - -# Settings -# ======== - -# Keep track of the current directory -EXERCISE_DIR=$(cd $(dirname "$0") && pwd) -TOP_DIR=$(cd $EXERCISE_DIR/..; pwd) - -# Import common functions -source $TOP_DIR/functions - -# Import EC2 configuration -source $TOP_DIR/eucarc - -# Import exercise configuration -source $TOP_DIR/exerciserc - -# Remove old certificates -rm -f $TOP_DIR/cacert.pem -rm -f $TOP_DIR/cert.pem -rm -f $TOP_DIR/pk.pem - -# If nova api is not enabled we exit with exitcode 55 so that -# the exercise is skipped -is_service_enabled n-api || exit 55 - -# Get Certificates -nova x509-get-root-cert $TOP_DIR/cacert.pem -nova x509-create-cert $TOP_DIR/pk.pem $TOP_DIR/cert.pem - -# Max time to wait for image to be registered -REGISTER_TIMEOUT=${REGISTER_TIMEOUT:-15} - -BUCKET=testbucket -IMAGE=bundle.img -truncate -s 5M /tmp/$IMAGE -euca-bundle-image -i /tmp/$IMAGE || die $LINENO "Failure bundling image $IMAGE" - -euca-upload-bundle --debug -b $BUCKET -m /tmp/$IMAGE.manifest.xml || die $LINENO "Failure uploading bundle $IMAGE to $BUCKET" - -AMI=`euca-register $BUCKET/$IMAGE.manifest.xml | cut -f2` -die_if_not_set $LINENO AMI "Failure registering $BUCKET/$IMAGE" - -# Wait for the image to become available -if ! timeout $REGISTER_TIMEOUT sh -c "while euca-describe-images | grep $AMI | grep -q available; do sleep 1; done"; then - die $LINENO "Image $AMI not available within $REGISTER_TIMEOUT seconds" -fi - -# Clean up -euca-deregister $AMI || die $LINENO "Failure deregistering $AMI" - -set +o xtrace -echo "*********************************************************************" -echo "SUCCESS: End DevStack Exercise: $0" -echo "*********************************************************************" diff --git a/exercises/client-args.sh b/exercises/client-args.sh deleted file mode 100755 index c33ef44e9a..0000000000 --- a/exercises/client-args.sh +++ /dev/null @@ -1,176 +0,0 @@ -#!/usr/bin/env bash - -# **client-args.sh** - -# Test OpenStack client authentication arguments handling - -echo "*********************************************************************" -echo "Begin DevStack Exercise: $0" -echo "*********************************************************************" - -# This script exits on an error so that errors don't compound and you see -# only the first error that occurred. -set -o errexit - -# Print the commands being run so that we can see the command that triggers -# an error. It is also useful for following allowing as the install occurs. -set -o xtrace - - -# Settings -# ======== - -# Keep track of the current directory -EXERCISE_DIR=$(cd $(dirname "$0") && pwd) -TOP_DIR=$(cd $EXERCISE_DIR/..; pwd) - -# Import common functions -source $TOP_DIR/functions - -# Import configuration -source $TOP_DIR/openrc - -# Import exercise configuration -source $TOP_DIR/exerciserc - -# Unset all of the known NOVA_* vars -unset NOVA_API_KEY -unset NOVA_ENDPOINT_NAME -unset NOVA_PASSWORD -unset NOVA_PROJECT_ID -unset NOVA_REGION_NAME -unset NOVA_URL -unset NOVA_USERNAME -unset NOVA_VERSION - -# Save the known variables for later -export x_TENANT_NAME=$OS_TENANT_NAME -export x_USERNAME=$OS_USERNAME -export x_PASSWORD=$OS_PASSWORD -export x_AUTH_URL=$OS_AUTH_URL - -# Unset the usual variables to force argument processing -unset OS_TENANT_NAME -unset OS_USERNAME -unset OS_PASSWORD -unset OS_AUTH_URL - -# Common authentication args -TENANT_ARG="--os-tenant-name=$x_TENANT_NAME" -ARGS="--os-username=$x_USERNAME --os-password=$x_PASSWORD --os-auth-url=$x_AUTH_URL" - -# Set global return -RETURN=0 - -# Keystone client -# --------------- -if [[ "$ENABLED_SERVICES" =~ "key" ]]; then - if [[ "$SKIP_EXERCISES" =~ "key" ]]; then - STATUS_KEYSTONE="Skipped" - else - echo -e "\nTest Keystone" - if openstack $TENANT_ARG $ARGS catalog show identity; then - STATUS_KEYSTONE="Succeeded" - else - STATUS_KEYSTONE="Failed" - RETURN=1 - fi - fi -fi - -# Nova client -# ----------- - -if [[ "$ENABLED_SERVICES" =~ "n-api" ]]; then - if [[ "$SKIP_EXERCISES" =~ "n-api" ]]; then - STATUS_NOVA="Skipped" - STATUS_EC2="Skipped" - else - # Test OSAPI - echo -e "\nTest Nova" - if nova $TENANT_ARG $ARGS flavor-list; then - STATUS_NOVA="Succeeded" - else - STATUS_NOVA="Failed" - RETURN=1 - fi - fi -fi - -# Cinder client -# ------------- - -if [[ "$ENABLED_SERVICES" =~ "c-api" ]]; then - if [[ "$SKIP_EXERCISES" =~ "c-api" ]]; then - STATUS_CINDER="Skipped" - else - echo -e "\nTest Cinder" - if cinder $TENANT_ARG $ARGS list; then - STATUS_CINDER="Succeeded" - else - STATUS_CINDER="Failed" - RETURN=1 - fi - fi -fi - -# Glance client -# ------------- - -if [[ "$ENABLED_SERVICES" =~ "g-api" ]]; then - if [[ "$SKIP_EXERCISES" =~ "g-api" ]]; then - STATUS_GLANCE="Skipped" - else - echo -e "\nTest Glance" - if openstack $TENANT_ARG $ARGS image list; then - STATUS_GLANCE="Succeeded" - else - STATUS_GLANCE="Failed" - RETURN=1 - fi - fi -fi - -# Swift client -# ------------ - -if [[ "$ENABLED_SERVICES" =~ "swift" || "$ENABLED_SERVICES" =~ "s-proxy" ]]; then - if [[ "$SKIP_EXERCISES" =~ "swift" ]]; then - STATUS_SWIFT="Skipped" - else - echo -e "\nTest Swift" - if swift $TENANT_ARG $ARGS stat; then - STATUS_SWIFT="Succeeded" - else - STATUS_SWIFT="Failed" - RETURN=1 - fi - fi -fi - -set +o xtrace - - -# Results -# ======= - -function report { - if [[ -n "$2" ]]; then - echo "$1: $2" - fi -} - -echo -e "\n" -report "Keystone" $STATUS_KEYSTONE -report "Nova" $STATUS_NOVA -report "Cinder" $STATUS_CINDER -report "Glance" $STATUS_GLANCE -report "Swift" $STATUS_SWIFT - -if (( $RETURN == 0 )); then - echo "*********************************************************************" - echo "SUCCESS: End DevStack Exercise: $0" - echo "*********************************************************************" -fi - -exit $RETURN diff --git a/exercises/client-env.sh b/exercises/client-env.sh deleted file mode 100755 index 4a0609a944..0000000000 --- a/exercises/client-env.sh +++ /dev/null @@ -1,188 +0,0 @@ -#!/usr/bin/env bash - -# **client-env.sh** - -# Test OpenStack client environment variable handling - -echo "*********************************************************************" -echo "Begin DevStack Exercise: $0" -echo "*********************************************************************" - -# This script exits on an error so that errors don't compound and you see -# only the first error that occurred. -set -o errexit - -# Print the commands being run so that we can see the command that triggers -# an error. It is also useful for following allowing as the install occurs. -set -o xtrace - - -# Settings -# ======== - -# Keep track of the current directory -EXERCISE_DIR=$(cd $(dirname "$0") && pwd) -TOP_DIR=$(cd $EXERCISE_DIR/..; pwd) - -# Import common functions -source $TOP_DIR/functions - -# Import configuration -source $TOP_DIR/openrc admin - -# Import exercise configuration -source $TOP_DIR/exerciserc - -# Unset all of the known NOVA_* vars -unset NOVA_API_KEY -unset NOVA_ENDPOINT_NAME -unset NOVA_PASSWORD -unset NOVA_PROJECT_ID -unset NOVA_REGION_NAME -unset NOVA_URL -unset NOVA_USERNAME -unset NOVA_VERSION - -for i in OS_TENANT_NAME OS_USERNAME OS_PASSWORD OS_AUTH_URL; do - is_set $i - if [[ $? -ne 0 ]]; then - echo "$i expected to be set" - ABORT=1 - fi -done -if [[ -n "$ABORT" ]]; then - exit 1 -fi - -# Set global return -RETURN=0 - -# Keystone client -# --------------- -if [[ "$ENABLED_SERVICES" =~ "key" ]]; then - if [[ "$SKIP_EXERCISES" =~ "key" ]]; then - STATUS_KEYSTONE="Skipped" - else - echo -e "\nTest Keystone" - if openstack endpoint show identity; then - STATUS_KEYSTONE="Succeeded" - else - STATUS_KEYSTONE="Failed" - RETURN=1 - fi - fi -fi - -# Nova client -# ----------- - -if [[ "$ENABLED_SERVICES" =~ "n-api" ]]; then - if [[ "$SKIP_EXERCISES" =~ "n-api" ]]; then - STATUS_NOVA="Skipped" - STATUS_EC2="Skipped" - else - # Test OSAPI - echo -e "\nTest Nova" - if nova flavor-list; then - STATUS_NOVA="Succeeded" - else - STATUS_NOVA="Failed" - RETURN=1 - fi - - # Test EC2 API - echo -e "\nTest EC2" - # Get EC2 creds - source $TOP_DIR/eucarc - - if euca-describe-images; then - STATUS_EC2="Succeeded" - else - STATUS_EC2="Failed" - RETURN=1 - fi - - # Clean up side effects - unset NOVA_VERSION - fi -fi - -# Cinder client -# ------------- - -if [[ "$ENABLED_SERVICES" =~ "c-api" ]]; then - if [[ "$SKIP_EXERCISES" =~ "c-api" ]]; then - STATUS_CINDER="Skipped" - else - echo -e "\nTest Cinder" - if cinder list; then - STATUS_CINDER="Succeeded" - else - STATUS_CINDER="Failed" - RETURN=1 - fi - fi -fi - -# Glance client -# ------------- - -if [[ "$ENABLED_SERVICES" =~ "g-api" ]]; then - if [[ "$SKIP_EXERCISES" =~ "g-api" ]]; then - STATUS_GLANCE="Skipped" - else - echo -e "\nTest Glance" - if openstack image list; then - STATUS_GLANCE="Succeeded" - else - STATUS_GLANCE="Failed" - RETURN=1 - fi - fi -fi - -# Swift client -# ------------ - - -if [[ "$ENABLED_SERVICES" =~ "swift" || "$ENABLED_SERVICES" =~ "s-proxy" ]]; then - if [[ "$SKIP_EXERCISES" =~ "swift" ]]; then - STATUS_SWIFT="Skipped" - else - echo -e "\nTest Swift" - if swift stat; then - STATUS_SWIFT="Succeeded" - else - STATUS_SWIFT="Failed" - RETURN=1 - fi - fi -fi - -set +o xtrace - - -# Results -# ======= - -function report { - if [[ -n "$2" ]]; then - echo "$1: $2" - fi -} - -echo -e "\n" -report "Keystone" $STATUS_KEYSTONE -report "Nova" $STATUS_NOVA -report "EC2" $STATUS_EC2 -report "Cinder" $STATUS_CINDER -report "Glance" $STATUS_GLANCE -report "Swift" $STATUS_SWIFT - -if (( $RETURN == 0 )); then - echo "*********************************************************************" - echo "SUCCESS: End DevStack Exercise: $0" - echo "*********************************************************************" -fi - -exit $RETURN diff --git a/exercises/euca.sh b/exercises/euca.sh deleted file mode 100755 index c2957e222b..0000000000 --- a/exercises/euca.sh +++ /dev/null @@ -1,192 +0,0 @@ -#!/usr/bin/env bash - -# **euca.sh** - -# we will use the ``euca2ools`` cli tool that wraps the python boto -# library to test ec2 compatibility - -echo "*********************************************************************" -echo "Begin DevStack Exercise: $0" -echo "*********************************************************************" - -# This script exits on an error so that errors don't compound and you see -# only the first error that occurred. -set -o errexit - -# Print the commands being run so that we can see the command that triggers -# an error. It is also useful for following allowing as the install occurs. -set -o xtrace - - -# Settings -# ======== - -# Keep track of the current directory -EXERCISE_DIR=$(cd $(dirname "$0") && pwd) -TOP_DIR=$(cd $EXERCISE_DIR/..; pwd) -VOLUME_SIZE=1 -ATTACH_DEVICE=/dev/vdc - -# Import common functions -source $TOP_DIR/functions - -# Import EC2 configuration -source $TOP_DIR/eucarc - -# Import exercise configuration -source $TOP_DIR/exerciserc - -# Import project functions -source $TOP_DIR/lib/neutron-legacy - -# If nova api is not enabled we exit with exitcode 55 so that -# the exercise is skipped -is_service_enabled n-api || exit 55 - -# Instance type to create -DEFAULT_INSTANCE_TYPE=${DEFAULT_INSTANCE_TYPE:-m1.tiny} - -# Boot this image, use first AMI image if unset -DEFAULT_IMAGE_NAME=${DEFAULT_IMAGE_NAME:-ami} - -# Security group name -SECGROUP=${SECGROUP:-euca_secgroup} - - -# Launching a server -# ================== - -# Find a machine image to boot -IMAGE=`euca-describe-images | grep machine | grep ${DEFAULT_IMAGE_NAME} | cut -f2 | head -n1` -die_if_not_set $LINENO IMAGE "Failure getting image $DEFAULT_IMAGE_NAME" - -if is_service_enabled n-cell; then - # Cells does not support security groups, so force the use of "default" - SECGROUP="default" - echo "Using the default security group because of Cells." -else - # Add a secgroup - if ! euca-describe-groups | grep -q $SECGROUP; then - euca-add-group -d "$SECGROUP description" $SECGROUP - if ! timeout $ASSOCIATE_TIMEOUT sh -c "while ! euca-describe-groups | grep -q $SECGROUP; do sleep 1; done"; then - die $LINENO "Security group not created" - fi - fi -fi - -# Launch it -INSTANCE=`euca-run-instances -g $SECGROUP -t $DEFAULT_INSTANCE_TYPE $IMAGE | grep INSTANCE | cut -f2` -die_if_not_set $LINENO INSTANCE "Failure launching instance" - -# Assure it has booted within a reasonable time -if ! timeout $RUNNING_TIMEOUT sh -c "while ! euca-describe-instances $INSTANCE | grep -q running; do sleep 1; done"; then - die $LINENO "server didn't become active within $RUNNING_TIMEOUT seconds" -fi - -# Volumes -# ------- -if is_service_enabled c-vol && ! is_service_enabled n-cell && [ "$VIRT_DRIVER" != "ironic" ]; then - VOLUME_ZONE=`euca-describe-availability-zones | head -n1 | cut -f2` - die_if_not_set $LINENO VOLUME_ZONE "Failure to find zone for volume" - - VOLUME=`euca-create-volume -s 1 -z $VOLUME_ZONE | cut -f2` - die_if_not_set $LINENO VOLUME "Failure to create volume" - - # Test that volume has been created - VOLUME=`euca-describe-volumes $VOLUME | cut -f2` - die_if_not_set $LINENO VOLUME "Failure to get volume" - - # Test volume has become available - if ! timeout $RUNNING_TIMEOUT sh -c "while ! euca-describe-volumes $VOLUME | grep -q available; do sleep 1; done"; then - die $LINENO "volume didn't become available within $RUNNING_TIMEOUT seconds" - fi - - # Attach volume to an instance - euca-attach-volume -i $INSTANCE -d $ATTACH_DEVICE $VOLUME || \ - die $LINENO "Failure attaching volume $VOLUME to $INSTANCE" - if ! timeout $ACTIVE_TIMEOUT sh -c "while ! euca-describe-volumes $VOLUME | grep -A 1 in-use | grep -q attach; do sleep 1; done"; then - die $LINENO "Could not attach $VOLUME to $INSTANCE" - fi - - # Detach volume from an instance - euca-detach-volume $VOLUME || \ - die $LINENO "Failure detaching volume $VOLUME to $INSTANCE" - if ! timeout $ACTIVE_TIMEOUT sh -c "while ! euca-describe-volumes $VOLUME | grep -q available; do sleep 1; done"; then - die $LINENO "Could not detach $VOLUME to $INSTANCE" - fi - - # Remove volume - euca-delete-volume $VOLUME || \ - die $LINENO "Failure to delete volume" - if ! timeout $ACTIVE_TIMEOUT sh -c "while euca-describe-volumes | grep $VOLUME; do sleep 1; done"; then - die $LINENO "Could not delete $VOLUME" - fi -else - echo "Volume Tests Skipped" -fi - -if is_service_enabled n-cell; then - echo "Floating IP Tests Skipped because of Cells." -else - # Allocate floating address - FLOATING_IP=`euca-allocate-address | cut -f2` - die_if_not_set $LINENO FLOATING_IP "Failure allocating floating IP" - # describe all instances at this moment - euca-describe-instances - # Associate floating address - euca-associate-address -i $INSTANCE $FLOATING_IP || \ - die $LINENO "Failure associating address $FLOATING_IP to $INSTANCE" - - # Authorize pinging - euca-authorize -P icmp -s 0.0.0.0/0 -t -1:-1 $SECGROUP || \ - die $LINENO "Failure authorizing rule in $SECGROUP" - - # Test we can ping our floating ip within ASSOCIATE_TIMEOUT seconds - ping_check $FLOATING_IP $ASSOCIATE_TIMEOUT "$PUBLIC_NETWORK_NAME" - - # Revoke pinging - euca-revoke -P icmp -s 0.0.0.0/0 -t -1:-1 $SECGROUP || \ - die $LINENO "Failure revoking rule in $SECGROUP" - - # Release floating address - euca-disassociate-address $FLOATING_IP || \ - die $LINENO "Failure disassociating address $FLOATING_IP" - - # Wait just a tick for everything above to complete so release doesn't fail - if ! timeout $ASSOCIATE_TIMEOUT sh -c "while euca-describe-addresses | grep $INSTANCE | grep -q $FLOATING_IP; do sleep 1; done"; then - die $LINENO "Floating ip $FLOATING_IP not disassociated within $ASSOCIATE_TIMEOUT seconds" - fi - - # Release floating address - euca-release-address $FLOATING_IP || \ - die $LINENO "Failure releasing address $FLOATING_IP" - - # Wait just a tick for everything above to complete so terminate doesn't fail - if ! timeout $ASSOCIATE_TIMEOUT sh -c "while euca-describe-addresses | grep -q $FLOATING_IP; do sleep 1; done"; then - die $LINENO "Floating ip $FLOATING_IP not released within $ASSOCIATE_TIMEOUT seconds" - fi -fi - -# Terminate instance -euca-terminate-instances $INSTANCE || \ - die $LINENO "Failure terminating instance $INSTANCE" - -# Assure it has terminated within a reasonable time. The behaviour of this -# case changed with bug/836978. Requesting the status of an invalid instance -# will now return an error message including the instance id, so we need to -# filter that out. -if ! timeout $TERMINATE_TIMEOUT sh -c "while euca-describe-instances $INSTANCE | grep -ve '\(InstanceNotFound\|InvalidInstanceID\.NotFound\)' | grep -q $INSTANCE; do sleep 1; done"; then - die $LINENO "server didn't terminate within $TERMINATE_TIMEOUT seconds" -fi - -if [[ "$SECGROUP" = "default" ]] ; then - echo "Skipping deleting default security group" -else - # Delete secgroup - euca-delete-group $SECGROUP || die $LINENO "Failure deleting security group $SECGROUP" -fi - -set +o xtrace -echo "*********************************************************************" -echo "SUCCESS: End DevStack Exercise: $0" -echo "*********************************************************************" diff --git a/exercises/floating_ips.sh b/exercises/floating_ips.sh deleted file mode 100755 index 4b72a0073f..0000000000 --- a/exercises/floating_ips.sh +++ /dev/null @@ -1,215 +0,0 @@ -#!/usr/bin/env bash - -# **floating_ips.sh** - using the cloud can be fun - -# Test instance connectivity with the ``nova`` command from ``python-novaclient`` - -echo "*********************************************************************" -echo "Begin DevStack Exercise: $0" -echo "*********************************************************************" - -# This script exits on an error so that errors don't compound and you see -# only the first error that occurred. -set -o errexit - -# Print the commands being run so that we can see the command that triggers -# an error. It is also useful for following allowing as the install occurs. -set -o xtrace - - -# Settings -# ======== - -# Keep track of the current directory -EXERCISE_DIR=$(cd $(dirname "$0") && pwd) -TOP_DIR=$(cd $EXERCISE_DIR/..; pwd) - -# Import common functions -source $TOP_DIR/functions - -# Import configuration -source $TOP_DIR/openrc - -# Import project functions -source $TOP_DIR/lib/neutron-legacy - -# Import exercise configuration -source $TOP_DIR/exerciserc - -# If nova api is not enabled we exit with exitcode 55 so that -# the exercise is skipped -is_service_enabled n-api || exit 55 - -# Instance type to create -DEFAULT_INSTANCE_TYPE=${DEFAULT_INSTANCE_TYPE:-m1.tiny} - -# Boot this image, use first AMI image if unset -DEFAULT_IMAGE_NAME=${DEFAULT_IMAGE_NAME:-ami} - -# Security group name -SECGROUP=${SECGROUP:-test_secgroup} - -# Default floating IP pool name -DEFAULT_FLOATING_POOL=${DEFAULT_FLOATING_POOL:-public} - -# Additional floating IP pool and range -TEST_FLOATING_POOL=${TEST_FLOATING_POOL:-test} - -# Instance name -VM_NAME="ex-float" - -# Cells does not support floating ips API calls -is_service_enabled n-cell && exit 55 - -# Launching a server -# ================== - -# List servers for tenant: -nova list - -# Images -# ------ - -# List the images available -openstack image list - -# Grab the id of the image to launch -IMAGE=$(openstack image list | egrep " $DEFAULT_IMAGE_NAME " | get_field 1) -die_if_not_set $LINENO IMAGE "Failure getting image $DEFAULT_IMAGE_NAME" - -# Security Groups -# --------------- - -# List security groups -nova secgroup-list - -# Create a secgroup -if ! nova secgroup-list | grep -q $SECGROUP; then - nova secgroup-create $SECGROUP "$SECGROUP description" - if ! timeout $ASSOCIATE_TIMEOUT sh -c "while ! nova secgroup-list | grep -q $SECGROUP; do sleep 1; done"; then - die $LINENO "Security group not created" - fi -fi - -# Configure Security Group Rules -if ! nova secgroup-list-rules $SECGROUP | grep -q icmp; then - nova secgroup-add-rule $SECGROUP icmp -1 -1 0.0.0.0/0 -fi -if ! nova secgroup-list-rules $SECGROUP | grep -q " tcp .* 22 "; then - nova secgroup-add-rule $SECGROUP tcp 22 22 0.0.0.0/0 -fi - -# List secgroup rules -nova secgroup-list-rules $SECGROUP - -# Set up instance -# --------------- - -# List flavors -nova flavor-list - -# Select a flavor -INSTANCE_TYPE=$(nova flavor-list | grep $DEFAULT_INSTANCE_TYPE | get_field 1) -if [[ -z "$INSTANCE_TYPE" ]]; then - # grab the first flavor in the list to launch if default doesn't exist - INSTANCE_TYPE=$(nova flavor-list | head -n 4 | tail -n 1 | get_field 1) - die_if_not_set $LINENO INSTANCE_TYPE "Failure retrieving INSTANCE_TYPE" -fi - -# Clean-up from previous runs -nova delete $VM_NAME || true -if ! timeout $ACTIVE_TIMEOUT sh -c "while nova show $VM_NAME; do sleep 1; done"; then - die $LINENO "server didn't terminate!" - exit 1 -fi - -# Boot instance -# ------------- - -VM_UUID=$(nova boot --flavor $INSTANCE_TYPE --image $IMAGE --security-groups=$SECGROUP $VM_NAME | grep ' id ' | get_field 2) -die_if_not_set $LINENO VM_UUID "Failure launching $VM_NAME" - -# Check that the status is active within ACTIVE_TIMEOUT seconds -if ! timeout $ACTIVE_TIMEOUT sh -c "while ! nova show $VM_UUID | grep status | grep -q ACTIVE; do sleep 1; done"; then - die $LINENO "server didn't become active!" -fi - -# Get the instance IP -IP=$(get_instance_ip $VM_UUID $PRIVATE_NETWORK_NAME) -die_if_not_set $LINENO IP "Failure retrieving IP address" - -# Private IPs can be pinged in single node deployments -ping_check $IP $BOOT_TIMEOUT "$PRIVATE_NETWORK_NAME" - -# Floating IPs -# ------------ - -# Allocate a floating IP from the default pool -FLOATING_IP=$(nova floating-ip-create | grep $DEFAULT_FLOATING_POOL | get_field 1) -die_if_not_set $LINENO FLOATING_IP "Failure creating floating IP from pool $DEFAULT_FLOATING_POOL" - -# List floating addresses -if ! timeout $ASSOCIATE_TIMEOUT sh -c "while ! nova floating-ip-list | grep -q $FLOATING_IP; do sleep 1; done"; then - die $LINENO "Floating IP not allocated" -fi - -# Add floating IP to our server -nova add-floating-ip $VM_UUID $FLOATING_IP || \ - die $LINENO "Failure adding floating IP $FLOATING_IP to $VM_NAME" - -# Test we can ping our floating IP within ASSOCIATE_TIMEOUT seconds -ping_check $FLOATING_IP $ASSOCIATE_TIMEOUT "$PUBLIC_NETWORK_NAME" - -if ! is_service_enabled neutron; then - # Allocate an IP from second floating pool - TEST_FLOATING_IP=$(nova floating-ip-create $TEST_FLOATING_POOL | grep $TEST_FLOATING_POOL | get_field 1) - die_if_not_set $LINENO TEST_FLOATING_IP "Failure creating floating IP in $TEST_FLOATING_POOL" - - # list floating addresses - if ! timeout $ASSOCIATE_TIMEOUT sh -c "while ! nova floating-ip-list | grep $TEST_FLOATING_POOL | grep -q $TEST_FLOATING_IP; do sleep 1; done"; then - die $LINENO "Floating IP not allocated" - fi -fi - -# Dis-allow icmp traffic (ping) -nova secgroup-delete-rule $SECGROUP icmp -1 -1 0.0.0.0/0 || \ - die $LINENO "Failure deleting security group rule from $SECGROUP" - -if ! timeout $ASSOCIATE_TIMEOUT sh -c "while nova secgroup-list-rules $SECGROUP | grep -q icmp; do sleep 1; done"; then - die $LINENO "Security group rule not deleted from $SECGROUP" -fi - -# FIXME (anthony): make xs support security groups -if [ "$VIRT_DRIVER" != "ironic" -a "$VIRT_DRIVER" != "xenserver" -a "$VIRT_DRIVER" != "openvz" ]; then - # Test we can aren't able to ping our floating ip within ASSOCIATE_TIMEOUT seconds - ping_check $FLOATING_IP $ASSOCIATE_TIMEOUT "$PUBLIC_NETWORK_NAME" Fail -fi - -# Clean up -# -------- - -if ! is_service_enabled neutron; then - # Delete second floating IP - nova floating-ip-delete $TEST_FLOATING_IP || \ - die $LINENO "Failure deleting floating IP $TEST_FLOATING_IP" -fi - -# Delete the floating ip -nova floating-ip-delete $FLOATING_IP || \ - die $LINENO "Failure deleting floating IP $FLOATING_IP" - -# Delete instance -nova delete $VM_UUID || die $LINENO "Failure deleting instance $VM_NAME" -# Wait for termination -if ! timeout $TERMINATE_TIMEOUT sh -c "while nova list | grep -q $VM_UUID; do sleep 1; done"; then - die $LINENO "Server $VM_NAME not deleted" -fi - -# Delete secgroup -nova secgroup-delete $SECGROUP || \ - die $LINENO "Failure deleting security group $SECGROUP" - -set +o xtrace -echo "*********************************************************************" -echo "SUCCESS: End DevStack Exercise: $0" -echo "*********************************************************************" diff --git a/exercises/neutron-adv-test.sh b/exercises/neutron-adv-test.sh deleted file mode 100755 index 04892b0e93..0000000000 --- a/exercises/neutron-adv-test.sh +++ /dev/null @@ -1,453 +0,0 @@ -#!/usr/bin/env bash -# -# Copyright 2012, Cisco Systems -# Copyright 2012, VMware, Inc. -# Copyright 2012, NTT MCL, Inc. -# -# Please direct any questions to dedutta@cisco.com, dwendlandt@vmware.com, nachi@nttmcl.com -# -# **neutron-adv-test.sh** - -# Perform integration testing of Nova and other components with Neutron. - -echo "*********************************************************************" -echo "Begin DevStack Exercise: $0" -echo "*********************************************************************" - -# This script exits on an error so that errors don't compound and you see -# only the first error that occurred. - -set -o errtrace - -trap failed ERR -function failed { - local r=$? - set +o errtrace - set +o xtrace - echo "Failed to execute" - echo "Starting cleanup..." - delete_all - echo "Finished cleanup" - exit $r -} - -# Print the commands being run so that we can see the command that triggers -# an error. It is also useful for following allowing as the install occurs. -set -o xtrace - -# Environment -# ----------- - -# Keep track of the current directory -EXERCISE_DIR=$(cd $(dirname "$0") && pwd) -TOP_DIR=$(cd $EXERCISE_DIR/..; pwd) - -# Import common functions -source $TOP_DIR/functions - -# Import configuration -source $TOP_DIR/openrc - -# Import neutron functions -source $TOP_DIR/lib/neutron-legacy - -# If neutron is not enabled we exit with exitcode 55, which means exercise is skipped. -neutron_plugin_check_adv_test_requirements || exit 55 - -# Import exercise configuration -source $TOP_DIR/exerciserc - -# Neutron Settings -# ---------------- - -TENANTS="DEMO1" -# TODO (nati)_Test public network -#TENANTS="DEMO1,DEMO2" - -PUBLIC_NAME="admin" -DEMO1_NAME="demo1" -DEMO2_NAME="demo2" - -PUBLIC_NUM_NET=1 -DEMO1_NUM_NET=1 -DEMO2_NUM_NET=2 - -PUBLIC_NET1_CIDR="200.0.0.0/24" -DEMO1_NET1_CIDR="10.10.0.0/24" -DEMO2_NET1_CIDR="10.20.0.0/24" -DEMO2_NET2_CIDR="10.20.1.0/24" - -PUBLIC_NET1_GATEWAY="200.0.0.1" -DEMO1_NET1_GATEWAY="10.10.0.1" -DEMO2_NET1_GATEWAY="10.20.0.1" -DEMO2_NET2_GATEWAY="10.20.1.1" - -PUBLIC_NUM_VM=1 -DEMO1_NUM_VM=1 -DEMO2_NUM_VM=2 - -PUBLIC_VM1_NET='admin-net1' -DEMO1_VM1_NET='demo1-net1' -# Multinic settings. But this is fail without nic setting in OS image -DEMO2_VM1_NET='demo2-net1' -DEMO2_VM2_NET='demo2-net2' - -PUBLIC_NUM_ROUTER=1 -DEMO1_NUM_ROUTER=1 -DEMO2_NUM_ROUTER=1 - -PUBLIC_ROUTER1_NET="admin-net1" -DEMO1_ROUTER1_NET="demo1-net1" -DEMO2_ROUTER1_NET="demo2-net1" - -# Various functions -# ----------------- - -function foreach_tenant { - COMMAND=$1 - for TENANT in ${TENANTS//,/ };do - eval ${COMMAND//%TENANT%/$TENANT} - done -} - -function foreach_tenant_resource { - COMMAND=$1 - RESOURCE=$2 - for TENANT in ${TENANTS//,/ };do - eval 'NUM=$'"${TENANT}_NUM_$RESOURCE" - for i in `seq $NUM`;do - local COMMAND_LOCAL=${COMMAND//%TENANT%/$TENANT} - COMMAND_LOCAL=${COMMAND_LOCAL//%NUM%/$i} - eval $COMMAND_LOCAL - done - done -} - -function foreach_tenant_vm { - COMMAND=$1 - foreach_tenant_resource "$COMMAND" 'VM' -} - -function foreach_tenant_net { - COMMAND=$1 - foreach_tenant_resource "$COMMAND" 'NET' -} - -function get_image_id { - local IMAGE_ID=$(openstack image list | egrep " $DEFAULT_IMAGE_NAME " | get_field 1) - die_if_not_set $LINENO IMAGE_ID "Failure retrieving IMAGE_ID" - echo "$IMAGE_ID" -} - -function get_tenant_id { - local TENANT_NAME=$1 - local TENANT_ID=`openstack project list | grep " $TENANT_NAME " | head -n 1 | get_field 1` - die_if_not_set $LINENO TENANT_ID "Failure retrieving TENANT_ID for $TENANT_NAME" - echo "$TENANT_ID" -} - -function get_user_id { - local USER_NAME=$1 - local USER_ID=`openstack user list | grep $USER_NAME | awk '{print $2}'` - die_if_not_set $LINENO USER_ID "Failure retrieving USER_ID for $USER_NAME" - echo "$USER_ID" -} - -function get_role_id { - local ROLE_NAME=$1 - local ROLE_ID=`openstack role list | grep $ROLE_NAME | awk '{print $2}'` - die_if_not_set $LINENO ROLE_ID "Failure retrieving ROLE_ID for $ROLE_NAME" - echo "$ROLE_ID" -} - -function get_network_id { - local NETWORK_NAME="$1" - local NETWORK_ID=`neutron net-list -F id -- --name=$NETWORK_NAME | awk "NR==4" | awk '{print $2}'` - echo $NETWORK_ID -} - -function get_flavor_id { - local INSTANCE_TYPE=$1 - local FLAVOR_ID=`nova flavor-list | grep $INSTANCE_TYPE | awk '{print $2}'` - die_if_not_set $LINENO FLAVOR_ID "Failure retrieving FLAVOR_ID for $INSTANCE_TYPE" - echo "$FLAVOR_ID" -} - -function confirm_server_active { - local VM_UUID=$1 - if ! timeout $ACTIVE_TIMEOUT sh -c "while ! nova show $VM_UUID | grep status | grep -q ACTIVE; do sleep 1; done"; then - echo "server '$VM_UUID' did not become active!" - false - fi -} - -function neutron_debug_admin { - local os_username=$OS_USERNAME - local os_tenant_id=$OS_TENANT_ID - source $TOP_DIR/openrc admin admin - neutron-debug $@ - source $TOP_DIR/openrc $os_username $os_tenant_id -} - -function add_tenant { - openstack project create $1 - openstack user create $2 --password ${ADMIN_PASSWORD} --project $1 - openstack role add Member --project $1 --user $2 -} - -function remove_tenant { - local TENANT=$1 - local TENANT_ID=$(get_tenant_id $TENANT) - openstack project delete $TENANT_ID -} - -function remove_user { - local USER=$1 - local USER_ID=$(get_user_id $USER) - openstack user delete $USER_ID -} - -function create_tenants { - source $TOP_DIR/openrc admin admin - add_tenant demo1 demo1 demo1 - add_tenant demo2 demo2 demo2 - source $TOP_DIR/openrc demo demo -} - -function delete_tenants_and_users { - source $TOP_DIR/openrc admin admin - remove_user demo1 - remove_tenant demo1 - remove_user demo2 - remove_tenant demo2 - echo "removed all tenants" - source $TOP_DIR/openrc demo demo -} - -function create_network { - local TENANT=$1 - local GATEWAY=$2 - local CIDR=$3 - local NUM=$4 - local EXTRA=$5 - local NET_NAME="${TENANT}-net$NUM" - local ROUTER_NAME="${TENANT}-router${NUM}" - source $TOP_DIR/openrc admin admin - local TENANT_ID=$(get_tenant_id $TENANT) - source $TOP_DIR/openrc $TENANT $TENANT - local NET_ID=$(neutron net-create --tenant-id $TENANT_ID $NET_NAME $EXTRA| grep ' id ' | awk '{print $4}' ) - die_if_not_set $LINENO NET_ID "Failure creating NET_ID for $TENANT_ID $NET_NAME $EXTRA" - neutron subnet-create --ip-version 4 --tenant-id $TENANT_ID --gateway $GATEWAY $NET_ID $CIDR - neutron_debug_admin probe-create --device-owner compute $NET_ID - source $TOP_DIR/openrc demo demo -} - -function create_networks { - foreach_tenant_net 'create_network ${%TENANT%_NAME} ${%TENANT%_NET%NUM%_GATEWAY} ${%TENANT%_NET%NUM%_CIDR} %NUM% ${%TENANT%_NET%NUM%_EXTRA}' - #TODO(nati) test security group function - # allow ICMP for both tenant's security groups - #source $TOP_DIR/openrc demo1 demo1 - #$NOVA secgroup-add-rule default icmp -1 -1 0.0.0.0/0 - #source $TOP_DIR/openrc demo2 demo2 - #$NOVA secgroup-add-rule default icmp -1 -1 0.0.0.0/0 -} - -function create_vm { - local TENANT=$1 - local NUM=$2 - local NET_NAMES=$3 - source $TOP_DIR/openrc $TENANT $TENANT - local NIC="" - for NET_NAME in ${NET_NAMES//,/ };do - NIC="$NIC --nic net-id="`get_network_id $NET_NAME` - done - #TODO (nati) Add multi-nic test - #TODO (nati) Add public-net test - local VM_UUID=`nova boot --flavor $(get_flavor_id m1.tiny) \ - --image $(get_image_id) \ - $NIC \ - $TENANT-server$NUM | grep ' id ' | cut -d"|" -f3 | sed 's/ //g'` - die_if_not_set $LINENO VM_UUID "Failure launching $TENANT-server$NUM" - confirm_server_active $VM_UUID -} - -function create_vms { - foreach_tenant_vm 'create_vm ${%TENANT%_NAME} %NUM% ${%TENANT%_VM%NUM%_NET}' -} - -function ping_ip { - # Test agent connection. Assumes namespaces are disabled, and - # that DHCP is in use, but not L3 - local VM_NAME=$1 - local NET_NAME=$2 - IP=$(get_instance_ip $VM_NAME $NET_NAME) - ping_check $IP $BOOT_TIMEOUT $NET_NAME -} - -function check_vm { - local TENANT=$1 - local NUM=$2 - local VM_NAME="$TENANT-server$NUM" - local NET_NAME=$3 - source $TOP_DIR/openrc $TENANT $TENANT - ping_ip $VM_NAME $NET_NAME - # TODO (nati) test ssh connection - # TODO (nati) test inter connection between vm - # TODO (nati) test dhcp host routes - # TODO (nati) test multi-nic -} - -function check_vms { - foreach_tenant_vm 'check_vm ${%TENANT%_NAME} %NUM% ${%TENANT%_VM%NUM%_NET}' -} - -function shutdown_vm { - local TENANT=$1 - local NUM=$2 - source $TOP_DIR/openrc $TENANT $TENANT - VM_NAME=${TENANT}-server$NUM - nova delete $VM_NAME -} - -function shutdown_vms { - foreach_tenant_vm 'shutdown_vm ${%TENANT%_NAME} %NUM%' - if ! timeout $TERMINATE_TIMEOUT sh -c "while nova list | grep -q ACTIVE; do sleep 1; done"; then - die $LINENO "Some VMs failed to shutdown" - fi -} - -function delete_network { - local TENANT=$1 - local NUM=$2 - local NET_NAME="${TENANT}-net$NUM" - source $TOP_DIR/openrc admin admin - local TENANT_ID=$(get_tenant_id $TENANT) - #TODO(nati) comment out until l3-agent merged - #for res in port subnet net router;do - for net_id in `neutron net-list -c id -c name | grep $NET_NAME | awk '{print $2}'`;do - delete_probe $net_id - neutron subnet-list | grep $net_id | awk '{print $2}' | xargs -I% neutron subnet-delete % - neutron net-delete $net_id - done - source $TOP_DIR/openrc demo demo -} - -function delete_networks { - foreach_tenant_net 'delete_network ${%TENANT%_NAME} %NUM%' - # TODO(nati) add secuirty group check after it is implemented - # source $TOP_DIR/openrc demo1 demo1 - # nova secgroup-delete-rule default icmp -1 -1 0.0.0.0/0 - # source $TOP_DIR/openrc demo2 demo2 - # nova secgroup-delete-rule default icmp -1 -1 0.0.0.0/0 -} - -function create_all { - create_tenants - create_networks - create_vms -} - -function delete_all { - shutdown_vms - delete_networks - delete_tenants_and_users -} - -function all { - create_all - check_vms - delete_all -} - -# Test functions -# -------------- - -function test_functions { - IMAGE=$(get_image_id) - echo $IMAGE - - TENANT_ID=$(get_tenant_id demo) - echo $TENANT_ID - - FLAVOR_ID=$(get_flavor_id m1.tiny) - echo $FLAVOR_ID - - NETWORK_ID=$(get_network_id admin) - echo $NETWORK_ID -} - -# Usage and main -# -------------- - -function usage { - echo "$0: [-h]" - echo " -h, --help Display help message" - echo " -t, --tenant Create tenants" - echo " -n, --net Create networks" - echo " -v, --vm Create vms" - echo " -c, --check Check connection" - echo " -x, --delete-tenants Delete tenants" - echo " -y, --delete-nets Delete networks" - echo " -z, --delete-vms Delete vms" - echo " -T, --test Test functions" -} - -function main { - - echo Description - - if [ $# -eq 0 ] ; then - # if no args are provided, run all tests - all - else - - while [ "$1" != "" ]; do - case $1 in - -h | --help ) usage - exit - ;; - -n | --net ) create_networks - exit - ;; - -v | --vm ) create_vms - exit - ;; - -t | --tenant ) create_tenants - exit - ;; - -c | --check ) check_vms - exit - ;; - -T | --test ) test_functions - exit - ;; - -x | --delete-tenants ) delete_tenants_and_users - exit - ;; - -y | --delete-nets ) delete_networks - exit - ;; - -z | --delete-vms ) shutdown_vms - exit - ;; - -a | --all ) all - exit - ;; - * ) usage - exit 1 - esac - shift - done - fi -} - -# Kick off script -# --------------- - -echo $* -main $* - -set +o xtrace -echo "*********************************************************************" -echo "SUCCESS: End DevStack Exercise: $0" -echo "*********************************************************************" diff --git a/exercises/sahara.sh b/exercises/sahara.sh deleted file mode 100755 index 2589e28c0c..0000000000 --- a/exercises/sahara.sh +++ /dev/null @@ -1,43 +0,0 @@ -#!/usr/bin/env bash - -# **sahara.sh** - -# Sanity check that Sahara started if enabled - -echo "*********************************************************************" -echo "Begin DevStack Exercise: $0" -echo "*********************************************************************" - -# This script exits on an error so that errors don't compound and you see -# only the first error that occurred. -set -o errexit - -# Print the commands being run so that we can see the command that triggers -# an error. It is also useful for following allowing as the install occurs. -set -o xtrace - - -# Settings -# ======== - -# Keep track of the current directory -EXERCISE_DIR=$(cd $(dirname "$0") && pwd) -TOP_DIR=$(cd $EXERCISE_DIR/..; pwd) - -# Import common functions -source $TOP_DIR/functions - -# Import configuration -source $TOP_DIR/openrc - -# Import exercise configuration -source $TOP_DIR/exerciserc - -is_service_enabled sahara || exit 55 - -$CURL_GET http://$SERVICE_HOST:8386/ 2>/dev/null | grep -q 'Auth' || die $LINENO "Sahara API isn't functioning!" - -set +o xtrace -echo "*********************************************************************" -echo "SUCCESS: End DevStack Exercise: $0" -echo "*********************************************************************" diff --git a/exercises/sec_groups.sh b/exercises/sec_groups.sh deleted file mode 100755 index 5f8b0a4d5d..0000000000 --- a/exercises/sec_groups.sh +++ /dev/null @@ -1,81 +0,0 @@ -#!/usr/bin/env bash - -# **sec_groups.sh** - -# Test security groups via the command line - -echo "*********************************************************************" -echo "Begin DevStack Exercise: $0" -echo "*********************************************************************" - -# This script exits on an error so that errors don't compound and you see -# only the first error that occurred. -set -o errexit - -# Print the commands being run so that we can see the command that triggers -# an error. It is also useful for following allowing as the install occurs. -set -o xtrace - - -# Settings -# ======== - -# Keep track of the current directory -EXERCISE_DIR=$(cd $(dirname "$0") && pwd) -TOP_DIR=$(cd $EXERCISE_DIR/..; pwd) - -# Import common functions -source $TOP_DIR/functions - -# Import configuration -source $TOP_DIR/openrc - -# Import exercise configuration -source $TOP_DIR/exerciserc - -# If nova api is not enabled we exit with exitcode 55 so that -# the exercise is skipped -is_service_enabled n-api || exit 55 - - -# Testing Security Groups -# ======================= - -# List security groups -nova secgroup-list - -# Create random name for new sec group and create secgroup of said name -SEC_GROUP_NAME="ex-secgroup-$(openssl rand -hex 4)" -nova secgroup-create $SEC_GROUP_NAME 'a test security group' - -# Add some rules to the secgroup -RULES_TO_ADD=( 22 3389 5900 ) - -for RULE in "${RULES_TO_ADD[@]}"; do - nova secgroup-add-rule $SEC_GROUP_NAME tcp $RULE $RULE 0.0.0.0/0 -done - -# Check to make sure rules were added -SEC_GROUP_RULES=( $(nova secgroup-list-rules $SEC_GROUP_NAME | grep -v \- | grep -v 'Source Group' | cut -d '|' -f3 | tr -d ' ') ) -die_if_not_set $LINENO SEC_GROUP_RULES "Failure retrieving SEC_GROUP_RULES for $SEC_GROUP_NAME" -for i in "${RULES_TO_ADD[@]}"; do - skip= - for j in "${SEC_GROUP_RULES[@]}"; do - [[ $i == $j ]] && { skip=1; break; } - done - [[ -n $skip ]] || exit 1 -done - -# Delete rules and secgroup -for RULE in "${RULES_TO_ADD[@]}"; do - nova secgroup-delete-rule $SEC_GROUP_NAME tcp $RULE $RULE 0.0.0.0/0 -done - -# Delete secgroup -nova secgroup-delete $SEC_GROUP_NAME || \ - die $LINENO "Failure deleting security group $SEC_GROUP_NAME" - -set +o xtrace -echo "*********************************************************************" -echo "SUCCESS: End DevStack Exercise: $0" -echo "*********************************************************************" diff --git a/exercises/swift.sh b/exercises/swift.sh deleted file mode 100755 index afcede81cd..0000000000 --- a/exercises/swift.sh +++ /dev/null @@ -1,66 +0,0 @@ -#!/usr/bin/env bash - -# **swift.sh** - -# Test swift via the ``swift`` command line from ``python-swiftclient`` - -echo "*********************************************************************" -echo "Begin DevStack Exercise: $0" -echo "*********************************************************************" - -# This script exits on an error so that errors don't compound and you see -# only the first error that occurred. -set -o errexit - -# Print the commands being run so that we can see the command that triggers -# an error. It is also useful for following allowing as the install occurs. -set -o xtrace - - -# Settings -# ======== - -# Keep track of the current directory -EXERCISE_DIR=$(cd $(dirname "$0") && pwd) -TOP_DIR=$(cd $EXERCISE_DIR/..; pwd) - -# Import common functions -source $TOP_DIR/functions - -# Import configuration -source $TOP_DIR/openrc - -# Import exercise configuration -source $TOP_DIR/exerciserc - -# If swift is not enabled we exit with exitcode 55 which mean -# exercise is skipped. -is_service_enabled s-proxy || exit 55 - -# Container name -CONTAINER=ex-swift - - -# Testing Swift -# ============= - -# Check if we have to swift via keystone -swift stat || die $LINENO "Failure getting status" - -# We start by creating a test container -openstack container create $CONTAINER || die $LINENO "Failure creating container $CONTAINER" - -# add some files into it. -openstack object create $CONTAINER /etc/issue || die $LINENO "Failure uploading file to container $CONTAINER" - -# list them -openstack object list $CONTAINER || die $LINENO "Failure listing contents of container $CONTAINER" - -# And we may want to delete them now that we have tested that -# everything works. -swift delete $CONTAINER || die $LINENO "Failure deleting container $CONTAINER" - -set +o xtrace -echo "*********************************************************************" -echo "SUCCESS: End DevStack Exercise: $0" -echo "*********************************************************************" diff --git a/exercises/volumes.sh b/exercises/volumes.sh deleted file mode 100755 index f95c81fdf1..0000000000 --- a/exercises/volumes.sh +++ /dev/null @@ -1,224 +0,0 @@ -#!/usr/bin/env bash - -# **volumes.sh** - -# Test cinder volumes with the ``cinder`` command from ``python-cinderclient`` - -echo "*********************************************************************" -echo "Begin DevStack Exercise: $0" -echo "*********************************************************************" - -# This script exits on an error so that errors don't compound and you see -# only the first error that occurred. -set -o errexit - -# Print the commands being run so that we can see the command that triggers -# an error. It is also useful for following allowing as the install occurs. -set -o xtrace - - -# Settings -# ======== - -# Keep track of the current directory -EXERCISE_DIR=$(cd $(dirname "$0") && pwd) -TOP_DIR=$(cd $EXERCISE_DIR/..; pwd) - -# Import common functions -source $TOP_DIR/functions - -# Import configuration -source $TOP_DIR/openrc - -# Import project functions -source $TOP_DIR/lib/cinder -source $TOP_DIR/lib/neutron-legacy - -# Import exercise configuration -source $TOP_DIR/exerciserc - -# If cinder is not enabled we exit with exitcode 55 which mean -# exercise is skipped. -is_service_enabled cinder || exit 55 - -# Ironic does not currently support volume attachment. -[ "$VIRT_DRIVER" == "ironic" ] && exit 55 - -# Instance type to create -DEFAULT_INSTANCE_TYPE=${DEFAULT_INSTANCE_TYPE:-m1.tiny} - -# Boot this image, use first AMI image if unset -DEFAULT_IMAGE_NAME=${DEFAULT_IMAGE_NAME:-ami} - -# Security group name -SECGROUP=${SECGROUP:-vol_secgroup} - -# Instance and volume names -VM_NAME=${VM_NAME:-ex-vol-inst} -VOL_NAME="ex-vol-$(openssl rand -hex 4)" - - -# Launching a server -# ================== - -# List servers for tenant: -nova list - -# Images -# ------ - -# List the images available -openstack image list - -# Grab the id of the image to launch -IMAGE=$(openstack image list | egrep " $DEFAULT_IMAGE_NAME " | get_field 1) -die_if_not_set $LINENO IMAGE "Failure getting image $DEFAULT_IMAGE_NAME" - -# Security Groups -# --------------- - -# List security groups -nova secgroup-list - -if is_service_enabled n-cell; then - # Cells does not support security groups, so force the use of "default" - SECGROUP="default" - echo "Using the default security group because of Cells." -else - # Create a secgroup - if ! nova secgroup-list | grep -q $SECGROUP; then - nova secgroup-create $SECGROUP "$SECGROUP description" - if ! timeout $ASSOCIATE_TIMEOUT sh -c "while ! nova secgroup-list | grep -q $SECGROUP; do sleep 1; done"; then - echo "Security group not created" - exit 1 - fi - fi -fi - -# Configure Security Group Rules -if ! nova secgroup-list-rules $SECGROUP | grep -q icmp; then - nova secgroup-add-rule $SECGROUP icmp -1 -1 0.0.0.0/0 -fi -if ! nova secgroup-list-rules $SECGROUP | grep -q " tcp .* 22 "; then - nova secgroup-add-rule $SECGROUP tcp 22 22 0.0.0.0/0 -fi - -# List secgroup rules -nova secgroup-list-rules $SECGROUP - -# Set up instance -# --------------- - -# List flavors -nova flavor-list - -# Select a flavor -INSTANCE_TYPE=$(nova flavor-list | grep $DEFAULT_INSTANCE_TYPE | get_field 1) -if [[ -z "$INSTANCE_TYPE" ]]; then - # grab the first flavor in the list to launch if default doesn't exist - INSTANCE_TYPE=$(nova flavor-list | head -n 4 | tail -n 1 | get_field 1) - die_if_not_set $LINENO INSTANCE_TYPE "Failure retrieving INSTANCE_TYPE" -fi - -# Clean-up from previous runs -nova delete $VM_NAME || true -if ! timeout $ACTIVE_TIMEOUT sh -c "while nova show $VM_NAME; do sleep 1; done"; then - die $LINENO "server didn't terminate!" -fi - -# Boot instance -# ------------- - -VM_UUID=$(nova boot --flavor $INSTANCE_TYPE --image $IMAGE --security-groups=$SECGROUP $VM_NAME | grep ' id ' | get_field 2) -die_if_not_set $LINENO VM_UUID "Failure launching $VM_NAME" - -# Check that the status is active within ACTIVE_TIMEOUT seconds -if ! timeout $ACTIVE_TIMEOUT sh -c "while ! nova show $VM_UUID | grep status | grep -q ACTIVE; do sleep 1; done"; then - die $LINENO "server didn't become active!" -fi - -# Get the instance IP -IP=$(get_instance_ip $VM_UUID $PRIVATE_NETWORK_NAME) - -die_if_not_set $LINENO IP "Failure retrieving IP address" - -# Private IPs can be pinged in single node deployments -ping_check $IP $BOOT_TIMEOUT "$PRIVATE_NETWORK_NAME" - -# Volumes -# ------- - -# Verify it doesn't exist -if [[ -n $(cinder list | grep $VOL_NAME | head -1 | get_field 2) ]]; then - die $LINENO "Volume $VOL_NAME already exists" -fi - -# Create a new volume -start_time=$(date +%s) -cinder create --display-name $VOL_NAME --display-description "test volume: $VOL_NAME" $DEFAULT_VOLUME_SIZE || \ - die $LINENO "Failure creating volume $VOL_NAME" -if ! timeout $ACTIVE_TIMEOUT sh -c "while ! cinder list | grep $VOL_NAME | grep available; do sleep 1; done"; then - die $LINENO "Volume $VOL_NAME not created" -fi -end_time=$(date +%s) -echo "Completed cinder create in $((end_time - start_time)) seconds" - -# Get volume ID -VOL_ID=$(cinder list | grep $VOL_NAME | head -1 | get_field 1) -die_if_not_set $LINENO VOL_ID "Failure retrieving volume ID for $VOL_NAME" - -# Attach to server -DEVICE=/dev/vdb -start_time=$(date +%s) -nova volume-attach $VM_UUID $VOL_ID $DEVICE || \ - die $LINENO "Failure attaching volume $VOL_NAME to $VM_NAME" -if ! timeout $ACTIVE_TIMEOUT sh -c "while ! cinder list | grep $VOL_NAME | grep in-use; do sleep 1; done"; then - die $LINENO "Volume $VOL_NAME not attached to $VM_NAME" -fi -end_time=$(date +%s) -echo "Completed volume-attach in $((end_time - start_time)) seconds" - -VOL_ATTACH=$(cinder list | grep $VOL_NAME | head -1 | get_field -1) -die_if_not_set $LINENO VOL_ATTACH "Failure retrieving $VOL_NAME status" -if [[ "$VOL_ATTACH" != $VM_UUID ]]; then - die $LINENO "Volume not attached to correct instance" -fi - -# Clean up -# -------- - -# Detach volume -start_time=$(date +%s) -nova volume-detach $VM_UUID $VOL_ID || die $LINENO "Failure detaching volume $VOL_NAME from $VM_NAME" -if ! timeout $ACTIVE_TIMEOUT sh -c "while ! cinder list | grep $VOL_NAME | grep available; do sleep 1; done"; then - die $LINENO "Volume $VOL_NAME not detached from $VM_NAME" -fi -end_time=$(date +%s) -echo "Completed volume-detach in $((end_time - start_time)) seconds" - -# Delete volume -start_time=$(date +%s) -cinder delete $VOL_ID || die $LINENO "Failure deleting volume $VOL_NAME" -if ! timeout $ACTIVE_TIMEOUT sh -c "while cinder list | grep $VOL_NAME; do sleep 1; done"; then - die $LINENO "Volume $VOL_NAME not deleted" -fi -end_time=$(date +%s) -echo "Completed cinder delete in $((end_time - start_time)) seconds" - -# Delete instance -nova delete $VM_UUID || die $LINENO "Failure deleting instance $VM_NAME" -if ! timeout $TERMINATE_TIMEOUT sh -c "while nova list | grep -q $VM_UUID; do sleep 1; done"; then - die $LINENO "Server $VM_NAME not deleted" -fi - -if [[ $SECGROUP = "default" ]] ; then - echo "Skipping deleting default security group" -else - # Delete secgroup - nova secgroup-delete $SECGROUP || die $LINENO "Failure deleting security group $SECGROUP" -fi - -set +o xtrace -echo "*********************************************************************" -echo "SUCCESS: End DevStack Exercise: $0" -echo "*********************************************************************" diff --git a/exercises/zaqar.sh b/exercises/zaqar.sh deleted file mode 100755 index c370b12c85..0000000000 --- a/exercises/zaqar.sh +++ /dev/null @@ -1,43 +0,0 @@ -#!/usr/bin/env bash - -# **zaqar.sh** - -# Sanity check that Zaqar started if enabled - -echo "*********************************************************************" -echo "Begin DevStack Exercise: $0" -echo "*********************************************************************" - -# This script exits on an error so that errors don't compound and you see -# only the first error that occurred. -set -o errexit - -# Print the commands being run so that we can see the command that triggers -# an error. It is also useful for following allowing as the install occurs. -set -o xtrace - - -# Settings -# ======== - -# Keep track of the current directory -EXERCISE_DIR=$(cd $(dirname "$0") && pwd) -TOP_DIR=$(cd $EXERCISE_DIR/..; pwd) - -# Import common functions -source $TOP_DIR/functions - -# Import configuration -source $TOP_DIR/openrc - -# Import exercise configuration -source $TOP_DIR/exerciserc - -is_service_enabled zaqar-server || exit 55 - -$CURL_GET http://$SERVICE_HOST:8888/v1/ 2>/dev/null | grep -q 'queue_name' || die $LINENO "Zaqar API not functioning!" - -set +o xtrace -echo "*********************************************************************" -echo "SUCCESS: End DevStack Exercise: $0" -echo "*********************************************************************" diff --git a/extras.d/50-ironic.sh b/extras.d/50-ironic.sh deleted file mode 100644 index 3b8e3d5045..0000000000 --- a/extras.d/50-ironic.sh +++ /dev/null @@ -1,43 +0,0 @@ -# ironic.sh - Devstack extras script to install ironic - -if is_service_enabled ir-api ir-cond; then - if [[ "$1" == "source" ]]; then - # Initial source - source $TOP_DIR/lib/ironic - elif [[ "$1" == "stack" && "$2" == "install" ]]; then - echo_summary "Installing Ironic" - install_ironic - install_ironicclient - cleanup_ironic - elif [[ "$1" == "stack" && "$2" == "post-config" ]]; then - echo_summary "Configuring Ironic" - configure_ironic - - if is_service_enabled key; then - create_ironic_accounts - fi - - elif [[ "$1" == "stack" && "$2" == "extra" ]]; then - # Initialize ironic - init_ironic - - # Start the ironic API and ironic taskmgr components - echo_summary "Starting Ironic" - start_ironic - - if [[ "$IRONIC_BAREMETAL_BASIC_OPS" = "True" ]]; then - prepare_baremetal_basic_ops - fi - fi - - if [[ "$1" == "unstack" ]]; then - stop_ironic - if [[ "$IRONIC_BAREMETAL_BASIC_OPS" = "True" ]]; then - cleanup_baremetal_basic_ops - fi - fi - - if [[ "$1" == "clean" ]]; then - cleanup_ironic - fi -fi diff --git a/extras.d/60-ceph.sh b/extras.d/60-ceph.sh deleted file mode 100644 index 38b901b767..0000000000 --- a/extras.d/60-ceph.sh +++ /dev/null @@ -1,75 +0,0 @@ -# ceph.sh - DevStack extras script to install Ceph - -if is_service_enabled ceph; then - if [[ "$1" == "source" ]]; then - # Initial source - source $TOP_DIR/lib/ceph - elif [[ "$1" == "stack" && "$2" == "pre-install" ]]; then - echo_summary "Installing Ceph" - check_os_support_ceph - if [ "$REMOTE_CEPH" = "False" ]; then - install_ceph - echo_summary "Configuring Ceph" - configure_ceph - # NOTE (leseb): Do everything here because we need to have Ceph started before the main - # OpenStack components. Ceph OSD must start here otherwise we can't upload any images. - echo_summary "Initializing Ceph" - init_ceph - start_ceph - else - install_ceph_remote - fi - elif [[ "$1" == "stack" && "$2" == "post-config" ]]; then - if is_service_enabled glance; then - echo_summary "Configuring Glance for Ceph" - configure_ceph_glance - fi - if is_service_enabled nova; then - echo_summary "Configuring Nova for Ceph" - configure_ceph_nova - fi - if is_service_enabled cinder; then - echo_summary "Configuring Cinder for Ceph" - configure_ceph_cinder - fi - if is_service_enabled cinder || is_service_enabled nova; then - # NOTE (leseb): the part below is a requirement to attach Ceph block devices - echo_summary "Configuring libvirt secret" - import_libvirt_secret_ceph - fi - - if [ "$REMOTE_CEPH" = "False" ]; then - if is_service_enabled glance; then - echo_summary "Configuring Glance for Ceph" - configure_ceph_embedded_glance - fi - if is_service_enabled nova; then - echo_summary "Configuring Nova for Ceph" - configure_ceph_embedded_nova - fi - if is_service_enabled cinder; then - echo_summary "Configuring Cinder for Ceph" - configure_ceph_embedded_cinder - fi - fi - fi - - if [[ "$1" == "unstack" ]]; then - if [ "$REMOTE_CEPH" = "True" ]; then - cleanup_ceph_remote - else - cleanup_ceph_embedded - stop_ceph - fi - cleanup_ceph_general - fi - - if [[ "$1" == "clean" ]]; then - if [ "$REMOTE_CEPH" = "True" ]; then - cleanup_ceph_remote - else - cleanup_ceph_embedded - fi - cleanup_ceph_general - fi -fi diff --git a/extras.d/70-sahara.sh b/extras.d/70-sahara.sh deleted file mode 100644 index f177766d3b..0000000000 --- a/extras.d/70-sahara.sh +++ /dev/null @@ -1,29 +0,0 @@ -# sahara.sh - DevStack extras script to install Sahara - -if is_service_enabled sahara; then - if [[ "$1" == "source" ]]; then - # Initial source - source $TOP_DIR/lib/sahara - elif [[ "$1" == "stack" && "$2" == "install" ]]; then - echo_summary "Installing sahara" - install_sahara - install_python_saharaclient - cleanup_sahara - elif [[ "$1" == "stack" && "$2" == "post-config" ]]; then - echo_summary "Configuring sahara" - configure_sahara - create_sahara_accounts - elif [[ "$1" == "stack" && "$2" == "extra" ]]; then - echo_summary "Initializing sahara" - sahara_register_images - start_sahara - fi - - if [[ "$1" == "unstack" ]]; then - stop_sahara - fi - - if [[ "$1" == "clean" ]]; then - cleanup_sahara - fi -fi diff --git a/extras.d/70-zaqar.sh b/extras.d/70-zaqar.sh deleted file mode 100644 index 63c4fd5ad5..0000000000 --- a/extras.d/70-zaqar.sh +++ /dev/null @@ -1,29 +0,0 @@ -# zaqar.sh - Devstack extras script to install Zaqar - -if is_service_enabled zaqar-server; then - if [[ "$1" == "source" ]]; then - # Initial source - source $TOP_DIR/lib/zaqar - elif [[ "$1" == "stack" && "$2" == "install" ]]; then - echo_summary "Installing Zaqar" - install_zaqarclient - install_zaqar - elif [[ "$1" == "stack" && "$2" == "post-config" ]]; then - echo_summary "Configuring Zaqar" - configure_zaqar - configure_zaqarclient - - if is_service_enabled key; then - create_zaqar_accounts - fi - - elif [[ "$1" == "stack" && "$2" == "extra" ]]; then - echo_summary "Initializing Zaqar" - init_zaqar - start_zaqar - fi - - if [[ "$1" == "unstack" ]]; then - stop_zaqar - fi -fi diff --git a/extras.d/80-tempest.sh b/extras.d/80-tempest.sh index 74f4c60d10..15ecfe39eb 100644 --- a/extras.d/80-tempest.sh +++ b/extras.d/80-tempest.sh @@ -9,14 +9,18 @@ if is_service_enabled tempest; then install_tempest elif [[ "$1" == "stack" && "$2" == "post-config" ]]; then # Tempest config must come after layer 2 services are running - create_tempest_accounts + : elif [[ "$1" == "stack" && "$2" == "extra" ]]; then - echo_summary "Initializing Tempest" - configure_tempest - init_tempest + # Tempest config must come after all other plugins are run + : elif [[ "$1" == "stack" && "$2" == "post-extra" ]]; then # local.conf Tempest option overrides : + elif [[ "$1" == "stack" && "$2" == "test-config" ]]; then + echo_summary "Initializing Tempest" + configure_tempest + echo_summary "Installing Tempest Plugins" + install_tempest_plugins fi if [[ "$1" == "unstack" ]]; then @@ -29,4 +33,3 @@ if is_service_enabled tempest; then : fi fi - diff --git a/extras.d/README.md b/extras.d/README.md index 7c2e4fe970..4cec14b4e7 100644 --- a/extras.d/README.md +++ b/extras.d/README.md @@ -14,10 +14,13 @@ The scripts are sourced at the beginning of each script that calls them. The entire `stack.sh` variable space is available. The scripts are sourced with one or more arguments, the first of which defines the hook phase: - source | stack | unstack | clean + override_defaults | source | stack | unstack | clean - source: always called first in any of the scripts, used to set the - initial defaults in a lib/* script or similar + override_defaults: always called first in any of the scripts, used to + override defaults (if need be) that are otherwise set in lib/* scripts + + source: called by stack.sh. Used to set the initial defaults in a lib/* + script or similar stack: called by stack.sh. There are four possible values for the second arg to distinguish the phase stack.sh is in: diff --git a/files/apache-ceilometer.template b/files/apache-ceilometer.template deleted file mode 100644 index 1c57b328b8..0000000000 --- a/files/apache-ceilometer.template +++ /dev/null @@ -1,15 +0,0 @@ -Listen %PORT% - - - WSGIDaemonProcess ceilometer-api processes=2 threads=10 user=%USER% display-name=%{GROUP} - WSGIProcessGroup ceilometer-api - WSGIScriptAlias / %WSGIAPP% - WSGIApplicationGroup %{GLOBAL} - = 2.4> - ErrorLogFormat "%{cu}t %M" - - ErrorLog /var/log/%APACHE_NAME%/ceilometer.log - CustomLog /var/log/%APACHE_NAME%/ceilometer_access.log combined - - -WSGISocketPrefix /var/run/%APACHE_NAME% diff --git a/files/apache-cinder-api.template b/files/apache-cinder-api.template new file mode 100644 index 0000000000..e1246f11b6 --- /dev/null +++ b/files/apache-cinder-api.template @@ -0,0 +1,26 @@ +Listen %PUBLICPORT% + + + WSGIDaemonProcess osapi_volume processes=%APIWORKERS% threads=1 user=%USER% display-name=%{GROUP} %VIRTUALENV% + WSGIProcessGroup osapi_volume + WSGIScriptAlias / %CINDER_BIN_DIR%/cinder-wsgi + WSGIApplicationGroup %{GLOBAL} + WSGIPassAuthorization On + = 2.4> + ErrorLogFormat "%{cu}t %M" + + ErrorLog /var/log/%APACHE_NAME%/c-api.log + %SSLENGINE% + %SSLCERTFILE% + %SSLKEYFILE% + + + = 2.4> + Require all granted + + + Order allow,deny + Allow from all + + + diff --git a/files/apache-heat-pip-repo.template b/files/apache-heat-pip-repo.template deleted file mode 100644 index d88ac3e35a..0000000000 --- a/files/apache-heat-pip-repo.template +++ /dev/null @@ -1,15 +0,0 @@ -Listen %HEAT_PIP_REPO_PORT% - - - DocumentRoot %HEAT_PIP_REPO% - - DirectoryIndex index.html - Require all granted - Order allow,deny - allow from all - - - ErrorLog /var/log/%APACHE_NAME%/heat_pip_repo_error.log - LogLevel warn - CustomLog /var/log/%APACHE_NAME%/heat_pip_repo_access.log combined - diff --git a/files/apache-horizon.template b/files/apache-horizon.template index 68838985ee..efcfc0360b 100644 --- a/files/apache-horizon.template +++ b/files/apache-horizon.template @@ -1,5 +1,5 @@ - WSGIScriptAlias / %HORIZON_DIR%/openstack_dashboard/wsgi/django.wsgi + WSGIScriptAlias %WEBROOT% %HORIZON_DIR%/openstack_dashboard/wsgi.py WSGIDaemonProcess horizon user=%USER% group=%GROUP% processes=3 threads=10 home=%HORIZON_DIR% display-name=%{GROUP} WSGIApplicationGroup %{GLOBAL} @@ -8,7 +8,10 @@ WSGIProcessGroup horizon DocumentRoot %HORIZON_DIR%/.blackhole/ - Alias /media %HORIZON_DIR%/openstack_dashboard/static + Alias %WEBROOT%/media %HORIZON_DIR%/openstack_dashboard/static + Alias %WEBROOT%/static %HORIZON_DIR%/static + + RedirectMatch "^/$" "%WEBROOT%/" Options FollowSymLinks diff --git a/files/apache-ironic.template b/files/apache-ironic.template deleted file mode 100644 index 88641946f6..0000000000 --- a/files/apache-ironic.template +++ /dev/null @@ -1,12 +0,0 @@ -Listen %PUBLICPORT% - - - DocumentRoot "%HTTPROOT%" - - Options Indexes FollowSymLinks - AllowOverride None - Order allow,deny - Allow from all - Require all granted - - diff --git a/files/apache-keystone.template b/files/apache-keystone.template index 0b914e2b8f..128436027d 100644 --- a/files/apache-keystone.template +++ b/files/apache-keystone.template @@ -2,15 +2,17 @@ Listen %PUBLICPORT% Listen %ADMINPORT% LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-agent}i\" %D(us)" keystone_combined + + Require all granted + + - WSGIDaemonProcess keystone-public processes=5 threads=1 user=%USER% display-name=%{GROUP} %VIRTUALENV% + WSGIDaemonProcess keystone-public processes=3 threads=1 user=%USER% display-name=%{GROUP} %VIRTUALENV% WSGIProcessGroup keystone-public - WSGIScriptAlias / %PUBLICWSGI% + WSGIScriptAlias / %KEYSTONE_BIN%/keystone-wsgi-public WSGIApplicationGroup %{GLOBAL} WSGIPassAuthorization On - = 2.4> - ErrorLogFormat "%{cu}t %M" - + ErrorLogFormat "%M" ErrorLog /var/log/%APACHE_NAME%/keystone.log CustomLog /var/log/%APACHE_NAME%/keystone_access.log keystone_combined %SSLENGINE% @@ -19,17 +21,41 @@ LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-agent}i\" %D(us)" - WSGIDaemonProcess keystone-admin processes=5 threads=1 user=%USER% display-name=%{GROUP} %VIRTUALENV% + WSGIDaemonProcess keystone-admin processes=3 threads=1 user=%USER% display-name=%{GROUP} %VIRTUALENV% WSGIProcessGroup keystone-admin - WSGIScriptAlias / %ADMINWSGI% + WSGIScriptAlias / %KEYSTONE_BIN%/keystone-wsgi-admin WSGIApplicationGroup %{GLOBAL} WSGIPassAuthorization On - = 2.4> - ErrorLogFormat "%{cu}t %M" - + ErrorLogFormat "%M" ErrorLog /var/log/%APACHE_NAME%/keystone.log CustomLog /var/log/%APACHE_NAME%/keystone_access.log keystone_combined %SSLENGINE% %SSLCERTFILE% %SSLKEYFILE% + +%SSLLISTEN% +%SSLLISTEN% %SSLENGINE% +%SSLLISTEN% %SSLCERTFILE% +%SSLLISTEN% %SSLKEYFILE% +%SSLLISTEN% + +Alias /identity %KEYSTONE_BIN%/keystone-wsgi-public + + SetHandler wsgi-script + Options +ExecCGI + + WSGIProcessGroup keystone-public + WSGIApplicationGroup %{GLOBAL} + WSGIPassAuthorization On + + +Alias /identity_admin %KEYSTONE_BIN%/keystone-wsgi-admin + + SetHandler wsgi-script + Options +ExecCGI + + WSGIProcessGroup keystone-admin + WSGIApplicationGroup %{GLOBAL} + WSGIPassAuthorization On + diff --git a/files/apache-neutron.template b/files/apache-neutron.template new file mode 100644 index 0000000000..c7796b93bf --- /dev/null +++ b/files/apache-neutron.template @@ -0,0 +1,36 @@ +Listen %PUBLICPORT% +LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-agent}i\" %D(us)" neutron_combined + + + Require all granted + + + + WSGIDaemonProcess neutron-server processes=%APIWORKERS% threads=1 user=%USER% display-name=%{GROUP} %VIRTUALENV% + WSGIProcessGroup neutron-server + WSGIScriptAlias / %NEUTRON_BIN%/neutron-api + WSGIApplicationGroup %{GLOBAL} + WSGIPassAuthorization On + ErrorLogFormat "%M" + ErrorLog /var/log/%APACHE_NAME%/neutron.log + CustomLog /var/log/%APACHE_NAME%/neutron_access.log neutron_combined + %SSLENGINE% + %SSLCERTFILE% + %SSLKEYFILE% + + + +%SSLLISTEN% +%SSLLISTEN% %SSLENGINE% +%SSLLISTEN% %SSLCERTFILE% +%SSLLISTEN% %SSLKEYFILE% +%SSLLISTEN% + +Alias /networking %NEUTRON_BIN%/neutron-api + + SetHandler wsgi-script + Options +ExecCGI + WSGIProcessGroup neutron-server + WSGIApplicationGroup %{GLOBAL} + WSGIPassAuthorization On + diff --git a/files/apache-nova-api.template b/files/apache-nova-api.template index 70ccedddc8..bcf406edf3 100644 --- a/files/apache-nova-api.template +++ b/files/apache-nova-api.template @@ -1,16 +1,25 @@ Listen %PUBLICPORT% - WSGIDaemonProcess nova-api processes=5 threads=1 user=%USER% display-name=%{GROUP} %VIRTUALENV% + WSGIDaemonProcess nova-api processes=%APIWORKERS% threads=1 user=%USER% display-name=%{GROUP} %VIRTUALENV% WSGIProcessGroup nova-api WSGIScriptAlias / %PUBLICWSGI% WSGIApplicationGroup %{GLOBAL} WSGIPassAuthorization On = 2.4> - ErrorLogFormat "%{cu}t %M" + ErrorLogFormat "%M" ErrorLog /var/log/%APACHE_NAME%/nova-api.log %SSLENGINE% %SSLCERTFILE% %SSLKEYFILE% - \ No newline at end of file + + +Alias /compute %PUBLICWSGI% + + SetHandler wsgi-script + Options +ExecCGI + WSGIProcessGroup nova-api + WSGIApplicationGroup %{GLOBAL} + WSGIPassAuthorization On + diff --git a/files/apache-nova-ec2-api.template b/files/apache-nova-ec2-api.template deleted file mode 100644 index ae4cf94a38..0000000000 --- a/files/apache-nova-ec2-api.template +++ /dev/null @@ -1,16 +0,0 @@ -Listen %PUBLICPORT% - - - WSGIDaemonProcess nova-ec2-api processes=5 threads=1 user=%USER% display-name=%{GROUP} %VIRTUALENV% - WSGIProcessGroup nova-ec2-api - WSGIScriptAlias / %PUBLICWSGI% - WSGIApplicationGroup %{GLOBAL} - WSGIPassAuthorization On - = 2.4> - ErrorLogFormat "%{cu}t %M" - - ErrorLog /var/log/%APACHE_NAME%/nova-ec2-api.log - %SSLENGINE% - %SSLCERTFILE% - %SSLKEYFILE% - \ No newline at end of file diff --git a/files/apache-nova-metadata.template b/files/apache-nova-metadata.template new file mode 100644 index 0000000000..6231c1ced8 --- /dev/null +++ b/files/apache-nova-metadata.template @@ -0,0 +1,25 @@ +Listen %PUBLICPORT% + + + WSGIDaemonProcess nova-metadata processes=%APIWORKERS% threads=1 user=%USER% display-name=%{GROUP} %VIRTUALENV% + WSGIProcessGroup nova-metadata + WSGIScriptAlias / %PUBLICWSGI% + WSGIApplicationGroup %{GLOBAL} + WSGIPassAuthorization On + = 2.4> + ErrorLogFormat "%M" + + ErrorLog /var/log/%APACHE_NAME%/nova-metadata.log + %SSLENGINE% + %SSLCERTFILE% + %SSLKEYFILE% + + +Alias /metadata %PUBLICWSGI% + + SetHandler wsgi-script + Options +ExecCGI + WSGIProcessGroup nova-metadata + WSGIApplicationGroup %{GLOBAL} + WSGIPassAuthorization On + diff --git a/files/apache-placement-api.template b/files/apache-placement-api.template new file mode 100644 index 0000000000..011abb95fc --- /dev/null +++ b/files/apache-placement-api.template @@ -0,0 +1,27 @@ +# NOTE(sbauza): This virtualhost is only here because some directives can +# only be set by a virtualhost or server context, so that's why the port is not bound. +# TODO(sbauza): Find a better way to identify a free port that is not corresponding to an existing +# vhost. + + WSGIDaemonProcess placement-api processes=%APIWORKERS% threads=1 user=%USER% display-name=%{GROUP} %VIRTUALENV% + WSGIProcessGroup placement-api + WSGIScriptAlias / %PUBLICWSGI% + WSGIApplicationGroup %{GLOBAL} + WSGIPassAuthorization On + = 2.4> + ErrorLogFormat "%M" + + ErrorLog /var/log/%APACHE_NAME%/placement-api.log + %SSLENGINE% + %SSLCERTFILE% + %SSLKEYFILE% + + +Alias /placement %PUBLICWSGI% + + SetHandler wsgi-script + Options +ExecCGI + WSGIProcessGroup placement-api + WSGIApplicationGroup %{GLOBAL} + WSGIPassAuthorization On + diff --git a/files/debs/ceilometer-collector b/files/debs/ceilometer-collector deleted file mode 100644 index f1b692ac71..0000000000 --- a/files/debs/ceilometer-collector +++ /dev/null @@ -1,6 +0,0 @@ -python-pymongo #NOPRIME -mongodb-server #NOPRIME -libnspr4-dev -pkg-config -libxml2-dev -libxslt-dev \ No newline at end of file diff --git a/files/debs/cinder b/files/debs/cinder index 51908eb27b..c1b79fda47 100644 --- a/files/debs/cinder +++ b/files/debs/cinder @@ -1,6 +1,6 @@ -tgt # NOPRIME lvm2 -qemu-utils -libpq-dev open-iscsi open-iscsi-utils # Deprecated since quantal dist:precise +qemu-utils +tgt # NOPRIME +thin-provisioning-tools diff --git a/files/debs/devlibs b/files/debs/devlibs deleted file mode 100644 index 0446ceb6b6..0000000000 --- a/files/debs/devlibs +++ /dev/null @@ -1,7 +0,0 @@ -libffi-dev # pyOpenSSL -libmysqlclient-dev # MySQL-python -libpq-dev # psycopg2 -libssl-dev # pyOpenSSL -libxml2-dev # lxml -libxslt1-dev # lxml -python-dev # pyOpenSSL diff --git a/files/debs/dstat b/files/debs/dstat index 2b643b8b1b..0d9da4434f 100644 --- a/files/debs/dstat +++ b/files/debs/dstat @@ -1 +1,2 @@ dstat +python-psutil diff --git a/files/debs/general b/files/debs/general index 146052643c..df872a0a6c 100644 --- a/files/debs/general +++ b/files/debs/general @@ -1,27 +1,39 @@ +apache2 +apache2-dev +bc bridge-utils -screen -unzip -wget -psmisc -gcc +bsdmainutils +curl +default-jre-headless # NOPRIME g++ +gcc +gettext # used for compiling message catalogs git graphviz # needed for docs +iputils-ping +libapache2-mod-proxy-uwsgi +libffi-dev # for pyOpenSSL +libjpeg-dev # Pillow 3.0.0 +libmysqlclient-dev # MySQL-python +libpcre3-dev # for python-pcre +libpq-dev # psycopg2 +libssl-dev # for pyOpenSSL +libsystemd-dev # for systemd-python +libxml2-dev # lxml +libxslt1-dev # lxml +libyaml-dev lsof # useful when debugging openssh-server openssl -iputils-ping -wget -curl -tcpdump -tar -python-dev +pkg-config +psmisc python2.7 +python-dev python-gdbm # needed for testr -bc -libyaml-dev -libffi-dev -libssl-dev # for pyOpenSSL -gettext # used for compiling message catalogs -openjdk-7-jre-headless # NOPRIME -pkg-config +tar +tcpdump +unzip +uuid-runtime +wget +wget +zlib1g-dev diff --git a/files/debs/glance b/files/debs/glance deleted file mode 100644 index 37877a85c2..0000000000 --- a/files/debs/glance +++ /dev/null @@ -1,6 +0,0 @@ -libmysqlclient-dev -libpq-dev -libssl-dev -libxml2-dev -libxslt1-dev -zlib1g-dev diff --git a/files/debs/heat b/files/debs/heat deleted file mode 100644 index 1ecbc780b1..0000000000 --- a/files/debs/heat +++ /dev/null @@ -1 +0,0 @@ -gettext # dist:trusty diff --git a/files/debs/horizon b/files/debs/horizon index 1f45b54f7c..48332893b1 100644 --- a/files/debs/horizon +++ b/files/debs/horizon @@ -1,3 +1,2 @@ apache2 # NOPRIME libapache2-mod-wsgi # NOPRIME -libpcre3-dev # pyScss diff --git a/files/debs/ironic b/files/debs/ironic deleted file mode 100644 index 0a906dbffc..0000000000 --- a/files/debs/ironic +++ /dev/null @@ -1,19 +0,0 @@ -docker.io -ipmitool -iptables -ipxe -libguestfs0 -libvirt-bin -open-iscsi -openssh-client -openvswitch-switch -openvswitch-datapath-dkms -python-libguestfs -python-libvirt -qemu -qemu-kvm -qemu-utils -sgabios -syslinux -tftpd-hpa -xinetd diff --git a/files/debs/keystone b/files/debs/keystone index 70a56499e9..fd0317b9b6 100644 --- a/files/debs/keystone +++ b/files/debs/keystone @@ -1,7 +1,6 @@ -python-lxml -sqlite3 -python-mysqldb -python-mysql.connector +libkrb5-dev libldap2-dev libsasl2-dev -libkrb5-dev +memcached +python-mysqldb +sqlite3 diff --git a/files/debs/ldap b/files/debs/ldap index 26f7aeffe3..aa3a934d95 100644 --- a/files/debs/ldap +++ b/files/debs/ldap @@ -1,3 +1,3 @@ ldap-utils -slapd python-ldap +slapd diff --git a/files/debs/n-api b/files/debs/n-api deleted file mode 100644 index 0928cd56b9..0000000000 --- a/files/debs/n-api +++ /dev/null @@ -1 +0,0 @@ -fping diff --git a/files/debs/n-cpu b/files/debs/n-cpu index 5d5052aa4e..636644f10d 100644 --- a/files/debs/n-cpu +++ b/files/debs/n-cpu @@ -1,7 +1,11 @@ -qemu-utils +cryptsetup +dosfstools +genisoimage +gir1.2-libosinfo-1.0 lvm2 # NOPRIME +netcat-openbsd open-iscsi -genisoimage -sysfsutils -sg3-utils python-guestfs # NOPRIME +qemu-utils +sg3-utils +sysfsutils diff --git a/files/debs/n-novnc b/files/debs/n-novnc deleted file mode 100644 index c8722b9f66..0000000000 --- a/files/debs/n-novnc +++ /dev/null @@ -1 +0,0 @@ -python-numpy diff --git a/files/debs/neutron-agent b/files/debs/neutron-agent new file mode 100644 index 0000000000..ea8819e884 --- /dev/null +++ b/files/debs/neutron-agent @@ -0,0 +1 @@ +ipset diff --git a/files/debs/neutron b/files/debs/neutron-common similarity index 78% rename from files/debs/neutron rename to files/debs/neutron-common index 2d69a71c3a..e30f678f7a 100644 --- a/files/debs/neutron +++ b/files/debs/neutron-common @@ -1,20 +1,17 @@ acl +dnsmasq-base +dnsmasq-utils # for dhcp_release only available in dist:precise ebtables +haproxy # to serve as metadata proxy inside router/dhcp namespaces iptables -iputils-ping iputils-arping +iputils-ping libmysqlclient-dev mysql-server #NOPRIME -sudo postgresql-server-dev-all python-mysqldb -python-mysql.connector -python-qpid # NOPRIME -dnsmasq-base -dnsmasq-utils # for dhcp_release only available in dist:precise rabbitmq-server # NOPRIME -qpidd # NOPRIME +radvd # NOPRIME sqlite3 +sudo vlan -radvd # NOPRIME -uuid-runtime diff --git a/files/debs/neutron-l3 b/files/debs/neutron-l3 new file mode 100644 index 0000000000..106a6a35aa --- /dev/null +++ b/files/debs/neutron-l3 @@ -0,0 +1,3 @@ +conntrack +conntrackd +keepalived diff --git a/files/debs/nova b/files/debs/nova index 9d9acde3e9..5e14aec836 100644 --- a/files/debs/nova +++ b/files/debs/nova @@ -1,33 +1,27 @@ +conntrack +curl dnsmasq-base dnsmasq-utils # for dhcp_release -conntrack -kpartx -parted +ebtables +gawk +genisoimage # required for config_drive +iptables iputils-arping +kpartx +libjs-jquery-tablesorter # Needed for coverage html reports libmysqlclient-dev +libvirt-bin # dist:xenial NOPRIME +libvirt-clients # not:xenial NOPRIME +libvirt-daemon-system # not:xenial NOPRIME +libvirt-dev # NOPRIME mysql-server # NOPRIME +parted +pm-utils python-mysqldb -python-mysql.connector -python-lxml # needed for glance which is needed for nova --- this shouldn't be here -gawk -iptables -ebtables -sqlite3 -sudo -qemu-kvm # NOPRIME qemu # dist:wheezy,jessie NOPRIME -libvirt-bin # NOPRIME -libvirt-dev # NOPRIME -pm-utils -libjs-jquery-tablesorter # Needed for coverage html reports -vlan -curl -genisoimage # required for config_drive +qemu-kvm # NOPRIME rabbitmq-server # NOPRIME -qpidd # NOPRIME socat # used by ajaxterm -python-libvirt # NOPRIME -python-libxml2 -python-numpy # used by websockify for spice console -python-m2crypto -python-qpid # NOPRIME +sqlite3 +sudo +vlan diff --git a/files/debs/q-agt b/files/debs/q-agt deleted file mode 100644 index ea8819e884..0000000000 --- a/files/debs/q-agt +++ /dev/null @@ -1 +0,0 @@ -ipset diff --git a/files/debs/q-agt b/files/debs/q-agt new file mode 120000 index 0000000000..99fe353094 --- /dev/null +++ b/files/debs/q-agt @@ -0,0 +1 @@ +neutron-agent \ No newline at end of file diff --git a/files/debs/q-l3 b/files/debs/q-l3 deleted file mode 100644 index 106a6a35aa..0000000000 --- a/files/debs/q-l3 +++ /dev/null @@ -1,3 +0,0 @@ -conntrack -conntrackd -keepalived diff --git a/files/debs/q-l3 b/files/debs/q-l3 new file mode 120000 index 0000000000..0a5ca2a45f --- /dev/null +++ b/files/debs/q-l3 @@ -0,0 +1 @@ +neutron-l3 \ No newline at end of file diff --git a/files/debs/qpid b/files/debs/qpid deleted file mode 100644 index e3bbf0961c..0000000000 --- a/files/debs/qpid +++ /dev/null @@ -1 +0,0 @@ -sasl2-bin # NOPRIME diff --git a/files/debs/swift b/files/debs/swift index 726786ee18..4b8ac3d793 100644 --- a/files/debs/swift +++ b/files/debs/swift @@ -1,4 +1,5 @@ curl +liberasurecode-dev make memcached sqlite3 diff --git a/files/debs/tempest b/files/debs/tempest deleted file mode 100644 index bb095297e0..0000000000 --- a/files/debs/tempest +++ /dev/null @@ -1,2 +0,0 @@ -libxml2-dev -libxslt1-dev diff --git a/files/debs/tls-proxy b/files/debs/tls-proxy index dce9c07d3f..5bd8e213a2 100644 --- a/files/debs/tls-proxy +++ b/files/debs/tls-proxy @@ -1 +1 @@ -stud +apache2 diff --git a/files/debs/trove b/files/debs/trove deleted file mode 100644 index 96f8f29277..0000000000 --- a/files/debs/trove +++ /dev/null @@ -1 +0,0 @@ -libxslt1-dev diff --git a/files/debs/zaqar-server b/files/debs/zaqar-server deleted file mode 100644 index 6c2a4d154a..0000000000 --- a/files/debs/zaqar-server +++ /dev/null @@ -1,4 +0,0 @@ -python-pymongo -mongodb-server -pkg-config -redis-server # NOPRIME \ No newline at end of file diff --git a/files/default_catalog.templates b/files/default_catalog.templates deleted file mode 100644 index 4aab4160c1..0000000000 --- a/files/default_catalog.templates +++ /dev/null @@ -1,63 +0,0 @@ -# config for TemplatedCatalog, using camelCase because I don't want to do -# translations for legacy compat -catalog.RegionOne.identity.publicURL = http://%SERVICE_HOST%:$(public_port)s/v2.0 -catalog.RegionOne.identity.adminURL = http://%SERVICE_HOST%:$(admin_port)s/v2.0 -catalog.RegionOne.identity.internalURL = http://%SERVICE_HOST%:$(public_port)s/v2.0 -catalog.RegionOne.identity.name = Identity Service - - -catalog.RegionOne.compute.publicURL = http://%SERVICE_HOST%:8774/v2/$(tenant_id)s -catalog.RegionOne.compute.adminURL = http://%SERVICE_HOST%:8774/v2/$(tenant_id)s -catalog.RegionOne.compute.internalURL = http://%SERVICE_HOST%:8774/v2/$(tenant_id)s -catalog.RegionOne.compute.name = Compute Service - - -catalog.RegionOne.computev21.publicURL = http://%SERVICE_HOST%:8774/v2.1/$(tenant_id)s -catalog.RegionOne.computev21.adminURL = http://%SERVICE_HOST%:8774/v2.1/$(tenant_id)s -catalog.RegionOne.computev21.internalURL = http://%SERVICE_HOST%:8774/v2.1/$(tenant_id)s -catalog.RegionOne.computev21.name = Compute Service V2.1 - - -catalog.RegionOne.volume.publicURL = http://%SERVICE_HOST%:8776/v1/$(tenant_id)s -catalog.RegionOne.volume.adminURL = http://%SERVICE_HOST%:8776/v1/$(tenant_id)s -catalog.RegionOne.volume.internalURL = http://%SERVICE_HOST%:8776/v1/$(tenant_id)s -catalog.RegionOne.volume.name = Volume Service - - -catalog.RegionOne.volumev2.publicURL = http://%SERVICE_HOST%:8776/v2/$(tenant_id)s -catalog.RegionOne.volumev2.adminURL = http://%SERVICE_HOST%:8776/v2/$(tenant_id)s -catalog.RegionOne.volumev2.internalURL = http://%SERVICE_HOST%:8776/v2/$(tenant_id)s -catalog.RegionOne.volumev2.name = Volume Service V2 - - -catalog.RegionOne.ec2.publicURL = http://%SERVICE_HOST%:8773/ -catalog.RegionOne.ec2.adminURL = http://%SERVICE_HOST%:8773/ -catalog.RegionOne.ec2.internalURL = http://%SERVICE_HOST%:8773/ -catalog.RegionOne.ec2.name = EC2 Service - - -catalog.RegionOne.s3.publicURL = http://%SERVICE_HOST%:%S3_SERVICE_PORT% -catalog.RegionOne.s3.adminURL = http://%SERVICE_HOST%:%S3_SERVICE_PORT% -catalog.RegionOne.s3.internalURL = http://%SERVICE_HOST%:%S3_SERVICE_PORT% -catalog.RegionOne.s3.name = S3 Service - - -catalog.RegionOne.image.publicURL = http://%SERVICE_HOST%:9292 -catalog.RegionOne.image.adminURL = http://%SERVICE_HOST%:9292 -catalog.RegionOne.image.internalURL = http://%SERVICE_HOST%:9292 -catalog.RegionOne.image.name = Image Service - -catalog.RegionOne.cloudformation.publicURL = http://%SERVICE_HOST%:8000/v1 -catalog.RegionOne.cloudformation.adminURL = http://%SERVICE_HOST%:8000/v1 -catalog.RegionOne.cloudformation.internalURL = http://%SERVICE_HOST%:8000/v1 -catalog.RegionOne.cloudformation.name = CloudFormation service - -catalog.RegionOne.orchestration.publicURL = http://%SERVICE_HOST%:8004/v1/$(tenant_id)s -catalog.RegionOne.orchestration.adminURL = http://%SERVICE_HOST%:8004/v1/$(tenant_id)s -catalog.RegionOne.orchestration.internalURL = http://%SERVICE_HOST%:8004/v1/$(tenant_id)s -catalog.RegionOne.orchestration.name = Orchestration Service - -catalog.RegionOne.metering.publicURL = http://%SERVICE_HOST%:8777/v1 -catalog.RegionOne.metering.adminURL = http://%SERVICE_HOST%:8777/v1 -catalog.RegionOne.metering.internalURL = http://%SERVICE_HOST%:8777/v1 -catalog.RegionOne.metering.name = Telemetry Service diff --git a/files/ldap/user.ldif.in b/files/ldap/user.ldif.in new file mode 100644 index 0000000000..16a980757d --- /dev/null +++ b/files/ldap/user.ldif.in @@ -0,0 +1,23 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +# implied. See the License for the specific language governing +# permissions and limitations under the License. + +# Demo LDAP user +dn: cn=demo,ou=Users,${BASE_DN} +cn: demo +displayName: demo +givenName: demo +mail: demo@openstack.org +objectClass: inetOrgPerson +objectClass: top +sn: demo +uid: demo +userPassword: demo diff --git a/files/rpms-suse/ceilometer-collector b/files/rpms-suse/ceilometer-collector deleted file mode 100644 index c76454fded..0000000000 --- a/files/rpms-suse/ceilometer-collector +++ /dev/null @@ -1,4 +0,0 @@ -# Not available in openSUSE main repositories, but can be fetched from OBS -# (devel:languages:python and server:database projects) -mongodb -python-pymongo diff --git a/files/rpms-suse/ceph b/files/rpms-suse/ceph index 8d465000e1..8c4955df90 100644 --- a/files/rpms-suse/ceph +++ b/files/rpms-suse/ceph @@ -1,3 +1,3 @@ ceph # NOPRIME -xfsprogs lsb +xfsprogs diff --git a/files/rpms-suse/cinder b/files/rpms-suse/cinder index 3fd03cc9be..189a232fa7 100644 --- a/files/rpms-suse/cinder +++ b/files/rpms-suse/cinder @@ -1,6 +1,4 @@ lvm2 -tgt # NOPRIME -qemu-tools -python-devel -postgresql-devel open-iscsi +qemu-tools +tgt # NOPRIME diff --git a/files/rpms-suse/devlibs b/files/rpms-suse/devlibs deleted file mode 100644 index c9238252af..0000000000 --- a/files/rpms-suse/devlibs +++ /dev/null @@ -1,6 +0,0 @@ -libffi-devel # pyOpenSSL -libopenssl-devel # pyOpenSSL -libxml2-devel # lxml -libxslt-devel # lxml -postgresql-devel # psycopg2 -python-devel # pyOpenSSL diff --git a/files/rpms-suse/dstat b/files/rpms-suse/dstat index 2b643b8b1b..0d9da4434f 100644 --- a/files/rpms-suse/dstat +++ b/files/rpms-suse/dstat @@ -1 +1,2 @@ dstat +python-psutil diff --git a/files/rpms-suse/general b/files/rpms-suse/general index 42756d8fcc..b870d72149 100644 --- a/files/rpms-suse/general +++ b/files/rpms-suse/general @@ -1,23 +1,34 @@ +apache2 +apache2-devel bc bridge-utils ca-certificates-mozilla curl -euca2ools gcc gcc-c++ git-core graphviz # docs iputils +libffi-devel # pyOpenSSL +libjpeg8-devel # Pillow 3.0.0 libopenssl-devel # to rebuild pyOpenSSL if needed +libxslt-devel # lxml lsof # useful when debugging make +net-tools openssh openssl +pcre-devel # python-pcre +postgresql-devel # psycopg2 psmisc python-cmd2 # dist:opensuse-12.3 -screen +python-devel # pyOpenSSL +python-xml +systemd-devel # for systemd-python tar tcpdump unzip +util-linux wget -net-tools +which +zlib-devel diff --git a/files/rpms-suse/glance b/files/rpms-suse/glance deleted file mode 100644 index 9b962f9643..0000000000 --- a/files/rpms-suse/glance +++ /dev/null @@ -1,11 +0,0 @@ -libxml2-devel -python-PasteDeploy -python-Routes -python-SQLAlchemy -python-argparse -python-devel -python-eventlet -python-greenlet -python-iso8601 -python-pyOpenSSL -python-xattr diff --git a/files/rpms-suse/horizon b/files/rpms-suse/horizon index c45eae6153..753ea76e04 100644 --- a/files/rpms-suse/horizon +++ b/files/rpms-suse/horizon @@ -1,16 +1,2 @@ -apache2 # NOPRIME apache2-mod_wsgi # NOPRIME -python-CherryPy # why? (coming from apts) -python-Paste -python-PasteDeploy -python-Routes -python-SQLAlchemy -python-WebOb -python-anyjson -python-beautifulsoup -python-coverage -python-dateutil -python-eventlet -python-mox -python-sqlalchemy-migrate -python-xattr +apache2 # NOPRIME diff --git a/files/rpms-suse/keystone b/files/rpms-suse/keystone index 4c37adef9b..66cfc23423 100644 --- a/files/rpms-suse/keystone +++ b/files/rpms-suse/keystone @@ -1,15 +1,4 @@ cyrus-sasl-devel +memcached openldap2-devel -python-Paste -python-PasteDeploy -python-PasteScript -python-Routes -python-SQLAlchemy -python-WebOb -python-devel -python-greenlet -python-lxml -python-mysql -python-mysql-connector-python -python-pysqlite sqlite3 diff --git a/files/rpms-suse/n-api b/files/rpms-suse/n-api index 6f59e603b2..0f08daace3 100644 --- a/files/rpms-suse/n-api +++ b/files/rpms-suse/n-api @@ -1,2 +1 @@ python-dateutil -fping diff --git a/files/rpms-suse/n-cpu b/files/rpms-suse/n-cpu index 7040b843bf..c11e9f0763 100644 --- a/files/rpms-suse/n-cpu +++ b/files/rpms-suse/n-cpu @@ -1,6 +1,9 @@ -# Stuff for diablo volumes -genisoimage +cryptsetup +dosfstools +libosinfo lvm2 +mkisofs open-iscsi -sysfsutils sg3_utils +# Stuff for diablo volumes +sysfsutils diff --git a/files/rpms-suse/neutron b/files/rpms-suse/neutron deleted file mode 100644 index d278363e98..0000000000 --- a/files/rpms-suse/neutron +++ /dev/null @@ -1,28 +0,0 @@ -acl -dnsmasq -dnsmasq-utils # dist:opensuse-12.3,opensuse-13.1 -ebtables -iptables -iputils -mariadb # NOPRIME -postgresql-devel -python-eventlet -python-greenlet -python-iso8601 -python-mysql -python-mysql-connector-python -python-Paste -python-PasteDeploy -python-pyudev -python-Routes -python-SQLAlchemy -python-suds -rabbitmq-server # NOPRIME -sqlite3 -sudo -vlan -radvd # NOPRIME - -# FIXME: qpid is not part of openSUSE, those names are tentative -python-qpid # NOPRIME -qpidd # NOPRIME diff --git a/files/rpms-suse/neutron-agent b/files/rpms-suse/neutron-agent new file mode 100644 index 0000000000..ea8819e884 --- /dev/null +++ b/files/rpms-suse/neutron-agent @@ -0,0 +1 @@ +ipset diff --git a/files/rpms-suse/neutron-common b/files/rpms-suse/neutron-common new file mode 100644 index 0000000000..d1cc73f115 --- /dev/null +++ b/files/rpms-suse/neutron-common @@ -0,0 +1,13 @@ +acl +dnsmasq +dnsmasq-utils # dist:opensuse-12.3,opensuse-13.1 +ebtables +haproxy # to serve as metadata proxy inside router/dhcp namespaces +iptables +iputils +mariadb # NOPRIME +rabbitmq-server # NOPRIME +radvd # NOPRIME +sqlite3 +sudo +vlan diff --git a/files/rpms-suse/neutron-l3 b/files/rpms-suse/neutron-l3 new file mode 100644 index 0000000000..a7a190c063 --- /dev/null +++ b/files/rpms-suse/neutron-l3 @@ -0,0 +1,2 @@ +conntrack-tools +keepalived diff --git a/files/rpms-suse/nova b/files/rpms-suse/nova index b1c4f6a8d0..4103a407d2 100644 --- a/files/rpms-suse/nova +++ b/files/rpms-suse/nova @@ -1,50 +1,23 @@ +conntrack-tools curl dnsmasq dnsmasq-utils # dist:opensuse-12.3,opensuse-13.1 -conntrack-tools ebtables gawk -genisoimage # required for config_drive iptables iputils kpartx kvm # NOPRIME -# qemu as fallback if kvm cannot be used -qemu # NOPRIME libvirt # NOPRIME libvirt-python # NOPRIME mariadb # NOPRIME +mkisofs # required for config_drive parted polkit -python-M2Crypto -python-m2crypto # dist:sle11sp2 -python-Paste -python-PasteDeploy -python-Routes -python-SQLAlchemy -python-Tempita -python-cheetah -python-eventlet -python-feedparser -python-greenlet -python-iso8601 -python-libxml2 -python-lockfile -python-lxml # needed for glance which is needed for nova --- this shouldn't be here -python-mox -python-mysql -python-mysql-connector-python -python-numpy # needed by websockify for spice console -python-paramiko -python-sqlalchemy-migrate -python-suds -python-xattr # needed for glance which is needed for nova --- this shouldn't be here +# qemu as fallback if kvm cannot be used +qemu # NOPRIME rabbitmq-server # NOPRIME socat sqlite3 sudo vlan - -# FIXME: qpid is not part of openSUSE, those names are tentative -python-qpid # NOPRIME -qpidd # NOPRIME diff --git a/files/rpms-suse/openvswitch b/files/rpms-suse/openvswitch index edfb4d21aa..53f8bb22cf 100644 --- a/files/rpms-suse/openvswitch +++ b/files/rpms-suse/openvswitch @@ -1,3 +1,3 @@ + openvswitch openvswitch-switch - diff --git a/files/rpms-suse/q-agt b/files/rpms-suse/q-agt deleted file mode 100644 index ea8819e884..0000000000 --- a/files/rpms-suse/q-agt +++ /dev/null @@ -1 +0,0 @@ -ipset diff --git a/files/rpms-suse/q-agt b/files/rpms-suse/q-agt new file mode 120000 index 0000000000..99fe353094 --- /dev/null +++ b/files/rpms-suse/q-agt @@ -0,0 +1 @@ +neutron-agent \ No newline at end of file diff --git a/files/rpms-suse/q-l3 b/files/rpms-suse/q-l3 new file mode 120000 index 0000000000..0a5ca2a45f --- /dev/null +++ b/files/rpms-suse/q-l3 @@ -0,0 +1 @@ +neutron-l3 \ No newline at end of file diff --git a/files/rpms-suse/swift b/files/rpms-suse/swift index 9c0d188fe2..3663b98545 100644 --- a/files/rpms-suse/swift +++ b/files/rpms-suse/swift @@ -1,15 +1,6 @@ curl +liberasurecode-devel memcached -python-PasteDeploy -python-WebOb -python-configobj -python-coverage -python-devel -python-eventlet -python-greenlet -python-netifaces -python-simplejson -python-xattr sqlite3 xfsprogs xinetd diff --git a/files/rpms-suse/trove b/files/rpms-suse/trove deleted file mode 100644 index 96f8f29277..0000000000 --- a/files/rpms-suse/trove +++ /dev/null @@ -1 +0,0 @@ -libxslt1-dev diff --git a/files/rpms/ceilometer-collector b/files/rpms/ceilometer-collector deleted file mode 100644 index b139ed2b6b..0000000000 --- a/files/rpms/ceilometer-collector +++ /dev/null @@ -1,3 +0,0 @@ -selinux-policy-targeted -mongodb-server #NOPRIME -mongodb # NOPRIME diff --git a/files/rpms/ceph b/files/rpms/ceph index 5483735741..64befc5f00 100644 --- a/files/rpms/ceph +++ b/files/rpms/ceph @@ -1,3 +1,3 @@ ceph # NOPRIME -xfsprogs redhat-lsb-core +xfsprogs diff --git a/files/rpms/cinder b/files/rpms/cinder index a88503b8bc..058c2354dc 100644 --- a/files/rpms/cinder +++ b/files/rpms/cinder @@ -1,5 +1,5 @@ +iscsi-initiator-utils lvm2 -scsi-target-utils # NOPRIME qemu-img -postgresql-devel -iscsi-initiator-utils +scsi-target-utils # not:rhel7,f25,f26,f27,f28 NOPRIME +targetcli # dist:rhel7,f25,f26,f27,f28 NOPRIME diff --git a/files/rpms/devlibs b/files/rpms/devlibs deleted file mode 100644 index 834a4b6cf1..0000000000 --- a/files/rpms/devlibs +++ /dev/null @@ -1,9 +0,0 @@ -libffi-devel # pyOpenSSL -libxml2-devel # lxml -libxslt-devel # lxml -mariadb-devel # MySQL-python f20,f21,rhel7 -mysql-devel # MySQL-python rhel6 -openssl-devel # pyOpenSSL -postgresql-devel # psycopg2 -python-devel # pyOpenSSL -redhat-rpm-config # MySQL-python rhbz-1195207 f21 diff --git a/files/rpms/dstat b/files/rpms/dstat index 8a8f8fe737..0d9da4434f 100644 --- a/files/rpms/dstat +++ b/files/rpms/dstat @@ -1 +1,2 @@ -dstat \ No newline at end of file +dstat +python-psutil diff --git a/files/rpms/general b/files/rpms/general index 7b2c00ad5c..c7863e4320 100644 --- a/files/rpms/general +++ b/files/rpms/general @@ -1,30 +1,39 @@ +bc bridge-utils curl dbus -euca2ools # only for testing client gcc gcc-c++ +gettext # used for compiling message catalogs git-core graphviz # needed only for docs +httpd +httpd-devel +iptables-services # NOPRIME f25,f26,f27,f28 +java-1.7.0-openjdk-headless # NOPRIME rhel7 +java-1.8.0-openjdk-headless # NOPRIME f25,f26,f27,f28 +libffi-devel +libjpeg-turbo-devel # Pillow 3.0.0 +libxml2-devel # lxml +libxslt-devel # lxml +libyaml-devel +mariadb-devel # MySQL-python +net-tools openssh-server openssl openssl-devel # to rebuild pyOpenSSL if needed -libffi-devel -libxml2-devel -libxslt-devel +pcre-devel # for python-pcre pkgconfig +postgresql-devel # psycopg2 psmisc +pyOpenSSL # version in pip uses too much memory python-devel -screen +redhat-rpm-config # missing dep for gcc hardening flags, see rhbz#1217376 +systemd-devel # for systemd-python tar tcpdump unzip +util-linux wget which -bc -libyaml-devel -gettext # used for compiling message catalogs -net-tools -java-1.7.0-openjdk-headless # NOPRIME rhel7,f20 -java-1.8.0-openjdk-headless # NOPRIME f21,f22 -pyOpenSSL # version in pip uses too much memory +zlib-devel diff --git a/files/rpms/glance b/files/rpms/glance deleted file mode 100644 index 479194f918..0000000000 --- a/files/rpms/glance +++ /dev/null @@ -1,6 +0,0 @@ -libxml2-devel -libxslt-devel -mysql-devel -openssl-devel -postgresql-devel -zlib-devel diff --git a/files/rpms/horizon b/files/rpms/horizon index b2cf0ded6f..a88552bc84 100644 --- a/files/rpms/horizon +++ b/files/rpms/horizon @@ -1,5 +1,2 @@ -Django httpd # NOPRIME mod_wsgi # NOPRIME -pyxattr -pcre-devel # pyScss diff --git a/files/rpms/ironic b/files/rpms/ironic deleted file mode 100644 index 2bf8bb370e..0000000000 --- a/files/rpms/ironic +++ /dev/null @@ -1,14 +0,0 @@ -docker-io -ipmitool -iptables -ipxe-bootimgs -libguestfs -libvirt -libvirt-python -net-tools -openssh-clients -openvswitch -sgabios -syslinux -tftp-server -xinetd diff --git a/files/rpms/keystone b/files/rpms/keystone index 8074119fdb..5f19c6f70c 100644 --- a/files/rpms/keystone +++ b/files/rpms/keystone @@ -1,4 +1,3 @@ -MySQL-python -libxslt-devel -sqlite +memcached mod_ssl +sqlite diff --git a/files/rpms/ldap b/files/rpms/ldap index d89c4cf8c1..d5b8fa4374 100644 --- a/files/rpms/ldap +++ b/files/rpms/ldap @@ -1,2 +1,2 @@ -openldap-servers openldap-clients +openldap-servers diff --git a/files/rpms/n-api b/files/rpms/n-api deleted file mode 100644 index 0928cd56b9..0000000000 --- a/files/rpms/n-api +++ /dev/null @@ -1 +0,0 @@ -fping diff --git a/files/rpms/n-cpu b/files/rpms/n-cpu index c1a8e8ffa6..68e5472685 100644 --- a/files/rpms/n-cpu +++ b/files/rpms/n-cpu @@ -1,7 +1,9 @@ -# Stuff for diablo volumes +cryptsetup +dosfstools +genisoimage iscsi-initiator-utils +libosinfo lvm2 -genisoimage -sysfsutils sg3_utils - +# Stuff for diablo volumes +sysfsutils diff --git a/files/rpms/neutron-agent b/files/rpms/neutron-agent new file mode 100644 index 0000000000..ea8819e884 --- /dev/null +++ b/files/rpms/neutron-agent @@ -0,0 +1 @@ +ipset diff --git a/files/rpms/neutron b/files/rpms/neutron-common similarity index 69% rename from files/rpms/neutron rename to files/rpms/neutron-common index 8292e7bffe..0cc8d11ceb 100644 --- a/files/rpms/neutron +++ b/files/rpms/neutron-common @@ -1,17 +1,14 @@ -MySQL-python acl dnsmasq # for q-dhcp dnsmasq-utils # for dhcp_release ebtables +haproxy # to serve as metadata proxy inside router/dhcp namespaces iptables iputils -mysql-connector-python mysql-devel mysql-server # NOPRIME openvswitch # NOPRIME -postgresql-devel rabbitmq-server # NOPRIME -qpid-cpp-server # NOPRIME +radvd # NOPRIME sqlite sudo -radvd # NOPRIME diff --git a/files/rpms/neutron-l3 b/files/rpms/neutron-l3 new file mode 100644 index 0000000000..a7a190c063 --- /dev/null +++ b/files/rpms/neutron-l3 @@ -0,0 +1,2 @@ +conntrack-tools +keepalived diff --git a/files/rpms/nova b/files/rpms/nova index ebd667454a..4140cd7bae 100644 --- a/files/rpms/nova +++ b/files/rpms/nova @@ -1,27 +1,21 @@ -MySQL-python +conntrack-tools curl dnsmasq # for nova-network dnsmasq-utils # for dhcp_release -conntrack-tools ebtables gawk genisoimage # required for config_drive iptables iputils +kernel-modules # dist:f25,f26,f27,f28 kpartx -kvm # NOPRIME -libvirt-bin # NOPRIME -libvirt-devel # NOPRIME -libvirt-python # NOPRIME libxml2-python -numpy # needed by websockify for spice console m2crypto -mysql-connector-python mysql-devel mysql-server # NOPRIME +numpy # needed by websockify for spice console parted polkit rabbitmq-server # NOPRIME -qpid-cpp-server # NOPRIME sqlite sudo diff --git a/files/rpms/q-agt b/files/rpms/q-agt deleted file mode 100644 index ea8819e884..0000000000 --- a/files/rpms/q-agt +++ /dev/null @@ -1 +0,0 @@ -ipset diff --git a/files/rpms/q-agt b/files/rpms/q-agt new file mode 120000 index 0000000000..99fe353094 --- /dev/null +++ b/files/rpms/q-agt @@ -0,0 +1 @@ +neutron-agent \ No newline at end of file diff --git a/files/rpms/q-l3 b/files/rpms/q-l3 deleted file mode 100644 index a7a190c063..0000000000 --- a/files/rpms/q-l3 +++ /dev/null @@ -1,2 +0,0 @@ -conntrack-tools -keepalived diff --git a/files/rpms/q-l3 b/files/rpms/q-l3 new file mode 120000 index 0000000000..0a5ca2a45f --- /dev/null +++ b/files/rpms/q-l3 @@ -0,0 +1 @@ +neutron-l3 \ No newline at end of file diff --git a/files/rpms/qpid b/files/rpms/qpid deleted file mode 100644 index 41dd2f69f9..0000000000 --- a/files/rpms/qpid +++ /dev/null @@ -1,3 +0,0 @@ -qpid-proton-c-devel # NOPRIME -cyrus-sasl-lib # NOPRIME -cyrus-sasl-plain # NOPRIME diff --git a/files/rpms/swift b/files/rpms/swift index 1bf57cc3a2..f2f5de69b0 100644 --- a/files/rpms/swift +++ b/files/rpms/swift @@ -1,7 +1,8 @@ curl +liberasurecode-devel memcached pyxattr +rsync-daemon # dist:f25,f26,f27,f28 sqlite xfsprogs xinetd -rsync-daemon # dist:f22,f23 diff --git a/files/rpms/tempest b/files/rpms/tempest deleted file mode 100644 index e7bbd43cd6..0000000000 --- a/files/rpms/tempest +++ /dev/null @@ -1 +0,0 @@ -libxslt-devel diff --git a/files/rpms/trove b/files/rpms/trove deleted file mode 100644 index e7bbd43cd6..0000000000 --- a/files/rpms/trove +++ /dev/null @@ -1 +0,0 @@ -libxslt-devel diff --git a/files/rpms/zaqar-server b/files/rpms/zaqar-server deleted file mode 100644 index 78806fb3f6..0000000000 --- a/files/rpms/zaqar-server +++ /dev/null @@ -1,5 +0,0 @@ -selinux-policy-targeted -mongodb -mongodb-server -pymongo -redis # NOPRIME diff --git a/files/swift/rsyncd.conf b/files/swift/rsyncd.conf index c670531b31..c49f716fa7 100644 --- a/files/swift/rsyncd.conf +++ b/files/swift/rsyncd.conf @@ -4,76 +4,76 @@ log file = %SWIFT_DATA_DIR%/logs/rsyncd.log pid file = %SWIFT_DATA_DIR%/run/rsyncd.pid address = 127.0.0.1 -[account6012] +[account6612] max connections = 25 path = %SWIFT_DATA_DIR%/1/node/ read only = false -lock file = %SWIFT_DATA_DIR%/run/account6012.lock +lock file = %SWIFT_DATA_DIR%/run/account6612.lock -[account6022] +[account6622] max connections = 25 path = %SWIFT_DATA_DIR%/2/node/ read only = false -lock file = %SWIFT_DATA_DIR%/run/account6022.lock +lock file = %SWIFT_DATA_DIR%/run/account6622.lock -[account6032] +[account6632] max connections = 25 path = %SWIFT_DATA_DIR%/3/node/ read only = false -lock file = %SWIFT_DATA_DIR%/run/account6032.lock +lock file = %SWIFT_DATA_DIR%/run/account6632.lock -[account6042] +[account6642] max connections = 25 path = %SWIFT_DATA_DIR%/4/node/ read only = false -lock file = %SWIFT_DATA_DIR%/run/account6042.lock +lock file = %SWIFT_DATA_DIR%/run/account6642.lock -[container6011] +[container6611] max connections = 25 path = %SWIFT_DATA_DIR%/1/node/ read only = false -lock file = %SWIFT_DATA_DIR%/run/container6011.lock +lock file = %SWIFT_DATA_DIR%/run/container6611.lock -[container6021] +[container6621] max connections = 25 path = %SWIFT_DATA_DIR%/2/node/ read only = false -lock file = %SWIFT_DATA_DIR%/run/container6021.lock +lock file = %SWIFT_DATA_DIR%/run/container6621.lock -[container6031] +[container6631] max connections = 25 path = %SWIFT_DATA_DIR%/3/node/ read only = false -lock file = %SWIFT_DATA_DIR%/run/container6031.lock +lock file = %SWIFT_DATA_DIR%/run/container6631.lock -[container6041] +[container6641] max connections = 25 path = %SWIFT_DATA_DIR%/4/node/ read only = false -lock file = %SWIFT_DATA_DIR%/run/container6041.lock +lock file = %SWIFT_DATA_DIR%/run/container6641.lock -[object6010] +[object6613] max connections = 25 path = %SWIFT_DATA_DIR%/1/node/ read only = false -lock file = %SWIFT_DATA_DIR%/run/object6010.lock +lock file = %SWIFT_DATA_DIR%/run/object6613.lock -[object6020] +[object6623] max connections = 25 path = %SWIFT_DATA_DIR%/2/node/ read only = false -lock file = %SWIFT_DATA_DIR%/run/object6020.lock +lock file = %SWIFT_DATA_DIR%/run/object6623.lock -[object6030] +[object6633] max connections = 25 path = %SWIFT_DATA_DIR%/3/node/ read only = false -lock file = %SWIFT_DATA_DIR%/run/object6030.lock +lock file = %SWIFT_DATA_DIR%/run/object6633.lock -[object6040] +[object6643] max connections = 25 path = %SWIFT_DATA_DIR%/4/node/ read only = false -lock file = %SWIFT_DATA_DIR%/run/object6040.lock +lock file = %SWIFT_DATA_DIR%/run/object6643.lock diff --git a/files/venv-requirements.txt b/files/venv-requirements.txt deleted file mode 100644 index 73d05793ce..0000000000 --- a/files/venv-requirements.txt +++ /dev/null @@ -1,12 +0,0 @@ -# Once we can prebuild wheels before a devstack run, uncomment the skipped libraries -cryptography -# lxml # still install from from packages -MySQL-python -# netifaces # still install from packages -#numpy # slowest wheel by far, stop building until we are actually using the output -posix-ipc -# psycopg # still install from packages -pycrypto -pyOpenSSL -PyYAML -xattr diff --git a/functions b/functions index 1668e16b6d..051c8160f7 100644 --- a/functions +++ b/functions @@ -10,6 +10,10 @@ # - ``GLANCE_HOSTPORT`` # +# ensure we don't re-source this in the same environment +[[ -z "$_DEVSTACK_FUNCTIONS" ]] || return 0 +declare -r -g _DEVSTACK_FUNCTIONS=1 + # Include the common functions FUNC_DIR=$(cd $(dirname "${BASH_SOURCE:-$0}") && pwd) source ${FUNC_DIR}/functions-common @@ -18,7 +22,7 @@ source ${FUNC_DIR}/inc/python source ${FUNC_DIR}/inc/rootwrap # Save trace setting -XTRACE=$(set +o | grep xtrace) +_XTRACE_FUNCTIONS=$(set +o | grep xtrace) set +o xtrace # Check if a function already exists @@ -26,16 +30,62 @@ function function_exists { declare -f -F $1 > /dev/null } +# short_source prints out the current location of the caller in a way +# that strips redundant directories. This is useful for PS4 usage. +function short_source { + saveIFS=$IFS + IFS=" " + called=($(caller 0)) + IFS=$saveIFS + file=${called[2]} + file=${file#$RC_DIR/} + printf "%-40s " "$file:${called[1]}:${called[0]}" +} +# PS4 is exported to child shells and uses the 'short_source' function, so +# export it so child shells have access to the 'short_source' function also. +export -f short_source + +# Download a file from a URL +# +# Will check cache (in $FILES) or download given URL. +# +# Argument is the URL to the remote file +# +# Will echo the local path to the file as the output. Will die on +# failure to download. +# +# Files can be pre-cached for CI environments, see EXTRA_CACHE_URLS +# and tools/image_list.sh +function get_extra_file { + local file_url=$1 + + file_name=$(basename "$file_url") + if [[ $file_url != file* ]]; then + # If the file isn't cache, download it + if [[ ! -f $FILES/$file_name ]]; then + wget --progress=dot:giga -t 2 -c $file_url -O $FILES/$file_name + if [[ $? -ne 0 ]]; then + die "$file_url could not be downloaded" + fi + fi + echo "$FILES/$file_name" + return + else + # just strip the file:// bit and that's the path to the file + echo $file_url | sed 's/$file:\/\///g' + fi +} + + # Retrieve an image from a URL and upload into Glance. # Uses the following variables: # # - ``FILES`` must be set to the cache dir # - ``GLANCE_HOSTPORT`` # -# upload_image image-url glance-token +# upload_image image-url function upload_image { local image_url=$1 - local token=$2 local image image_fname image_name @@ -67,7 +117,7 @@ function upload_image { # OpenVZ-format images are provided as .tar.gz, but not decompressed prior to loading if [[ "$image_url" =~ 'openvz' ]]; then image_name="${image_fname%.tar.gz}" - openstack --os-token $token --os-url $GLANCE_SERVICE_PROTOCOL://$GLANCE_HOSTPORT image create "$image_name" --public --container-format ami --disk-format ami < "${image}" + openstack --os-cloud=devstack-admin --os-region-name="$REGION_NAME" image create "$image_name" --public --container-format ami --disk-format ami < "${image}" return fi @@ -91,12 +141,14 @@ function upload_image { local path_len # vmdk adapter type - local vmdk_adapter_type="$(head -25 $image | { grep -a -F -m 1 'ddb.adapterType =' $image || true; })" + local vmdk_adapter_type + vmdk_adapter_type="$(head -25 $image | { grep -a -F -m 1 'ddb.adapterType =' $image || true; })" vmdk_adapter_type="${vmdk_adapter_type#*\"}" vmdk_adapter_type="${vmdk_adapter_type%?}" # vmdk disk type - local vmdk_create_type="$(head -25 $image | { grep -a -F -m 1 'createType=' $image || true; })" + local vmdk_create_type + vmdk_create_type="$(head -25 $image | { grep -a -F -m 1 'createType=' $image || true; })" vmdk_create_type="${vmdk_create_type#*\"}" vmdk_create_type="${vmdk_create_type%\"*}" @@ -106,7 +158,8 @@ function upload_image { vmdk_disktype="sparse" elif [[ "$vmdk_create_type" = "monolithicFlat" || "$vmdk_create_type" = "vmfs" ]]; then # Attempt to retrieve the ``*-flat.vmdk`` - local flat_fname="$(head -25 $image | { grep -G 'RW\|RDONLY [0-9]+ FLAT\|VMFS' $image || true; })" + local flat_fname + flat_fname="$(head -25 $image | { grep -G 'RW\|RDONLY [0-9]+ FLAT\|VMFS' $image || true; })" flat_fname="${flat_fname#*\"}" flat_fname="${flat_fname%?}" if [[ -z "$flat_fname" ]]; then @@ -178,7 +231,7 @@ function upload_image { vmdk_adapter_type="${props[1]:-$vmdk_adapter_type}" vmdk_net_adapter="${props[2]:-$vmdk_net_adapter}" - openstack --os-token $token --os-url $GLANCE_SERVICE_PROTOCOL://$GLANCE_HOSTPORT image create "$image_name" --public --container-format bare --disk-format vmdk --property vmware_disktype="$vmdk_disktype" --property vmware_adaptertype="$vmdk_adapter_type" --property hw_vif_model="$vmdk_net_adapter" < "${image}" + openstack --os-cloud=devstack-admin --os-region-name="$REGION_NAME" image create "$image_name" --public --container-format bare --disk-format vmdk --property vmware_disktype="$vmdk_disktype" --property vmware_adaptertype="$vmdk_adapter_type" --property hw_vif_model="$vmdk_net_adapter" < "${image}" return fi @@ -195,8 +248,7 @@ function upload_image { force_vm_mode="--property vm_mode=xen" fi openstack \ - --os-token $token \ - --os-url $GLANCE_SERVICE_PROTOCOL://$GLANCE_HOSTPORT \ + --os-cloud=devstack-admin --os-region-name="$REGION_NAME" \ image create \ "$image_name" --public \ --container-format=ovf --disk-format=vhd \ @@ -210,8 +262,7 @@ function upload_image { if [[ "$image_url" =~ '.xen-raw.tgz' ]]; then image_name="${image_fname%.xen-raw.tgz}" openstack \ - --os-token $token \ - --os-url $GLANCE_SERVICE_PROTOCOL://$GLANCE_HOSTPORT \ + --os-cloud=devstack-admin --os-region-name="$REGION_NAME" \ image create \ "$image_name" --public \ --container-format=tgz --disk-format=raw \ @@ -219,6 +270,22 @@ function upload_image { return fi + if [[ "$image_url" =~ '.hds' ]]; then + image_name="${image_fname%.hds}" + vm_mode=${image_name##*-} + if [[ $vm_mode != 'exe' && $vm_mode != 'hvm' ]]; then + die $LINENO "Unknown vm_mode=${vm_mode} for Virtuozzo image" + fi + + openstack \ + --os-cloud=devstack-admin --os-region-name="$REGION_NAME" \ + image create \ + "$image_name" --public \ + --container-format=bare --disk-format=ploop \ + --property vm_mode=$vm_mode < "${image}" + return + fi + local kernel="" local ramdisk="" local disk_format="" @@ -247,7 +314,8 @@ function upload_image { ;; *.img) image_name=$(basename "$image" ".img") - local format=$(qemu-img info ${image} | awk '/^file format/ { print $3; exit }') + local format + format=$(qemu-img info ${image} | awk '/^file format/ { print $3; exit }') if [[ ",qcow2,raw,vdi,vmdk,vpc," =~ ",$format," ]]; then disk_format=$format else @@ -261,11 +329,22 @@ function upload_image { container_format=bare unpack=zcat ;; + *.img.bz2) + image_name=$(basename "$image" ".img.bz2") + disk_format=qcow2 + container_format=bare + unpack=bunzip2 + ;; *.qcow2) image_name=$(basename "$image" ".qcow2") disk_format=qcow2 container_format=bare ;; + *.raw) + image_name=$(basename "$image" ".raw") + disk_format=raw + container_format=bare + ;; *.iso) image_name=$(basename "$image" ".iso") disk_format=iso @@ -274,7 +353,7 @@ function upload_image { *.vhd|*.vhdx|*.vhd.gz|*.vhdx.gz) local extension="${image_fname#*.}" image_name=$(basename "$image" ".$extension") - disk_format=vhd + disk_format=$(echo $image_fname | grep -oP '(?<=\.)vhdx?(?=\.|$)') container_format=bare if [ "${image_fname##*.}" == "gz" ]; then unpack=zcat @@ -283,19 +362,21 @@ function upload_image { *) echo "Do not know what to do with $image_fname"; false;; esac - if is_arch "ppc64"; then - img_property="--property hw_cdrom_bus=scsi" + if is_arch "ppc64le" || is_arch "ppc64" || is_arch "ppc"; then + img_property="--property hw_cdrom_bus=scsi --property os_command_line=console=hvc0" fi if is_arch "aarch64"; then - img_property="--property hw_machine_type=virt --property hw_cdrom_bus=virtio --property os_command_line='console=ttyAMA0'" + img_property="--property hw_machine_type=virt --property hw_cdrom_bus=scsi --property hw_scsi_model=virtio-scsi --property os_command_line='console=ttyAMA0'" fi if [ "$container_format" = "bare" ]; then if [ "$unpack" = "zcat" ]; then - openstack --os-token $token --os-url $GLANCE_SERVICE_PROTOCOL://$GLANCE_HOSTPORT image create "$image_name" $img_property --public --container-format=$container_format --disk-format $disk_format < <(zcat --force "${image}") + openstack --os-cloud=devstack-admin --os-region-name="$REGION_NAME" image create "$image_name" $img_property --public --container-format=$container_format --disk-format $disk_format < <(zcat --force "${image}") + elif [ "$unpack" = "bunzip2" ]; then + openstack --os-cloud=devstack-admin --os-region-name="$REGION_NAME" image create "$image_name" $img_property --public --container-format=$container_format --disk-format $disk_format < <(bunzip2 -cdk "${image}") else - openstack --os-token $token --os-url $GLANCE_SERVICE_PROTOCOL://$GLANCE_HOSTPORT image create "$image_name" $img_property --public --container-format=$container_format --disk-format $disk_format < "${image}" + openstack --os-cloud=devstack-admin --os-region-name="$REGION_NAME" image create "$image_name" $img_property --public --container-format=$container_format --disk-format $disk_format < "${image}" fi else # Use glance client to add the kernel the root filesystem. @@ -303,12 +384,12 @@ function upload_image { # kernel for use when uploading the root filesystem. local kernel_id="" ramdisk_id=""; if [ -n "$kernel" ]; then - kernel_id=$(openstack --os-token $token --os-url $GLANCE_SERVICE_PROTOCOL://$GLANCE_HOSTPORT image create "$image_name-kernel" $img_property --public --container-format aki --disk-format aki < "$kernel" | grep ' id ' | get_field 2) + kernel_id=$(openstack --os-cloud=devstack-admin --os-region-name="$REGION_NAME" image create "$image_name-kernel" $img_property --public --container-format aki --disk-format aki < "$kernel" | grep ' id ' | get_field 2) fi if [ -n "$ramdisk" ]; then - ramdisk_id=$(openstack --os-token $token --os-url $GLANCE_SERVICE_PROTOCOL://$GLANCE_HOSTPORT image create "$image_name-ramdisk" $img_property --public --container-format ari --disk-format ari < "$ramdisk" | grep ' id ' | get_field 2) + ramdisk_id=$(openstack --os-cloud=devstack-admin --os-region-name="$REGION_NAME" image create "$image_name-ramdisk" $img_property --public --container-format ari --disk-format ari < "$ramdisk" | grep ' id ' | get_field 2) fi - openstack --os-token $token --os-url $GLANCE_SERVICE_PROTOCOL://$GLANCE_HOSTPORT image create "${image_name%.img}" $img_property --public --container-format ami --disk-format ami ${kernel_id:+--property kernel_id=$kernel_id} ${ramdisk_id:+--property ramdisk_id=$ramdisk_id} < "${image}" + openstack --os-cloud=devstack-admin --os-region-name="$REGION_NAME" image create "${image_name%.img}" $img_property --public --container-format ami --disk-format ami ${kernel_id:+--property kernel_id=$kernel_id} ${ramdisk_id:+--property ramdisk_id=$ramdisk_id} < "${image}" fi } @@ -324,7 +405,7 @@ function use_database { # No backends registered means this is likely called from ``localrc`` # This is now deprecated usage DATABASE_TYPE=$1 - DEPRECATED_TEXT="$DEPRECATED_TEXT\nThe database backend needs to be properly set in ENABLED_SERVICES; use_database is deprecated localrc\n" + deprecated "The database backend needs to be properly set in ENABLED_SERVICES; use_database is deprecated localrc" else # This should no longer get called...here for posterity use_exclusive_service DATABASE_BACKENDS DATABASE_TYPE $1 @@ -336,10 +417,54 @@ CURL_GET="${CURL_GET:-curl -g}" # Wait for an HTTP server to start answering requests # wait_for_service timeout url +# +# If the service we want is behind a proxy, the proxy may be available +# before the service. Compliant proxies will return a 503 in this case +# Loop until we get something else. +# Also check for the case where there is no proxy and the service just +# hasn't started yet. curl returns 7 for Failed to connect to host. function wait_for_service { local timeout=$1 local url=$2 - timeout $timeout sh -c "while ! $CURL_GET -k --noproxy '*' -s $url >/dev/null; do sleep 1; done" + local rval=0 + time_start "wait_for_service" + timeout $timeout bash -x < ver2)); then - echo 1; return 0 - elif ((ver2 > ver1)); then - echo -1; return 0 - fi - - if ((sep <= 1)); then - echo 0; return 0 - fi - - _vercmp_r $((sep-1)) "${ver1[@]:1}" "${ver2[@]:1}" +# vercmp ver1 op ver2 +# Compare VER1 to VER2 +# - op is one of < <= == >= > +# - returns true if satisified +# e.g. +# if vercmp 1.0 "<" 2.0; then +# ... +# fi +function vercmp { + local v1=$1 + local op=$2 + local v2=$3 + local result + + # sort the two numbers with sort's "-V" argument. Based on if v2 + # swapped places with v1, we can determine ordering. + result=$(echo -e "$v1\n$v2" | sort -V | head -1) + + case $op in + "==") + [ "$v1" = "$v2" ] + return + ;; + ">") + [ "$v1" != "$v2" ] && [ "$result" = "$v2" ] + return + ;; + "<") + [ "$v1" != "$v2" ] && [ "$result" = "$v1" ] + return + ;; + ">=") + [ "$result" = "$v2" ] + return + ;; + "<=") + [ "$result" = "$v1" ] + return + ;; + *) + die $LINENO "unrecognised op: $op" + ;; + esac } - -# This function compares two versions and is meant to be called by -# external callers. Please note the function assumes non-alphabetic -# versions. For example, this will work: -# -# vercmp_numbers 1.10 1.4 -# -# The above will return "1", as 1.10 is greater than 1.4. -# -# vercmp_numbers 5.2 6.4 -# -# The above will return "-1", as 5.2 is less than 6.4. -# -# vercmp_numbers 4.0 4.0 -# -# The above will return "0", as the versions are equal. -# -# vercmp_numbers ver1 ver2 -function vercmp_numbers { - typeset v1=$1 v2=$2 sep - typeset -a ver1 ver2 - - IFS=. read -ra ver1 <<< "$v1" - IFS=. read -ra ver2 <<< "$v2" - - _vercmp_r "${#ver1[@]}" "${ver1[@]}" "${ver2[@]}" +# This sets up defaults we like in devstack for logging for tracking +# down issues, and makes sure everything is done the same between +# projects. +function setup_logging { + local conf_file=$1 + local other_cond=${2:-"False"} + if [[ "$USE_SYSTEMD" == "True" ]]; then + setup_systemd_logging $conf_file + elif [ "$LOG_COLOR" == "True" ] && [ "$SYSLOG" == "False" ] && [ "$other_cond" == "False" ]; then + setup_colorized_logging $conf_file + else + setup_standard_logging_identity $conf_file + fi } - # This function sets log formatting options for colorizing log # output to stdout. It is meant to be called by lib modules. # The last two parameters are optional and can be used to specify @@ -523,16 +658,43 @@ function vercmp_numbers { # setup_colorized_logging something.conf SOMESECTION function setup_colorized_logging { local conf_file=$1 - local conf_section=$2 - local project_var=${3:-"project_name"} - local user_var=${4:-"user_name"} + local conf_section="DEFAULT" + local project_var="project_name" + local user_var="user_name" # Add color to logging output - iniset $conf_file $conf_section logging_context_format_string "%(asctime)s.%(msecs)03d %(color)s%(levelname)s %(name)s [%(request_id)s %("$user_var")s %("$project_var")s%(color)s] %(instance)s%(color)s%(message)s" + iniset $conf_file $conf_section logging_context_format_string "%(asctime)s.%(msecs)03d %(color)s%(levelname)s %(name)s [%(request_id)s %("$project_var")s %("$user_var")s%(color)s] %(instance)s%(color)s%(message)s" iniset $conf_file $conf_section logging_default_format_string "%(asctime)s.%(msecs)03d %(color)s%(levelname)s %(name)s [-%(color)s] %(instance)s%(color)s%(message)s" iniset $conf_file $conf_section logging_debug_format_suffix "from (pid=%(process)d) %(funcName)s %(pathname)s:%(lineno)d" iniset $conf_file $conf_section logging_exception_prefix "%(color)s%(asctime)s.%(msecs)03d TRACE %(name)s %(instance)s" } +function setup_systemd_logging { + local conf_file=$1 + local conf_section="DEFAULT" + # NOTE(sdague): this is a nice to have, and means we're using the + # native systemd path, which provides for things like search on + # request-id. However, there may be an eventlet interaction here, + # so going off for now. + USE_JOURNAL=$(trueorfalse False USE_JOURNAL) + local pidstr="" + if [[ "$USE_JOURNAL" == "True" ]]; then + iniset $conf_file $conf_section use_journal "True" + # if we are using the journal directly, our process id is already correct + else + pidstr="(pid=%(process)d) " + fi + iniset $conf_file $conf_section logging_debug_format_suffix "{{${pidstr}%(funcName)s %(pathname)s:%(lineno)d}}" + + iniset $conf_file $conf_section logging_context_format_string "%(color)s%(levelname)s %(name)s [%(global_request_id)s %(request_id)s %(project_name)s %(user_name)s%(color)s] %(instance)s%(color)s%(message)s" + iniset $conf_file $conf_section logging_default_format_string "%(color)s%(levelname)s %(name)s [-%(color)s] %(instance)s%(color)s%(message)s" + iniset $conf_file $conf_section logging_exception_prefix "ERROR %(name)s %(instance)s" +} + +function setup_standard_logging_identity { + local conf_file=$1 + iniset $conf_file DEFAULT logging_user_identity_format "%(project_name)s %(user_name)s" +} + # These functions are provided for basic fall-back functionality for # projects that include parts of DevStack (Grenade). stack.sh will # override these with more specific versions for DevStack (with fancy @@ -559,7 +721,7 @@ function create_disk { # Create a loopback disk and format it to XFS. if [[ -e ${disk_image} ]]; then if egrep -q ${storage_data_dir} /proc/mounts; then - sudo umount ${storage_data_dir}/drives/sdb1 + sudo umount ${storage_data_dir} sudo rm -f ${disk_image} fi fi @@ -582,8 +744,85 @@ function create_disk { fi } + +# set_mtu - Set MTU on a device +function set_mtu { + local dev=$1 + local mtu=$2 + sudo ip link set mtu $mtu dev $dev +} + + +# running_in_container - Returns true otherwise false +function running_in_container { + [[ $(systemd-detect-virt --container) != 'none' ]] +} + + +# enable_kernel_bridge_firewall - Enable kernel support for bridge firewalling +function enable_kernel_bridge_firewall { + # Load bridge module. This module provides access to firewall for bridged + # frames; and also on older kernels (pre-3.18) it provides sysctl knobs to + # enable/disable bridge firewalling + sudo modprobe bridge + # For newer kernels (3.18+), those sysctl settings are split into a separate + # kernel module (br_netfilter). Load it too, if present. + sudo modprobe br_netfilter 2>> /dev/null || : + # Enable bridge firewalling in case it's disabled in kernel (upstream + # default is enabled, but some distributions may decide to change it). + # This is at least needed for RHEL 7.2 and earlier releases. + for proto in ip ip6; do + sudo sysctl -w net.bridge.bridge-nf-call-${proto}tables=1 + done +} + + +# Set a systemd system override +# +# This sets a system-side override in system.conf. A per-service +# override would be /etc/systemd/system/${service}.service/override.conf +function set_systemd_override { + local key="$1" + local value="$2" + + local sysconf="/etc/systemd/system.conf" + iniset -sudo "${sysconf}" "Manager" "$key" "$value" + echo "Set systemd system override for ${key}=${value}" + + sudo systemctl daemon-reload +} + +# Get a random port from the local port range +# +# This function returns an available port in the local port range. The search +# order is not truly random, but should be considered a random value by the +# user because it depends on the state of your local system. +function get_random_port { + read lower_port upper_port < /proc/sys/net/ipv4/ip_local_port_range + while true; do + for (( port = upper_port ; port >= lower_port ; port-- )); do + sudo lsof -i ":$port" &> /dev/null + if [[ $? > 0 ]] ; then + break 2 + fi + done + done + echo $port +} + +# Save some state information +# +# Write out various useful state information to /etc/devstack-version +function write_devstack_version { + cat - </dev/null +DevStack Version: ${DEVSTACK_SERIES} +Change: $(git log --format="%H %s %ci" -1) +OS Version: ${os_VENDOR} ${os_RELEASE} ${os_CODENAME} +EOF +} + # Restore xtrace -$XTRACE +$_XTRACE_FUNCTIONS # Local variables: # mode: shell-script diff --git a/functions-common b/functions-common index 52d80fb95b..af95bfb879 100644 --- a/functions-common +++ b/functions-common @@ -28,31 +28,126 @@ # - ``REQUIREMENTS_DIR`` # - ``STACK_USER`` # - ``TRACK_DEPENDS`` -# - ``UNDO_REQUIREMENTS`` # - ``http_proxy``, ``https_proxy``, ``no_proxy`` # # Save trace setting -XTRACE=$(set +o | grep xtrace) +_XTRACE_FUNCTIONS_COMMON=$(set +o | grep xtrace) set +o xtrace +# ensure we don't re-source this in the same environment +[[ -z "$_DEVSTACK_FUNCTIONS_COMMON" ]] || return 0 +declare -r -g _DEVSTACK_FUNCTIONS_COMMON=1 + # Global Config Variables -declare -A GITREPO -declare -A GITBRANCH -declare -A GITDIR +declare -A -g GITREPO +declare -A -g GITBRANCH +declare -A -g GITDIR TRACK_DEPENDS=${TRACK_DEPENDS:-False} +KILL_PATH="$(which kill)" + +# Save these variables to .stackenv +STACK_ENV_VARS="BASE_SQL_CONN DATA_DIR DEST ENABLED_SERVICES HOST_IP \ + KEYSTONE_AUTH_URI KEYSTONE_SERVICE_URI \ + LOGFILE OS_CACERT SERVICE_HOST STACK_USER TLS_IP \ + HOST_IPV6 SERVICE_IP_VERSION" + + +# Saves significant environment variables to .stackenv for later use +# Refers to a lot of globals, only TOP_DIR and STACK_ENV_VARS are required to +# function, the rest are simply saved and do not cause problems if they are undefined. +# save_stackenv [tag] +function save_stackenv { + local tag=${1:-""} + # Save some values we generated for later use + time_stamp=$(date "+$TIMESTAMP_FORMAT") + echo "# $time_stamp $tag" >$TOP_DIR/.stackenv + for i in $STACK_ENV_VARS; do + echo $i=${!i} >>$TOP_DIR/.stackenv + done +} - -# Normalize config values to True or False -# Accepts as False: 0 no No NO false False FALSE -# Accepts as True: 1 yes Yes YES true True TRUE -# VAR=$(trueorfalse default-value test-value) +# Update/create user clouds.yaml file. +# clouds.yaml will have +# - A `devstack` entry for the `demo` user for the `demo` project. +# - A `devstack-admin` entry for the `admin` user for the `admin` project. +# write_clouds_yaml +function write_clouds_yaml { + # The location is a variable to allow for easier refactoring later to make it + # overridable. There is currently no usecase where doing so makes sense, so + # it's not currently configurable. + + CLOUDS_YAML=/etc/openstack/clouds.yaml + + sudo mkdir -p $(dirname $CLOUDS_YAML) + sudo chown -R $STACK_USER /etc/openstack + + CA_CERT_ARG='' + if [ -f "$SSL_BUNDLE_FILE" ]; then + CA_CERT_ARG="--os-cacert $SSL_BUNDLE_FILE" + fi + # demo -> devstack + $PYTHON $TOP_DIR/tools/update_clouds_yaml.py \ + --file $CLOUDS_YAML \ + --os-cloud devstack \ + --os-region-name $REGION_NAME \ + --os-identity-api-version 3 \ + $CA_CERT_ARG \ + --os-auth-url $KEYSTONE_SERVICE_URI \ + --os-username demo \ + --os-password $ADMIN_PASSWORD \ + --os-project-name demo + + # alt_demo -> devstack-alt + $PYTHON $TOP_DIR/tools/update_clouds_yaml.py \ + --file $CLOUDS_YAML \ + --os-cloud devstack-alt \ + --os-region-name $REGION_NAME \ + --os-identity-api-version 3 \ + $CA_CERT_ARG \ + --os-auth-url $KEYSTONE_SERVICE_URI \ + --os-username alt_demo \ + --os-password $ADMIN_PASSWORD \ + --os-project-name alt_demo + + # admin -> devstack-admin + $PYTHON $TOP_DIR/tools/update_clouds_yaml.py \ + --file $CLOUDS_YAML \ + --os-cloud devstack-admin \ + --os-region-name $REGION_NAME \ + --os-identity-api-version 3 \ + $CA_CERT_ARG \ + --os-auth-url $KEYSTONE_SERVICE_URI \ + --os-username admin \ + --os-password $ADMIN_PASSWORD \ + --os-project-name admin + + # CLean up any old clouds.yaml files we had laying around + rm -f $(eval echo ~"$STACK_USER")/.config/openstack/clouds.yaml +} + +# trueorfalse +# +# Normalize config-value provided in variable VAR to either "True" or +# "False". If VAR is unset (i.e. $VAR evaluates as empty), the value +# of the second argument will be used as the default value. +# +# Accepts as False: 0 no No NO false False FALSE +# Accepts as True: 1 yes Yes YES true True TRUE +# +# usage: +# VAL=$(trueorfalse False VAL) function trueorfalse { - local xtrace=$(set +o | grep xtrace) + local xtrace + xtrace=$(set +o | grep xtrace) set +o xtrace local default=$1 + + if [ -z $2 ]; then + die $LINENO "variable to normalize required" + fi local testval=${!2:-} case "$testval" in @@ -68,6 +163,7 @@ function isset { [[ -v "$1" ]] } + # Control Functions # ================= @@ -76,7 +172,8 @@ function isset { # backtrace level function backtrace { local level=$1 - local deep=$((${#BASH_SOURCE[@]} - 1)) + local deep + deep=$((${#BASH_SOURCE[@]} - 1)) echo "[Call Trace]" while [ $level -le $deep ]; do echo "${BASH_SOURCE[$deep]}:${BASH_LINENO[$deep-1]}:${FUNCNAME[$deep-1]}" @@ -106,7 +203,8 @@ function die { # die_if_not_set $LINENO env-var "message" function die_if_not_set { local exitcode=$? - local xtrace=$(set +o | grep xtrace) + local xtrace + xtrace=$(set +o | grep xtrace) set +o xtrace local line=$1; shift local evar=$1; shift @@ -116,16 +214,23 @@ function die_if_not_set { $xtrace } +function deprecated { + local text=$1 + DEPRECATED_TEXT+="\n$text" + echo "WARNING: $text" >&2 +} + # Prints line number and "message" in error format # err $LINENO "message" function err { local exitcode=$? - local xtrace=$(set +o | grep xtrace) + local xtrace + xtrace=$(set +o | grep xtrace) set +o xtrace local msg="[ERROR] ${BASH_SOURCE[2]}:$1 $2" - echo $msg 1>&2; + echo "$msg" 1>&2; if [[ -n ${LOGDIR} ]]; then - echo $msg >> "${LOGDIR}/error.log" + echo "$msg" >> "${LOGDIR}/error.log" fi $xtrace return $exitcode @@ -137,7 +242,8 @@ function err { # err_if_not_set $LINENO env-var "message" function err_if_not_set { local exitcode=$? - local xtrace=$(set +o | grep xtrace) + local xtrace + xtrace=$(set +o | grep xtrace) set +o xtrace local line=$1; shift local evar=$1; shift @@ -173,10 +279,11 @@ function is_set { # warn $LINENO "message" function warn { local exitcode=$? - local xtrace=$(set +o | grep xtrace) + local xtrace + xtrace=$(set +o | grep xtrace) set +o xtrace local msg="[WARNING] ${BASH_SOURCE[2]}:$1 $2" - echo $msg + echo "$msg" $xtrace return $exitcode } @@ -186,146 +293,127 @@ function warn { # ================ # Determine OS Vendor, Release and Update -# Tested with OS/X, Ubuntu, RedHat, CentOS, Fedora -# Returns results in global variables: + +# +# NOTE : For portability, you almost certainly do not want to use +# these variables directly! The "is_*" functions defined below this +# bundle up compatible platforms under larger umbrellas that we have +# determinted are compatible enough (e.g. is_ubuntu covers Ubuntu & +# Debian, is_fedora covers RPM-based distros). Higher-level functions +# such as "install_package" further abstract things in better ways. +# # ``os_VENDOR`` - vendor name: ``Ubuntu``, ``Fedora``, etc -# ``os_RELEASE`` - major release: ``14.04`` (Ubuntu), ``20`` (Fedora) -# ``os_UPDATE`` - update: ex. the ``5`` in ``RHEL6.5`` +# ``os_RELEASE`` - major release: ``16.04`` (Ubuntu), ``23`` (Fedora) # ``os_PACKAGE`` - package type: ``deb`` or ``rpm`` -# ``os_CODENAME`` - vendor's codename for release: ``snow leopard``, ``trusty`` -os_VENDOR="" -os_RELEASE="" -os_UPDATE="" -os_PACKAGE="" -os_CODENAME="" +# ``os_CODENAME`` - vendor's codename for release: ``xenial`` + +declare -g os_VENDOR os_RELEASE os_PACKAGE os_CODENAME + +# Make a *best effort* attempt to install lsb_release packages for the +# user if not available. Note can't use generic install_package* +# because they depend on this! +function _ensure_lsb_release { + if [[ -x $(command -v lsb_release 2>/dev/null) ]]; then + return + fi + + if [[ -x $(command -v apt-get 2>/dev/null) ]]; then + sudo apt-get install -y lsb-release + elif [[ -x $(command -v zypper 2>/dev/null) ]]; then + sudo zypper -n install lsb-release + elif [[ -x $(command -v dnf 2>/dev/null) ]]; then + sudo dnf install -y redhat-lsb-core + elif [[ -x $(command -v yum 2>/dev/null) ]]; then + # all rh patforms (fedora, centos, rhel) have this pkg + sudo yum install -y redhat-lsb-core + else + die $LINENO "Unable to find or auto-install lsb_release" + fi +} # GetOSVersion +# Set the following variables: +# - os_RELEASE +# - os_CODENAME +# - os_VENDOR +# - os_PACKAGE function GetOSVersion { + # We only support distros that provide a sane lsb_release + _ensure_lsb_release - # Figure out which vendor we are - if [[ -x "`which sw_vers 2>/dev/null`" ]]; then - # OS/X - os_VENDOR=`sw_vers -productName` - os_RELEASE=`sw_vers -productVersion` - os_UPDATE=${os_RELEASE##*.} - os_RELEASE=${os_RELEASE%.*} - os_PACKAGE="" - if [[ "$os_RELEASE" =~ "10.7" ]]; then - os_CODENAME="lion" - elif [[ "$os_RELEASE" =~ "10.6" ]]; then - os_CODENAME="snow leopard" - elif [[ "$os_RELEASE" =~ "10.5" ]]; then - os_CODENAME="leopard" - elif [[ "$os_RELEASE" =~ "10.4" ]]; then - os_CODENAME="tiger" - elif [[ "$os_RELEASE" =~ "10.3" ]]; then - os_CODENAME="panther" - else - os_CODENAME="" - fi - elif [[ -x $(which lsb_release 2>/dev/null) ]]; then - os_VENDOR=$(lsb_release -i -s) - os_RELEASE=$(lsb_release -r -s) - os_UPDATE="" - os_PACKAGE="rpm" - if [[ "Debian,Ubuntu,LinuxMint" =~ $os_VENDOR ]]; then - os_PACKAGE="deb" - elif [[ "SUSE LINUX" =~ $os_VENDOR ]]; then - lsb_release -d -s | grep -q openSUSE - if [[ $? -eq 0 ]]; then - os_VENDOR="openSUSE" - fi - elif [[ $os_VENDOR == "openSUSE project" ]]; then - os_VENDOR="openSUSE" - elif [[ $os_VENDOR =~ Red.*Hat ]]; then - os_VENDOR="Red Hat" - fi - os_CODENAME=$(lsb_release -c -s) - elif [[ -r /etc/redhat-release ]]; then - # Red Hat Enterprise Linux Server release 5.5 (Tikanga) - # Red Hat Enterprise Linux Server release 7.0 Beta (Maipo) - # CentOS release 5.5 (Final) - # CentOS Linux release 6.0 (Final) - # Fedora release 16 (Verne) - # XenServer release 6.2.0-70446c (xenenterprise) - # Oracle Linux release 7 - os_CODENAME="" - for r in "Red Hat" CentOS Fedora XenServer; do - os_VENDOR=$r - if [[ -n "`grep \"$r\" /etc/redhat-release`" ]]; then - ver=`sed -e 's/^.* \([0-9].*\) (\(.*\)).*$/\1\|\2/' /etc/redhat-release` - os_CODENAME=${ver#*|} - os_RELEASE=${ver%|*} - os_UPDATE=${os_RELEASE##*.} - os_RELEASE=${os_RELEASE%.*} - break - fi - os_VENDOR="" - done - if [ "$os_VENDOR" = "Red Hat" ] && [[ -r /etc/oracle-release ]]; then - os_VENDOR=OracleLinux - fi - os_PACKAGE="rpm" - elif [[ -r /etc/SuSE-release ]]; then - for r in openSUSE "SUSE Linux"; do - if [[ "$r" = "SUSE Linux" ]]; then - os_VENDOR="SUSE LINUX" - else - os_VENDOR=$r - fi + os_RELEASE=$(lsb_release -r -s) + os_CODENAME=$(lsb_release -c -s) + os_VENDOR=$(lsb_release -i -s) - if [[ -n "`grep \"$r\" /etc/SuSE-release`" ]]; then - os_CODENAME=`grep "CODENAME = " /etc/SuSE-release | sed 's:.* = ::g'` - os_RELEASE=`grep "VERSION = " /etc/SuSE-release | sed 's:.* = ::g'` - os_UPDATE=`grep "PATCHLEVEL = " /etc/SuSE-release | sed 's:.* = ::g'` - break - fi - os_VENDOR="" - done - os_PACKAGE="rpm" - # If lsb_release is not installed, we should be able to detect Debian OS - elif [[ -f /etc/debian_version ]] && [[ $(cat /proc/version) =~ "Debian" ]]; then - os_VENDOR="Debian" + if [[ $os_VENDOR =~ (Debian|Ubuntu|LinuxMint) ]]; then os_PACKAGE="deb" - os_CODENAME=$(awk '/VERSION=/' /etc/os-release | sed 's/VERSION=//' | sed -r 's/\"|\(|\)//g' | awk '{print $2}') - os_RELEASE=$(awk '/VERSION_ID=/' /etc/os-release | sed 's/VERSION_ID=//' | sed 's/\"//g') + else + os_PACKAGE="rpm" fi - export os_VENDOR os_RELEASE os_UPDATE os_PACKAGE os_CODENAME + + typeset -xr os_VENDOR + typeset -xr os_RELEASE + typeset -xr os_PACKAGE + typeset -xr os_CODENAME } # Translate the OS version values into common nomenclature # Sets global ``DISTRO`` from the ``os_*`` values -declare DISTRO +declare -g DISTRO function GetDistro { GetOSVersion - if [[ "$os_VENDOR" =~ (Ubuntu) || "$os_VENDOR" =~ (Debian) ]]; then - # 'Everyone' refers to Ubuntu / Debian releases by the code name adjective + if [[ "$os_VENDOR" =~ (Ubuntu) || "$os_VENDOR" =~ (Debian) || \ + "$os_VENDOR" =~ (LinuxMint) ]]; then + # 'Everyone' refers to Ubuntu / Debian / Mint releases by + # the code name adjective DISTRO=$os_CODENAME elif [[ "$os_VENDOR" =~ (Fedora) ]]; then # For Fedora, just use 'f' and the release DISTRO="f$os_RELEASE" elif [[ "$os_VENDOR" =~ (openSUSE) ]]; then DISTRO="opensuse-$os_RELEASE" + # Tumbleweed uses "n/a" as a codename, and the release is a datestring + # like 20180218, so not very useful. Leap however uses a release + # with a "dot", so for example 15.0 + [ "$os_CODENAME" = "n/a" -a "$os_RELEASE" = "${os_RELEASE/\./}" ] && \ + DISTRO="opensuse-tumbleweed" elif [[ "$os_VENDOR" =~ (SUSE LINUX) ]]; then - # For SLE, also use the service pack - if [[ -z "$os_UPDATE" ]]; then - DISTRO="sle${os_RELEASE}" - else - DISTRO="sle${os_RELEASE}sp${os_UPDATE}" - fi - elif [[ "$os_VENDOR" =~ (Red Hat) || \ + # just use major release + DISTRO="sle${os_RELEASE%.*}" + elif [[ "$os_VENDOR" =~ (Red.*Hat) || \ "$os_VENDOR" =~ (CentOS) || \ - "$os_VENDOR" =~ (OracleLinux) ]]; then + "$os_VENDOR" =~ (Scientific) || \ + "$os_VENDOR" =~ (OracleServer) || \ + "$os_VENDOR" =~ (Virtuozzo) ]]; then # Drop the . release as we assume it's compatible + # XXX re-evaluate when we get RHEL10 DISTRO="rhel${os_RELEASE::1}" elif [[ "$os_VENDOR" =~ (XenServer) ]]; then - DISTRO="xs$os_RELEASE" + DISTRO="xs${os_RELEASE%.*}" else - # Catch-all for now is Vendor + Release + Update - DISTRO="$os_VENDOR-$os_RELEASE.$os_UPDATE" - fi - export DISTRO + # We can't make a good choice here. Setting a sensible DISTRO + # is part of the problem, but not the major issue -- we really + # only use DISTRO in the code as a fine-filter. + # + # The bigger problem is categorising the system into one of + # our two big categories as Ubuntu/Debian-ish or + # Fedora/CentOS-ish. + # + # The setting of os_PACKAGE above is only set to "deb" based + # on a hard-coded list of vendor names ... thus we will + # default to thinking unknown distros are RPM based + # (ie. is_ubuntu does not match). But the platform will then + # also not match in is_fedora, because that also has a list of + # names. + # + # So, if you are reading this, getting your distro supported + # is really about making sure it matches correctly in these + # functions. Then you can choose a sensible way to construct + # DISTRO based on your distros release approach. + die $LINENO "Unable to determine DISTRO, can not continue." + fi + typeset -xr DISTRO } # Utility function for checking machine architecture @@ -341,7 +429,7 @@ function is_oraclelinux { GetOSVersion fi - [ "$os_VENDOR" = "OracleLinux" ] + [ "$os_VENDOR" = "OracleServer" ] } @@ -354,7 +442,9 @@ function is_fedora { fi [ "$os_VENDOR" = "Fedora" ] || [ "$os_VENDOR" = "Red Hat" ] || \ - [ "$os_VENDOR" = "CentOS" ] || [ "$os_VENDOR" = "OracleLinux" ] + [ "$os_VENDOR" = "RedHatEnterpriseServer" ] || \ + [ "$os_VENDOR" = "CentOS" ] || [ "$os_VENDOR" = "OracleServer" ] || \ + [ "$os_VENDOR" = "Virtuozzo" ] } @@ -366,7 +456,7 @@ function is_suse { GetOSVersion fi - [ "$os_VENDOR" = "openSUSE" ] || [ "$os_VENDOR" = "SUSE LINUX" ] + [[ "$os_VENDOR" =~ (openSUSE) || "$os_VENDOR" == "SUSE LINUX" ]] } @@ -407,7 +497,8 @@ function git_clone { local git_remote=$1 local git_dest=$2 local git_ref=$3 - local orig_dir=$(pwd) + local orig_dir + orig_dir=$(pwd) local git_clone_flags="" RECLONE=$(trueorfalse False RECLONE) @@ -427,8 +518,11 @@ function git_clone { if echo $git_ref | egrep -q "^refs"; then # If our branch name is a gerrit style refs/changes/... if [[ ! -d $git_dest ]]; then - [[ "$ERROR_ON_CLONE" = "True" ]] && \ + if [[ "$ERROR_ON_CLONE" = "True" ]]; then + echo "The $git_dest project was not found; if this is a gate job, add" + echo "the project to 'required-projects' in the job definition." die $LINENO "Cloning not allowed in this configuration" + fi git_timed clone $git_clone_flags $git_remote $git_dest fi cd $git_dest @@ -436,12 +530,13 @@ function git_clone { else # do a full clone only if the directory doesn't exist if [[ ! -d $git_dest ]]; then - [[ "$ERROR_ON_CLONE" = "True" ]] && \ + if [[ "$ERROR_ON_CLONE" = "True" ]]; then + echo "The $git_dest project was not found; if this is a gate job, add" + echo "the project to the \$PROJECTS variable in the job definition." die $LINENO "Cloning not allowed in this configuration" - git_timed clone $git_clone_flags $git_remote $git_dest - cd $git_dest - # This checkout syntax works for both branches and tags - git checkout $git_ref + fi + # '--branch' can also take tags + git_timed clone $git_clone_flags $git_remote $git_dest --branch $git_ref elif [[ "$RECLONE" = "True" ]]; then # if it does exist then simulate what clone does if asked to RECLONE cd $git_dest @@ -500,6 +595,7 @@ function git_timed { timeout=${GIT_TIMEOUT} fi + time_start "git_timed" until timeout -s SIGINT ${timeout} git "$@"; do # 124 is timeout(1)'s special return code when it reached the # timeout; otherwise assume fatal failure @@ -514,6 +610,7 @@ function git_timed { fi sleep 5 done + time_stop "git_timed" } # git update using reference as a branch. @@ -558,13 +655,15 @@ function get_default_host_ip { local floating_range=$2 local host_ip_iface=$3 local host_ip=$4 + local af=$5 # Search for an IP unless an explicit is set by ``HOST_IP`` environment variable if [ -z "$host_ip" -o "$host_ip" == "dhcp" ]; then host_ip="" # Find the interface used for the default route - host_ip_iface=${host_ip_iface:-$(ip route | awk '/default/ {print $5}' | head -1)} - local host_ips=$(LC_ALL=C ip -f inet addr show ${host_ip_iface} | awk '/inet/ {split($2,parts,"/"); print parts[1]}') + host_ip_iface=${host_ip_iface:-$(ip -f $af route | awk '/default/ {print $5}' | head -1)} + local host_ips + host_ips=$(LC_ALL=C ip -f $af addr show ${host_ip_iface} | sed /temporary/d |awk /$af'/ {split($2,parts,"/"); print parts[1]}') local ip for ip in $host_ips; do # Attempt to filter out IP addresses that are part of the fixed and @@ -573,6 +672,10 @@ function get_default_host_ip { # will be printed and the first IP from the interface will be used. # If that is not correct set ``HOST_IP`` in ``localrc`` to the correct # address. + if [[ "$af" == "inet6" ]]; then + host_ip=$ip + break; + fi if ! (address_in_net $ip $fixed_range || address_in_net $ip $floating_range); then host_ip=$ip break; @@ -609,7 +712,8 @@ function get_field { # copy over a default policy.json and policy.d for projects function install_default_policy { local project=$1 - local project_uc=$(echo $1|tr a-z A-Z) + local project_uc + project_uc=$(echo $1|tr a-z A-Z) local conf_dir="${project_uc}_CONF_DIR" # eval conf dir to get the variable conf_dir="${!conf_dir}" @@ -642,7 +746,8 @@ function policy_add { # Add a terminating comma to policy lines without one # Remove the closing '}' and all lines following to the end-of-file - local tmpfile=$(mktemp) + local tmpfile + tmpfile=$(mktemp) uniq ${policy_file} | sed -e ' s/]$/],/ /^[}]/,$d @@ -658,16 +763,14 @@ function policy_add { # Gets or creates a domain # Usage: get_or_create_domain function get_or_create_domain { - local os_url="$KEYSTONE_SERVICE_URI_V3" + local domain_id # Gets domain id - local domain_id=$( + domain_id=$( # Gets domain id - openstack --os-token=$OS_TOKEN --os-url=$os_url \ - --os-identity-api-version=3 domain show $1 \ + openstack domain show $1 \ -f value -c id 2>/dev/null || # Creates new domain - openstack --os-token=$OS_TOKEN --os-url=$os_url \ - --os-identity-api-version=3 domain create $1 \ + openstack domain create $1 \ --description "$2" \ -f value -c id ) @@ -675,44 +778,37 @@ function get_or_create_domain { } # Gets or creates group -# Usage: get_or_create_group [ ] +# Usage: get_or_create_group [] function get_or_create_group { - local domain=${2:+--domain ${2}} local desc="${3:-}" - local os_url="$KEYSTONE_SERVICE_URI_V3" + local group_id # Gets group id - local group_id=$( + group_id=$( # Creates new group with --or-show - openstack --os-token=$OS_TOKEN --os-url=$os_url \ - --os-identity-api-version=3 group create $1 \ - $domain --description "$desc" --or-show \ + openstack group create $1 \ + --domain $2 --description "$desc" --or-show \ -f value -c id ) echo $group_id } # Gets or creates user -# Usage: get_or_create_user [ []] +# Usage: get_or_create_user [] function get_or_create_user { - if [[ ! -z "$3" ]]; then - local email="--email=$3" + local user_id + if [[ ! -z "$4" ]]; then + local email="--email=$4" else local email="" fi - local os_cmd="openstack" - local domain="" - if [[ ! -z "$4" ]]; then - domain="--domain=$4" - os_cmd="$os_cmd --os-url=$KEYSTONE_SERVICE_URI_V3 --os-identity-api-version=3" - fi # Gets user id - local user_id=$( + user_id=$( # Creates new user with --or-show - $os_cmd user create \ + openstack user create \ $1 \ --password "$2" \ + --domain=$3 \ $email \ - $domain \ --or-show \ -f value -c id ) @@ -720,18 +816,14 @@ function get_or_create_user { } # Gets or creates project -# Usage: get_or_create_project [] +# Usage: get_or_create_project function get_or_create_project { - # Gets project id - local os_cmd="openstack" - local domain="" - if [[ ! -z "$2" ]]; then - domain="--domain=$2" - os_cmd="$os_cmd --os-url=$KEYSTONE_SERVICE_URI_V3 --os-identity-api-version=3" - fi - local project_id=$( + local project_id + project_id=$( # Creates new project with --or-show - $os_cmd project create $1 $domain --or-show -f value -c id + openstack project create $1 \ + --domain=$2 \ + --or-show -f value -c id ) echo $project_id } @@ -739,30 +831,81 @@ function get_or_create_project { # Gets or creates role # Usage: get_or_create_role function get_or_create_role { - local role_id=$( + local role_id + role_id=$( # Creates role with --or-show - openstack role create $1 --or-show -f value -c id + openstack role create $1 \ + --or-show -f value -c id ) echo $role_id } +# Returns the domain parts of a function call if present +# Usage: _get_domain_args [ ] +function _get_domain_args { + local domain + domain="" + + if [[ -n "$1" ]]; then + domain="$domain --user-domain $1" + fi + if [[ -n "$2" ]]; then + domain="$domain --project-domain $2" + fi + + echo $domain +} + # Gets or adds user role to project -# Usage: get_or_add_user_project_role +# Usage: get_or_add_user_project_role [ ] function get_or_add_user_project_role { + local user_role_id + + domain_args=$(_get_domain_args $4 $5) + # Gets user role id - local user_role_id=$(openstack role list \ + user_role_id=$(openstack role assignment list \ + --role $1 \ --user $2 \ --project $3 \ - --column "ID" \ - --column "Name" \ - | grep " $1 " | get_field 1) + $domain_args \ + | grep '^|\s[a-f0-9]\+' | get_field 1) if [[ -z "$user_role_id" ]]; then - # Adds role to user - user_role_id=$(openstack role add \ - $1 \ + # Adds role to user and get it + openstack role add $1 \ --user $2 \ --project $3 \ - | grep " id " | get_field 2) + $domain_args + user_role_id=$(openstack role assignment list \ + --role $1 \ + --user $2 \ + --project $3 \ + $domain_args \ + | grep '^|\s[a-f0-9]\+' | get_field 1) + fi + echo $user_role_id +} + +# Gets or adds user role to domain +# Usage: get_or_add_user_domain_role +function get_or_add_user_domain_role { + local user_role_id + # Gets user role id + user_role_id=$(openstack role assignment list \ + --role $1 \ + --user $2 \ + --domain $3 \ + | grep '^|\s[a-f0-9]\+' | get_field 1) + if [[ -z "$user_role_id" ]]; then + # Adds role to user and get it + openstack role add $1 \ + --user $2 \ + --domain $3 + user_role_id=$(openstack role assignment list \ + --role $1 \ + --user $2 \ + --domain $3 \ + | grep '^|\s[a-f0-9]\+' | get_field 1) fi echo $user_role_id } @@ -770,20 +913,23 @@ function get_or_add_user_project_role { # Gets or adds group role to project # Usage: get_or_add_group_project_role function get_or_add_group_project_role { + local group_role_id # Gets group role id - local group_role_id=$(openstack role list \ + group_role_id=$(openstack role assignment list \ + --role $1 \ --group $2 \ --project $3 \ - --column "ID" \ - --column "Name" \ - | grep " $1 " | get_field 1) + -f value) if [[ -z "$group_role_id" ]]; then - # Adds role to group - group_role_id=$(openstack role add \ - $1 \ + # Adds role to group and get it + openstack role add $1 \ + --group $2 \ + --project $3 + group_role_id=$(openstack role assignment list \ + --role $1 \ --group $2 \ --project $3 \ - | grep " id " | get_field 2) + -f value) fi echo $group_role_id } @@ -791,10 +937,11 @@ function get_or_add_group_project_role { # Gets or creates service # Usage: get_or_create_service function get_or_create_service { + local service_id # Gets service id - local service_id=$( + service_id=$( # Gets service id - openstack service show $1 -f value -c id 2>/dev/null || + openstack service show $2 -f value -c id 2>/dev/null || # Creates new service if not exists openstack service create \ $2 \ @@ -805,29 +952,65 @@ function get_or_create_service { echo $service_id } -# Gets or creates endpoint -# Usage: get_or_create_endpoint -function get_or_create_endpoint { - # Gets endpoint id - local endpoint_id=$(openstack endpoint list \ - --column "ID" \ - --column "Region" \ - --column "Service Name" \ - | grep " $2 " \ - | grep " $1 " | get_field 1) +# Create an endpoint with a specific interface +# Usage: _get_or_create_endpoint_with_interface +function _get_or_create_endpoint_with_interface { + local endpoint_id + endpoint_id=$(openstack endpoint list \ + --service $1 \ + --interface $2 \ + --region $4 \ + -c ID -f value) if [[ -z "$endpoint_id" ]]; then # Creates new endpoint endpoint_id=$(openstack endpoint create \ - $1 \ - --region $2 \ - --publicurl $3 \ - --adminurl $4 \ - --internalurl $5 \ - | grep " id " | get_field 2) + $1 $2 $3 --region $4 -f value -c id) fi + echo $endpoint_id } +# Gets or creates endpoint +# Usage: get_or_create_endpoint [adminurl] [internalurl] +function get_or_create_endpoint { + # NOTE(jamielennnox): when converting to v3 endpoint creation we go from + # creating one endpoint with multiple urls to multiple endpoints each with + # a different interface. To maintain the existing function interface we + # create 3 endpoints and return the id of the public one. In reality + # returning the public id will not make a lot of difference as there are no + # scenarios currently that use the returned id. Ideally this behaviour + # should be pushed out to the service setups and let them create the + # endpoints they need. + local public_id + public_id=$(_get_or_create_endpoint_with_interface $1 public $3 $2) + # only create admin/internal urls if provided content for them + if [[ -n "$4" ]]; then + _get_or_create_endpoint_with_interface $1 admin $4 $2 + fi + if [[ -n "$5" ]]; then + _get_or_create_endpoint_with_interface $1 internal $5 $2 + fi + # return the public id to indicate success, and this is the endpoint most likely wanted + echo $public_id +} + +# Get a URL from the identity service +# Usage: get_endpoint_url +function get_endpoint_url { + echo $(openstack endpoint list \ + --service $1 --interface $2 \ + -c URL -f value) +} + +# check if we are using ironic with hardware +# TODO(jroll) this is a kludge left behind when ripping ironic code +# out of tree, as it is used by nova and neutron. +# figure out a way to refactor nova/neutron code to eliminate this +function is_ironic_hardware { + is_service_enabled ironic && [[ "$IRONIC_IS_HARDWARE" == "True" ]] && return 0 + return 1 +} + # Package Functions # ================= @@ -852,23 +1035,60 @@ function _get_package_dir { echo "$pkg_dir" } +# Wrapper for ``apt-get update`` to try multiple times on the update +# to address bad package mirrors (which happen all the time). +function apt_get_update { + # only do this once per run + if [[ "$REPOS_UPDATED" == "True" && "$RETRY_UPDATE" != "True" ]]; then + return + fi + + # bail if we are offline + [[ "$OFFLINE" = "True" ]] && return + + local sudo="sudo" + [[ "$(id -u)" = "0" ]] && sudo="env" + + # time all the apt operations + time_start "apt-get-update" + + local proxies="http_proxy=${http_proxy:-} https_proxy=${https_proxy:-} no_proxy=${no_proxy:-} " + local update_cmd="$sudo $proxies apt-get update" + if ! timeout 300 sh -c "while ! $update_cmd; do sleep 30; done"; then + die $LINENO "Failed to update apt repos, we're dead now" + fi + + REPOS_UPDATED=True + # stop the clock + time_stop "apt-get-update" +} + # Wrapper for ``apt-get`` to set cache and proxy environment variables # Uses globals ``OFFLINE``, ``*_proxy`` # apt_get operation package [package ...] function apt_get { - local xtrace=$(set +o | grep xtrace) + local xtrace result + xtrace=$(set +o | grep xtrace) set +o xtrace [[ "$OFFLINE" = "True" || -z "$@" ]] && return local sudo="sudo" [[ "$(id -u)" = "0" ]] && sudo="env" + # time all the apt operations + time_start "apt-get" + $xtrace $sudo DEBIAN_FRONTEND=noninteractive \ http_proxy=${http_proxy:-} https_proxy=${https_proxy:-} \ no_proxy=${no_proxy:-} \ - apt-get --option "Dpkg::Options::=--force-confold" --assume-yes "$@" + apt-get --option "Dpkg::Options::=--force-confold" --assume-yes "$@" < /dev/null + result=$? + + # stop the clock + time_stop "apt-get" + return $result } function _parse_package_files { @@ -889,8 +1109,9 @@ function _parse_package_files { continue fi - # Assume we want this package - package=${line%#*} + # Assume we want this package; free-form + # comments allowed after a # + package=${line%%#*} inst_pkg=1 # Look for # dist:xxx in comment @@ -898,7 +1119,7 @@ function _parse_package_files { # We are using BASH regexp matching feature. package=${BASH_REMATCH[1]} distros=${BASH_REMATCH[2]} - # In bash ${VAR,,} will lowecase VAR + # In bash ${VAR,,} will lowercase VAR # Look for a match in the distro list if [[ ! ${distros,,} =~ ${DISTRO,,} ]]; then # If no match then skip this package @@ -906,6 +1127,19 @@ function _parse_package_files { fi fi + # Look for # not:xxx in comment + if [[ $line =~ (.*)#.*not:([^ ]*) ]]; then + # We are using BASH regexp matching feature. + package=${BASH_REMATCH[1]} + distros=${BASH_REMATCH[2]} + # In bash ${VAR,,} will lowercase VAR + # Look for a match in the distro list + if [[ ${distros,,} =~ ${DISTRO,,} ]]; then + # If match then skip this package + inst_pkg=0 + fi + fi + if [[ $inst_pkg = 1 ]]; then echo $package fi @@ -924,14 +1158,22 @@ function _parse_package_files { # - ``# NOPRIME`` defers installation to be performed later in `stack.sh` # - ``# dist:DISTRO`` or ``dist:DISTRO1,DISTRO2`` limits the selection # of the package to the distros listed. The distro names are case insensitive. +# - ``# not:DISTRO`` or ``not:DISTRO1,DISTRO2`` limits the selection +# of the package to the distros not listed. The distro names are case insensitive. function get_packages { - local xtrace=$(set +o | grep xtrace) + local xtrace + xtrace=$(set +o | grep xtrace) set +o xtrace local services=$@ - local package_dir=$(_get_package_dir) + local package_dir + package_dir=$(_get_package_dir) local file_to_parse="" local service="" + if [ $# -ne 1 ]; then + die $LINENO "get_packages takes a single, comma-separated argument" + fi + if [[ -z "$package_dir" ]]; then echo "No package directory supplied" return 1 @@ -954,10 +1196,6 @@ function get_packages { if [[ ! $file_to_parse =~ $package_dir/cinder ]]; then file_to_parse="${file_to_parse} ${package_dir}/cinder" fi - elif [[ $service == ceilometer-* ]]; then - if [[ ! $file_to_parse =~ $package_dir/ceilometer ]]; then - file_to_parse="${file_to_parse} ${package_dir}/ceilometer" - fi elif [[ $service == s-* ]]; then if [[ ! $file_to_parse =~ $package_dir/swift ]]; then file_to_parse="${file_to_parse} ${package_dir}/swift" @@ -974,9 +1212,9 @@ function get_packages { if [[ ! $file_to_parse =~ $package_dir/keystone ]]; then file_to_parse="${file_to_parse} ${package_dir}/keystone" fi - elif [[ $service == q-* ]]; then - if [[ ! $file_to_parse =~ $package_dir/neutron ]]; then - file_to_parse="${file_to_parse} ${package_dir}/neutron" + elif [[ $service == q-* || $service == neutron-* ]]; then + if [[ ! $file_to_parse =~ $package_dir/neutron-common ]]; then + file_to_parse="${file_to_parse} ${package_dir}/neutron-common" fi elif [[ $service == ir-* ]]; then if [[ ! $file_to_parse =~ $package_dir/ironic ]]; then @@ -997,13 +1235,14 @@ function get_packages { # The same metadata used in the main DevStack prerequisite files may be used # in these prerequisite files, see get_packages() for more info. function get_plugin_packages { - local xtrace=$(set +o | grep xtrace) + local xtrace + xtrace=$(set +o | grep xtrace) set +o xtrace local files_to_parse="" local package_dir="" for plugin in ${DEVSTACK_PLUGINS//,/ }; do - local package_dir="$(_get_package_dir ${GITDIR[$plugin]}/devstack/files)" - files_to_parse+="$package_dir/$plugin" + package_dir="$(_get_package_dir ${GITDIR[$plugin]}/devstack/files)" + files_to_parse+=" $package_dir/$plugin" done echo "$(_parse_package_files $files_to_parse)" $xtrace @@ -1022,15 +1261,7 @@ function update_package_repo { fi if is_ubuntu; then - local xtrace=$(set +o | grep xtrace) - set +o xtrace - if [[ "$REPOS_UPDATED" != "True" || "$RETRY_UPDATE" = "True" ]]; then - # if there are transient errors pulling the updates, that's fine. - # It may be secondary repositories that we don't really care about. - apt_get update || /bin/true - REPOS_UPDATED=True - fi - $xtrace + apt_get_update fi } @@ -1050,7 +1281,9 @@ function real_install_package { # install_package package [package ...] function install_package { update_package_repo - real_install_package $@ || RETRY_UPDATE=True update_package_repo && real_install_package $@ + if ! real_install_package "$@"; then + RETRY_UPDATE=True update_package_repo && real_install_package "$@" + fi } # Distro-agnostic function to tell if a package is installed @@ -1081,7 +1314,7 @@ function uninstall_package { elif is_fedora; then sudo ${YUM:-yum} remove -y "$@" ||: elif is_suse; then - sudo zypper rm "$@" + sudo zypper remove -y "$@" ||: else exit_distro_not_supported "uninstalling packages" fi @@ -1091,27 +1324,49 @@ function uninstall_package { # Uses globals ``OFFLINE``, ``*_proxy``, ``YUM`` # yum_install package [package ...] function yum_install { + local result parse_yum_result + [[ "$OFFLINE" = "True" ]] && return - local sudo="sudo" - [[ "$(id -u)" = "0" ]] && sudo="env" - # The manual check for missing packages is because yum -y assumes - # missing packages are OK. See - # https://bugzilla.redhat.com/show_bug.cgi?id=965567 - $sudo http_proxy="${http_proxy:-}" https_proxy="${https_proxy:-}" \ - no_proxy="${no_proxy:-}" \ - ${YUM:-yum} install -y "$@" 2>&1 | \ - awk ' - BEGIN { fail=0 } - /No package/ { fail=1 } - { print } - END { exit fail }' || \ - die $LINENO "Missing packages detected" + time_start "yum_install" + + # This is a bit tricky, because yum -y assumes missing or failed + # packages are OK (see [1]). We want devstack to stop if we are + # installing missing packages. + # + # Thus we manually match on the output (stack.sh runs in a fixed + # locale, so lang shouldn't change). + # + # If yum returns !0, we echo the result as "YUM_FAILED" and return + # that from the awk (we're subverting -e with this trick). + # Otherwise we use awk to look for failure strings and return "2" + # to indicate a terminal failure. + # + # [1] https://bugzilla.redhat.com/show_bug.cgi?id=965567 + parse_yum_result=' \ + BEGIN { result=0 } \ + /^YUM_FAILED/ { result=$2 } \ + /^No package/ { result=2 } \ + /^Failed:/ { result=2 } \ + //{ print } \ + END { exit result }' + (sudo_with_proxies "${YUM:-yum}" install -y "$@" 2>&1 || echo YUM_FAILED $?) \ + | awk "$parse_yum_result" && result=$? || result=$? + + time_stop "yum_install" - # also ensure we catch a yum failure - if [[ ${PIPESTATUS[0]} != 0 ]]; then - die $LINENO "${YUM:-yum} install failure" + # if we return 1, then the wrapper functions will run an update + # and try installing the package again as a defense against bad + # mirrors. This can hide failures, especially when we have + # packages that are in the "Failed:" section because their rpm + # install scripts failed to run correctly (in this case, the + # package looks installed, so when the retry happens we just think + # the package is OK, and incorrectly continue on). + if [ "$result" == 2 ]; then + die "Detected fatal package install failure" fi + + return "$result" } # zypper wrapper to set arguments correctly @@ -1123,77 +1378,110 @@ function zypper_install { [[ "$(id -u)" = "0" ]] && sudo="env" $sudo http_proxy="${http_proxy:-}" https_proxy="${https_proxy:-}" \ no_proxy="${no_proxy:-}" \ - zypper --non-interactive install --auto-agree-with-licenses "$@" + zypper --non-interactive install --auto-agree-with-licenses --no-recommends "$@" } +function write_user_unit_file { + local service=$1 + local command="$2" + local group=$3 + local user=$4 + local extra="" + if [[ -n "$group" ]]; then + extra="Group=$group" + fi + local unitfile="$SYSTEMD_DIR/$service" + mkdir -p $SYSTEMD_DIR -# Process Functions -# ================= + iniset -sudo $unitfile "Unit" "Description" "Devstack $service" + iniset -sudo $unitfile "Service" "User" "$user" + iniset -sudo $unitfile "Service" "ExecStart" "$command" + iniset -sudo $unitfile "Service" "KillMode" "process" + iniset -sudo $unitfile "Service" "TimeoutStopSec" "300" + iniset -sudo $unitfile "Service" "ExecReload" "$KILL_PATH -HUP \$MAINPID" + if [[ -n "$group" ]]; then + iniset -sudo $unitfile "Service" "Group" "$group" + fi + iniset -sudo $unitfile "Install" "WantedBy" "multi-user.target" -# _run_process() is designed to be backgrounded by run_process() to simulate a -# fork. It includes the dirty work of closing extra filehandles and preparing log -# files to produce the same logs as screen_it(). The log filename is derived -# from the service name. -# Uses globals ``CURRENT_LOG_TIME``, ``LOGDIR``, ``SCREEN_LOGDIR``, ``SCREEN_NAME``, ``SERVICE_DIR`` -# If an optional group is provided sg will be used to set the group of -# the command. -# _run_process service "command-line" [group] -function _run_process { - # disable tracing through the exec redirects, it's just confusing in the logs. - xtrace=$(set +o | grep xtrace) - set +o xtrace + # changes to existing units sometimes need a refresh + $SYSTEMCTL daemon-reload +} +function write_uwsgi_user_unit_file { local service=$1 local command="$2" local group=$3 + local user=$4 + local unitfile="$SYSTEMD_DIR/$service" + mkdir -p $SYSTEMD_DIR + + iniset -sudo $unitfile "Unit" "Description" "Devstack $service" + iniset -sudo $unitfile "Service" "SyslogIdentifier" "$service" + iniset -sudo $unitfile "Service" "User" "$user" + iniset -sudo $unitfile "Service" "ExecStart" "$command" + iniset -sudo $unitfile "Service" "ExecReload" "$KILL_PATH -HUP \$MAINPID" + iniset -sudo $unitfile "Service" "Type" "notify" + iniset -sudo $unitfile "Service" "KillMode" "process" + iniset -sudo $unitfile "Service" "Restart" "always" + iniset -sudo $unitfile "Service" "NotifyAccess" "all" + iniset -sudo $unitfile "Service" "RestartForceExitStatus" "100" - # Undo logging redirections and close the extra descriptors - exec 1>&3 - exec 2>&3 - exec 3>&- - exec 6>&- + if [[ -n "$group" ]]; then + iniset -sudo $unitfile "Service" "Group" "$group" + fi + iniset -sudo $unitfile "Install" "WantedBy" "multi-user.target" - local real_logfile="${LOGDIR}/${service}.log.${CURRENT_LOG_TIME}" - if [[ -n ${LOGDIR} ]]; then - exec 1>&"$real_logfile" 2>&1 - ln -sf "$real_logfile" ${LOGDIR}/${service}.log - if [[ -n ${SCREEN_LOGDIR} ]]; then - # Drop the backward-compat symlink - ln -sf "$real_logfile" ${SCREEN_LOGDIR}/screen-${service}.log - fi + # changes to existing units sometimes need a refresh + $SYSTEMCTL daemon-reload +} - # TODO(dtroyer): Hack to get stdout from the Python interpreter for the logs. - export PYTHONUNBUFFERED=1 +function _common_systemd_pitfalls { + local cmd=$1 + # do some sanity checks on $cmd to see things we don't expect to work + + if [[ "$cmd" =~ "sudo" ]]; then + read -r -d '' msg << EOF || true # read returns 1 for EOF, but it is ok here +You are trying to use run_process with sudo, this is not going to work under systemd. + +If you need to run a service as a user other than \$STACK_USER call it with: + + run_process \$name \$cmd \$group \$user +EOF + die $LINENO "$msg" fi - # reenable xtrace before we do *real* work - $xtrace + if [[ ! "$cmd" =~ ^/ ]]; then + read -r -d '' msg << EOF || true # read returns 1 for EOF, but it is ok here +The cmd="$cmd" does not start with an absolute path. It will fail to +start under systemd. - # Run under ``setsid`` to force the process to become a session and group leader. - # The pid saved can be used with pkill -g to get the entire process group. - if [[ -n "$group" ]]; then - setsid sg $group "$command" & echo $! >$SERVICE_DIR/$SCREEN_NAME/$service.pid - else - setsid $command & echo $! >$SERVICE_DIR/$SCREEN_NAME/$service.pid +Please update your run_process stanza to have an absolute path. +EOF + die $LINENO "$msg" fi - # Just silently exit this process - exit 0 } -# Helper to remove the ``*.failure`` files under ``$SERVICE_DIR/$SCREEN_NAME``. -# This is used for ``service_check`` when all the ``screen_it`` are called finished -# Uses globals ``SCREEN_NAME``, ``SERVICE_DIR`` -# init_service_check -function init_service_check { - SCREEN_NAME=${SCREEN_NAME:-stack} - SERVICE_DIR=${SERVICE_DIR:-${DEST}/status} +# Helper function to build a basic unit file and run it under systemd. +function _run_under_systemd { + local service=$1 + local command="$2" + local cmd=$command + # sanity check the command + _common_systemd_pitfalls "$cmd" - if [[ ! -d "$SERVICE_DIR/$SCREEN_NAME" ]]; then - mkdir -p "$SERVICE_DIR/$SCREEN_NAME" + local systemd_service="devstack@$service.service" + local group=$3 + local user=${4:-$STACK_USER} + if [[ "$command" =~ "uwsgi" ]] ; then + write_uwsgi_user_unit_file $systemd_service "$cmd" "$group" "$user" + else + write_user_unit_file $systemd_service "$cmd" "$group" "$user" fi - rm -f "$SERVICE_DIR/$SCREEN_NAME"/*.failure + $SYSTEMCTL enable $systemd_service + $SYSTEMCTL start $systemd_service } # Find out if a process exists by partial name. @@ -1210,271 +1498,63 @@ function is_running { # If the command includes shell metachatacters (;<>*) it must be run using a shell # If an optional group is provided sg will be used to run the # command as that group. -# run_process service "command-line" [group] +# run_process service "command-line" [group] [user] function run_process { local service=$1 local command="$2" local group=$3 + local user=$4 - if is_service_enabled $service; then - if [[ "$USE_SCREEN" = "True" ]]; then - screen_process "$service" "$command" "$group" - else - # Spawn directly without screen - _run_process "$service" "$command" "$group" & - fi - fi -} - -# Helper to launch a process in a named screen -# Uses globals ``CURRENT_LOG_TIME``, ```LOGDIR``, ``SCREEN_LOGDIR``, `SCREEN_NAME``, -# ``SERVICE_DIR``, ``USE_SCREEN`` -# screen_process name "command-line" [group] -# Run a command in a shell in a screen window, if an optional group -# is provided, use sg to set the group of the command. -function screen_process { - local name=$1 - local command="$2" - local group=$3 - - SCREEN_NAME=${SCREEN_NAME:-stack} - SERVICE_DIR=${SERVICE_DIR:-${DEST}/status} - USE_SCREEN=$(trueorfalse True USE_SCREEN) - - screen -S $SCREEN_NAME -X screen -t $name - - local real_logfile="${LOGDIR}/${name}.log.${CURRENT_LOG_TIME}" - echo "LOGDIR: $LOGDIR" - echo "SCREEN_LOGDIR: $SCREEN_LOGDIR" - echo "log: $real_logfile" - if [[ -n ${LOGDIR} ]]; then - screen -S $SCREEN_NAME -p $name -X logfile "$real_logfile" - screen -S $SCREEN_NAME -p $name -X log on - ln -sf "$real_logfile" ${LOGDIR}/${name}.log - if [[ -n ${SCREEN_LOGDIR} ]]; then - # Drop the backward-compat symlink - ln -sf "$real_logfile" ${SCREEN_LOGDIR}/screen-${1}.log - fi - fi - - # sleep to allow bash to be ready to be send the command - we are - # creating a new window in screen and then sends characters, so if - # bash isn't running by the time we send the command, nothing - # happens. This sleep was added originally to handle gate runs - # where we needed this to be at least 3 seconds to pass - # consistently on slow clouds. Now this is configurable so that we - # can determine a reasonable value for the local case which should - # be much smaller. - sleep ${SCREEN_SLEEP:-3} - - NL=`echo -ne '\015'` - # This fun command does the following: - # - the passed server command is backgrounded - # - the pid of the background process is saved in the usual place - # - the server process is brought back to the foreground - # - if the server process exits prematurely the fg command errors - # and a message is written to stdout and the process failure file - # - # The pid saved can be used in stop_process() as a process group - # id to kill off all child processes - if [[ -n "$group" ]]; then - command="sg $group '$command'" - fi - - # Append the process to the screen rc file - screen_rc "$name" "$command" - - screen -S $SCREEN_NAME -p $name -X stuff "$command & echo \$! >$SERVICE_DIR/$SCREEN_NAME/${name}.pid; fg || echo \"$name failed to start\" | tee \"$SERVICE_DIR/$SCREEN_NAME/${name}.failure\"$NL" -} - -# Screen rc file builder -# Uses globals ``SCREEN_NAME``, ``SCREENRC`` -# screen_rc service "command-line" -function screen_rc { - SCREEN_NAME=${SCREEN_NAME:-stack} - SCREENRC=$TOP_DIR/$SCREEN_NAME-screenrc - if [[ ! -e $SCREENRC ]]; then - # Name the screen session - echo "sessionname $SCREEN_NAME" > $SCREENRC - # Set a reasonable statusbar - echo "hardstatus alwayslastline '$SCREEN_HARDSTATUS'" >> $SCREENRC - # Some distributions override PROMPT_COMMAND for the screen terminal type - turn that off - echo "setenv PROMPT_COMMAND /bin/true" >> $SCREENRC - echo "screen -t shell bash" >> $SCREENRC - fi - # If this service doesn't already exist in the screenrc file - if ! grep $1 $SCREENRC 2>&1 > /dev/null; then - NL=`echo -ne '\015'` - echo "screen -t $1 bash" >> $SCREENRC - echo "stuff \"$2$NL\"" >> $SCREENRC - - if [[ -n ${LOGDIR} ]]; then - echo "logfile ${LOGDIR}/${1}.log.${CURRENT_LOG_TIME}" >>$SCREENRC - echo "log on" >>$SCREENRC - fi - fi -} - -# Stop a service in screen -# If a PID is available use it, kill the whole process group via TERM -# If screen is being used kill the screen window; this will catch processes -# that did not leave a PID behind -# Uses globals ``SCREEN_NAME``, ``SERVICE_DIR``, ``USE_SCREEN`` -# screen_stop_service service -function screen_stop_service { - local service=$1 - - SCREEN_NAME=${SCREEN_NAME:-stack} - SERVICE_DIR=${SERVICE_DIR:-${DEST}/status} - USE_SCREEN=$(trueorfalse True USE_SCREEN) + local name=$service + time_start "run_process" if is_service_enabled $service; then - # Clean up the screen window - screen -S $SCREEN_NAME -p $service -X kill + _run_under_systemd "$name" "$command" "$group" "$user" fi + time_stop "run_process" } # Stop a service process # If a PID is available use it, kill the whole process group via TERM # If screen is being used kill the screen window; this will catch processes # that did not leave a PID behind -# Uses globals ``SERVICE_DIR``, ``USE_SCREEN`` +# Uses globals ``SERVICE_DIR`` # stop_process service function stop_process { local service=$1 SERVICE_DIR=${SERVICE_DIR:-${DEST}/status} - USE_SCREEN=$(trueorfalse True USE_SCREEN) if is_service_enabled $service; then - # Kill via pid if we have one available - if [[ -r $SERVICE_DIR/$SCREEN_NAME/$service.pid ]]; then - pkill -g $(cat $SERVICE_DIR/$SCREEN_NAME/$service.pid) - rm $SERVICE_DIR/$SCREEN_NAME/$service.pid - fi - if [[ "$USE_SCREEN" = "True" ]]; then - # Clean up the screen window - screen_stop_service $service + # Only do this for units which appear enabled, this also + # catches units that don't really exist for cases like + # keystone without a failure. + if $SYSTEMCTL is-enabled devstack@$service.service; then + $SYSTEMCTL stop devstack@$service.service + $SYSTEMCTL disable devstack@$service.service fi fi } -# Helper to get the status of each running service -# Uses globals ``SCREEN_NAME``, ``SERVICE_DIR`` -# service_check +# use systemctl to check service status function service_check { local service - local failures - SCREEN_NAME=${SCREEN_NAME:-stack} - SERVICE_DIR=${SERVICE_DIR:-${DEST}/status} - - - if [[ ! -d "$SERVICE_DIR/$SCREEN_NAME" ]]; then - echo "No service status directory found" - return - fi - - # Check if there is any falure flag file under $SERVICE_DIR/$SCREEN_NAME - # make this -o errexit safe - failures=`ls "$SERVICE_DIR/$SCREEN_NAME"/*.failure 2>/dev/null || /bin/true` - - for service in $failures; do - service=`basename $service` - service=${service%.failure} - echo "Error: Service $service is not running" + for service in ${ENABLED_SERVICES//,/ }; do + # because some things got renamed like key => keystone + if $SYSTEMCTL is-enabled devstack@$service.service; then + # no-pager is needed because otherwise status dumps to a + # pager when in interactive mode, which will stop a manual + # devstack run. + $SYSTEMCTL status devstack@$service.service --no-pager + fi done - - if [ -n "$failures" ]; then - die $LINENO "More details about the above errors can be found with screen, with ./rejoin-stack.sh" - fi -} - -# Tail a log file in a screen if USE_SCREEN is true. -function tail_log { - local name=$1 - local logfile=$2 - - USE_SCREEN=$(trueorfalse True USE_SCREEN) - if [[ "$USE_SCREEN" = "True" ]]; then - screen_process "$name" "sudo tail -f $logfile" - fi -} - - -# Deprecated Functions -# -------------------- - -# _old_run_process() is designed to be backgrounded by old_run_process() to simulate a -# fork. It includes the dirty work of closing extra filehandles and preparing log -# files to produce the same logs as screen_it(). The log filename is derived -# from the service name and global-and-now-misnamed ``SCREEN_LOGDIR`` -# Uses globals ``CURRENT_LOG_TIME``, ``SCREEN_LOGDIR``, ``SCREEN_NAME``, ``SERVICE_DIR`` -# _old_run_process service "command-line" -function _old_run_process { - local service=$1 - local command="$2" - - # Undo logging redirections and close the extra descriptors - exec 1>&3 - exec 2>&3 - exec 3>&- - exec 6>&- - - if [[ -n ${SCREEN_LOGDIR} ]]; then - exec 1>&${SCREEN_LOGDIR}/screen-${1}.log.${CURRENT_LOG_TIME} 2>&1 - ln -sf ${SCREEN_LOGDIR}/screen-${1}.log.${CURRENT_LOG_TIME} ${SCREEN_LOGDIR}/screen-${1}.log - - # TODO(dtroyer): Hack to get stdout from the Python interpreter for the logs. - export PYTHONUNBUFFERED=1 - fi - - exec /bin/bash -c "$command" - die "$service exec failure: $command" -} - -# old_run_process() launches a child process that closes all file descriptors and -# then exec's the passed in command. This is meant to duplicate the semantics -# of screen_it() without screen. PIDs are written to -# ``$SERVICE_DIR/$SCREEN_NAME/$service.pid`` by the spawned child process. -# old_run_process service "command-line" -function old_run_process { - local service=$1 - local command="$2" - - # Spawn the child process - _old_run_process "$service" "$command" & - echo $! } -# Compatibility for existing start_XXXX() functions -# Uses global ``USE_SCREEN`` -# screen_it service "command-line" -function screen_it { - if is_service_enabled $1; then - # Append the service to the screen rc file - screen_rc "$1" "$2" - if [[ "$USE_SCREEN" = "True" ]]; then - screen_process "$1" "$2" - else - # Spawn directly without screen - old_run_process "$1" "$2" >$SERVICE_DIR/$SCREEN_NAME/$1.pid - fi - fi -} - -# Compatibility for existing stop_XXXX() functions -# Stop a service in screen -# If a PID is available use it, kill the whole process group via TERM -# If screen is being used kill the screen window; this will catch processes -# that did not leave a PID behind -# screen_stop service -function screen_stop { - # Clean up the screen window - stop_process $1 +function tail_log { + deprecated "With the removal of screen support, tail_log is deprecated and will be removed after Queens" } - # Plugin Functions # ================= @@ -1489,12 +1569,28 @@ function enable_plugin { local name=$1 local url=$2 local branch=${3:-master} + if is_plugin_enabled $name; then + die $LINENO "Plugin attempted to be enabled twice: ${name} ${url} ${branch}" + fi DEVSTACK_PLUGINS+=",$name" GITREPO[$name]=$url GITDIR[$name]=$DEST/$name GITBRANCH[$name]=$branch } +# is_plugin_enabled +# +# Check if the plugin was enabled, e.g. using enable_plugin +# +# ``name`` The name with which the plugin was enabled +function is_plugin_enabled { + local name=$1 + if [[ ",${DEVSTACK_PLUGINS}," =~ ",${name}," ]]; then + return 0 + fi + return 1 +} + # fetch_plugins # # clones all plugins @@ -1555,7 +1651,7 @@ function plugin_override_defaults { if [[ -f $dir/devstack/override-defaults ]]; then # be really verbose that an override is happening, as it # may not be obvious if things fail later. - echo "$plugin has overriden the following defaults" + echo "$plugin has overridden the following defaults" cat $dir/devstack/override-defaults source $dir/devstack/override-defaults fi @@ -1584,13 +1680,27 @@ function run_phase { local mode=$1 local phase=$2 if [[ -d $TOP_DIR/extras.d ]]; then - for i in $TOP_DIR/extras.d/*.sh; do - [[ -r $i ]] && source $i $mode $phase + local extra_plugin_file_name + for extra_plugin_file_name in $TOP_DIR/extras.d/*.sh; do + # NOTE(sdague): only process extras.d for the 3 explicitly + # white listed elements in tree. We want these to move out + # over time as well, but they are in tree, so we need to + # manage that. + local exceptions="80-tempest.sh" + local extra + extra=$(basename $extra_plugin_file_name) + if [[ ! ( $exceptions =~ "$extra" ) ]]; then + warn "use of extras.d is no longer supported" + warn "processing of project $extra is skipped" + else + [[ -r $extra_plugin_file_name ]] && source $extra_plugin_file_name $mode $phase + fi done fi # the source phase corresponds to settings loading in plugins if [[ "$mode" == "source" ]]; then load_plugin_settings + verify_disabled_services elif [[ "$mode" == "override_defaults" ]]; then plugin_override_defaults else @@ -1598,6 +1708,35 @@ function run_phase { fi } +# define_plugin +# +# This function is a no-op. It allows a plugin to define its name So +# that other plugins may reference it by name. It should generally be +# the last component of the canonical git repo name. E.g., +# openstack/devstack-foo should use "devstack-foo" as the name here. +# +# This function is currently a noop, but the value may still be used +# by external tools (as in plugin_requires) and may be used by +# devstack in the future. +# +# ``name`` is an arbitrary name - (aka: glusterfs, nova-docker, zaqar) +function define_plugin { + : +} + +# plugin_requires +# +# This function is a no-op. It is currently used by external tools +# (such as the devstack module for Ansible) to automatically generate +# local.conf files. It is not currently used by devstack itself to +# resolve dependencies. +# +# ``name`` is an arbitrary name - (aka: glusterfs, nova-docker, zaqar) +# ``other`` is the name of another plugin +function plugin_requires { + : +} + # Service Functions # ================= @@ -1605,11 +1744,17 @@ function run_phase { # remove extra commas from the input string (i.e. ``ENABLED_SERVICES``) # _cleanup_service_list service-list function _cleanup_service_list { + local xtrace + xtrace=$(set +o | grep xtrace) + set +o xtrace + echo "$1" | sed -e ' s/,,/,/g; s/^,//; s/,$// ' + + $xtrace } # disable_all_services() removes all current services @@ -1627,9 +1772,12 @@ function disable_all_services { # Uses global ``ENABLED_SERVICES`` # disable_negated_services function disable_negated_services { + local xtrace + xtrace=$(set +o | grep xtrace) + set +o xtrace + local to_remove="" local remaining="" - local enabled="" local service # build up list of services that should be removed; i.e. they @@ -1644,64 +1792,69 @@ function disable_negated_services { # go through the service list. if this service appears in the "to # be removed" list, drop it - for service in ${remaining//,/ }; do - local remove - local add=1 - for remove in ${to_remove//,/ }; do - if [[ ${remove} == ${service} ]]; then - add=0 - break - fi - done - if [[ $add == 1 ]]; then - enabled="${enabled},$service" - fi - done + ENABLED_SERVICES=$(remove_disabled_services "$remaining" "$to_remove") - ENABLED_SERVICES=$(_cleanup_service_list "$enabled") + $xtrace } -# disable_service() removes the services passed as argument to the -# ``ENABLED_SERVICES`` list, if they are present. +# disable_service() prepares the services passed as argument to be +# removed from the ``ENABLED_SERVICES`` list, if they are present. # # For example: # disable_service rabbit # -# This function does not know about the special cases -# for nova, glance, and neutron built into is_service_enabled(). -# Uses global ``ENABLED_SERVICES`` +# Uses global ``DISABLED_SERVICES`` # disable_service service [service ...] function disable_service { - local tmpsvcs=",${ENABLED_SERVICES}," + local xtrace + xtrace=$(set +o | grep xtrace) + set +o xtrace + + local disabled_svcs="${DISABLED_SERVICES}" + local enabled_svcs=",${ENABLED_SERVICES}," local service for service in $@; do + disabled_svcs+=",$service" if is_service_enabled $service; then - tmpsvcs=${tmpsvcs//,$service,/,} + enabled_svcs=${enabled_svcs//,$service,/,} fi done - ENABLED_SERVICES=$(_cleanup_service_list "$tmpsvcs") + DISABLED_SERVICES=$(_cleanup_service_list "$disabled_svcs") + ENABLED_SERVICES=$(_cleanup_service_list "$enabled_svcs") + + $xtrace } # enable_service() adds the services passed as argument to the # ``ENABLED_SERVICES`` list, if they are not already present. # # For example: -# enable_service qpid +# enable_service q-svc # # This function does not know about the special cases # for nova, glance, and neutron built into is_service_enabled(). # Uses global ``ENABLED_SERVICES`` # enable_service service [service ...] function enable_service { + local xtrace + xtrace=$(set +o | grep xtrace) + set +o xtrace + local tmpsvcs="${ENABLED_SERVICES}" local service for service in $@; do + if [[ ,${DISABLED_SERVICES}, =~ ,${service}, ]]; then + warn $LINENO "Attempt to enable_service ${service} when it has been disabled" + continue + fi if ! is_service_enabled $service; then tmpsvcs+=",$service" fi done ENABLED_SERVICES=$(_cleanup_service_list "$tmpsvcs") disable_negated_services + + $xtrace } # is_service_enabled() checks if the service(s) specified as arguments are @@ -1713,7 +1866,6 @@ function enable_service { # There are special cases for some 'catch-all' services:: # **nova** returns true if any service enabled start with **n-** # **cinder** returns true if any service enabled start with **c-** -# **ceilometer** returns true if any service enabled start with **ceilometer** # **glance** returns true if any service enabled start with **g-** # **neutron** returns true if any service enabled start with **q-** # **swift** returns true if any service enabled start with **s-** @@ -1728,8 +1880,10 @@ function enable_service { # Uses global ``ENABLED_SERVICES`` # is_service_enabled service [service ...] function is_service_enabled { - local xtrace=$(set +o | grep xtrace) + local xtrace + xtrace=$(set +o | grep xtrace) set +o xtrace + local enabled=1 local services=$@ local service @@ -1739,29 +1893,57 @@ function is_service_enabled { # Look for top-level 'enabled' function for this service if type is_${service}_enabled >/dev/null 2>&1; then # A function exists for this service, use it - is_${service}_enabled - enabled=$? + is_${service}_enabled && enabled=0 fi # TODO(dtroyer): Remove these legacy special-cases after the is_XXX_enabled() # are implemented - [[ ${service} == n-cell-* && ${ENABLED_SERVICES} =~ "n-cell" ]] && enabled=0 - [[ ${service} == n-cpu-* && ${ENABLED_SERVICES} =~ "n-cpu" ]] && enabled=0 - [[ ${service} == "nova" && ${ENABLED_SERVICES} =~ "n-" ]] && enabled=0 - [[ ${service} == "cinder" && ${ENABLED_SERVICES} =~ "c-" ]] && enabled=0 - [[ ${service} == "ceilometer" && ${ENABLED_SERVICES} =~ "ceilometer-" ]] && enabled=0 - [[ ${service} == "glance" && ${ENABLED_SERVICES} =~ "g-" ]] && enabled=0 - [[ ${service} == "ironic" && ${ENABLED_SERVICES} =~ "ir-" ]] && enabled=0 - [[ ${service} == "neutron" && ${ENABLED_SERVICES} =~ "q-" ]] && enabled=0 - [[ ${service} == "trove" && ${ENABLED_SERVICES} =~ "tr-" ]] && enabled=0 - [[ ${service} == "swift" && ${ENABLED_SERVICES} =~ "s-" ]] && enabled=0 - [[ ${service} == s-* && ${ENABLED_SERVICES} =~ "swift" ]] && enabled=0 + [[ ${service} == n-cell-* && ,${ENABLED_SERVICES} =~ ,"n-cell" ]] && enabled=0 + [[ ${service} == n-cpu-* && ,${ENABLED_SERVICES} =~ ,"n-cpu" ]] && enabled=0 + [[ ${service} == "nova" && ,${ENABLED_SERVICES} =~ ,"n-" ]] && enabled=0 + [[ ${service} == "glance" && ,${ENABLED_SERVICES} =~ ,"g-" ]] && enabled=0 + [[ ${service} == "neutron" && ,${ENABLED_SERVICES} =~ ,"q-" ]] && enabled=0 + [[ ${service} == "trove" && ,${ENABLED_SERVICES} =~ ,"tr-" ]] && enabled=0 + [[ ${service} == "swift" && ,${ENABLED_SERVICES} =~ ,"s-" ]] && enabled=0 + [[ ${service} == s-* && ,${ENABLED_SERVICES} =~ ,"swift" ]] && enabled=0 done + $xtrace return $enabled } +# remove specified list from the input string +# remove_disabled_services service-list remove-list +function remove_disabled_services { + local xtrace + xtrace=$(set +o | grep xtrace) + set +o xtrace + + local service_list=$1 + local remove_list=$2 + local service + local enabled="" + + for service in ${service_list//,/ }; do + local remove + local add=1 + for remove in ${remove_list//,/ }; do + if [[ ${remove} == ${service} ]]; then + add=0 + break + fi + done + if [[ $add == 1 ]]; then + enabled="${enabled},$service" + fi + done + + $xtrace + + _cleanup_service_list "$enabled" +} + # Toggle enable/disable_service for services that must run exclusive of each other # $1 The name of a variable containing a space-separated list of services # $2 The name of a variable in which to store the enabled service's name @@ -1779,6 +1961,18 @@ function use_exclusive_service { return 0 } +# Make sure that nothing has manipulated ENABLED_SERVICES in a way +# that conflicts with prior calls to disable_service. +# Uses global ``ENABLED_SERVICES`` +function verify_disabled_services { + local service + for service in ${ENABLED_SERVICES//,/ }; do + if [[ ,${DISABLED_SERVICES}, =~ ,${service}, ]]; then + die $LINENO "ENABLED_SERVICES directly modified to overcome 'disable_service ${service}'" + fi + done +} + # System Functions # ================ @@ -1786,7 +1980,8 @@ function use_exclusive_service { # Only run the command if the target file (the last arg) is not on an # NFS filesystem. function _safe_permission_operation { - local xtrace=$(set +o | grep xtrace) + local xtrace + xtrace=$(set +o | grep xtrace) set +o xtrace local args=( $@ ) local last @@ -1822,8 +2017,10 @@ function address_in_net { local ip=$1 local range=$2 local masklen=${range#*/} - local network=$(maskip ${range%/*} $(cidr2netmask $masklen)) - local subnet=$(maskip $ip $(cidr2netmask $masklen)) + local network + network=$(maskip ${range%/*} $(cidr2netmask $masklen)) + local subnet + subnet=$(maskip $ip $(cidr2netmask $masklen)) [[ $network == $subnet ]] } @@ -1833,16 +2030,7 @@ function add_user_to_group { local user=$1 local group=$2 - if [[ -z "$os_VENDOR" ]]; then - GetOSVersion - fi - - # SLE11 and openSUSE 12.2 don't have the usual usermod - if ! is_suse || [[ "$os_VENDOR" = "openSUSE" && "$os_RELEASE" != "12.2" ]]; then - sudo usermod -a -G "$group" "$user" - else - sudo usermod -A "$group" "$user" - fi + sudo usermod -a -G "$group" "$user" } # Convert CIDR notation to a IPv4 netmask @@ -1854,6 +2042,23 @@ function cidr2netmask { echo ${1-0}.${2-0}.${3-0}.${4-0} } +# Check if this is a valid ipv4 address string +function is_ipv4_address { + local address=$1 + local regex='([0-9]{1,3}\.){3}[0-9]{1,3}' + # TODO(clarkb) make this more robust + if [[ "$address" =~ $regex ]] ; then + return 0 + else + return 1 + fi +} + +# Remove "[]" around urlquoted IPv6 addresses +function ipv6_unquote { + echo $1 | tr -d [] +} + # Gracefully cp only if source file/dir exists # cp_it source destination function cp_it { @@ -1884,7 +2089,8 @@ function export_proxy_variables { # Returns true if the directory is on a filesystem mounted via NFS. function is_nfs_directory { - local mount_type=`stat -f -L -c %T $1` + local mount_type + mount_type=`stat -f -L -c %T $1` test "$mount_type" == "nfs" } @@ -1895,24 +2101,53 @@ function maskip { local ip=$1 local mask=$2 local l="${ip%.*}"; local r="${ip#*.}"; local n="${mask%.*}"; local m="${mask#*.}" - local subnet=$((${ip%%.*}&${mask%%.*})).$((${r%%.*}&${m%%.*})).$((${l##*.}&${n##*.})).$((${ip##*.}&${mask##*.})) + local subnet + subnet=$((${ip%%.*}&${mask%%.*})).$((${r%%.*}&${m%%.*})).$((${l##*.}&${n##*.})).$((${ip##*.}&${mask##*.})) echo $subnet } +function is_provider_network { + if [ "$Q_USE_PROVIDER_NETWORKING" == "True" ]; then + return 0 + fi + return 1 +} + + +# Return just the . for the given python interpreter +function _get_python_version { + local interp=$1 + local version + # disable erroring out here, otherwise if python 3 doesn't exist we fail hard. + if [[ -x $(which $interp 2> /dev/null) ]]; then + version=$($interp -c 'import sys; print("%s.%s" % sys.version_info[0:2])') + fi + echo ${version} +} + # Return the current python as "python." function python_version { - local python_version=$(python -c 'import sys; print("%s.%s" % sys.version_info[0:2])') + local python_version + python_version=$(_get_python_version python2) echo "python${python_version}" } +function python3_version { + local python3_version + python3_version=$(_get_python_version python3) + echo "python${python3_version}" +} + + # Service wrapper to restart services # restart_service service-name function restart_service { - if is_ubuntu; then - sudo /usr/sbin/service $1 restart + if [ -x /bin/systemctl ]; then + sudo /bin/systemctl restart $1 else - sudo /sbin/service $1 restart + sudo service $1 restart fi + } # Only change permissions of a file or directory if it is not on an @@ -1930,26 +2165,204 @@ function safe_chown { # Service wrapper to start services # start_service service-name function start_service { - if is_ubuntu; then - sudo /usr/sbin/service $1 start + if [ -x /bin/systemctl ]; then + sudo /bin/systemctl start $1 else - sudo /sbin/service $1 start + sudo service $1 start fi } # Service wrapper to stop services # stop_service service-name function stop_service { - if is_ubuntu; then - sudo /usr/sbin/service $1 stop + if [ -x /bin/systemctl ]; then + sudo /bin/systemctl stop $1 else - sudo /sbin/service $1 stop + sudo service $1 stop fi } +# Service wrapper to reload services +# If the service was not in running state it will start it +# reload_service service-name +function reload_service { + if [ -x /bin/systemctl ]; then + sudo /bin/systemctl reload-or-restart $1 + else + sudo service $1 reload + fi +} + +# Test with a finite retry loop. +# +function test_with_retry { + local testcmd=$1 + local failmsg=$2 + local until=${3:-10} + local sleep=${4:-0.5} + + time_start "test_with_retry" + if ! timeout $until sh -c "while ! $testcmd; do sleep $sleep; done"; then + die $LINENO "$failmsg" + fi + time_stop "test_with_retry" +} + +# Like sudo but forwarding http_proxy https_proxy no_proxy environment vars. +# If it is run as superuser then sudo is replaced by env. +# +function sudo_with_proxies { + local sudo + + [[ "$(id -u)" = "0" ]] && sudo="env" || sudo="sudo" + + $sudo http_proxy="${http_proxy:-}" https_proxy="${https_proxy:-}"\ + no_proxy="${no_proxy:-}" "$@" +} + +# Timing infrastructure - figure out where large blocks of time are +# used in DevStack +# +# The timing infrastructure for DevStack is about collecting buckets +# of time that are spend in some subtask. For instance, that might be +# 'apt', 'pip', 'osc', even database migrations. We do this by a pair +# of functions: time_start / time_stop. +# +# These take a single parameter: $name - which specifies the name of +# the bucket to be accounted against. time_totals function spits out +# the results. +# +# Resolution is only in whole seconds, so should be used for long +# running activities. + +declare -A -g _TIME_TOTAL +declare -A -g _TIME_START +declare -r -g _TIME_BEGIN=$(date +%s) + +# time_start $name +# +# starts the clock for a timer by name. Errors if that clock is +# already started. +function time_start { + local name=$1 + local start_time=${_TIME_START[$name]} + if [[ -n "$start_time" ]]; then + die $LINENO "Trying to start the clock on $name, but it's already been started" + fi + _TIME_START[$name]=$(date +%s%3N) +} + +# time_stop $name +# +# stops the clock for a timer by name, and accumulate that time in the +# global counter for that name. Errors if that clock had not +# previously been started. +function time_stop { + local name + local end_time + local elapsed_time + local total + local start_time + + name=$1 + start_time=${_TIME_START[$name]} + + if [[ -z "$start_time" ]]; then + die $LINENO "Trying to stop the clock on $name, but it was never started" + fi + end_time=$(date +%s%3N) + elapsed_time=$(($end_time - $start_time)) + total=${_TIME_TOTAL[$name]:-0} + # reset the clock so we can start it in the future + _TIME_START[$name]="" + _TIME_TOTAL[$name]=$(($total + $elapsed_time)) +} + +function oscwrap { + local out + local rc + local start + local end + # Cannot use timer_start and timer_stop as we run in subshells + # and those rely on modifying vars in the same process (which cannot + # happen from a subshell. + start=$(date +%s%3N) + out=$(command openstack "$@") + rc=$? + end=$(date +%s%3N) + echo $((end - start)) >> $OSCWRAP_TIMER_FILE + + echo "$out" + return $rc +} + +function install_oscwrap { + # File to accumulate our timing data + OSCWRAP_TIMER_FILE=$(mktemp) + # Bash by default doesn't expand aliases, allow it for the aliases + # we want to whitelist. + shopt -s expand_aliases + # Remove all aliases that might be expanded to preserve old unexpanded + # behavior + unalias -a + # Add only the alias we want for openstack + alias openstack=oscwrap +} + +function cleanup_oscwrap { + local total=0 + total=$(cat $OSCWRAP_TIMER_FILE | $PYTHON -c "import sys; print(sum(int(l) for l in sys.stdin))") + _TIME_TOTAL["osc"]=$total + rm $OSCWRAP_TIMER_FILE +} + +# time_totals +# Print out total time summary +function time_totals { + local elapsed_time + local end_time + local len=20 + local xtrace + local unaccounted_time + + end_time=$(date +%s) + elapsed_time=$(($end_time - $_TIME_BEGIN)) + unaccounted_time=$elapsed_time + + # pad 1st column this far + for t in ${!_TIME_TOTAL[*]}; do + if [[ ${#t} -gt $len ]]; then + len=${#t} + fi + done + + cleanup_oscwrap + + xtrace=$(set +o | grep xtrace) + set +o xtrace + + echo + echo "=========================" + echo "DevStack Component Timing" + echo " (times are in seconds) " + echo "=========================" + for t in ${!_TIME_TOTAL[*]}; do + local v=${_TIME_TOTAL[$t]} + # because we're recording in milliseconds + v=$(($v / 1000)) + printf "%-${len}s %3d\n" "$t" "$v" + unaccounted_time=$(($unaccounted_time - $v)) + done + echo "-------------------------" + printf "%-${len}s %3d\n" "Unaccounted time" "$unaccounted_time" + echo "=========================" + printf "%-${len}s %3d\n" "Total runtime" "$elapsed_time" + + $xtrace +} # Restore xtrace -$XTRACE +$_XTRACE_FUNCTIONS_COMMON # Local variables: # mode: shell-script diff --git a/inc/ini-config b/inc/ini-config index 26401f3917..6fe7788158 100644 --- a/inc/ini-config +++ b/inc/ini-config @@ -15,37 +15,51 @@ set +o xtrace # ================ # Append a new option in an ini file without replacing the old value -# iniadd config-file section option value1 value2 value3 ... +# iniadd [-sudo] config-file section option value1 value2 value3 ... function iniadd { - local xtrace=$(set +o | grep xtrace) + local xtrace + xtrace=$(set +o | grep xtrace) set +o xtrace + local sudo="" + if [ $1 == "-sudo" ]; then + sudo="-sudo " + shift + fi local file=$1 local section=$2 local option=$3 shift 3 - local values="$(iniget_multiline $file $section $option) $@" - iniset_multiline $file $section $option $values + local values + values="$(iniget_multiline $file $section $option) $@" + iniset_multiline $sudo $file $section $option $values $xtrace } # Comment an option in an INI file -# inicomment config-file section option +# inicomment [-sudo] config-file section option function inicomment { - local xtrace=$(set +o | grep xtrace) + local xtrace + xtrace=$(set +o | grep xtrace) set +o xtrace + local sudo="" + if [ $1 == "-sudo" ]; then + sudo="sudo " + shift + fi local file=$1 local section=$2 local option=$3 - sed -i -e "/^\[$section\]/,/^\[.*\]/ s|^\($option[ \t]*=.*$\)|#\1|" "$file" + $sudo sed -i -e "/^\[$section\]/,/^\[.*\]/ s|^\($option[ \t]*=.*$\)|#\1|" "$file" $xtrace } # Get an option from an INI file # iniget config-file section option function iniget { - local xtrace=$(set +o | grep xtrace) + local xtrace + xtrace=$(set +o | grep xtrace) set +o xtrace local file=$1 local section=$2 @@ -60,7 +74,8 @@ function iniget { # Get a multiple line option from an INI file # iniget_multiline config-file section option function iniget_multiline { - local xtrace=$(set +o | grep xtrace) + local xtrace + xtrace=$(set +o | grep xtrace) set +o xtrace local file=$1 local section=$2 @@ -75,7 +90,8 @@ function iniget_multiline { # Determinate is the given option present in the INI file # ini_has_option config-file section option function ini_has_option { - local xtrace=$(set +o | grep xtrace) + local xtrace + xtrace=$(set +o | grep xtrace) set +o xtrace local file=$1 local section=$2 @@ -95,19 +111,28 @@ function ini_has_option { # in the argument list. Doing that will cause incorrect configuration # if spaces are used in the config values. # -# iniadd_literal config-file section option value +# iniadd_literal [-sudo] config-file section option value function iniadd_literal { - local xtrace=$(set +o | grep xtrace) + local xtrace + xtrace=$(set +o | grep xtrace) set +o xtrace + local sudo="" + if [ $1 == "-sudo" ]; then + sudo="sudo " + shift + fi local file=$1 local section=$2 local option=$3 local value=$4 - [[ -z $section || -z $option ]] && return + if [[ -z $section || -z $option ]]; then + $xtrace + return + fi # Add it - sed -i -e "/^\[$section\]/ a\\ + $sudo sed -i -e "/^\[$section\]/ a\\ $option = $value " "$file" @@ -115,56 +140,82 @@ $option = $value } # Remove an option from an INI file -# inidelete config-file section option +# inidelete [-sudo] config-file section option function inidelete { - local xtrace=$(set +o | grep xtrace) + local xtrace + xtrace=$(set +o | grep xtrace) set +o xtrace + local sudo="" + if [ $1 == "-sudo" ]; then + sudo="sudo " + shift + fi local file=$1 local section=$2 local option=$3 - [[ -z $section || -z $option ]] && return + if [[ -z $section || -z $option ]]; then + $xtrace + return + fi # Remove old values - sed -i -e "/^\[$section\]/,/^\[.*\]/ { /^$option[ \t]*=/ d; }" "$file" + $sudo sed -i -e "/^\[$section\]/,/^\[.*\]/ { /^$option[ \t]*=/ d; }" "$file" $xtrace } # Set an option in an INI file -# iniset config-file section option value +# iniset [-sudo] config-file section option value +# - if the file does not exist, it is created function iniset { - local xtrace=$(set +o | grep xtrace) + local xtrace + xtrace=$(set +o | grep xtrace) set +o xtrace + local sudo="" + if [ $1 == "-sudo" ]; then + sudo="sudo " + shift + fi local file=$1 local section=$2 local option=$3 local value=$4 - [[ -z $section || -z $option ]] && return + if [[ -z $section || -z $option ]]; then + $xtrace + return + fi if ! grep -q "^\[$section\]" "$file" 2>/dev/null; then # Add section at the end - echo -e "\n[$section]" >>"$file" + echo -e "\n[$section]" | $sudo tee --append "$file" > /dev/null fi if ! ini_has_option "$file" "$section" "$option"; then # Add it - sed -i -e "/^\[$section\]/ a\\ + $sudo sed -i -e "/^\[$section\]/ a\\ $option = $value " "$file" else - local sep=$(echo -ne "\x01") + local sep + sep=$(echo -ne "\x01") # Replace it - sed -i -e '/^\['${section}'\]/,/^\[.*\]/ s'${sep}'^\('${option}'[ \t]*=[ \t]*\).*$'${sep}'\1'"${value}"${sep} "$file" + $sudo sed -i -e '/^\['${section}'\]/,/^\[.*\]/ s'${sep}'^\('"${option}"'[ \t]*=[ \t]*\).*$'${sep}'\1'"${value}"${sep} "$file" fi $xtrace } # Set a multiple line option in an INI file -# iniset_multiline config-file section option value1 value2 valu3 ... +# iniset_multiline [-sudo] config-file section option value1 value2 value3 ... function iniset_multiline { - local xtrace=$(set +o | grep xtrace) + local xtrace + xtrace=$(set +o | grep xtrace) set +o xtrace + local sudo="" + if [ $1 == "-sudo" ]; then + sudo="sudo " + shift + fi local file=$1 local section=$2 local option=$3 @@ -179,14 +230,14 @@ function iniset_multiline { done if ! grep -q "^\[$section\]" "$file"; then # Add section at the end - echo -e "\n[$section]" >>"$file" + echo -e "\n[$section]" | $sudo tee --append "$file" > /dev/null else # Remove old values - sed -i -e "/^\[$section\]/,/^\[.*\]/ { /^$option[ \t]*=/ d; }" "$file" + $sudo sed -i -e "/^\[$section\]/,/^\[.*\]/ { /^$option[ \t]*=/ d; }" "$file" fi # Add new ones for v in $values; do - sed -i -e "/^\[$section\]/ a\\ + $sudo sed -i -e "/^\[$section\]/ a\\ $option = $v " "$file" done @@ -196,12 +247,194 @@ $option = $v # Uncomment an option in an INI file # iniuncomment config-file section option function iniuncomment { - local xtrace=$(set +o | grep xtrace) + local xtrace + xtrace=$(set +o | grep xtrace) set +o xtrace + local sudo="" + if [ $1 == "-sudo" ]; then + sudo="sudo " + shift + fi local file=$1 local section=$2 local option=$3 - sed -i -e "/^\[$section\]/,/^\[.*\]/ s|[^ \t]*#[ \t]*\($option[ \t]*=.*$\)|\1|" "$file" + $sudo sed -i -e "/^\[$section\]/,/^\[.*\]/ s|[^ \t]*#[ \t]*\($option[ \t]*=.*$\)|\1|" "$file" + $xtrace +} + +# Get list of sections from an INI file +# iniget_sections config-file +function iniget_sections { + local xtrace + xtrace=$(set +o | grep xtrace) + set +o xtrace + local file=$1 + + echo $(sed -ne "s/^\[\(.*\)\]/\1/p" "$file") + $xtrace +} + +# Set a localrc var +function localrc_set { + local file=$1 + local group="local" + local conf="localrc" + local section="" + local option=$2 + local value=$3 + localconf_set "$file" "$group" "$conf" "$section" "$option" "$value" +} + +# Check if local.conf has section. +function localconf_has_section { + local file=$1 + local group=$2 + local conf=$3 + local section=$4 + local sep + sep=$(echo -ne "\x01") + local line + line=$(sed -ne "\\${sep}^\[\[${group}|${conf}\]\]${sep},\\${sep}\[\[.*\]\]${sep}{ + /\[${section}\]/p + }" "$file") + [ -n "$line" ] +} + +# Check if local.conf has option. +function localconf_has_option { + local file=$1 + local group=$2 + local conf=$3 + local section=$4 + local option=$5 + local sep + sep=$(echo -ne "\x01") + local line + if [[ -z "$section" ]]; then + line=$(sed -ne "\\${sep}^\[\[${group}|${conf}\]\]${sep},\\${sep}\[\[.*\]\]${sep}{ + /${option}[ \t]*=.*$/p + }" "$file") + else + line=$(sed -ne "\\${sep}^\[\[${group}|${conf}\]\]${sep},\\${sep}\[\[.*\]\]${sep}{ + /\[${section}\]/,/\[\[.*\]\]\|\[.*\]/{ + /${option}[ \t]*=.*$/p} + }" "$file") + fi + [ -n "$line" ] +} + +# Update option in local.conf. +function localconf_update_option { + local sudo=$1 + local file=$2 + local group=$3 + local conf=$4 + local section=$5 + local option=$6 + local value=$7 + local sep + sep=$(echo -ne "\x01") + if [[ -z "$section" ]]; then + $sudo sed -i -e "\\${sep}^\[\[${group}|${conf}\]\]${sep},\\${sep}\[\[.*\]\]${sep}{ + s${sep}^\(${option}[ \t]*=[ \t]*\).*\$${sep}\1${value}${sep} + }" "$file" + else + $sudo sed -i -e "\\${sep}^\[\[${group}|${conf}\]\]${sep},\\${sep}\[\[.*\]\]${sep}{ + /\[${section}\]/,/\[\[.*\]\]\|\[.*\]/s${sep}^\(${option}[ \t]*=[ \t]*\).*\$${sep}\1${value}${sep} + }" "$file" + fi +} + +# Add option in local.conf. +function localconf_add_option { + local sudo=$1 + local file=$2 + local group=$3 + local conf=$4 + local section=$5 + local option=$6 + local value=$7 + local sep + sep=$(echo -ne "\x01") + if [[ -z "$section" ]]; then + $sudo sed -i -e "\\${sep}^\[\[${group}|${conf}\]\]${sep} a $option=$value" "$file" + else + $sudo sed -i -e "\\${sep}^\[\[${group}|${conf}\]\]${sep},\\${sep}\[\[.*\]\]${sep}{ + /\[${section}\]/ a $option=$value + }" "$file" + fi +} + +# Add section and option in local.conf. +function localconf_add_section_and_option { + local sudo=$1 + local file=$2 + local group=$3 + local conf=$4 + local section=$5 + local option=$6 + local value=$7 + local sep + sep=$(echo -ne "\x01") + $sudo sed -i -e "\\${sep}^\[\[${group}|${conf}\]\]${sep} { + a [$section] + a $option=$value + }" "$file" +} + +# Set an option in a local.conf file. +# localconf_set [-sudo] config-file group conf-name section option value +# - if the file does not exist, it is created +function localconf_set { + local xtrace + xtrace=$(set +o | grep xtrace) + set +o xtrace + local sep + sep=$(echo -ne "\x01") + local sudo="" + if [ $1 == "-sudo" ]; then + sudo="sudo " + shift + fi + local file=$1 + local group=$2 + local conf=$3 + local section=$4 + local option=$5 + local value=$6 + + if [[ -z $group || -z $conf || -z $option || -z $value ]]; then + $xtrace + return + fi + + if ! grep -q "^\[\[${group}|${conf}\]\]" "$file" 2>/dev/null; then + # Add meta section at the end if it does not exist + echo -e "\n[[${group}|${conf}]]" | $sudo tee --append "$file" > /dev/null + # Add section at the end + if [[ -n "$section" ]]; then + echo -e "[$section]" | $sudo tee --append "$file" > /dev/null + fi + # Add option at the end + echo -e "$option=$value" | $sudo tee --append "$file" > /dev/null + elif [[ -z "$section" ]]; then + if ! localconf_has_option "$file" "$group" "$conf" "$section" "$option"; then + # Add option + localconf_add_option "$sudo" "$file" "$group" "$conf" "$section" "$option" "$value" + else + # Replace it + localconf_update_option "$sudo" "$file" "$group" "$conf" "$section" "$option" "$value" + fi + elif ! localconf_has_section "$file" "$group" "$conf" "$section"; then + # Add section and option in specified meta section + localconf_add_section_and_option "$sudo" "$file" "$group" "$conf" "$section" "$option" "$value" + elif ! localconf_has_option "$file" "$group" "$conf" "$section" "$option"; then + # Add option + localconf_add_option "$sudo" "$file" "$group" "$conf" "$section" "$option" "$value" + else + # Replace it + localconf_update_option "$sudo" "$file" "$group" "$conf" "$section" "$option" "$value" + fi $xtrace } diff --git a/inc/meta-config b/inc/meta-config index e5f902d1dd..be73b60800 100644 --- a/inc/meta-config +++ b/inc/meta-config @@ -20,7 +20,7 @@ # file-name is the destination of the config file # Save trace setting -INC_META_XTRACE=$(set +o | grep xtrace) +_XTRACE_INC_META=$(set +o | grep xtrace) set +o xtrace @@ -40,12 +40,10 @@ function get_meta_section { $CONFIG_AWK_CMD -v matchgroup=$matchgroup -v configfile=$configfile ' BEGIN { group = "" } /^\[\[.+\|.*\]\]/ { - if (group == "") { - gsub("[][]", "", $1); - split($1, a, "|"); - if (a[1] == matchgroup && a[2] == configfile) { - group=a[1] - } + gsub("[][]", "", $1); + split($1, a, "|"); + if (a[1] == matchgroup && a[2] == configfile) { + group=a[1] } else { group="" } @@ -89,9 +87,10 @@ function merge_config_file { # note, configfile might be a variable (note the iniset, etc # created in the mega-awk below is "eval"ed too, so we just leave # it alone. - local real_configfile=$(eval echo $configfile) + local real_configfile + real_configfile=$(eval echo $configfile) if [ ! -f $real_configfile ]; then - touch $real_configfile + touch $real_configfile || die $LINENO "could not create config file $real_configfile ($configfile)" fi get_meta_section $file $matchgroup $configfile | \ @@ -177,16 +176,46 @@ function merge_config_group { local configfile group for group in $matchgroups; do for configfile in $(get_meta_section_files $localfile $group); do - if [[ -d $(dirname $(eval "echo $configfile")) ]]; then + local realconfigfile + local dir + + realconfigfile=$(eval "echo $configfile") + if [[ -z $realconfigfile ]]; then + warn $LINENO "unknown config file specification: $configfile is undefined" + break + fi + dir=$(dirname $realconfigfile) + if [[ -d $dir ]]; then merge_config_file $localfile $group $configfile + else + die $LINENO "bogus config file specification $configfile ($configfile=$realconfigfile, $dir is not a directory)" fi done done } +function extract_localrc_section { + local configfile=$1 # top_dir/local.conf + local localrcfile=$2 # top_dir/localrc + local localautofile=$3 # top_dir/.localrc.auto + + if [[ -r $configfile ]]; then + LRC=$(get_meta_section_files $configfile local) + for lfile in $LRC; do + if [[ "$lfile" == "localrc" ]]; then + if [[ -r $localrcfile ]]; then + echo "localrc and local.conf:[[local]] both exist, using localrc" + else + echo "# Generated file, do not edit" >$localautofile + get_meta_section $configfile local $lfile >>$localautofile + fi + fi + done + fi +} # Restore xtrace -$INC_META_XTRACE +$_XTRACE_INC_META # Local variables: # mode: shell-script diff --git a/inc/python b/inc/python index 3d329b59a9..5fb7245623 100644 --- a/inc/python +++ b/inc/python @@ -17,9 +17,9 @@ set +o xtrace # Global Config Variables -# PROJECT_VENV contains the name of the virtual enviromnet for each +# PROJECT_VENV contains the name of the virtual environment for each # project. A null value installs to the system Python directories. -declare -A PROJECT_VENV +declare -A -g PROJECT_VENV # Python Functions @@ -28,24 +28,32 @@ declare -A PROJECT_VENV # Get the path to the pip command. # get_pip_command function get_pip_command { - which pip || which pip-python + local version="$1" + # NOTE(dhellmann): I don't know if we actually get a pip3.4-python + # under any circumstances. + which pip${version} || which pip${version}-python if [ $? -ne 0 ]; then - die $LINENO "Unable to find pip; cannot continue" + die $LINENO "Unable to find pip${version}; cannot continue" fi } -# Get the path to the direcotry where python executables are installed. +# Get the path to the directory where python executables are installed. # get_python_exec_prefix function get_python_exec_prefix { - local xtrace=$(set +o | grep xtrace) + local xtrace + xtrace=$(set +o | grep xtrace) set +o xtrace if [[ -z "$os_PACKAGE" ]]; then GetOSVersion fi $xtrace - if is_fedora || is_suse; then + if python3_enabled && [[ "$os_VENDOR" == "Fedora" && $os_RELEASE -gt 26 ]]; then + # Default Python 3 install prefix changed to /usr/local in Fedora 27: + # https://fedoraproject.org/wiki/Changes/Making_sudo_pip_safe + echo "/usr/local/bin" + elif is_fedora || is_suse; then echo "/usr/bin" else echo "/usr/local/bin" @@ -60,16 +68,166 @@ function get_python_exec_prefix { # pip_install_gr packagename function pip_install_gr { local name=$1 - local clean_name=$(get_from_global_requirements $name) + local clean_name + clean_name=$(get_from_global_requirements $name) pip_install $clean_name } +# Wrapper for ``pip install`` that only installs versions of libraries +# from the global-requirements specification with extras. +# +# Uses globals ``REQUIREMENTS_DIR`` +# +# pip_install_gr_extras packagename extra1,extra2,... +function pip_install_gr_extras { + local name=$1 + local extras=$2 + local clean_name + clean_name=$(get_from_global_requirements $name) + pip_install $clean_name[$extras] +} + +# Determine the python versions supported by a package +function get_python_versions_for_package { + local name=$1 + cd $name && python setup.py --classifiers \ + | grep 'Language' | cut -f5 -d: | grep '\.' | tr '\n' ' ' +} + +# Check for python3 classifier in local directory +function check_python3_support_for_package_local { + local name=$1 + cd $name + set +e + classifier=$(python setup.py --classifiers \ + | grep 'Programming Language :: Python :: 3$') + set -e + echo $classifier +} + +# Check for python3 classifier on pypi +function check_python3_support_for_package_remote { + local name=$1 + set +e + classifier=$(curl -s -L "https://pypi.python.org/pypi/$name/json" \ + | grep '"Programming Language :: Python :: 3"') + set -e + echo $classifier +} + +# python3_enabled_for() checks if the service(s) specified as arguments are +# enabled by the user in ``ENABLED_PYTHON3_PACKAGES``. +# +# Multiple services specified as arguments are ``OR``'ed together; the test +# is a short-circuit boolean, i.e it returns on the first match. +# +# Uses global ``ENABLED_PYTHON3_PACKAGES`` +# python3_enabled_for dir [dir ...] +function python3_enabled_for { + local xtrace + xtrace=$(set +o | grep xtrace) + set +o xtrace + + local enabled=1 + local dirs=$@ + local dir + for dir in ${dirs}; do + [[ ,${ENABLED_PYTHON3_PACKAGES}, =~ ,${dir}, ]] && enabled=0 + done + + $xtrace + return $enabled +} + +# python3_disabled_for() checks if the service(s) specified as arguments are +# disabled by the user in ``DISABLED_PYTHON3_PACKAGES``. +# +# Multiple services specified as arguments are ``OR``'ed together; the test +# is a short-circuit boolean, i.e it returns on the first match. +# +# Uses global ``DISABLED_PYTHON3_PACKAGES`` +# python3_disabled_for dir [dir ...] +function python3_disabled_for { + local xtrace + xtrace=$(set +o | grep xtrace) + set +o xtrace + + local enabled=1 + local dirs=$@ + local dir + for dir in ${dirs}; do + [[ ,${DISABLED_PYTHON3_PACKAGES}, =~ ,${dir}, ]] && enabled=0 + done + + $xtrace + return $enabled +} + +# enable_python3_package() adds the repositories passed as argument to the +# ``ENABLED_PYTHON3_PACKAGES`` list, if they are not already present. +# +# For example: +# enable_python3_package nova +# +# Uses global ``ENABLED_PYTHON3_PACKAGES`` +# enable_python3_package dir [dir ...] +function enable_python3_package { + local xtrace + xtrace=$(set +o | grep xtrace) + set +o xtrace + + local tmpsvcs="${ENABLED_PYTHON3_PACKAGES}" + local python3 + for dir in $@; do + if [[ ,${DISABLED_PYTHON3_PACKAGES}, =~ ,${dir}, ]]; then + warn $LINENO "Attempt to enable_python3_package ${dir} when it has been disabled" + continue + fi + if ! python3_enabled_for $dir; then + tmpsvcs+=",$dir" + fi + done + ENABLED_PYTHON3_PACKAGES=$(_cleanup_service_list "$tmpsvcs") + + $xtrace +} + +# disable_python3_package() prepares the services passed as argument to be +# removed from the ``ENABLED_PYTHON3_PACKAGES`` list, if they are present. +# +# For example: +# disable_python3_package swift +# +# Uses globals ``ENABLED_PYTHON3_PACKAGES`` and ``DISABLED_PYTHON3_PACKAGES`` +# disable_python3_package dir [dir ...] +function disable_python3_package { + local xtrace + xtrace=$(set +o | grep xtrace) + set +o xtrace + + local disabled_svcs="${DISABLED_PYTHON3_PACKAGES}" + local enabled_svcs=",${ENABLED_PYTHON3_PACKAGES}," + local dir + for dir in $@; do + disabled_svcs+=",$dir" + if python3_enabled_for $dir; then + enabled_svcs=${enabled_svcs//,$dir,/,} + fi + done + DISABLED_PYTHON3_PACKAGES=$(_cleanup_service_list "$disabled_svcs") + ENABLED_PYTHON3_PACKAGES=$(_cleanup_service_list "$enabled_svcs") + + $xtrace +} + # Wrapper for ``pip install`` to set cache and proxy environment variables # Uses globals ``OFFLINE``, ``PIP_VIRTUAL_ENV``, -# ``PIP_UPGRADE``, ``TRACK_DEPENDS``, ``*_proxy`` -# pip_install package [package ...] +# ``PIP_UPGRADE``, ``TRACK_DEPENDS``, ``*_proxy``, +# Usage: +# pip_install pip_arguments function pip_install { - local xtrace=$(set +o | grep xtrace) + local xtrace result + xtrace=$(set +o | grep xtrace) set +o xtrace local upgrade="" local offline=${OFFLINE:-False} @@ -78,6 +236,8 @@ function pip_install { return fi + time_start "pip_install" + PIP_UPGRADE=$(trueorfalse False PIP_UPGRADE) if [[ "$PIP_UPGRADE" = "True" ]] ; then upgrade="--upgrade" @@ -86,9 +246,29 @@ function pip_install { if [[ -z "$os_PACKAGE" ]]; then GetOSVersion fi + + # Try to extract the path of the package we are installing into + # package_dir. We need this to check for test-requirements.txt, + # at least. + # + # ${!#} expands to the last positional argument to this function. + # With "extras" syntax included, our arguments might be something + # like: + # -e /path/to/fooproject[extra] + # Thus this magic line grabs just the path without extras + # + # Note that this makes no sense if this is a pypi (rather than + # local path) install; ergo you must check this path exists before + # use. Also, if we had multiple or mixed installs, we would also + # likely break. But for historical reasons, it's basically only + # the other wrapper functions in here calling this to install + # local packages, and they do so with single call per install. So + # this works (for now...) + local package_dir=${!#%\[*\]} + if [[ $TRACK_DEPENDS = True && ! "$@" =~ virtualenv ]]; then # TRACK_DEPENDS=True installation creates a circular dependency when - # we attempt to install virtualenv into a virualenv, so we must global + # we attempt to install virtualenv into a virtualenv, so we must global # that installation. source $DEST/.venv/bin/activate local cmd_pip=$DEST/.venv/bin/pip @@ -98,46 +278,120 @@ function pip_install { local cmd_pip=$PIP_VIRTUAL_ENV/bin/pip local sudo_pip="env" else - local cmd_pip=$(get_pip_command) + local cmd_pip + cmd_pip=$(get_pip_command $PYTHON2_VERSION) local sudo_pip="sudo -H" + if python3_enabled; then + # Look at the package classifiers to find the python + # versions supported, and if we find the version of + # python3 we've been told to use, use that instead of the + # default pip + local python_versions + + # Special case some services that have experimental + # support for python3 in progress, but don't claim support + # in their classifier + echo "Check python version for : $package_dir" + if python3_disabled_for ${package_dir##*/}; then + echo "Explicitly using $PYTHON2_VERSION version to install $package_dir based on DISABLED_PYTHON3_PACKAGES" + elif python3_enabled_for ${package_dir##*/}; then + echo "Explicitly using $PYTHON3_VERSION version to install $package_dir based on ENABLED_PYTHON3_PACKAGES" + sudo_pip="$sudo_pip LC_ALL=en_US.UTF-8" + cmd_pip=$(get_pip_command $PYTHON3_VERSION) + elif [[ -d "$package_dir" ]]; then + python_versions=$(get_python_versions_for_package $package_dir) + if [[ $python_versions =~ $PYTHON3_VERSION ]]; then + echo "Automatically using $PYTHON3_VERSION version to install $package_dir based on classifiers" + sudo_pip="$sudo_pip LC_ALL=en_US.UTF-8" + cmd_pip=$(get_pip_command $PYTHON3_VERSION) + else + # The package may not have yet advertised python3.5 + # support so check for just python3 classifier and log + # a warning. + python3_classifier=$(check_python3_support_for_package_local $package_dir) + if [[ ! -z "$python3_classifier" ]]; then + echo "Automatically using $PYTHON3_VERSION version to install $package_dir based on local package settings" + sudo_pip="$sudo_pip LC_ALL=en_US.UTF-8" + cmd_pip=$(get_pip_command $PYTHON3_VERSION) + fi + fi + else + # Check pypi as we don't have the package on disk + package=$(echo $package_dir | grep -o '^[.a-zA-Z0-9_-]*') + python3_classifier=$(check_python3_support_for_package_remote $package) + if [[ ! -z "$python3_classifier" ]]; then + echo "Automatically using $PYTHON3_VERSION version to install $package based on remote package settings" + sudo_pip="$sudo_pip LC_ALL=en_US.UTF-8" + cmd_pip=$(get_pip_command $PYTHON3_VERSION) + fi + fi + fi fi fi - local pip_version=$(python -c "import pip; \ - print(pip.__version__.strip('.')[0])") + cmd_pip="$cmd_pip install" + # Always apply constraints + cmd_pip="$cmd_pip -c $REQUIREMENTS_DIR/upper-constraints.txt" + + # FIXME(dhellmann): Need to force multiple versions of pip for + # packages like setuptools? + local pip_version + pip_version=$(python -c "import pip; \ + print(pip.__version__.split('.')[0])") if (( pip_version<6 )); then die $LINENO "Currently installed pip version ${pip_version} does not" \ "meet minimum requirements (>=6)." fi $xtrace + + # Also install test requirements + local install_test_reqs="" + local test_req="${package_dir}/test-requirements.txt" + if [[ -e "$test_req" ]]; then + install_test_reqs="-r $test_req" + fi + + # adding SETUPTOOLS_SYS_PATH_TECHNIQUE is a workaround to keep + # the same behaviour of setuptools before version 25.0.0. + # related issue: https://github.com/pypa/pip/issues/3874 $sudo_pip \ http_proxy="${http_proxy:-}" \ https_proxy="${https_proxy:-}" \ no_proxy="${no_proxy:-}" \ PIP_FIND_LINKS=$PIP_FIND_LINKS \ - $cmd_pip install $upgrade \ + SETUPTOOLS_SYS_PATH_TECHNIQUE=rewrite \ + $cmd_pip $upgrade $install_test_reqs \ $@ + result=$? - # Also install test requirements - local test_req="$@/test-requirements.txt" - if [[ -e "$test_req" ]]; then - echo "Installing test-requirements for $test_req" - $sudo_pip \ - http_proxy=${http_proxy:-} \ - https_proxy=${https_proxy:-} \ - no_proxy=${no_proxy:-} \ - PIP_FIND_LINKS=$PIP_FIND_LINKS \ - $cmd_pip install $upgrade \ - -r $test_req + time_stop "pip_install" + return $result +} + +function pip_uninstall { + # Skip uninstall if offline + [[ "${OFFLINE}" = "True" ]] && return + + local name=$1 + if [[ -n ${PIP_VIRTUAL_ENV:=} && -d ${PIP_VIRTUAL_ENV} ]]; then + local cmd_pip=$PIP_VIRTUAL_ENV/bin/pip + local sudo_pip="env" + else + local cmd_pip + cmd_pip=$(get_pip_command $PYTHON2_VERSION) + local sudo_pip="sudo -H" fi + # don't error if we can't uninstall, it might not be there + $sudo_pip $cmd_pip uninstall -y $name || /bin/true } # get version of a package from global requirements file # get_from_global_requirements function get_from_global_requirements { local package=$1 - local required_pkg=$(grep -i -h ^${package} $REQUIREMENTS_DIR/global-requirements.txt | cut -d\# -f1) + local required_pkg + required_pkg=$(grep -i -h ^${package} $REQUIREMENTS_DIR/global-requirements.txt | cut -d\# -f1) if [[ $required_pkg == "" ]]; then die $LINENO "Can't find package $package in requirements" fi @@ -149,10 +403,32 @@ function get_from_global_requirements { function use_library_from_git { local name=$1 local enabled=1 - [[ ,${LIBS_FROM_GIT}, =~ ,${name}, ]] && enabled=0 + [[ ${LIBS_FROM_GIT} = 'ALL' ]] || [[ ,${LIBS_FROM_GIT}, =~ ,${name}, ]] && enabled=0 return $enabled } +# determine if a package was installed from git +function lib_installed_from_git { + local name=$1 + local safe_name + safe_name=$(python -c "from pkg_resources import safe_name; \ + print(safe_name('${name}'))") + # Note "pip freeze" doesn't always work here, because it tries to + # be smart about finding the remote of the git repo the package + # was installed from. This doesn't work with zuul which clones + # repos with no remote. + # + # The best option seems to be to use "pip list" which will tell + # you the path an editable install was installed from; for example + # in response to something like + # pip install -e 'git+http://git.openstack.org/openstack-dev/bashate#egg=bashate' + # pip list --format columns shows + # bashate 0.5.2.dev19 /tmp/env/src/bashate + # Thus we check the third column to see if we're installed from + # some local place. + [[ -n $(pip list --format=columns 2>/dev/null | awk "/^$safe_name/ {print \$3}") ]] +} + # setup a library by name. If we are trying to use the library from # git, we'll do a git based install, otherwise we'll punt and the # library should be installed by a requirements pull from another @@ -163,7 +439,7 @@ function setup_lib { setup_install $dir } -# setup a library by name in editiable mode. If we are trying to use +# setup a library by name in editable mode. If we are trying to use # the library from git, we'll do a git based install, otherwise we'll # punt and the library should be installed by a requirements pull from # another project. @@ -172,97 +448,153 @@ function setup_lib { function setup_dev_lib { local name=$1 local dir=${GITDIR[$name]} + if python3_enabled; then + # Turn off Python 3 mode and install the package again, + # forcing a Python 2 installation. This ensures that all libs + # being used for development are installed under both versions + # of Python. + echo "Installing $name again without Python 3 enabled" + USE_PYTHON3=False + setup_develop $dir + USE_PYTHON3=True + fi setup_develop $dir } # this should be used if you want to install globally, all libraries should # use this, especially *oslo* ones +# +# setup_install project_dir [extras] +# project_dir: directory of project repo (e.g., /opt/stack/keystone) +# extras: comma-separated list of optional dependencies to install +# (e.g., ldap,memcache). +# See https://docs.openstack.org/pbr/latest/user/using.html#extra-requirements +# The command is like "pip install []" function setup_install { local project_dir=$1 - setup_package_with_req_sync $project_dir + local extras=$2 + _setup_package_with_constraints_edit $project_dir "" $extras } # this should be used for projects which run services, like all services +# +# setup_develop project_dir [extras] +# project_dir: directory of project repo (e.g., /opt/stack/keystone) +# extras: comma-separated list of optional dependencies to install +# (e.g., ldap,memcache). +# See https://docs.openstack.org/pbr/latest/user/using.html#extra-requirements +# The command is like "pip install -e []" function setup_develop { local project_dir=$1 - setup_package_with_req_sync $project_dir -e -} - -# determine if a project as specified by directory is in -# projects.txt. This will not be an exact match because we throw away -# the namespacing when we clone, but it should be good enough in all -# practical ways. -function is_in_projects_txt { - local project_dir=$1 - local project_name=$(basename $project_dir) - return grep "/$project_name\$" $REQUIREMENTS_DIR/projects.txt >/dev/null + local extras=$2 + _setup_package_with_constraints_edit $project_dir -e $extras } # ``pip install -e`` the package, which processes the dependencies # using pip before running `setup.py develop` # -# Updates the dependencies in project_dir from the -# openstack/requirements global list before installing anything. +# Updates the constraints from REQUIREMENTS_DIR to reflect the +# future installed state of this package. This ensures when we +# install this package we get the from source version. # -# Uses globals ``TRACK_DEPENDS``, ``REQUIREMENTS_DIR``, ``UNDO_REQUIREMENTS`` -# setup_develop directory -function setup_package_with_req_sync { +# Uses globals ``REQUIREMENTS_DIR`` +# _setup_package_with_constraints_edit project_dir flags [extras] +# project_dir: directory of project repo (e.g., /opt/stack/keystone) +# flags: pip CLI options/flags +# extras: comma-separated list of optional dependencies to install +# (e.g., ldap,memcache). +# See https://docs.openstack.org/pbr/latest/user/using.html#extra-requirements +# The command is like "pip install []" +function _setup_package_with_constraints_edit { local project_dir=$1 local flags=$2 - - # Don't update repo if local changes exist - # Don't use buggy "git diff --quiet" - # ``errexit`` requires us to trap the exit code when the repo is changed - local update_requirements=$(cd $project_dir && git diff --exit-code >/dev/null || echo "changed") - - if [[ $update_requirements != "changed" ]]; then - if [[ "$REQUIREMENTS_MODE" == "soft" ]]; then - if is_in_projects_txt $project_dir; then - (cd $REQUIREMENTS_DIR; \ - python update.py $project_dir) - else - # soft update projects not found in requirements project.txt - (cd $REQUIREMENTS_DIR; \ - python update.py -s $project_dir) - fi - else - (cd $REQUIREMENTS_DIR; \ - python update.py $project_dir) - fi + local extras=$3 + + # Normalize the directory name to avoid + # "installation from path or url cannot be constrained to a version" + # error. + # REVISIT(yamamoto): Remove this when fixed in pip. + # https://github.com/pypa/pip/pull/3582 + project_dir=$(cd $project_dir && pwd) + + if [ -n "$REQUIREMENTS_DIR" ]; then + # Constrain this package to this project directory from here on out. + local name + name=$(awk '/^name.*=/ {print $3}' $project_dir/setup.cfg) + $REQUIREMENTS_DIR/.venv/bin/edit-constraints \ + $REQUIREMENTS_DIR/upper-constraints.txt -- $name \ + "$flags file://$project_dir#egg=$name" fi - setup_package $project_dir $flags + setup_package $project_dir "$flags" $extras - # We've just gone and possibly modified the user's source tree in an - # automated way, which is considered bad form if it's a development - # tree because we've screwed up their next git checkin. So undo it. - # - # However... there are some circumstances, like running in the gate - # where we really really want the overridden version to stick. So provide - # a variable that tells us whether or not we should UNDO the requirements - # changes (this will be set to False in the OpenStack ci gate) - if [ $UNDO_REQUIREMENTS = "True" ]; then - if [[ $update_requirements != "changed" ]]; then - (cd $project_dir && git reset --hard) + # If this project is in LIBS_FROM_GIT, verify it was actually installed + # correctly. This helps catch errors caused by constraints mismatches. + if use_library_from_git "$project_dir"; then + if ! lib_installed_from_git "$project_dir"; then + die $LINENO "The following LIBS_FROM_GIT was not installed correctly: $project_dir" fi fi } # ``pip install -e`` the package, which processes the dependencies # using pip before running `setup.py develop` +# # Uses globals ``STACK_USER`` -# setup_develop_no_requirements_update directory +# setup_package project_dir [flags] [extras] +# project_dir: directory of project repo (e.g., /opt/stack/keystone) +# flags: pip CLI options/flags +# extras: comma-separated list of optional dependencies to install +# (e.g., ldap,memcache). +# See https://docs.openstack.org/pbr/latest/user/using.html#extra-requirements +# The command is like "pip install []" function setup_package { local project_dir=$1 local flags=$2 + local extras=$3 + + # if the flags variable exists, and it doesn't look like a flag, + # assume it's actually the extras list. + if [[ -n "$flags" && -z "$extras" && ! "$flags" =~ ^-.* ]]; then + extras=$flags + flags="" + fi - pip_install $flags $project_dir + if [[ ! -z "$extras" ]]; then + extras="[$extras]" + fi + + pip_install $flags "$project_dir$extras" # ensure that further actions can do things like setup.py sdist if [[ "$flags" == "-e" ]]; then safe_chown -R $STACK_USER $1/*.egg-info fi } +# Report whether python 3 should be used +function python3_enabled { + if [[ $USE_PYTHON3 == "True" ]]; then + return 0 + else + return 1 + fi +} + +# Install python3 packages +function install_python3 { + if is_ubuntu; then + apt_get install python${PYTHON3_VERSION} python${PYTHON3_VERSION}-dev + elif is_suse; then + install_package python3-devel python3-dbm + fi +} + +function install_devstack_tools { + # intentionally old to ensure devstack-gate has control + local dstools_version=${DSTOOLS_VERSION:-0.1.2} + install_python3 + sudo pip3 install -U devstack-tools==${dstools_version} +} # Restore xtrace $INC_PY_TRACE diff --git a/inc/rootwrap b/inc/rootwrap index bac8e1e86c..2a6e4b648f 100644 --- a/inc/rootwrap +++ b/inc/rootwrap @@ -22,14 +22,14 @@ function add_sudo_secure_path { local line # This is pretty simplistic for now - assume only the first line is used - if [[ -r SUDO_SECURE_PATH_FILE ]]; then + if [[ -r $SUDO_SECURE_PATH_FILE ]]; then line=$(head -1 $SUDO_SECURE_PATH_FILE) else line="Defaults:$STACK_USER secure_path=/usr/local/sbin:/usr/local/bin:/usr/sbin:/sbin:/usr/bin:/bin" fi # Only add ``dir`` if it is not already present - if [[ $line =~ $dir ]]; then + if [[ ! $line =~ $dir ]]; then echo "${line}:$dir" | sudo tee $SUDO_SECURE_PATH_FILE sudo chmod 400 $SUDO_SECURE_PATH_FILE sudo chown root:root $SUDO_SECURE_PATH_FILE @@ -38,11 +38,18 @@ function add_sudo_secure_path { # Configure rootwrap # Make a load of assumptions otherwise we'll have 6 arguments -# configure_rootwrap project bin conf-src-dir +# configure_rootwrap project function configure_rootwrap { - local project=$1 # xx - local rootwrap_bin=$2 # /opt/stack/xx.venv/bin/xx-rootwrap - local rootwrap_conf_src_dir=$3 # /opt/stack/xx/etc/xx + local project=$1 + local project_uc + project_uc=$(echo $1|tr a-z A-Z) + local bin_dir="${project_uc}_BIN_DIR" + bin_dir="${!bin_dir}" + local project_dir="${project_uc}_DIR" + project_dir="${!project_dir}" + + local rootwrap_conf_src_dir="${project_dir}/etc/${project}" + local rootwrap_bin="${bin_dir}/${project}-rootwrap" # Start fresh with rootwrap filters sudo rm -rf /etc/${project}/rootwrap.d @@ -53,12 +60,17 @@ function configure_rootwrap { sudo install -o root -g root -m 644 $rootwrap_conf_src_dir/rootwrap.conf /etc/${project}/rootwrap.conf sudo sed -e "s:^filters_path=.*$:filters_path=/etc/${project}/rootwrap.d:" -i /etc/${project}/rootwrap.conf - # Specify rootwrap.conf as first parameter to rootwrap - rootwrap_sudo_cmd="$rootwrap_bin /etc/${project}/rootwrap.conf *" - # Set up the rootwrap sudoers - local tempfile=$(mktemp) + local tempfile + tempfile=$(mktemp) + # Specify rootwrap.conf as first parameter to rootwrap + rootwrap_sudo_cmd="${rootwrap_bin} /etc/${project}/rootwrap.conf *" echo "$STACK_USER ALL=(root) NOPASSWD: $rootwrap_sudo_cmd" >$tempfile + if [ -f ${bin_dir}/${project}-rootwrap-daemon ]; then + # rootwrap daemon does not need any parameters + rootwrap_sudo_cmd="${rootwrap_bin}-daemon /etc/${project}/rootwrap.conf" + echo "$STACK_USER ALL=(root) NOPASSWD: $rootwrap_sudo_cmd" >>$tempfile + fi chmod 0440 $tempfile sudo chown root:root $tempfile sudo mv $tempfile /etc/sudoers.d/${project}-rootwrap diff --git a/lib/apache b/lib/apache index c7d69f2ea7..84cec73234 100644 --- a/lib/apache +++ b/lib/apache @@ -11,7 +11,6 @@ # lib/apache exports the following functions: # # - install_apache_wsgi -# - config_apache_wsgi # - apache_site_config_for # - enable_apache_site # - disable_apache_site @@ -20,7 +19,7 @@ # - restart_apache_server # Save trace setting -XTRACE=$(set +o | grep xtrace) +_XTRACE_LIB_APACHE=$(set +o | grep xtrace) set +o xtrace # Allow overriding the default Apache user and group, default to @@ -30,77 +29,130 @@ APACHE_GROUP=${APACHE_GROUP:-$(id -gn $APACHE_USER)} # Set up apache name and configuration directory +# Note that APACHE_CONF_DIR is really more accurately apache's vhost +# configuration dir but we can't just change this because public interfaces. if is_ubuntu; then APACHE_NAME=apache2 APACHE_CONF_DIR=${APACHE_CONF_DIR:-/etc/$APACHE_NAME/sites-available} + APACHE_SETTINGS_DIR=${APACHE_SETTINGS_DIR:-/etc/$APACHE_NAME/conf-enabled} elif is_fedora; then APACHE_NAME=httpd APACHE_CONF_DIR=${APACHE_CONF_DIR:-/etc/$APACHE_NAME/conf.d} + APACHE_SETTINGS_DIR=${APACHE_SETTINGS_DIR:-/etc/$APACHE_NAME/conf.d} elif is_suse; then APACHE_NAME=apache2 APACHE_CONF_DIR=${APACHE_CONF_DIR:-/etc/$APACHE_NAME/vhosts.d} + APACHE_SETTINGS_DIR=${APACHE_SETTINGS_DIR:-/etc/$APACHE_NAME/conf.d} fi +APACHE_LOG_DIR="/var/log/${APACHE_NAME}" # Functions # --------- -# install_apache_wsgi() - Install Apache server and wsgi module -function install_apache_wsgi { + +# Enable apache mod and restart apache if it isn't already enabled. +function enable_apache_mod { + local mod=$1 # Apache installation, because we mark it NOPRIME if is_ubuntu; then - # Install apache2, which is NOPRIME'd - install_package apache2 libapache2-mod-wsgi - # WSGI isn't enabled by default, enable it - sudo a2enmod wsgi - elif is_fedora; then - sudo rm -f /etc/httpd/conf.d/000-* - install_package httpd mod_wsgi + # Skip mod_version as it is not a valid mod to enable + # on debuntu, instead it is built in. + if [[ "$mod" != "version" ]] && ! a2query -m $mod ; then + sudo a2enmod $mod + restart_apache_server + fi elif is_suse; then - install_package apache2 apache2-mod_wsgi - # WSGI isn't enabled by default, enable it - sudo a2enmod wsgi + if ! a2enmod -q $mod ; then + sudo a2enmod $mod + restart_apache_server + fi + elif is_fedora; then + # pass + true else - exit_distro_not_supported "apache installation" + exit_distro_not_supported "apache enable mod" fi +} - # ensure mod_version enabled for . This is - # built-in statically on anything recent, but precise (2.2) - # doesn't have it enabled - sudo a2enmod version || true +# NOTE(sdague): Install uwsgi including apache module, we need to get +# to 2.0.6+ to get a working mod_proxy_uwsgi. We can probably build a +# check for that and do it differently for different platforms. +function install_apache_uwsgi { + local apxs="apxs2" + if is_fedora; then + apxs="apxs" + fi + + # Ubuntu xenial is back level on uwsgi so the proxy doesn't + # actually work. Hence we have to build from source for now. + # + # Centos 7 actually has the module in epel, but there was a big + # push to disable epel by default. As such, compile from source + # there as well. + + local dir + dir=$(mktemp -d) + pushd $dir + pip_install uwsgi + pip download uwsgi -c $REQUIREMENTS_DIR/upper-constraints.txt + local uwsgi + uwsgi=$(ls uwsgi*) + tar xvf $uwsgi + cd uwsgi*/apache2 + sudo $apxs -i -c mod_proxy_uwsgi.c + popd + # delete the temp directory + sudo rm -rf $dir + + if is_ubuntu || is_suse ; then + # we've got to enable proxy and proxy_uwsgi for this to work + sudo a2enmod proxy + sudo a2enmod proxy_uwsgi + elif is_fedora; then + # redhat is missing a nice way to turn on/off modules + echo "LoadModule proxy_uwsgi_module modules/mod_proxy_uwsgi.so" \ + | sudo tee /etc/httpd/conf.modules.d/02-proxy-uwsgi.conf + fi + restart_apache_server } -# get_apache_version() - return the version of Apache installed -# This function is used to determine the Apache version installed. There are -# various differences between Apache 2.2 and 2.4 that warrant special handling. -function get_apache_version { +# install_apache_wsgi() - Install Apache server and wsgi module +function install_apache_wsgi { + # Apache installation, because we mark it NOPRIME if is_ubuntu; then - local version_str=$(sudo /usr/sbin/apache2ctl -v | awk '/Server version/ {print $3}' | cut -f2 -d/) + # Install apache2, which is NOPRIME'd + install_package apache2 + if python3_enabled; then + if is_package_installed libapache2-mod-wsgi; then + uninstall_package libapache2-mod-wsgi + fi + install_package libapache2-mod-wsgi-py3 + else + install_package libapache2-mod-wsgi + fi elif is_fedora; then - local version_str=$(rpm -qa --queryformat '%{VERSION}' httpd) + sudo rm -f /etc/httpd/conf.d/000-* + install_package httpd mod_wsgi + # For consistency with Ubuntu, switch to the worker mpm, as + # the default is event + sudo sed -i '/mod_mpm_prefork.so/s/^/#/g' /etc/httpd/conf.modules.d/00-mpm.conf + sudo sed -i '/mod_mpm_event.so/s/^/#/g' /etc/httpd/conf.modules.d/00-mpm.conf + sudo sed -i '/mod_mpm_worker.so/s/^#//g' /etc/httpd/conf.modules.d/00-mpm.conf elif is_suse; then - local version_str=$(rpm -qa --queryformat '%{VERSION}' apache2) - else - exit_distro_not_supported "cannot determine apache version" - fi - if [[ "$version_str" =~ ^2\.2\. ]]; then - echo "2.2" - elif [[ "$version_str" =~ ^2\.4\. ]]; then - echo "2.4" + install_package apache2 apache2-mod_wsgi else - exit_distro_not_supported "apache version not supported" + exit_distro_not_supported "apache wsgi installation" fi + # WSGI isn't enabled by default, enable it + enable_apache_mod wsgi } # apache_site_config_for() - The filename of the site's configuration file. # This function uses the global variables APACHE_NAME and APACHE_CONF_DIR. # -# On Ubuntu 14.04, the site configuration file must have a .conf suffix for a2ensite and a2dissite to +# On Ubuntu 14.04+, the site configuration file must have a .conf suffix for a2ensite and a2dissite to # recognise it. a2ensite and a2dissite ignore the .conf suffix used as parameter. The default sites' # files are 000-default.conf and default-ssl.conf. # -# On Ubuntu 12.04, the site configuration file may have any format, as long as it is in -# /etc/apache2/sites-available/. a2ensite and a2dissite need the entire file name to work. The default -# sites' files are default and default-ssl. -# # On Fedora and openSUSE, any file in /etc/httpd/conf.d/ whose name ends with .conf is enabled. # # On RHEL and CentOS, things should hopefully work as in Fedora. @@ -109,21 +161,14 @@ function get_apache_version { # +----------------------+--------------------+--------------------------+--------------------------+ # | Distribution | File name | Site enabling command | Site disabling command | # +----------------------+--------------------+--------------------------+--------------------------+ -# | Ubuntu 12.04 | site | a2ensite site | a2dissite site | # | Ubuntu 14.04 | site.conf | a2ensite site | a2dissite site | # | Fedora, RHEL, CentOS | site.conf.disabled | mv site.conf{.disabled,} | mv site.conf{,.disabled} | # +----------------------+--------------------+--------------------------+--------------------------+ function apache_site_config_for { local site=$@ if is_ubuntu; then - local apache_version=$(get_apache_version) - if [[ "$apache_version" == "2.2" ]]; then - # Ubuntu 12.04 - Apache 2.2 - echo $APACHE_CONF_DIR/${site} - else - # Ubuntu 14.04 - Apache 2.4 - echo $APACHE_CONF_DIR/${site}.conf - fi + # Ubuntu 14.04 - Apache 2.4 + echo $APACHE_CONF_DIR/${site}.conf elif is_fedora || is_suse; then # fedora conf.d is only imported if it ends with .conf so this is approx the same local enabled_site_file="$APACHE_CONF_DIR/${site}.conf" @@ -138,6 +183,8 @@ function apache_site_config_for { # enable_apache_site() - Enable a particular apache site function enable_apache_site { local site=$@ + # Many of our sites use mod version. Just enable it. + enable_apache_mod version if is_ubuntu; then sudo a2ensite ${site} elif is_fedora || is_suse; then @@ -153,7 +200,7 @@ function enable_apache_site { function disable_apache_site { local site=$@ if is_ubuntu; then - sudo a2dissite ${site} + sudo a2dissite ${site} || true elif is_fedora || is_suse; then local enabled_site_file="$APACHE_CONF_DIR/${site}.conf" # Do nothing if no site config exists @@ -182,13 +229,140 @@ function restart_apache_server { # Apache can be slow to stop, doing an explicit stop, sleep, start helps # to mitigate issues where apache will claim a port it's listening on is # still in use and fail to start. - stop_service $APACHE_NAME - sleep 3 - start_service $APACHE_NAME + restart_service $APACHE_NAME +} + +function write_uwsgi_config { + local file=$1 + local wsgi=$2 + local url=$3 + local http=$4 + local name="" + name=$(basename $wsgi) + + # create a home for the sockets; note don't use /tmp -- apache has + # a private view of it on some platforms. + local socket_dir='/var/run/uwsgi' + + # /var/run will be empty on ubuntu after reboot, so we can use systemd-temptiles + # to automatically create $socket_dir. + sudo mkdir -p /etc/tmpfiles.d/ + echo "d $socket_dir 0755 $STACK_USER root" | sudo tee /etc/tmpfiles.d/uwsgi.conf + sudo systemd-tmpfiles --create /etc/tmpfiles.d/uwsgi.conf + + local socket="$socket_dir/${name}.socket" + + # always cleanup given that we are using iniset here + rm -rf $file + iniset "$file" uwsgi wsgi-file "$wsgi" + iniset "$file" uwsgi processes $API_WORKERS + # This is running standalone + iniset "$file" uwsgi master true + # Set die-on-term & exit-on-reload so that uwsgi shuts down + iniset "$file" uwsgi die-on-term true + iniset "$file" uwsgi exit-on-reload false + # Set worker-reload-mercy so that worker will not exit till the time + # configured after graceful shutdown + iniset "$file" uwsgi worker-reload-mercy $WORKER_TIMEOUT + iniset "$file" uwsgi enable-threads true + iniset "$file" uwsgi plugins python + # uwsgi recommends this to prevent thundering herd on accept. + iniset "$file" uwsgi thunder-lock true + # Set hook to trigger graceful shutdown on SIGTERM + iniset "$file" uwsgi hook-master-start "unix_signal:15 gracefully_kill_them_all" + # Override the default size for headers from the 4k default. + iniset "$file" uwsgi buffer-size 65535 + # Make sure the client doesn't try to re-use the connection. + iniset "$file" uwsgi add-header "Connection: close" + # This ensures that file descriptors aren't shared between processes. + iniset "$file" uwsgi lazy-apps true + + # If we said bind directly to http, then do that and don't start the apache proxy + if [[ -n "$http" ]]; then + iniset "$file" uwsgi http $http + else + local apache_conf="" + apache_conf=$(apache_site_config_for $name) + iniset "$file" uwsgi socket "$socket" + iniset "$file" uwsgi chmod-socket 666 + echo "ProxyPass \"${url}\" \"unix:${socket}|uwsgi://uwsgi-uds-${name}/\" retry=0 " | sudo tee -a $apache_conf + enable_apache_site $name + restart_apache_server + fi +} + +# For services using chunked encoding, the only services known to use this +# currently are Glance and Swift, we need to use an http proxy instead of +# mod_proxy_uwsgi because the chunked encoding gets dropped. See: +# https://github.com/unbit/uwsgi/issues/1540 You can workaround this on python2 +# but that involves having apache buffer the request before sending it to +# uwsgi. +function write_local_uwsgi_http_config { + local file=$1 + local wsgi=$2 + local url=$3 + name=$(basename $wsgi) + + # create a home for the sockets; note don't use /tmp -- apache has + # a private view of it on some platforms. + + # always cleanup given that we are using iniset here + rm -rf $file + iniset "$file" uwsgi wsgi-file "$wsgi" + port=$(get_random_port) + iniset "$file" uwsgi http-socket "127.0.0.1:$port" + iniset "$file" uwsgi processes $API_WORKERS + # This is running standalone + iniset "$file" uwsgi master true + # Set die-on-term & exit-on-reload so that uwsgi shuts down + iniset "$file" uwsgi die-on-term true + iniset "$file" uwsgi exit-on-reload false + iniset "$file" uwsgi enable-threads true + iniset "$file" uwsgi plugins python + # uwsgi recommends this to prevent thundering herd on accept. + iniset "$file" uwsgi thunder-lock true + # Set hook to trigger graceful shutdown on SIGTERM + iniset "$file" uwsgi hook-master-start "unix_signal:15 gracefully_kill_them_all" + # Set worker-reload-mercy so that worker will not exit till the time + # configured after graceful shutdown + iniset "$file" uwsgi worker-reload-mercy $WORKER_TIMEOUT + # Override the default size for headers from the 4k default. + iniset "$file" uwsgi buffer-size 65535 + # Make sure the client doesn't try to re-use the connection. + iniset "$file" uwsgi add-header "Connection: close" + # This ensures that file descriptors aren't shared between processes. + iniset "$file" uwsgi lazy-apps true + iniset "$file" uwsgi chmod-socket 666 + iniset "$file" uwsgi http-raw-body true + iniset "$file" uwsgi http-chunked-input true + iniset "$file" uwsgi http-auto-chunked true + iniset "$file" uwsgi http-keepalive false + # Increase socket timeout for slow chunked uploads + iniset "$file" uwsgi socket-timeout 30 + + enable_apache_mod proxy + enable_apache_mod proxy_http + local apache_conf="" + apache_conf=$(apache_site_config_for $name) + echo "KeepAlive Off" | sudo tee $apache_conf + echo "SetEnv proxy-sendchunked 1" | sudo tee -a $apache_conf + echo "ProxyPass \"${url}\" \"http://127.0.0.1:$port\" retry=0 " | sudo tee -a $apache_conf + enable_apache_site $name + restart_apache_server +} + +function remove_uwsgi_config { + local file=$1 + local wsgi=$2 + local name="" + name=$(basename $wsgi) + + rm -rf $file + disable_apache_site $name } # Restore xtrace -$XTRACE +$_XTRACE_LIB_APACHE # Tell emacs to use shell-script-mode ## Local variables: diff --git a/lib/ceilometer b/lib/ceilometer deleted file mode 100644 index 9abdbfe286..0000000000 --- a/lib/ceilometer +++ /dev/null @@ -1,407 +0,0 @@ -#!/bin/bash -# -# lib/ceilometer -# Install and start **Ceilometer** service - -# To enable a minimal set of Ceilometer services, add the following to the -# ``localrc`` section of ``local.conf``: -# -# enable_service ceilometer-acompute ceilometer-acentral ceilometer-anotification ceilometer-collector ceilometer-api -# -# To ensure Ceilometer alarming services are enabled also, further add to the -# localrc section of local.conf: -# -# enable_service ceilometer-alarm-notifier ceilometer-alarm-evaluator -# -# To enable Ceilometer to collect the IPMI based meters, further add to the -# localrc section of local.conf: -# -# enable_service ceilometer-aipmi -# -# NOTE: Currently, there are two ways to get the IPMI based meters in -# OpenStack. One way is to configure Ironic conductor to report those meters -# for the nodes managed by Ironic and to have Ceilometer notification -# agent to collect them. Ironic by default does NOT enable that reporting -# functionality. So in order to do so, users need to set the option of -# conductor.send_sensor_data to true in the ironic.conf configuration file -# for the Ironic conductor service, and also enable the -# ceilometer-anotification service. -# -# The other way is to use Ceilometer ipmi agent only to get the IPMI based -# meters. To avoid duplicated meters, users need to make sure to set the -# option of conductor.send_sensor_data to false in the ironic.conf -# configuration file if the node on which Ceilometer ipmi agent is running -# is also managed by Ironic. -# -# Several variables set in the localrc section adjust common behaviors -# of Ceilometer (see within for additional settings): -# -# CEILOMETER_USE_MOD_WSGI: When True, run the api under mod_wsgi. -# CEILOMETER_PIPELINE_INTERVAL: Seconds between pipeline processing runs. Default 600. -# CEILOMETER_BACKEND: Database backend (e.g. 'mysql', 'mongodb', 'es') -# CEILOMETER_COORDINATION_URL: URL for group membership service provided by tooz. -# CEILOMETER_EVENTS: Enable event collection - -# Dependencies: -# -# - functions -# - OS_AUTH_URL for auth in api -# - DEST set to the destination directory -# - SERVICE_PASSWORD, SERVICE_TENANT_NAME for auth in api -# - STACK_USER service user - -# stack.sh -# --------- -# - install_ceilometer -# - configure_ceilometer -# - init_ceilometer -# - start_ceilometer -# - stop_ceilometer -# - cleanup_ceilometer - -# Save trace setting -XTRACE=$(set +o | grep xtrace) -set +o xtrace - - -# Defaults -# -------- - -# Set up default directories -GITDIR["python-ceilometerclient"]=$DEST/python-ceilometerclient -GITDIR["ceilometermiddleware"]=$DEST/ceilometermiddleware - -CEILOMETER_DIR=$DEST/ceilometer -CEILOMETER_CONF_DIR=/etc/ceilometer -CEILOMETER_CONF=$CEILOMETER_CONF_DIR/ceilometer.conf -CEILOMETER_API_LOG_DIR=/var/log/ceilometer-api -CEILOMETER_AUTH_CACHE_DIR=${CEILOMETER_AUTH_CACHE_DIR:-/var/cache/ceilometer} -CEILOMETER_WSGI_DIR=${CEILOMETER_WSGI_DIR:-/var/www/ceilometer} - -# Support potential entry-points console scripts -CEILOMETER_BIN_DIR=$(get_python_exec_prefix) - -# Set up database backend -CEILOMETER_BACKEND=${CEILOMETER_BACKEND:-mysql} - -# Ceilometer connection info. -CEILOMETER_SERVICE_PROTOCOL=http -CEILOMETER_SERVICE_HOST=$SERVICE_HOST -CEILOMETER_SERVICE_PORT=${CEILOMETER_SERVICE_PORT:-8777} -CEILOMETER_USE_MOD_WSGI=$(trueorfalse False CEILOMETER_USE_MOD_WSGI) - -# To enable OSprofiler change value of this variable to "notifications,profiler" -CEILOMETER_NOTIFICATION_TOPICS=${CEILOMETER_NOTIFICATION_TOPICS:-notifications} -CEILOMETER_EVENTS=${CEILOMETER_EVENTS:-True} - -CEILOMETER_COORDINATION_URL=${CEILOMETER_COORDINATION_URL:-} -CEILOMETER_PIPELINE_INTERVAL=${CEILOMETER_PIPELINE_INTERVAL:-} - -# Tell Tempest this project is present -TEMPEST_SERVICES+=,ceilometer - - -# Functions -# --------- - -# Test if any Ceilometer services are enabled -# is_ceilometer_enabled -function is_ceilometer_enabled { - [[ ,${ENABLED_SERVICES} =~ ,"ceilometer-" ]] && return 0 - return 1 -} - -# create_ceilometer_accounts() - Set up common required Ceilometer accounts -# -# Project User Roles -# ------------------------------------------------------------------ -# SERVICE_TENANT_NAME ceilometer admin -# SERVICE_TENANT_NAME ceilometer ResellerAdmin (if Swift is enabled) -function create_ceilometer_accounts { - - # Ceilometer - if [[ "$ENABLED_SERVICES" =~ "ceilometer-api" ]]; then - - create_service_user "ceilometer" "admin" - - if [[ "$KEYSTONE_CATALOG_BACKEND" = 'sql' ]]; then - local ceilometer_service=$(get_or_create_service "ceilometer" \ - "metering" "OpenStack Telemetry Service") - get_or_create_endpoint $ceilometer_service \ - "$REGION_NAME" \ - "$CEILOMETER_SERVICE_PROTOCOL://$CEILOMETER_SERVICE_HOST:$CEILOMETER_SERVICE_PORT/" \ - "$CEILOMETER_SERVICE_PROTOCOL://$CEILOMETER_SERVICE_HOST:$CEILOMETER_SERVICE_PORT/" \ - "$CEILOMETER_SERVICE_PROTOCOL://$CEILOMETER_SERVICE_HOST:$CEILOMETER_SERVICE_PORT/" - fi - if is_service_enabled swift; then - # Ceilometer needs ResellerAdmin role to access Swift account stats. - get_or_add_user_project_role "ResellerAdmin" "ceilometer" $SERVICE_TENANT_NAME - fi - fi -} - - -# _cleanup_keystone_apache_wsgi() - Remove WSGI files, disable and remove Apache vhost file -function _cleanup_ceilometer_apache_wsgi { - sudo rm -f $CEILOMETER_WSGI_DIR/* - sudo rm -f $(apache_site_config_for ceilometer) -} - -# cleanup_ceilometer() - Remove residual data files, anything left over from previous -# runs that a clean run would need to clean up -function cleanup_ceilometer { - if [ "$CEILOMETER_BACKEND" = 'mongodb' ] ; then - mongo ceilometer --eval "db.dropDatabase();" - elif [ "$CEILOMETER_BACKEND" = 'es' ] ; then - curl -XDELETE "localhost:9200/events_*" - fi - if [ "$CEILOMETER_USE_MOD_WSGI" == "True" ]; then - _cleanup_ceilometer_apache_wsgi - fi -} - -function _config_ceilometer_apache_wsgi { - sudo mkdir -p $CEILOMETER_WSGI_DIR - - local ceilometer_apache_conf=$(apache_site_config_for ceilometer) - local apache_version=$(get_apache_version) - - # Copy proxy vhost and wsgi file - sudo cp $CEILOMETER_DIR/ceilometer/api/app.wsgi $CEILOMETER_WSGI_DIR/app - - sudo cp $FILES/apache-ceilometer.template $ceilometer_apache_conf - sudo sed -e " - s|%PORT%|$CEILOMETER_SERVICE_PORT|g; - s|%APACHE_NAME%|$APACHE_NAME|g; - s|%WSGIAPP%|$CEILOMETER_WSGI_DIR/app|g; - s|%USER%|$STACK_USER|g - " -i $ceilometer_apache_conf -} - -# configure_ceilometer() - Set config files, create data dirs, etc -function configure_ceilometer { - sudo install -d -o $STACK_USER -m 755 $CEILOMETER_CONF_DIR $CEILOMETER_API_LOG_DIR - - iniset_rpc_backend ceilometer $CEILOMETER_CONF - - iniset $CEILOMETER_CONF DEFAULT notification_topics "$CEILOMETER_NOTIFICATION_TOPICS" - iniset $CEILOMETER_CONF DEFAULT verbose True - iniset $CEILOMETER_CONF DEFAULT debug "$ENABLE_DEBUG_LOG_LEVEL" - - if [[ -n "$CEILOMETER_COORDINATION_URL" ]]; then - iniset $CEILOMETER_CONF coordination backend_url $CEILOMETER_COORDINATION_URL - iniset $CEILOMETER_CONF compute workload_partitioning True - fi - - # Install the policy file for the API server - cp $CEILOMETER_DIR/etc/ceilometer/policy.json $CEILOMETER_CONF_DIR - iniset $CEILOMETER_CONF oslo_policy policy_file $CEILOMETER_CONF_DIR/policy.json - - cp $CEILOMETER_DIR/etc/ceilometer/pipeline.yaml $CEILOMETER_CONF_DIR - cp $CEILOMETER_DIR/etc/ceilometer/event_pipeline.yaml $CEILOMETER_CONF_DIR - cp $CEILOMETER_DIR/etc/ceilometer/api_paste.ini $CEILOMETER_CONF_DIR - cp $CEILOMETER_DIR/etc/ceilometer/event_definitions.yaml $CEILOMETER_CONF_DIR - - if [ "$CEILOMETER_PIPELINE_INTERVAL" ]; then - sed -i "s/interval:.*/interval: ${CEILOMETER_PIPELINE_INTERVAL}/" $CEILOMETER_CONF_DIR/pipeline.yaml - fi - - # The compute and central agents need these credentials in order to - # call out to other services' public APIs. - # The alarm evaluator needs these options to call ceilometer APIs - iniset $CEILOMETER_CONF service_credentials os_username ceilometer - iniset $CEILOMETER_CONF service_credentials os_password $SERVICE_PASSWORD - iniset $CEILOMETER_CONF service_credentials os_tenant_name $SERVICE_TENANT_NAME - iniset $CEILOMETER_CONF service_credentials os_region_name $REGION_NAME - iniset $CEILOMETER_CONF service_credentials os_auth_url $KEYSTONE_SERVICE_URI/v2.0 - - configure_auth_token_middleware $CEILOMETER_CONF ceilometer $CEILOMETER_AUTH_CACHE_DIR - - iniset $CEILOMETER_CONF notification store_events $CEILOMETER_EVENTS - - if [ "$CEILOMETER_BACKEND" = 'mysql' ] || [ "$CEILOMETER_BACKEND" = 'postgresql' ] ; then - iniset $CEILOMETER_CONF database alarm_connection $(database_connection_url ceilometer) - iniset $CEILOMETER_CONF database event_connection $(database_connection_url ceilometer) - iniset $CEILOMETER_CONF database metering_connection $(database_connection_url ceilometer) - iniset $CEILOMETER_CONF DEFAULT collector_workers $API_WORKERS - elif [ "$CEILOMETER_BACKEND" = 'es' ] ; then - # es is only supported for events. we will use sql for alarming/metering. - iniset $CEILOMETER_CONF database alarm_connection $(database_connection_url ceilometer) - iniset $CEILOMETER_CONF database event_connection es://localhost:9200 - iniset $CEILOMETER_CONF database metering_connection $(database_connection_url ceilometer) - iniset $CEILOMETER_CONF DEFAULT collector_workers $API_WORKERS - ${TOP_DIR}/pkg/elasticsearch.sh start - cleanup_ceilometer - else - iniset $CEILOMETER_CONF database alarm_connection mongodb://localhost:27017/ceilometer - iniset $CEILOMETER_CONF database event_connection mongodb://localhost:27017/ceilometer - iniset $CEILOMETER_CONF database metering_connection mongodb://localhost:27017/ceilometer - configure_mongodb - cleanup_ceilometer - fi - - if [[ "$VIRT_DRIVER" = 'vsphere' ]]; then - iniset $CEILOMETER_CONF DEFAULT hypervisor_inspector vsphere - iniset $CEILOMETER_CONF vmware host_ip "$VMWAREAPI_IP" - iniset $CEILOMETER_CONF vmware host_username "$VMWAREAPI_USER" - iniset $CEILOMETER_CONF vmware host_password "$VMWAREAPI_PASSWORD" - fi - - if [ "$CEILOMETER_USE_MOD_WSGI" == "True" ]; then - iniset $CEILOMETER_CONF api pecan_debug "False" - _config_ceilometer_apache_wsgi - fi - - if is_service_enabled ceilometer-aipmi; then - # Configure rootwrap for the ipmi agent - configure_rootwrap ceilometer $CEILOMETER_BIN_DIR/ceilometer-rootwrap $CEILOMETER_DIR/etc/ceilometer - fi -} - -function configure_mongodb { - # Server package is the same on all - local packages=mongodb-server - - if is_fedora; then - # mongodb client + python bindings - packages="${packages} mongodb pymongo" - else - packages="${packages} python-pymongo" - fi - - install_package ${packages} - - if is_fedora; then - # Ensure smallfiles is selected to minimize freespace requirements - sudo sed -i '/--smallfiles/!s/OPTIONS=\"/OPTIONS=\"--smallfiles /' /etc/sysconfig/mongod - - restart_service mongod - fi - - # Give mongodb time to start-up - sleep 5 -} - -# init_ceilometer() - Initialize etc. -function init_ceilometer { - # Create cache dir - sudo install -d -o $STACK_USER $CEILOMETER_AUTH_CACHE_DIR - rm -f $CEILOMETER_AUTH_CACHE_DIR/* - - if is_service_enabled mysql postgresql; then - if [ "$CEILOMETER_BACKEND" = 'mysql' ] || [ "$CEILOMETER_BACKEND" = 'postgresql' ] || [ "$CEILOMETER_BACKEND" = 'es' ] ; then - recreate_database ceilometer - $CEILOMETER_BIN_DIR/ceilometer-dbsync - fi - fi -} - -# install_redis() - Install the redis server. -function install_redis { - if is_ubuntu; then - install_package redis-server - restart_service redis-server - else - # This will fail (correctly) where a redis package is unavailable - install_package redis - restart_service redis - fi -} - -# install_ceilometer() - Collect source and prepare -function install_ceilometer { - git_clone $CEILOMETER_REPO $CEILOMETER_DIR $CEILOMETER_BRANCH - setup_develop $CEILOMETER_DIR - - if echo $CEILOMETER_COORDINATION_URL | grep -q '^memcached:'; then - install_package memcached - elif echo $CEILOMETER_COORDINATION_URL | grep -q '^redis:'; then - install_redis - fi - - if [ "$CEILOMETER_BACKEND" = 'es' ] ; then - ${TOP_DIR}/pkg/elasticsearch.sh download - ${TOP_DIR}/pkg/elasticsearch.sh install - fi -} - -# install_ceilometerclient() - Collect source and prepare -function install_ceilometerclient { - if use_library_from_git "python-ceilometerclient"; then - git_clone_by_name "python-ceilometerclient" - setup_dev_lib "python-ceilometerclient" - sudo install -D -m 0644 -o $STACK_USER {${GITDIR["python-ceilometerclient"]}/tools/,/etc/bash_completion.d/}ceilometer.bash_completion - fi -} - -# install_ceilometermiddleware() - Collect source and prepare -function install_ceilometermiddleware { - if use_library_from_git "ceilometermiddleware"; then - git_clone_by_name "ceilometermiddleware" - setup_dev_lib "ceilometermiddleware" - else - # BUG: this should be a pip_install_gr except it was never - # included in global-requirements. Needs to be fixed by - # https://bugs.launchpad.net/ceilometer/+bug/1441655 - pip_install ceilometermiddleware - fi -} - -# start_ceilometer() - Start running processes, including screen -function start_ceilometer { - run_process ceilometer-acentral "ceilometer-agent-central --config-file $CEILOMETER_CONF" - run_process ceilometer-anotification "ceilometer-agent-notification --config-file $CEILOMETER_CONF" - run_process ceilometer-collector "ceilometer-collector --config-file $CEILOMETER_CONF" - run_process ceilometer-aipmi "ceilometer-agent-ipmi --config-file $CEILOMETER_CONF" - - if [[ "$CEILOMETER_USE_MOD_WSGI" == "False" ]]; then - run_process ceilometer-api "ceilometer-api -d -v --log-dir=$CEILOMETER_API_LOG_DIR --config-file $CEILOMETER_CONF" - else - enable_apache_site ceilometer - restart_apache_server - tail_log ceilometer /var/log/$APACHE_NAME/ceilometer.log - tail_log ceilometer-api /var/log/$APACHE_NAME/ceilometer_access.log - fi - - - # Start the compute agent last to allow time for the collector to - # fully wake up and connect to the message bus. See bug #1355809 - if [[ "$VIRT_DRIVER" = 'libvirt' ]]; then - run_process ceilometer-acompute "ceilometer-agent-compute --config-file $CEILOMETER_CONF" $LIBVIRT_GROUP - fi - if [[ "$VIRT_DRIVER" = 'vsphere' ]]; then - run_process ceilometer-acompute "ceilometer-agent-compute --config-file $CEILOMETER_CONF" - fi - - # Only die on API if it was actually intended to be turned on - if is_service_enabled ceilometer-api; then - echo "Waiting for ceilometer-api to start..." - if ! wait_for_service $SERVICE_TIMEOUT $CEILOMETER_SERVICE_PROTOCOL://$CEILOMETER_SERVICE_HOST:$CEILOMETER_SERVICE_PORT/v2/; then - die $LINENO "ceilometer-api did not start" - fi - fi - - run_process ceilometer-alarm-notifier "ceilometer-alarm-notifier --config-file $CEILOMETER_CONF" - run_process ceilometer-alarm-evaluator "ceilometer-alarm-evaluator --config-file $CEILOMETER_CONF" -} - -# stop_ceilometer() - Stop running processes -function stop_ceilometer { - if [ "$CEILOMETER_USE_MOD_WSGI" == "True" ]; then - disable_apache_site ceilometer - restart_apache_server - fi - # Kill the ceilometer screen windows - for serv in ceilometer-acompute ceilometer-acentral ceilometer-aipmi ceilometer-anotification ceilometer-collector ceilometer-api ceilometer-alarm-notifier ceilometer-alarm-evaluator; do - stop_process $serv - done -} - - -# Restore xtrace -$XTRACE - -# Tell emacs to use shell-script-mode -## Local variables: -## mode: shell-script -## End: diff --git a/lib/ceph b/lib/ceph deleted file mode 100644 index 4068e26222..0000000000 --- a/lib/ceph +++ /dev/null @@ -1,364 +0,0 @@ -#!/bin/bash -# -# lib/ceph -# Functions to control the configuration and operation of the **Ceph** storage service - -# Dependencies: -# -# - ``functions`` file -# - ``CEPH_DATA_DIR`` or ``DATA_DIR`` must be defined - -# ``stack.sh`` calls the entry points in this order (via ``extras.d/60-ceph.sh``): -# -# - install_ceph -# - configure_ceph -# - init_ceph -# - start_ceph -# - stop_ceph -# - cleanup_ceph - -# Save trace setting -XTRACE=$(set +o | grep xtrace) -set +o xtrace - - -# Defaults -# -------- - -# Set ``CEPH_DATA_DIR`` to the location of Ceph drives and objects. -# Default is the common DevStack data directory. -CEPH_DATA_DIR=${CEPH_DATA_DIR:-/var/lib/ceph} -CEPH_DISK_IMAGE=${CEPH_DATA_DIR}/drives/images/ceph.img - -# Set ``CEPH_CONF_DIR`` to the location of the configuration files. -# Default is ``/etc/ceph``. -CEPH_CONF_DIR=${CEPH_CONF_DIR:-/etc/ceph} - -# DevStack will create a loop-back disk formatted as XFS to store the -# Ceph data. Set ``CEPH_LOOPBACK_DISK_SIZE`` to the disk size in -# kilobytes. -# Default is 1 gigabyte. -CEPH_LOOPBACK_DISK_SIZE_DEFAULT=4G -CEPH_LOOPBACK_DISK_SIZE=${CEPH_LOOPBACK_DISK_SIZE:-$CEPH_LOOPBACK_DISK_SIZE_DEFAULT} - -# Common -CEPH_FSID=$(uuidgen) -CEPH_CONF_FILE=${CEPH_CONF_DIR}/ceph.conf - -# Glance -GLANCE_CEPH_USER=${GLANCE_CEPH_USER:-glance} -GLANCE_CEPH_POOL=${GLANCE_CEPH_POOL:-images} -GLANCE_CEPH_POOL_PG=${GLANCE_CEPH_POOL_PG:-8} -GLANCE_CEPH_POOL_PGP=${GLANCE_CEPH_POOL_PGP:-8} - -# Nova -NOVA_CEPH_POOL=${NOVA_CEPH_POOL:-vms} -NOVA_CEPH_POOL_PG=${NOVA_CEPH_POOL_PG:-8} -NOVA_CEPH_POOL_PGP=${NOVA_CEPH_POOL_PGP:-8} - -# Cinder -CINDER_CEPH_POOL=${CINDER_CEPH_POOL:-volumes} -CINDER_CEPH_POOL_PG=${CINDER_CEPH_POOL_PG:-8} -CINDER_CEPH_POOL_PGP=${CINDER_CEPH_POOL_PGP:-8} -CINDER_CEPH_USER=${CINDER_CEPH_USER:-cinder} -CINDER_CEPH_UUID=${CINDER_CEPH_UUID:-$(uuidgen)} - -# Set ``CEPH_REPLICAS`` to configure how many replicas are to be -# configured for your Ceph cluster. By default we are configuring -# only one replica since this is way less CPU and memory intensive. If -# you are planning to test Ceph replication feel free to increase this value -CEPH_REPLICAS=${CEPH_REPLICAS:-1} -CEPH_REPLICAS_SEQ=$(seq ${CEPH_REPLICAS}) - -# Connect to an existing Ceph cluster -REMOTE_CEPH=$(trueorfalse False REMOTE_CEPH) -REMOTE_CEPH_ADMIN_KEY_PATH=${REMOTE_CEPH_ADMIN_KEY_PATH:-$CEPH_CONF_DIR/ceph.client.admin.keyring} - - -# Functions -# ------------ - -function get_ceph_version { - local ceph_version_str=$(sudo ceph daemon mon.$(hostname) version | cut -d '"' -f 4 | cut -f 1,2 -d '.') - echo $ceph_version_str -} - -# import_libvirt_secret_ceph() - Imports Cinder user key into libvirt -# so it can connect to the Ceph cluster while attaching a Cinder block device -function import_libvirt_secret_ceph { - cat > secret.xml < - ${CINDER_CEPH_UUID} - - client.${CINDER_CEPH_USER} secret - - -EOF - sudo virsh secret-define --file secret.xml - sudo virsh secret-set-value --secret ${CINDER_CEPH_UUID} --base64 $(sudo ceph -c ${CEPH_CONF_FILE} auth get-key client.${CINDER_CEPH_USER}) - sudo rm -f secret.xml -} - -# undefine_virsh_secret() - Undefine Cinder key secret from libvirt -function undefine_virsh_secret { - if is_service_enabled cinder || is_service_enabled nova; then - local virsh_uuid=$(sudo virsh secret-list | awk '/^ ?[0-9a-z]/ { print $1 }') - sudo virsh secret-undefine ${virsh_uuid} >/dev/null 2>&1 - fi -} - - -# check_os_support_ceph() - Check if the operating system provides a decent version of Ceph -function check_os_support_ceph { - if [[ ! ${DISTRO} =~ (trusty|f20|f21) ]]; then - echo "WARNING: your distro $DISTRO does not provide (at least) the Firefly release. Please use Ubuntu Trusty or Fedora 20 (and higher)" - if [[ "$FORCE_CEPH_INSTALL" != "yes" ]]; then - die $LINENO "If you wish to install Ceph on this distribution anyway run with FORCE_CEPH_INSTALL=yes" - fi - NO_UPDATE_REPOS=False - fi -} - -# cleanup_ceph() - Remove residual data files, anything left over from previous -# runs that a clean run would need to clean up -function cleanup_ceph_remote { - # do a proper cleanup from here to avoid leftover on the remote Ceph cluster - if is_service_enabled glance; then - sudo ceph osd pool delete $GLANCE_CEPH_POOL $GLANCE_CEPH_POOL --yes-i-really-really-mean-it > /dev/null 2>&1 - sudo ceph auth del client.$GLANCE_CEPH_USER > /dev/null 2>&1 - fi - if is_service_enabled cinder; then - sudo ceph osd pool delete $CINDER_CEPH_POOL $CINDER_CEPH_POOL --yes-i-really-really-mean-it > /dev/null 2>&1 - sudo ceph auth del client.$CINDER_CEPH_USER > /dev/null 2>&1 - fi - if is_service_enabled c-bak; then - sudo ceph osd pool delete $CINDER_BAK_CEPH_POOL $CINDER_BAK_CEPH_POOL --yes-i-really-really-mean-it > /dev/null 2>&1 - sudo ceph auth del client.$CINDER_BAK_CEPH_USER > /dev/null 2>&1 - fi - if is_service_enabled nova; then - iniset $NOVA_CONF libvirt rbd_secret_uuid "" - sudo ceph osd pool delete $NOVA_CEPH_POOL $NOVA_CEPH_POOL --yes-i-really-really-mean-it > /dev/null 2>&1 - fi -} - -function cleanup_ceph_embedded { - sudo killall -w -9 ceph-mon - sudo killall -w -9 ceph-osd - sudo rm -rf ${CEPH_DATA_DIR}/*/* - if egrep -q ${CEPH_DATA_DIR} /proc/mounts; then - sudo umount ${CEPH_DATA_DIR} - fi - if [[ -e ${CEPH_DISK_IMAGE} ]]; then - sudo rm -f ${CEPH_DISK_IMAGE} - fi - - # purge ceph config file and keys - sudo rm -rf ${CEPH_CONF_DIR}/* -} - -function cleanup_ceph_general { - undefine_virsh_secret - uninstall_package ceph ceph-common python-ceph libcephfs1 > /dev/null 2>&1 -} - - -# configure_ceph() - Set config files, create data dirs, etc -function configure_ceph { - local count=0 - - # create a backing file disk - create_disk ${CEPH_DISK_IMAGE} ${CEPH_DATA_DIR} ${CEPH_LOOPBACK_DISK_SIZE} - - # populate ceph directory - sudo mkdir -p ${CEPH_DATA_DIR}/{bootstrap-mds,bootstrap-osd,mds,mon,osd,tmp} - - # create ceph monitor initial key and directory - sudo ceph-authtool /var/lib/ceph/tmp/keyring.mon.$(hostname) --create-keyring --name=mon. --add-key=$(ceph-authtool --gen-print-key) --cap mon 'allow *' - sudo mkdir /var/lib/ceph/mon/ceph-$(hostname) - - # create a default ceph configuration file - sudo tee ${CEPH_CONF_FILE} > /dev/null < /dev/null - sudo chown ${STACK_USER}:$(id -g -n $whoami) ${CEPH_CONF_DIR}/ceph.client.${CINDER_CEPH_USER}.keyring - fi -} - -function configure_ceph_embedded_cinder { - # Configure Cinder service options, ceph pool, ceph user and ceph key - sudo ceph -c ${CEPH_CONF_FILE} osd pool set ${CINDER_CEPH_POOL} size ${CEPH_REPLICAS} - if [[ $CEPH_REPLICAS -ne 1 ]]; then - sudo ceph -c ${CEPH_CONF_FILE} osd pool set ${CINDER_CEPH_POOL} crush_ruleset ${RULE_ID} - fi -} - -# configure_ceph_cinder() - Cinder config needs to come after Cinder is set up -function configure_ceph_cinder { - sudo ceph -c ${CEPH_CONF_FILE} osd pool create ${CINDER_CEPH_POOL} ${CINDER_CEPH_POOL_PG} ${CINDER_CEPH_POOL_PGP} - sudo ceph -c ${CEPH_CONF_FILE} auth get-or-create client.${CINDER_CEPH_USER} mon "allow r" osd "allow class-read object_prefix rbd_children, allow rwx pool=${CINDER_CEPH_POOL}, allow rwx pool=${NOVA_CEPH_POOL},allow rx pool=${GLANCE_CEPH_POOL}" | sudo tee ${CEPH_CONF_DIR}/ceph.client.${CINDER_CEPH_USER}.keyring - sudo chown ${STACK_USER}:$(id -g -n $whoami) ${CEPH_CONF_DIR}/ceph.client.${CINDER_CEPH_USER}.keyring -} - -# init_ceph() - Initialize databases, etc. -function init_ceph { - # clean up from previous (possibly aborted) runs - # make sure to kill all ceph processes first - sudo pkill -f ceph-mon || true - sudo pkill -f ceph-osd || true -} - -# install_ceph() - Collect source and prepare -function install_ceph_remote { - install_package ceph-common -} - -function install_ceph { - install_package ceph -} - -# start_ceph() - Start running processes, including screen -function start_ceph { - if is_ubuntu; then - sudo initctl emit ceph-mon id=$(hostname) - for id in $(sudo ceph -c ${CEPH_CONF_FILE} osd ls); do - sudo start ceph-osd id=${id} - done - else - sudo service ceph start - fi -} - -# stop_ceph() - Stop running processes (non-screen) -function stop_ceph { - if is_ubuntu; then - sudo service ceph-mon-all stop > /dev/null 2>&1 - sudo service ceph-osd-all stop > /dev/null 2>&1 - else - sudo service ceph stop > /dev/null 2>&1 - fi -} - - -# Restore xtrace -$XTRACE - -## Local variables: -## mode: shell-script -## End: diff --git a/lib/cinder b/lib/cinder index 7ad7ef9b0c..76bf928413 100644 --- a/lib/cinder +++ b/lib/cinder @@ -20,7 +20,7 @@ # - cleanup_cinder # Save trace setting -XTRACE=$(set +o | grep xtrace) +_XTRACE_CINDER=$(set +o | grep xtrace) set +o xtrace @@ -39,6 +39,7 @@ fi # set up default directories GITDIR["python-cinderclient"]=$DEST/python-cinderclient +GITDIR["python-brick-cinderclient-ext"]=$DEST/python-brick-cinderclient-ext CINDER_DIR=$DEST/cinder # Cinder virtual environment @@ -54,17 +55,26 @@ CINDER_AUTH_CACHE_DIR=${CINDER_AUTH_CACHE_DIR:-/var/cache/cinder} CINDER_CONF_DIR=/etc/cinder CINDER_CONF=$CINDER_CONF_DIR/cinder.conf +CINDER_UWSGI=$CINDER_BIN_DIR/cinder-wsgi +CINDER_UWSGI_CONF=$CINDER_CONF_DIR/cinder-api-uwsgi.ini CINDER_API_PASTE_INI=$CINDER_CONF_DIR/api-paste.ini # Public facing bits -if is_ssl_enabled_service "cinder" || is_service_enabled tls-proxy; then +if is_service_enabled tls-proxy; then CINDER_SERVICE_PROTOCOL="https" fi CINDER_SERVICE_HOST=${CINDER_SERVICE_HOST:-$SERVICE_HOST} CINDER_SERVICE_PORT=${CINDER_SERVICE_PORT:-8776} CINDER_SERVICE_PORT_INT=${CINDER_SERVICE_PORT_INT:-18776} CINDER_SERVICE_PROTOCOL=${CINDER_SERVICE_PROTOCOL:-$SERVICE_PROTOCOL} +CINDER_SERVICE_LISTEN_ADDRESS=${CINDER_SERVICE_LISTEN_ADDRESS:-$(ipv6_unquote $SERVICE_LISTEN_ADDRESS)} +# What type of LVM device should Cinder use for LVM backend +# Defaults to auto, which will do thin provisioning if it's a fresh +# volume group, otherwise it will do thick. The other valid choices are +# default, which is thick, or thin, which as the name implies utilizes lvm +# thin provisioning. +CINDER_LVM_TYPE=${CINDER_LVM_TYPE:-auto} # Default backends # The backend format is type:name where type is one of the supported backend @@ -75,20 +85,6 @@ CINDER_SERVICE_PROTOCOL=${CINDER_SERVICE_PROTOCOL:-$SERVICE_PROTOCOL} # CINDER_ENABLED_BACKENDS=${CINDER_ENABLED_BACKENDS:-lvm:lvmdriver-1,lvm:lvmdriver-2} CINDER_ENABLED_BACKENDS=${CINDER_ENABLED_BACKENDS:-lvm:lvmdriver-1} - -# Should cinder perform secure deletion of volumes? -# Defaults to zero. Can also be set to none or shred. -# This was previously CINDER_SECURE_DELETE (True or False). -# Equivalents using CINDER_VOLUME_CLEAR are zero and none, respectively. -# Set to none to avoid this bug when testing: -# https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1023755 -if [[ -n $CINDER_SECURE_DELETE ]]; then - CINDER_SECURE_DELETE=$(trueorfalse True CINDER_SECURE_DELETE) - if [[ $CINDER_SECURE_DELETE == "False" ]]; then - CINDER_VOLUME_CLEAR_DEFAULT="none" - fi - DEPRECATED_TEXT="$DEPRECATED_TEXT\nConfigure secure Cinder volume deletion using CINDER_VOLUME_CLEAR instead of CINDER_SECURE_DELETE.\n" -fi CINDER_VOLUME_CLEAR=${CINDER_VOLUME_CLEAR:-${CINDER_VOLUME_CLEAR_DEFAULT:-zero}} CINDER_VOLUME_CLEAR=$(echo ${CINDER_VOLUME_CLEAR} | tr '[:upper:]' '[:lower:]') @@ -100,11 +96,20 @@ CINDER_VOLUME_CLEAR=$(echo ${CINDER_VOLUME_CLEAR} | tr '[:upper:]' '[:lower:]') # https://bugs.launchpad.net/cinder/+bug/1180976 CINDER_PERIODIC_INTERVAL=${CINDER_PERIODIC_INTERVAL:-60} -CINDER_ISCSI_HELPER=${CINDER_ISCSI_HELPER:-tgtadm} - -# Tell Tempest this project is present -TEMPEST_SERVICES+=,cinder +# Centos7 and OpenSUSE switched to using LIO and that's all that's supported, +# although the tgt bits are in EPEL and OpenSUSE we don't want that for CI +if is_fedora || is_suse; then + CINDER_ISCSI_HELPER=${CINDER_ISCSI_HELPER:-lioadm} + if [[ ${CINDER_ISCSI_HELPER} != "lioadm" ]]; then + die "lioadm is the only valid Cinder target_helper config on this platform" + fi +else + CINDER_ISCSI_HELPER=${CINDER_ISCSI_HELPER:-tgtadm} +fi +# Toggle for deploying Cinder under a wsgi server. Legacy mod_wsgi +# reference should be cleaned up to more accurately refer to uwsgi. +CINDER_USE_MOD_WSGI=${CINDER_USE_MOD_WSGI:-True} # Source the enabled backends if is_service_enabled c-vol && [[ -n "$CINDER_ENABLED_BACKENDS" ]]; then @@ -117,12 +122,17 @@ if is_service_enabled c-vol && [[ -n "$CINDER_ENABLED_BACKENDS" ]]; then done fi -# Change the default nova_catalog_info and nova_catalog_admin_info values in -# cinder so that the service name cinder is searching for matches that set for -# nova in keystone. -CINDER_NOVA_CATALOG_INFO=${CINDER_NOVA_CATALOG_INFO:-compute:nova:publicURL} -CINDER_NOVA_CATALOG_ADMIN_INFO=${CINDER_NOVA_CATALOG_ADMIN_INFO:-compute:nova:adminURL} +# Environment variables to configure the image-volume cache +CINDER_IMG_CACHE_ENABLED=${CINDER_IMG_CACHE_ENABLED:-True} + +# For limits, if left unset, it will use cinder defaults of 0 for unlimited +CINDER_IMG_CACHE_SIZE_GB=${CINDER_IMG_CACHE_SIZE_GB:-} +CINDER_IMG_CACHE_SIZE_COUNT=${CINDER_IMG_CACHE_SIZE_COUNT:-} +# Configure which cinder backends will have the image-volume cache, this takes the same +# form as the CINDER_ENABLED_BACKENDS config option. By default it will +# enable the cache for all cinder backends. +CINDER_CACHE_ENABLED_FOR_BACKENDS=${CINDER_CACHE_ENABLED_FOR_BACKENDS:-$CINDER_ENABLED_BACKENDS} # Functions # --------- @@ -130,17 +140,24 @@ CINDER_NOVA_CATALOG_ADMIN_INFO=${CINDER_NOVA_CATALOG_ADMIN_INFO:-compute:nova:ad # Test if any Cinder services are enabled # is_cinder_enabled function is_cinder_enabled { + [[ ,${DISABLED_SERVICES} =~ ,"cinder" ]] && return 1 [[ ,${ENABLED_SERVICES} =~ ,"c-" ]] && return 0 return 1 } +# _cinder_cleanup_apache_wsgi() - Remove wsgi files, disable and remove apache vhost file +function _cinder_cleanup_apache_wsgi { + sudo rm -f $(apache_site_config_for osapi-volume) +} + # cleanup_cinder() - Remove residual data files, anything left over from previous # runs that a clean run would need to clean up function cleanup_cinder { # ensure the volume group is cleared up because fails might # leave dead volumes in the group if [ "$CINDER_ISCSI_HELPER" = "tgtadm" ]; then - local targets=$(sudo tgtadm --op show --mode target) + local targets + targets=$(sudo tgtadm --op show --mode target) if [ $? -ne 0 ]; then # If tgt driver isn't running this won't work obviously # So check the response and restart if need be @@ -180,17 +197,22 @@ function cleanup_cinder { fi done fi + + stop_process "c-api" + remove_uwsgi_config "$CINDER_UWSGI_CONF" "$CINDER_UWSGI" } # configure_cinder() - Set config files, create data dirs, etc function configure_cinder { sudo install -d -o $STACK_USER -m 755 $CINDER_CONF_DIR - cp -p $CINDER_DIR/etc/cinder/policy.json $CINDER_CONF_DIR - rm -f $CINDER_CONF - configure_rootwrap cinder $CINDER_BIN_DIR/cinder-rootwrap $CINDER_DIR/etc/cinder + configure_rootwrap cinder + + if [[ -f "$CINDER_DIR/etc/cinder/resource_filters.json" ]]; then + cp -p "$CINDER_DIR/etc/cinder/resource_filters.json" "$CINDER_CONF_DIR/resource_filters.json" + fi cp $CINDER_DIR/etc/cinder/api-paste.ini $CINDER_API_PASTE_INI @@ -205,27 +227,21 @@ function configure_cinder { configure_auth_token_middleware $CINDER_CONF cinder $CINDER_AUTH_CACHE_DIR - iniset $CINDER_CONF DEFAULT nova_catalog_info $CINDER_NOVA_CATALOG_INFO - iniset $CINDER_CONF DEFAULT nova_catalog_admin_info $CINDER_NOVA_CATALOG_ADMIN_INFO - - iniset $CINDER_CONF DEFAULT auth_strategy keystone iniset $CINDER_CONF DEFAULT debug $ENABLE_DEBUG_LOG_LEVEL - iniset $CINDER_CONF DEFAULT verbose True - iniset $CINDER_CONF DEFAULT iscsi_helper "$CINDER_ISCSI_HELPER" + iniset $CINDER_CONF DEFAULT target_helper "$CINDER_ISCSI_HELPER" iniset $CINDER_CONF database connection `database_connection_url cinder` iniset $CINDER_CONF DEFAULT api_paste_config $CINDER_API_PASTE_INI iniset $CINDER_CONF DEFAULT rootwrap_config "$CINDER_CONF_DIR/rootwrap.conf" iniset $CINDER_CONF DEFAULT osapi_volume_extension cinder.api.contrib.standard_extensions + iniset $CINDER_CONF DEFAULT osapi_volume_listen $CINDER_SERVICE_LISTEN_ADDRESS iniset $CINDER_CONF DEFAULT state_path $CINDER_STATE_PATH iniset $CINDER_CONF oslo_concurrency lock_path $CINDER_STATE_PATH iniset $CINDER_CONF DEFAULT periodic_interval $CINDER_PERIODIC_INTERVAL - # NOTE(thingee): Cinder V1 API is deprecated and defaults to off as of - # Juno. Keep it enabled so we can continue testing while it's still - # supported. - iniset $CINDER_CONF DEFAULT enable_v1_api true + iniset $CINDER_CONF DEFAULT my_ip "$HOST_IP" - iniset $CINDER_CONF DEFAULT os_region_name "$REGION_NAME" + iniset $CINDER_CONF key_manager backend cinder.keymgr.conf_key_mgr.ConfKeyManager + iniset $CINDER_CONF key_manager fixed_key $(openssl rand -hex 16) if is_service_enabled c-vol && [[ -n "$CINDER_ENABLED_BACKENDS" ]]; then local enabled_backends="" @@ -241,24 +257,42 @@ function configure_cinder { default_name=$be_name fi enabled_backends+=$be_name, + + iniset $CINDER_CONF $be_name volume_clear $CINDER_VOLUME_CLEAR + done iniset $CINDER_CONF DEFAULT enabled_backends ${enabled_backends%,*} if [[ -n "$default_name" ]]; then iniset $CINDER_CONF DEFAULT default_volume_type ${default_name} fi + configure_cinder_image_volume_cache fi - if is_service_enabled swift; then - iniset $CINDER_CONF DEFAULT backup_swift_url "$SWIFT_SERVICE_PROTOCOL://$SERVICE_HOST:8080/v1/AUTH_" + if is_service_enabled c-bak; then + # NOTE(mriedem): The default backup driver uses swift and if we're + # on a subnode we might not know if swift is enabled, but chances are + # good that it is on the controller so configure the backup service + # to use it. If we want to configure the backup service to use + # a non-swift driver, we'll likely need environment variables. + iniset $CINDER_CONF DEFAULT backup_swift_url "$SWIFT_SERVICE_PROTOCOL://$SERVICE_HOST:$SWIFT_DEFAULT_BIND_PORT/v1/AUTH_" fi if is_service_enabled ceilometer; then - iniset $CINDER_CONF DEFAULT notification_driver "messaging" + iniset $CINDER_CONF oslo_messaging_notifications driver "messagingv2" fi if is_service_enabled tls-proxy; then - # Set the service port for a proxy to take the original - iniset $CINDER_CONF DEFAULT osapi_volume_listen_port $CINDER_SERVICE_PORT_INT + if [[ "$ENABLED_SERVICES" =~ "c-api" ]]; then + # Set the service port for a proxy to take the original + if [ "$CINDER_USE_MOD_WSGI" == "True" ]; then + iniset $CINDER_CONF DEFAULT osapi_volume_listen_port $CINDER_SERVICE_PORT_INT + iniset $CINDER_CONF oslo_middleware enable_proxy_headers_parsing True + else + iniset $CINDER_CONF DEFAULT osapi_volume_listen_port $CINDER_SERVICE_PORT_INT + iniset $CINDER_CONF DEFAULT public_endpoint $CINDER_SERVICE_PROTOCOL://$CINDER_SERVICE_HOST:$CINDER_SERVICE_PORT + iniset $CINDER_CONF DEFAULT osapi_volume_base_URL $CINDER_SERVICE_PROTOCOL://$CINDER_SERVICE_HOST:$CINDER_SERVICE_PORT + fi + fi fi if [ "$SYSLOG" != "False" ]; then @@ -267,17 +301,10 @@ function configure_cinder { iniset_rpc_backend cinder $CINDER_CONF - if [[ "$CINDER_VOLUME_CLEAR" == "none" ]] || [[ "$CINDER_VOLUME_CLEAR" == "zero" ]] || [[ "$CINDER_VOLUME_CLEAR" == "shred" ]]; then - iniset $CINDER_CONF DEFAULT volume_clear $CINDER_VOLUME_CLEAR - fi - # Format logging - if [ "$LOG_COLOR" == "True" ] && [ "$SYSLOG" == "False" ]; then - setup_colorized_logging $CINDER_CONF DEFAULT "project_id" "user_id" - else - # Set req-id, project-name and resource in log format - iniset $CINDER_CONF DEFAULT logging_context_format_string "%(asctime)s.%(msecs)03d %(levelname)s %(name)s [%(request_id)s %(project_name)s] %(resource)s%(message)s" - fi + setup_logging $CINDER_CONF $CINDER_USE_MOD_WSGI + + write_uwsgi_config "$CINDER_UWSGI_CONF" "$CINDER_UWSGI" "/volume" if [[ -r $CINDER_PLUGINS/$CINDER_DRIVER ]]; then configure_cinder_driver @@ -285,25 +312,26 @@ function configure_cinder { iniset $CINDER_CONF DEFAULT osapi_volume_workers "$API_WORKERS" - iniset $CINDER_CONF DEFAULT glance_api_servers "${GLANCE_SERVICE_PROTOCOL}://${GLANCE_HOSTPORT}" - if is_ssl_enabled_service glance || is_service_enabled tls-proxy; then + iniset $CINDER_CONF DEFAULT glance_api_servers "$GLANCE_URL" + if is_service_enabled tls-proxy; then iniset $CINDER_CONF DEFAULT glance_protocol https iniset $CINDER_CONF DEFAULT glance_ca_certificates_file $SSL_BUNDLE_FILE fi - # Register SSL certificates if provided - if is_ssl_enabled_service cinder; then - ensure_certificates CINDER - - iniset $CINDER_CONF DEFAULT ssl_cert_file "$CINDER_SSL_CERT" - iniset $CINDER_CONF DEFAULT ssl_key_file "$CINDER_SSL_KEY" + if [ "$GLANCE_V1_ENABLED" != "True" ]; then + iniset $CINDER_CONF DEFAULT glance_api_version 2 fi - # Set os_privileged_user credentials (used for os-assisted-snapshots) - iniset $CINDER_CONF DEFAULT os_privileged_user_name nova - iniset $CINDER_CONF DEFAULT os_privileged_user_password "$SERVICE_PASSWORD" - iniset $CINDER_CONF DEFAULT os_privileged_user_tenant "$SERVICE_TENANT_NAME" + # Set nova credentials (used for os-assisted-snapshots) + configure_auth_token_middleware $CINDER_CONF nova $CINDER_AUTH_CACHE_DIR nova + iniset $CINDER_CONF nova region_name "$REGION_NAME" + iniset $CINDER_CONF DEFAULT graceful_shutdown_timeout "$SERVICE_GRACEFUL_SHUTDOWN_TIMEOUT" + if [[ ! -z "$CINDER_COORDINATION_URL" ]]; then + iniset $CINDER_CONF coordination backend_url "$CINDER_COORDINATION_URL" + elif is_service_enabled etcd3; then + iniset $CINDER_CONF coordination backend_url "etcd3+http://${SERVICE_HOST}:$ETCD_PORT" + fi } # create_cinder_accounts() - Set up common required cinder accounts @@ -314,28 +342,61 @@ function configure_cinder { # Migrated from keystone_data.sh function create_cinder_accounts { - # Cinder if [[ "$ENABLED_SERVICES" =~ "c-api" ]]; then create_service_user "cinder" - if [[ "$KEYSTONE_CATALOG_BACKEND" = 'sql' ]]; then - - local cinder_service=$(get_or_create_service "cinder" \ - "volume" "Cinder Volume Service") - get_or_create_endpoint $cinder_service "$REGION_NAME" \ - "$CINDER_SERVICE_PROTOCOL://$CINDER_SERVICE_HOST:$CINDER_SERVICE_PORT/v1/\$(tenant_id)s" \ - "$CINDER_SERVICE_PROTOCOL://$CINDER_SERVICE_HOST:$CINDER_SERVICE_PORT/v1/\$(tenant_id)s" \ - "$CINDER_SERVICE_PROTOCOL://$CINDER_SERVICE_HOST:$CINDER_SERVICE_PORT/v1/\$(tenant_id)s" - - local cinder_v2_service=$(get_or_create_service "cinderv2" \ - "volumev2" "Cinder Volume Service V2") - get_or_create_endpoint $cinder_v2_service "$REGION_NAME" \ - "$CINDER_SERVICE_PROTOCOL://$CINDER_SERVICE_HOST:$CINDER_SERVICE_PORT/v2/\$(tenant_id)s" \ - "$CINDER_SERVICE_PROTOCOL://$CINDER_SERVICE_HOST:$CINDER_SERVICE_PORT/v2/\$(tenant_id)s" \ - "$CINDER_SERVICE_PROTOCOL://$CINDER_SERVICE_HOST:$CINDER_SERVICE_PORT/v2/\$(tenant_id)s" + # block-storage is the official service type + get_or_create_service "cinder" "block-storage" "Cinder Volume Service" + get_or_create_service "cinder" "volume" "Cinder Volume Service" + if [ "$CINDER_USE_MOD_WSGI" == "False" ]; then + get_or_create_endpoint \ + "block-storage" \ + "$REGION_NAME" \ + "$CINDER_SERVICE_PROTOCOL://$CINDER_SERVICE_HOST:$CINDER_SERVICE_PORT/v3/\$(project_id)s" + + get_or_create_endpoint \ + "volume" \ + "$REGION_NAME" \ + "$CINDER_SERVICE_PROTOCOL://$CINDER_SERVICE_HOST:$CINDER_SERVICE_PORT/v1/\$(project_id)s" + + get_or_create_service "cinderv2" "volumev2" "Cinder Volume Service V2" + get_or_create_endpoint \ + "volumev2" \ + "$REGION_NAME" \ + "$CINDER_SERVICE_PROTOCOL://$CINDER_SERVICE_HOST:$CINDER_SERVICE_PORT/v2/\$(project_id)s" + + get_or_create_service "cinderv3" "volumev3" "Cinder Volume Service V3" + get_or_create_endpoint \ + "volumev3" \ + "$REGION_NAME" \ + "$CINDER_SERVICE_PROTOCOL://$CINDER_SERVICE_HOST:$CINDER_SERVICE_PORT/v3/\$(project_id)s" + else + get_or_create_endpoint \ + "block-storage" \ + "$REGION_NAME" \ + "$CINDER_SERVICE_PROTOCOL://$CINDER_SERVICE_HOST/volume/v3/\$(project_id)s" + + get_or_create_endpoint \ + "volume" \ + "$REGION_NAME" \ + "$CINDER_SERVICE_PROTOCOL://$CINDER_SERVICE_HOST/volume/v1/\$(project_id)s" + + get_or_create_service "cinderv2" "volumev2" "Cinder Volume Service V2" + get_or_create_endpoint \ + "volumev2" \ + "$REGION_NAME" \ + "$CINDER_SERVICE_PROTOCOL://$CINDER_SERVICE_HOST/volume/v2/\$(project_id)s" + + get_or_create_service "cinderv3" "volumev3" "Cinder Volume Service V3" + get_or_create_endpoint \ + "volumev3" \ + "$REGION_NAME" \ + "$CINDER_SERVICE_PROTOCOL://$CINDER_SERVICE_HOST/volume/v3/\$(project_id)s" fi + + configure_cinder_internal_tenant fi } @@ -347,17 +408,15 @@ function create_cinder_cache_dir { } # init_cinder() - Initialize database and volume group -# Uses global ``NOVA_ENABLED_APIS`` function init_cinder { - # Force nova volumes off - NOVA_ENABLED_APIS=$(echo $NOVA_ENABLED_APIS | sed "s/osapi_volume,//") - if is_service_enabled $DATABASE_BACKENDS; then # (Re)create cinder database recreate_database cinder + time_start "dbsync" # Migrate cinder database - $CINDER_BIN_DIR/cinder-manage db sync + $CINDER_BIN_DIR/cinder-manage --config-file $CINDER_CONF db sync + time_stop "dbsync" fi if is_service_enabled c-vol && [[ -n "$CINDER_ENABLED_BACKENDS" ]]; then @@ -383,17 +442,20 @@ function init_cinder { function install_cinder { git_clone $CINDER_REPO $CINDER_DIR $CINDER_BRANCH setup_develop $CINDER_DIR - if [ "$CINDER_ISCSI_HELPER" = "tgtadm" ]; then - if is_fedora; then - install_package scsi-target-utils - else - install_package tgt - fi + if [[ "$CINDER_ISCSI_HELPER" == "tgtadm" ]]; then + install_package tgt + elif [[ "$CINDER_ISCSI_HELPER" == "lioadm" ]]; then + install_package targetcli fi } # install_cinderclient() - Collect source and prepare function install_cinderclient { + if use_library_from_git "python-brick-cinderclient-ext"; then + git_clone_by_name "python-brick-cinderclient-ext" + setup_dev_lib "python-brick-cinderclient-ext" + fi + if use_library_from_git "python-cinderclient"; then git_clone_by_name "python-cinderclient" setup_dev_lib "python-cinderclient" @@ -405,15 +467,18 @@ function install_cinderclient { function _configure_tgt_for_config_d { if [[ ! -d /etc/tgt/stack.d/ ]]; then sudo ln -sf $CINDER_STATE_PATH/volumes /etc/tgt/stack.d + fi + if ! grep -q "include /etc/tgt/stack.d/*" /etc/tgt/targets.conf; then echo "include /etc/tgt/stack.d/*" | sudo tee -a /etc/tgt/targets.conf fi } -# start_cinder() - Start running processes, including screen +# start_cinder() - Start running processes function start_cinder { local service_port=$CINDER_SERVICE_PORT local service_protocol=$CINDER_SERVICE_PROTOCOL - if is_service_enabled tls-proxy; then + local cinder_url + if is_service_enabled tls-proxy && [ "$CINDER_USE_MOD_WSGI" == "False" ]; then service_port=$CINDER_SERVICE_PORT_INT service_protocol="http" fi @@ -424,21 +489,35 @@ function start_cinder { _configure_tgt_for_config_d if is_ubuntu; then sudo service tgt restart - elif is_fedora || is_suse; then - restart_service tgtd + elif is_suse; then + # NOTE(dmllr): workaround restart bug + # https://bugzilla.suse.com/show_bug.cgi?id=934642 + stop_service tgtd + start_service tgtd else - # note for other distros: unstack.sh also uses the tgt/tgtd service - # name, and would need to be adjusted too - exit_distro_not_supported "restarting tgt" + restart_service tgtd fi # NOTE(gfidente): ensure tgtd is running in debug mode sudo tgtadm --mode system --op update --name debug --value on fi fi - run_process c-api "$CINDER_BIN_DIR/cinder-api --config-file $CINDER_CONF" + if [[ "$ENABLED_SERVICES" =~ "c-api" ]]; then + if [ "$CINDER_USE_MOD_WSGI" == "False" ]; then + run_process c-api "$CINDER_BIN_DIR/cinder-api --config-file $CINDER_CONF" + cinder_url=$service_protocol://$SERVICE_HOST:$service_port + # Start proxy if tls enabled + if is_service_enabled tls-proxy; then + start_tls_proxy cinder '*' $CINDER_SERVICE_PORT $CINDER_SERVICE_HOST $CINDER_SERVICE_PORT_INT + fi + else + run_process "c-api" "$CINDER_BIN_DIR/uwsgi --procname-prefix cinder-api --ini $CINDER_UWSGI_CONF" + cinder_url=$service_protocol://$SERVICE_HOST/volume/v3 + fi + fi + echo "Waiting for Cinder API to start..." - if ! wait_for_service $SERVICE_TIMEOUT $service_protocol://$CINDER_SERVICE_HOST:$service_port; then + if ! wait_for_service $SERVICE_TIMEOUT $cinder_url; then die $LINENO "c-api did not start" fi @@ -449,33 +528,34 @@ function start_cinder { # NOTE(jdg): For cinder, startup order matters. To ensure that repor_capabilities is received # by the scheduler start the cinder-volume service last (or restart it) after the scheduler # has started. This is a quick fix for lp bug/1189595 - - # Start proxies if enabled - if is_service_enabled c-api && is_service_enabled tls-proxy; then - start_tls_proxy '*' $CINDER_SERVICE_PORT $CINDER_SERVICE_HOST $CINDER_SERVICE_PORT_INT & - fi } # stop_cinder() - Stop running processes function stop_cinder { - # Kill the cinder screen windows - local serv - for serv in c-api c-bak c-sch c-vol; do - stop_process $serv - done + stop_process c-api + stop_process c-bak + stop_process c-sch + stop_process c-vol } # create_volume_types() - Create Cinder's configured volume types function create_volume_types { # Create volume types if is_service_enabled c-api && [[ -n "$CINDER_ENABLED_BACKENDS" ]]; then - local be be_name be_type + local be be_name for be in ${CINDER_ENABLED_BACKENDS//,/ }; do - be_type=${be%%:*} be_name=${be##*:} - # openstack volume type create --property volume_backend_name="${be_type}" ${be_name} - cinder type-create ${be_name} && \ - cinder type-key ${be_name} set volume_backend_name="${be_name}" + # NOTE (e0ne): openstack client doesn't work with cinder in noauth mode + if is_service_enabled keystone; then + openstack --os-region-name="$REGION_NAME" volume type create --property volume_backend_name="${be_name}" ${be_name} + else + # TODO (e0ne): use openstack client once it will support cinder in noauth mode: + # https://bugs.launchpad.net/python-cinderclient/+bug/1755279 + local cinder_url + cinder_url=$CINDER_SERVICE_PROTOCOL://$SERVICE_HOST:$CINDER_SERVICE_PORT/v3 + OS_USER_ID=$OS_USERNAME OS_PROJECT_ID=$OS_PROJECT_NAME cinder --os-auth-type noauth --os-endpoint=$cinder_url type-create ${be_name} + OS_USER_ID=$OS_USERNAME OS_PROJECT_ID=$OS_PROJECT_NAME cinder --os-auth-type noauth --os-endpoint=$cinder_url type-key ${be_name} set volume_backend_name=${be_name} + fi done fi } @@ -488,9 +568,34 @@ function create_cinder_volume_group { : } +function configure_cinder_internal_tenant { + # Re-use the Cinder service account for simplicity. + iniset $CINDER_CONF DEFAULT cinder_internal_tenant_project_id $(get_or_create_project $SERVICE_PROJECT_NAME) + iniset $CINDER_CONF DEFAULT cinder_internal_tenant_user_id $(get_or_create_user "cinder") +} + +function configure_cinder_image_volume_cache { + # Expect CINDER_CACHE_ENABLED_FOR_BACKENDS to be a list of backends + # similar to CINDER_ENABLED_BACKENDS with NAME:TYPE where NAME will + # be the backend specific configuration stanza in cinder.conf. + for be in ${CINDER_CACHE_ENABLED_FOR_BACKENDS//,/ }; do + local be_name=${be##*:} + + iniset $CINDER_CONF $be_name image_volume_cache_enabled $CINDER_IMG_CACHE_ENABLED + + if [[ -n $CINDER_IMG_CACHE_SIZE_GB ]]; then + iniset $CINDER_CONF $be_name image_volume_cache_max_size_gb $CINDER_IMG_CACHE_SIZE_GB + fi + + if [[ -n $CINDER_IMG_CACHE_SIZE_COUNT ]]; then + iniset $CINDER_CONF $be_name image_volume_cache_max_count $CINDER_IMG_CACHE_SIZE_COUNT + fi + done +} + # Restore xtrace -$XTRACE +$_XTRACE_CINDER # Tell emacs to use shell-script-mode ## Local variables: diff --git a/lib/cinder_backends/ceph b/lib/cinder_backends/ceph index 7e9d2d334e..33c9706d3d 100644 --- a/lib/cinder_backends/ceph +++ b/lib/cinder_backends/ceph @@ -22,7 +22,7 @@ # Save trace setting -MY_XTRACE=$(set +o | grep xtrace) +_XTRACE_CINDER_CEPH=$(set +o | grep xtrace) set +o xtrace @@ -45,10 +45,10 @@ function configure_cinder_backend_ceph { iniset $CINDER_CONF $be_name volume_backend_name $be_name iniset $CINDER_CONF $be_name volume_driver "cinder.volume.drivers.rbd.RBDDriver" - iniset $CINDER_CONF $be_name rbd_ceph_conf "$CEPH_CONF" + iniset $CINDER_CONF $be_name rbd_ceph_conf "$CEPH_CONF_FILE" iniset $CINDER_CONF $be_name rbd_pool "$CINDER_CEPH_POOL" iniset $CINDER_CONF $be_name rbd_user "$CINDER_CEPH_USER" - iniset $CINDER_CONF $be_name rbd_uuid "$CINDER_CEPH_UUID" + iniset $CINDER_CONF $be_name rbd_secret_uuid "$CINDER_CEPH_UUID" iniset $CINDER_CONF $be_name rbd_flatten_volume_from_snapshot False iniset $CINDER_CONF $be_name rbd_max_clone_depth 5 iniset $CINDER_CONF DEFAULT glance_api_version 2 @@ -62,11 +62,11 @@ function configure_cinder_backend_ceph { sudo ceph -c ${CEPH_CONF_FILE} osd pool set ${CINDER_BAK_CEPH_POOL} crush_ruleset ${RULE_ID} fi fi - sudo ceph -c ${CEPH_CONF_FILE} auth get-or-create client.${CINDER_BAK_CEPH_USER} mon "allow r" osd "allow class-read object_prefix rbd_children, allow rwx pool=${CINDER_BAK_CEPH_POOL}" | sudo tee ${CEPH_CONF_DIR}/ceph.client.${CINDER_BAK_CEPH_USER}.keyring + sudo ceph -c ${CEPH_CONF_FILE} auth get-or-create client.${CINDER_BAK_CEPH_USER} mon "allow r" osd "allow class-read object_prefix rbd_children, allow rwx pool=${CINDER_BAK_CEPH_POOL}, allow rwx pool=${CINDER_CEPH_POOL}" | sudo tee ${CEPH_CONF_DIR}/ceph.client.${CINDER_BAK_CEPH_USER}.keyring sudo chown $(whoami):$(whoami) ${CEPH_CONF_DIR}/ceph.client.${CINDER_BAK_CEPH_USER}.keyring - iniset $CINDER_CONF DEFAULT backup_driver "cinder.backup.drivers.ceph" - iniset $CINDER_CONF DEFAULT backup_ceph_conf "$CEPH_CONF" + iniset $CINDER_CONF DEFAULT backup_driver "cinder.backup.drivers.ceph.CephBackupDriver" + iniset $CINDER_CONF DEFAULT backup_ceph_conf "$CEPH_CONF_FILE" iniset $CINDER_CONF DEFAULT backup_ceph_pool "$CINDER_BAK_CEPH_POOL" iniset $CINDER_CONF DEFAULT backup_ceph_user "$CINDER_BAK_CEPH_USER" iniset $CINDER_CONF DEFAULT backup_ceph_stripe_unit 0 @@ -76,7 +76,7 @@ function configure_cinder_backend_ceph { } # Restore xtrace -$MY_XTRACE +$_XTRACE_CINDER_CEPH # Local variables: # mode: shell-script diff --git a/lib/cinder_backends/fake b/lib/cinder_backends/fake new file mode 100644 index 0000000000..4749aced69 --- /dev/null +++ b/lib/cinder_backends/fake @@ -0,0 +1,47 @@ +#!/bin/bash +# +# lib/cinder_backends/fake +# Configure the Fake backend + +# Enable with: +# +# CINDER_ENABLED_BACKENDS+=,fake:fake + +# Dependencies: +# +# - ``functions`` file +# - ``cinder`` configurations + +# CINDER_CONF + +# clean_cinder_backend_fake - called from clean_cinder() +# configure_cinder_backend_fake - called from configure_cinder() +# init_cinder_backend_fake - called from init_cinder() + + +# Save trace setting +_XTRACE_CINDER_FAKE=$(set +o | grep xtrace) +set +o xtrace + + +function cleanup_cinder_backend_fake { + local be_name=$1 +} + +function configure_cinder_backend_fake { + local be_name=$1 + + iniset $CINDER_CONF $be_name volume_backend_name $be_name + iniset $CINDER_CONF $be_name volume_driver "cinder.tests.fake_driver.FakeLoggingVolumeDriver" + +} + +function init_cinder_backend_fake { + local be_name=$1 +} + +# Restore xtrace +$_XTRACE_CINDER_FAKE + +# mode: shell-script +# End: diff --git a/lib/cinder_backends/fake_gate b/lib/cinder_backends/fake_gate new file mode 100644 index 0000000000..3ffd9a6785 --- /dev/null +++ b/lib/cinder_backends/fake_gate @@ -0,0 +1,74 @@ +#!/bin/bash +# +# lib/cinder_backends/lvm +# Configure the LVM backend + +# Enable with: +# +# CINDER_ENABLED_BACKENDS+=,fake_gate:lvmname + +# Dependencies: +# +# - ``functions`` file +# - ``cinder`` configurations + +# CINDER_CONF +# DATA_DIR +# VOLUME_GROUP_NAME + +# clean_cinder_backend_lvm - called from clean_cinder() +# configure_cinder_backend_lvm - called from configure_cinder() +# init_cinder_backend_lvm - called from init_cinder() + + +# Save trace setting +_XTRACE_CINDER_LVM=$(set +o | grep xtrace) +set +o xtrace + + +# TODO: resurrect backing device...need to know how to set values +#VOLUME_BACKING_DEVICE=${VOLUME_BACKING_DEVICE:-} + +# Entry Points +# ------------ + +# cleanup_cinder_backend_lvm - Delete volume group and remove backing file +# cleanup_cinder_backend_lvm $be_name +function cleanup_cinder_backend_lvm { + local be_name=$1 + + # Campsite rule: leave behind a volume group at least as clean as we found it + clean_lvm_volume_group $VOLUME_GROUP_NAME-$be_name + clean_lvm_filter +} + +# configure_cinder_backend_lvm - Set config files, create data dirs, etc +# configure_cinder_backend_lvm $be_name +function configure_cinder_backend_lvm { + local be_name=$1 + + iniset $CINDER_CONF $be_name volume_backend_name $be_name + iniset $CINDER_CONF $be_name volume_driver "cinder.tests.fake_driver.FakeGateDriver" + iniset $CINDER_CONF $be_name volume_group $VOLUME_GROUP_NAME-$be_name + iniset $CINDER_CONF $be_name target_helper "$CINDER_ISCSI_HELPER" + iniset $CINDER_CONF $be_name lvm_type "$CINDER_LVM_TYPE" + + if [[ "$CINDER_VOLUME_CLEAR" == "non" ]]; then + iniset $CINDER_CONF $be_name volume_clear none + fi +} + +# init_cinder_backend_lvm - Initialize volume group +# init_cinder_backend_lvm $be_name +function init_cinder_backend_lvm { + local be_name=$1 + + # Start with a clean volume group + init_lvm_volume_group $VOLUME_GROUP_NAME-$be_name $VOLUME_BACKING_FILE_SIZE +} + +# Restore xtrace +$_XTRACE_CINDER_LVM + +# mode: shell-script +# End: diff --git a/lib/cinder_backends/glusterfs b/lib/cinder_backends/glusterfs index 00c62e04cd..4e34f8ef6c 100644 --- a/lib/cinder_backends/glusterfs +++ b/lib/cinder_backends/glusterfs @@ -19,7 +19,7 @@ # configure_cinder_backend_glusterfs - Configure Cinder for GlusterFS backends # Save trace setting -GLUSTERFS_XTRACE=$(set +o | grep xtrace) +_XTRACE_CINDER_GLUSTERFS=$(set +o | grep xtrace) set +o xtrace @@ -41,7 +41,7 @@ function configure_cinder_backend_glusterfs { # Restore xtrace -$GLUSTERFS_XTRACE +$_XTRACE_CINDER_GLUSTERFS # Local variables: # mode: shell-script diff --git a/lib/cinder_backends/lvm b/lib/cinder_backends/lvm index 35ad209db7..497081c9e4 100644 --- a/lib/cinder_backends/lvm +++ b/lib/cinder_backends/lvm @@ -22,7 +22,7 @@ # Save trace setting -MY_XTRACE=$(set +o | grep xtrace) +_XTRACE_CINDER_LVM=$(set +o | grep xtrace) set +o xtrace @@ -50,11 +50,9 @@ function configure_cinder_backend_lvm { iniset $CINDER_CONF $be_name volume_backend_name $be_name iniset $CINDER_CONF $be_name volume_driver "cinder.volume.drivers.lvm.LVMVolumeDriver" iniset $CINDER_CONF $be_name volume_group $VOLUME_GROUP_NAME-$be_name - iniset $CINDER_CONF $be_name iscsi_helper "$CINDER_ISCSI_HELPER" + iniset $CINDER_CONF $be_name target_helper "$CINDER_ISCSI_HELPER" + iniset $CINDER_CONF $be_name lvm_type "$CINDER_LVM_TYPE" - if [[ "$CINDER_SECURE_DELETE" == "False" ]]; then - iniset $CINDER_CONF $be_name volume_clear none - fi } # init_cinder_backend_lvm - Initialize volume group @@ -67,7 +65,7 @@ function init_cinder_backend_lvm { } # Restore xtrace -$MY_XTRACE +$_XTRACE_CINDER_LVM # mode: shell-script # End: diff --git a/lib/cinder_backends/netapp_iscsi b/lib/cinder_backends/netapp_iscsi index be9442eb83..5cce30a6d3 100644 --- a/lib/cinder_backends/netapp_iscsi +++ b/lib/cinder_backends/netapp_iscsi @@ -20,7 +20,7 @@ # configure_cinder_backend_netapp_iscsi - configure iSCSI # Save trace setting -MY_XTRACE=$(set +o | grep xtrace) +_XTRACE_CINDER_NETAPP=$(set +o | grep xtrace) set +o xtrace @@ -59,7 +59,7 @@ function configure_cinder_backend_netapp_iscsi { # Restore xtrace -$MY_XTRACE +$_XTRACE_CINDER_NETAPP # Local variables: # mode: shell-script diff --git a/lib/cinder_backends/netapp_nfs b/lib/cinder_backends/netapp_nfs index dc919ad86b..7ba36d2a3b 100644 --- a/lib/cinder_backends/netapp_nfs +++ b/lib/cinder_backends/netapp_nfs @@ -20,7 +20,7 @@ # configure_cinder_backend_netapp_nfs - configure NFS # Save trace setting -MY_XTRACE=$(set +o | grep xtrace) +_XTRACE_CINDER_NETAPP=$(set +o | grep xtrace) set +o xtrace @@ -70,7 +70,7 @@ function cleanup_cinder_backend_netapp_nfs { # Restore xtrace -$MY_XTRACE +$_XTRACE_CINDER_NETAPP # Local variables: # mode: shell-script diff --git a/lib/cinder_backends/nfs b/lib/cinder_backends/nfs index fc51b2b440..89a37a1f02 100644 --- a/lib/cinder_backends/nfs +++ b/lib/cinder_backends/nfs @@ -19,7 +19,7 @@ # configure_cinder_backend_nfs - Configure Cinder for NFS backends # Save trace setting -NFS_XTRACE=$(set +o | grep xtrace) +_XTRACE_CINDER_NFS=$(set +o | grep xtrace) set +o xtrace @@ -38,7 +38,7 @@ function configure_cinder_backend_nfs { # Restore xtrace -$NFS_XTRACE +$_XTRACE_CINDER_NFS # Local variables: # mode: shell-script diff --git a/lib/cinder_backends/solidfire b/lib/cinder_backends/solidfire deleted file mode 100644 index 7cc70fc86d..0000000000 --- a/lib/cinder_backends/solidfire +++ /dev/null @@ -1,49 +0,0 @@ -#!/bin/bash -# -# lib/cinder_backends/solidfire -# Configure the solidfire driver - -# Enable with: -# -# CINDER_ENABLED_BACKENDS+=,solidfire: - -# Dependencies: -# -# - ``functions`` file -# - ``cinder`` configurations - -# CINDER_CONF - -# configure_cinder_driver - make configuration changes, including those to other services - -# Save trace setting -MY_XTRACE=$(set +o | grep xtrace) -set +o xtrace - - -# Entry Points -# ------------ - -# configure_cinder_backend_solidfire - Set config files, create data dirs, etc -function configure_cinder_backend_solidfire { - # To use SolidFire, set the following in local.conf: - # CINDER_ENABLED_BACKENDS+=,solidfire: - # SAN_IP= - # SAN_LOGIN= - # SAN_PASSWORD= - - local be_name=$1 - iniset $CINDER_CONF $be_name volume_backend_name $be_name - iniset $CINDER_CONF $be_name volume_driver "cinder.volume.drivers.solidfire.SolidFireDriver" - iniset $CINDER_CONF $be_name san_ip $SAN_IP - iniset $CINDER_CONF $be_name san_login $SAN_LOGIN - iniset $CINDER_CONF $be_name san_password $SAN_PASSWORD -} - - -# Restore xtrace -$MY_XTRACE - -# Local variables: -# mode: shell-script -# End: diff --git a/lib/cinder_backends/vmdk b/lib/cinder_backends/vmdk index d5b945354b..3a6a5cf2ff 100644 --- a/lib/cinder_backends/vmdk +++ b/lib/cinder_backends/vmdk @@ -15,7 +15,7 @@ # configure_cinder_backend_vmdk - Configure Cinder for VMware vmdk backends # Save trace setting -VMDK_XTRACE=$(set +o | grep xtrace) +_XTRACE_CINDER_VMDK=$(set +o | grep xtrace) set +o xtrace @@ -40,7 +40,7 @@ function configure_cinder_backend_vmdk { # Restore xtrace -$VMDK_XTRACE +$_XTRACE_CINDER_VMDK # Local variables: # mode: shell-script diff --git a/lib/cinder_backends/xiv b/lib/cinder_backends/xiv deleted file mode 100644 index 6eadaae93b..0000000000 --- a/lib/cinder_backends/xiv +++ /dev/null @@ -1,86 +0,0 @@ -#!/bin/bash -# -# Copyright 2014 IBM Corp. -# Copyright (c) 2014 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. -# -# Authors: -# Alon Marx -# - -# lib/cinder_plugins/xiv -# Configure the xiv_ds8k driver for xiv testing - -# Enable xiv_ds8k driver for xiv with: -# -# CINDER_ENABLED_BACKENDS+=,xiv: -# XIV_DRIVER_VERSION= -# SAN_IP= -# SAN_LOGIN= -# SAN_PASSWORD= -# SAN_CLUSTERNAME= -# CONNECTION_TYPE= iscsi|fc -# XIV_CHAP= disabled|enabled - -# Dependencies: -# -# - ``functions`` file -# - ``cinder`` configurations - -# configure_cinder_backend_xiv - Configure Cinder for xiv backends - -# Save trace setting -XIV_XTRACE=$(set +o | grep xtrace) -set +o xtrace - -# Defaults -# -------- -# Set up default directories - - -# Entry Points -# ------------ - -# configure_cinder_backend_xiv - Set config files, create data dirs, etc -function configure_cinder_backend_xiv { - - local be_name=$1 - - python -c 'from xiv_ds8k_openstack.xiv_nova_proxy import XIVNovaProxy' - if [ $? -ne 0 ]; then - die $LINENO "XIV_DS8K driver is missing. Please install first" - fi - - # For reference: - # ``XIV_DS8K_BACKEND='IBM-XIV_'${SAN_IP}'_'${SAN_CLUSTERNAME}'_'${CONNECTION_TYPE}`` - iniset $CINDER_CONF DEFAULT xiv_ds8k_driver_version $XIV_DRIVER_VERSION - - iniset $CINDER_CONF $be_name san_ip $SAN_IP - iniset $CINDER_CONF $be_name san_login $SAN_LOGIN - iniset $CINDER_CONF $be_name san_password $SAN_PASSWORD - iniset $CINDER_CONF $be_name san_clustername $SAN_CLUSTERNAME - iniset $CINDER_CONF $be_name xiv_ds8k_connection_type $CONNECTION_TYPE - iniset $CINDER_CONF $be_name volume_backend_name $be_name - iniset $CINDER_CONF $be_name volume_driver 'cinder.volume.drivers.ibm.xiv_ds8k.XIVDS8KDriver' - iniset $CINDER_CONF $be_name xiv_ds8k_proxy 'xiv_ds8k_openstack.xiv_nova_proxy.XIVNovaProxy' - iniset $CINDER_CONF $be_name xiv_chap $XIV_CHAP -} - -# Restore xtrace -$XIV_XTRACE - -# Local variables: -# mode: shell-script -# End: diff --git a/lib/cinder_plugins/XenAPINFS b/lib/cinder_plugins/XenAPINFS index f7306955cb..92135e7c4f 100644 --- a/lib/cinder_plugins/XenAPINFS +++ b/lib/cinder_plugins/XenAPINFS @@ -15,7 +15,7 @@ # configure_cinder_driver - make configuration changes, including those to other services # Save trace setting -MY_XTRACE=$(set +o | grep xtrace) +_XTRACE_CINDER_XENAPINFS=$(set +o | grep xtrace) set +o xtrace @@ -39,7 +39,7 @@ function configure_cinder_driver { } # Restore xtrace -$MY_XTRACE +$_XTRACE_CINDER_XENAPINFS # Local variables: # mode: shell-script diff --git a/lib/cinder_plugins/glusterfs b/lib/cinder_plugins/glusterfs index 35ceb27ce1..329dd6c649 100644 --- a/lib/cinder_plugins/glusterfs +++ b/lib/cinder_plugins/glusterfs @@ -15,7 +15,7 @@ # configure_cinder_driver - make configuration changes, including those to other services # Save trace setting -MY_XTRACE=$(set +o | grep xtrace) +_XTRACE_CINDER_GLUSTERFS=$(set +o | grep xtrace) set +o xtrace @@ -45,7 +45,7 @@ function configure_cinder_driver { } # Restore xtrace -$MY_XTRACE +$_XTRACE_CINDER_GLUSTERFS # Local variables: # mode: shell-script diff --git a/lib/cinder_plugins/nfs b/lib/cinder_plugins/nfs index 83b39932cf..6e4ffe068e 100644 --- a/lib/cinder_plugins/nfs +++ b/lib/cinder_plugins/nfs @@ -15,7 +15,7 @@ # configure_cinder_driver - make configuration changes, including those to other services # Save trace setting -MY_XTRACE=$(set +o | grep xtrace) +_XTRACE_CINDER_NFS=$(set +o | grep xtrace) set +o xtrace @@ -36,7 +36,7 @@ function configure_cinder_driver { } # Restore xtrace -$MY_XTRACE +$_XTRACE_CINDER_NFS # Local variables: # mode: shell-script diff --git a/lib/cinder_plugins/sheepdog b/lib/cinder_plugins/sheepdog index ca343f708b..558de46c6d 100644 --- a/lib/cinder_plugins/sheepdog +++ b/lib/cinder_plugins/sheepdog @@ -15,7 +15,7 @@ # configure_cinder_driver - make configuration changes, including those to other services # Save trace setting -MY_XTRACE=$(set +o | grep xtrace) +_XTRACE_CINDER_SHEEPDOG=$(set +o | grep xtrace) set +o xtrace @@ -34,7 +34,7 @@ function configure_cinder_driver { } # Restore xtrace -$MY_XTRACE +$_XTRACE_CINDER_SHEEPDOG # Local variables: # mode: shell-script diff --git a/lib/cinder_plugins/vsphere b/lib/cinder_plugins/vsphere index f14ddf0998..1b28ffe602 100644 --- a/lib/cinder_plugins/vsphere +++ b/lib/cinder_plugins/vsphere @@ -15,7 +15,7 @@ # configure_cinder_driver - make configuration changes, including those to other services # Save trace setting -MY_XTRACE=$(set +o | grep xtrace) +_XTRACE_CINDER_VSPHERE=$(set +o | grep xtrace) set +o xtrace @@ -37,7 +37,7 @@ function configure_cinder_driver { } # Restore xtrace -$MY_XTRACE +$_XTRACE_CINDER_VSPHERE # Local variables: # mode: shell-script diff --git a/lib/database b/lib/database index ff1fafee26..0d720527df 100644 --- a/lib/database +++ b/lib/database @@ -20,7 +20,7 @@ # and call register_database $DATABASE_TYPE # Save trace setting -XTRACE=$(set +o | grep xtrace) +_XTRACE_LIB_DB=$(set +o | grep xtrace) set +o xtrace DATABASE_BACKENDS="" @@ -70,10 +70,19 @@ function initialize_database_backends { # For backward-compatibility, read in the MYSQL_HOST/USER variables and use # them as the default values for the DATABASE_HOST/USER variables. - MYSQL_HOST=${MYSQL_HOST:-127.0.0.1} + MYSQL_HOST=${MYSQL_HOST:-$SERVICE_LOCAL_HOST} MYSQL_USER=${MYSQL_USER:-root} - DATABASE_HOST=${DATABASE_HOST:-${MYSQL_HOST}} + # Set DATABASE_HOST equal to MYSQL_HOST. If SERVICE_IP_VERSION is equal to 6, + # set DATABASE_HOST equal to [MYSQL_HOST]. MYSQL_HOST cannot use brackets due + # to mysql not using bracketing for IPv6 addresses. DATABASE_HOST must have brackets + # due to sqlalchemy only reading IPv6 addresses with brackets. + if [[ "$SERVICE_IP_VERSION" == 6 ]]; then + DATABASE_HOST=${DATABASE_HOST:-[$MYSQL_HOST]} + else + DATABASE_HOST=${DATABASE_HOST:-${MYSQL_HOST}} + fi + DATABASE_USER=${DATABASE_USER:-${MYSQL_USER}} if [ -n "$MYSQL_PASSWORD" ]; then @@ -92,7 +101,7 @@ function initialize_database_backends { # a multi-node DevStack installation. # NOTE: Don't specify ``/db`` in this string so we can use it for multiple services - BASE_SQL_CONN=${BASE_SQL_CONN:-$(get_database_type)://$DATABASE_USER:$DATABASE_PASSWORD@$DATABASE_HOST} + BASE_SQL_CONN=${BASE_SQL_CONN:-$(get_database_type_$DATABASE_TYPE)://$DATABASE_USER:$DATABASE_PASSWORD@$DATABASE_HOST} return 0 } @@ -126,17 +135,9 @@ function database_connection_url { database_connection_url_$DATABASE_TYPE $db } -function get_database_type { - if [[ -n "${SQLALCHEMY_DATABASE_DRIVER}" ]]; then - echo "${DATABASE_TYPE}+${SQLALCHEMY_DATABASE_DRIVER}" - else - echo "${DATABASE_TYPE}" - fi -} - # Restore xtrace -$XTRACE +$_XTRACE_LIB_DB # Tell emacs to use shell-script-mode ## Local variables: diff --git a/lib/databases/mysql b/lib/databases/mysql index 1b9a08199f..ac0c083c91 100644 --- a/lib/databases/mysql +++ b/lib/databases/mysql @@ -8,34 +8,42 @@ # - DATABASE_{HOST,USER,PASSWORD} must be defined # Save trace setting -MY_XTRACE=$(set +o | grep xtrace) +_XTRACE_DB_MYSQL=$(set +o | grep xtrace) set +o xtrace +MYSQL_DRIVER=${MYSQL_DRIVER:-PyMySQL} register_database mysql -# Linux distros, thank you for being incredibly consistent -MYSQL=mysql -if is_fedora && ! is_oraclelinux; then - MYSQL=mariadb +MYSQL_SERVICE_NAME=mysql +if is_suse || is_fedora && ! is_oraclelinux; then + MYSQL_SERVICE_NAME=mariadb fi # Functions # --------- +function get_database_type_mysql { + if [[ "$MYSQL_DRIVER" == "PyMySQL" ]]; then + echo mysql+pymysql + else + echo mysql + fi +} + # Get rid of everything enough to cleanly change database backends function cleanup_database_mysql { - stop_service $MYSQL + stop_service $MYSQL_SERVICE_NAME if is_ubuntu; then # Get ruthless with mysql apt_get purge -y mysql* mariadb* sudo rm -rf /var/lib/mysql sudo rm -rf /etc/mysql return - elif is_suse || is_oraclelinux; then + elif is_oraclelinux; then uninstall_package mysql-community-server sudo rm -rf /var/lib/mysql - elif is_fedora; then + elif is_suse || is_fedora; then uninstall_package mariadb-server sudo rm -rf /var/lib/mysql else @@ -55,13 +63,14 @@ function configure_database_mysql { if is_ubuntu; then my_conf=/etc/mysql/my.cnf - mysql=mysql elif is_suse || is_oraclelinux; then my_conf=/etc/my.cnf - mysql=mysql elif is_fedora; then - mysql=mariadb my_conf=/etc/my.cnf + local cracklib_conf=/etc/my.cnf.d/cracklib_password_check.cnf + if [ -f "$cracklib_conf" ]; then + inicomment -sudo "$cracklib_conf" "mariadb" "plugin-load-add" + fi else exit_distro_not_supported "mysql configuration" fi @@ -69,27 +78,27 @@ function configure_database_mysql { # Start mysql-server if is_fedora || is_suse; then # service is not started by default - start_service $mysql + start_service $MYSQL_SERVICE_NAME fi # Set the root password - only works the first time. For Ubuntu, we already - # did that with debconf before installing the package. - if ! is_ubuntu; then - sudo mysqladmin -u root password $DATABASE_PASSWORD || true - fi + # did that with debconf before installing the package, but we still try, + # because the package might have been installed already. + sudo mysqladmin -u root password $DATABASE_PASSWORD || true - # Update the DB to give user ‘$DATABASE_USER’@’%’ full control of the all databases: + # Update the DB to give user '$DATABASE_USER'@'%' full control of the all databases: sudo mysql -uroot -p$DATABASE_PASSWORD -h127.0.0.1 -e "GRANT ALL PRIVILEGES ON *.* TO '$DATABASE_USER'@'%' identified by '$DATABASE_PASSWORD';" # Now update ``my.cnf`` for some local needs and restart the mysql service - # Change ‘bind-address’ from localhost (127.0.0.1) to any (0.0.0.0) and + # Change bind-address from localhost (127.0.0.1) to any (::) and # set default db type to InnoDB - sudo bash -c "source $TOP_DIR/functions && \ - iniset $my_conf mysqld bind-address 0.0.0.0 && \ - iniset $my_conf mysqld sql_mode STRICT_ALL_TABLES && \ - iniset $my_conf mysqld default-storage-engine InnoDB" - + iniset -sudo $my_conf mysqld bind-address "$(ipv6_unquote $SERVICE_LISTEN_ADDRESS)" + iniset -sudo $my_conf mysqld sql_mode TRADITIONAL + iniset -sudo $my_conf mysqld default-storage-engine InnoDB + iniset -sudo $my_conf mysqld max_connections 1024 + iniset -sudo $my_conf mysqld query_cache_type OFF + iniset -sudo $my_conf mysqld query_cache_size 0 if [[ "$DATABASE_QUERY_LOGGING" == "True" ]]; then echo_summary "Enabling MySQL query logging" @@ -105,15 +114,13 @@ function configure_database_mysql { # Turn on slow query log, log all queries (any query taking longer than # 0 seconds) and log all non-indexed queries - sudo bash -c "source $TOP_DIR/functions && \ - iniset $my_conf mysqld slow-query-log 1 && \ - iniset $my_conf mysqld slow-query-log-file $slow_log && \ - iniset $my_conf mysqld long-query-time 0 && \ - iniset $my_conf mysqld log-queries-not-using-indexes 1" - + iniset -sudo $my_conf mysqld slow-query-log 1 + iniset -sudo $my_conf mysqld slow-query-log-file $slow_log + iniset -sudo $my_conf mysqld long-query-time 0 + iniset -sudo $my_conf mysqld log-queries-not-using-indexes 1 fi - restart_service $mysql + restart_service $MYSQL_SERVICE_NAME } function install_database_mysql { @@ -135,17 +142,16 @@ MYSQL_PRESEED [client] user=$DATABASE_USER password=$DATABASE_PASSWORD -host=$DATABASE_HOST +host=$MYSQL_HOST EOF chmod 0600 $HOME/.my.cnf fi # Install mysql-server - if is_suse || is_oraclelinux; then - if ! is_package_installed mariadb; then - install_package mysql-community-server - fi - elif is_fedora; then + if is_oraclelinux; then + install_package mysql-community-server + elif is_fedora || is_suse; then install_package mariadb-server + sudo systemctl enable $MYSQL_SERVICE_NAME elif is_ubuntu; then install_package mysql-server else @@ -155,8 +161,12 @@ EOF function install_database_python_mysql { # Install Python client module - pip_install_gr MySQL-python - ADDITIONAL_VENV_PACKAGES+=",MySQL-python" + pip_install_gr $MYSQL_DRIVER + if [[ "$MYSQL_DRIVER" == "MySQL-python" ]]; then + ADDITIONAL_VENV_PACKAGES+=",MySQL-python" + elif [[ "$MYSQL_DRIVER" == "PyMySQL" ]]; then + ADDITIONAL_VENV_PACKAGES+=",PyMySQL" + fi } function database_connection_url_mysql { @@ -166,7 +176,7 @@ function database_connection_url_mysql { # Restore xtrace -$MY_XTRACE +$_XTRACE_DB_MYSQL # Local variables: # mode: shell-script diff --git a/lib/databases/postgresql b/lib/databases/postgresql index e087a1e0d4..618834b550 100644 --- a/lib/databases/postgresql +++ b/lib/databases/postgresql @@ -8,7 +8,7 @@ # - DATABASE_{HOST,USER,PASSWORD} must be defined # Save trace setting -PG_XTRACE=$(set +o | grep xtrace) +_XTRACE_PG=$(set +o | grep xtrace) set +o xtrace @@ -21,6 +21,10 @@ register_database postgresql # Functions # --------- +function get_database_type_postgresql { + echo postgresql +} + # Get rid of everything enough to cleanly change database backends function cleanup_database_postgresql { stop_service postgresql @@ -43,7 +47,7 @@ function recreate_database_postgresql { } function configure_database_postgresql { - local pg_conf pg_dir pg_hba root_roles + local pg_conf pg_dir pg_hba check_role version echo_summary "Configuring and starting PostgreSQL" if is_fedora; then pg_hba=/var/lib/pgsql/data/pg_hba.conf @@ -52,6 +56,13 @@ function configure_database_postgresql { sudo postgresql-setup initdb fi elif is_ubuntu; then + version=`psql --version | cut -d ' ' -f3 | cut -d. -f1-2` + if vercmp $version '>=' 9.3; then + if [ -z "`pg_lsclusters -h`" ]; then + echo 'No PostgreSQL clusters exist; will create one' + sudo pg_createcluster $version main --start + fi + fi pg_dir=`find /etc/postgresql -name pg_hba.conf|xargs dirname` pg_hba=$pg_dir/pg_hba.conf pg_conf=$pg_dir/postgresql.conf @@ -74,8 +85,8 @@ function configure_database_postgresql { restart_service postgresql # Create the role if it's not here or else alter it. - root_roles=$(sudo -u root sudo -u postgres -i psql -t -c "SELECT 'HERE' from pg_roles where rolname='root'") - if [[ ${root_roles} == *HERE ]];then + check_role=$(sudo -u root sudo -u postgres -i psql -t -c "SELECT 'HERE' from pg_roles where rolname='$DATABASE_USER'") + if [[ ${check_role} == *HERE ]];then sudo -u root sudo -u postgres -i psql -c "ALTER ROLE $DATABASE_USER WITH SUPERUSER LOGIN PASSWORD '$DATABASE_PASSWORD'" else sudo -u root sudo -u postgres -i psql -c "CREATE ROLE $DATABASE_USER WITH SUPERUSER LOGIN PASSWORD '$DATABASE_PASSWORD'" @@ -84,6 +95,7 @@ function configure_database_postgresql { function install_database_postgresql { echo_summary "Installing postgresql" + deprecated "Use of postgresql in devstack is deprecated, and will be removed during the Pike cycle" local pgpass=$HOME/.pgpass if [[ ! -e $pgpass ]]; then cat < $pgpass @@ -97,6 +109,9 @@ EOF install_package postgresql elif is_fedora || is_suse; then install_package postgresql-server + if is_fedora; then + sudo systemctl enable postgresql + fi else exit_distro_not_supported "postgresql installation" fi @@ -115,7 +130,7 @@ function database_connection_url_postgresql { # Restore xtrace -$PG_XTRACE +$_XTRACE_PG # Local variables: # mode: shell-script diff --git a/lib/dstat b/lib/dstat index f11bfa55c0..fe38d75585 100644 --- a/lib/dstat +++ b/lib/dstat @@ -13,26 +13,31 @@ # - stop_dstat # Save trace setting -XTRACE=$(set +o | grep xtrace) +_XTRACE_DSTAT=$(set +o | grep xtrace) set +o xtrace -# start_dstat() - Start running processes, including screen +# start_dstat() - Start running processes function start_dstat { # A better kind of sysstat, with the top process per time slice - DSTAT_OPTS="-tcmndrylpg --top-cpu-adv --top-io-adv" - run_process dstat "dstat $DSTAT_OPTS" + run_process dstat "$TOP_DIR/tools/dstat.sh $LOGDIR" - # To enable peakmem_tracker add: - # enable_service peakmem_tracker + # To enable memory_tracker add: + # enable_service memory_tracker # to your localrc - run_process peakmem_tracker "$TOP_DIR/tools/peakmem_tracker.sh" + run_process memory_tracker "$TOP_DIR/tools/memory_tracker.sh" "" "root" + + # remove support for the old name when it's no longer used (sometime in Queens) + if is_service_enabled peakmem_tracker; then + deprecated "Use of peakmem_tracker in devstack is deprecated, use memory_tracker instead" + run_process peakmem_tracker "$TOP_DIR/tools/memory_tracker.sh" "" "root" + fi } # stop_dstat() stop dstat process function stop_dstat { stop_process dstat - stop_process peakmem_tracker + stop_process memory_tracker } # Restore xtrace -$XTRACE +$_XTRACE_DSTAT diff --git a/lib/etcd3 b/lib/etcd3 new file mode 100644 index 0000000000..26d07fd19e --- /dev/null +++ b/lib/etcd3 @@ -0,0 +1,123 @@ +#!/bin/bash +# +# lib/etcd3 +# +# Functions to control the installation and configuration of etcd 3.x +# that provides a key-value store (and possibly other functions). + +# Dependencies: +# +# - ``functions`` file + +# ``stack.sh`` calls the entry points in this order: +# +# - start_etcd3 +# - stop_etcd3 +# - cleanup_etcd3 + +# Save trace setting +_XTRACE_ETCD3=$(set +o | grep xtrace) +set +o xtrace + + +# Defaults +# -------- + +# Set up default values for etcd +ETCD_DATA_DIR="$DATA_DIR/etcd" +ETCD_SYSTEMD_SERVICE="devstack@etcd.service" +ETCD_BIN_DIR="$DEST/bin" + +if is_ubuntu ; then + UBUNTU_RELEASE_BASE_NUM=`lsb_release -r | awk '{print $2}' | cut -d '.' -f 1` +fi + +# start_etcd3() - Starts to run the etcd process +function start_etcd3 { + local cmd="$ETCD_BIN_DIR/etcd" + cmd+=" --name $HOSTNAME --data-dir $ETCD_DATA_DIR" + cmd+=" --initial-cluster-state new --initial-cluster-token etcd-cluster-01" + cmd+=" --initial-cluster $HOSTNAME=http://$SERVICE_HOST:$ETCD_PEER_PORT" + cmd+=" --initial-advertise-peer-urls http://$SERVICE_HOST:$ETCD_PEER_PORT" + cmd+=" --advertise-client-urls http://$SERVICE_HOST:$ETCD_PORT" + if [ "$SERVICE_LISTEN_ADDRESS" == "::" ]; then + cmd+=" --listen-peer-urls http://[::]:$ETCD_PEER_PORT " + else + cmd+=" --listen-peer-urls http://0.0.0.0:$ETCD_PEER_PORT " + fi + cmd+=" --listen-client-urls http://$SERVICE_HOST:$ETCD_PORT" + + local unitfile="$SYSTEMD_DIR/$ETCD_SYSTEMD_SERVICE" + write_user_unit_file $ETCD_SYSTEMD_SERVICE "$cmd" "" "root" + + iniset -sudo $unitfile "Unit" "After" "network.target" + iniset -sudo $unitfile "Service" "Type" "notify" + iniset -sudo $unitfile "Service" "Restart" "on-failure" + iniset -sudo $unitfile "Service" "LimitNOFILE" "65536" + if is_arch "aarch64"; then + iniset -sudo $unitfile "Service" "Environment" "ETCD_UNSUPPORTED_ARCH=arm64" + fi + + $SYSTEMCTL daemon-reload + $SYSTEMCTL enable $ETCD_SYSTEMD_SERVICE + $SYSTEMCTL start $ETCD_SYSTEMD_SERVICE +} + +# stop_etcd3() stops the etcd3 process +function stop_etcd3 { + # Don't install in sub nodes (multinode scenario) + if [ "$SERVICE_HOST" != "$HOST_IP" ]; then + return + fi + + $SYSTEMCTL stop $ETCD_SYSTEMD_SERVICE +} + +function cleanup_etcd3 { + # Don't install in sub nodes (multinode scenario) + if [ "$SERVICE_HOST" != "$HOST_IP" ]; then + return + fi + + $SYSTEMCTL disable $ETCD_SYSTEMD_SERVICE + + local unitfile="$SYSTEMD_DIR/$ETCD_SYSTEMD_SERVICE" + sudo rm -f $unitfile + + $SYSTEMCTL daemon-reload + + sudo rm -rf $ETCD_DATA_DIR +} + +function install_etcd3 { + echo "Installing etcd" + + # Create the necessary directories + sudo mkdir -p $ETCD_BIN_DIR + sudo mkdir -p $ETCD_DATA_DIR + + # Download and cache the etcd tgz for subsequent use + local etcd_file + etcd_file="$(get_extra_file $ETCD_DOWNLOAD_LOCATION)" + if [ ! -f "$FILES/etcd-$ETCD_VERSION-linux-$ETCD_ARCH/etcd" ]; then + echo "${ETCD_SHA256} $etcd_file" > $FILES/etcd.sha256sum + # NOTE(yuanke wei): rm the damaged file when checksum fails + sha256sum -c $FILES/etcd.sha256sum || (sudo rm -f $etcd_file; exit 1) + + tar xzvf $etcd_file -C $FILES + sudo cp $FILES/$ETCD_NAME/etcd $ETCD_BIN_DIR/etcd + sudo cp $FILES/$ETCD_NAME/etcdctl $ETCD_BIN_DIR/etcdctl + fi + if [ ! -f "$ETCD_BIN_DIR/etcd" ]; then + sudo cp $FILES/$ETCD_NAME/etcd $ETCD_BIN_DIR/etcd + sudo cp $FILES/$ETCD_NAME/etcdctl $ETCD_BIN_DIR/etcdctl + fi +} + +# Restore xtrace +$_XTRACE_ETCD3 + +# Tell emacs to use shell-script-mode +## Local variables: +## mode: shell-script +## End: diff --git a/lib/glance b/lib/glance index 4e1bd24ef5..94f6a22931 100644 --- a/lib/glance +++ b/lib/glance @@ -21,7 +21,7 @@ # - cleanup_glance # Save trace setting -XTRACE=$(set +o | grep xtrace) +_XTRACE_GLANCE=$(set +o | grep xtrace) set +o xtrace @@ -43,38 +43,45 @@ fi GLANCE_CACHE_DIR=${GLANCE_CACHE_DIR:=$DATA_DIR/glance/cache} GLANCE_IMAGE_DIR=${GLANCE_IMAGE_DIR:=$DATA_DIR/glance/images} +GLANCE_LOCK_DIR=${GLANCE_LOCK_DIR:=$DATA_DIR/glance/locks} GLANCE_AUTH_CACHE_DIR=${GLANCE_AUTH_CACHE_DIR:-/var/cache/glance} GLANCE_CONF_DIR=${GLANCE_CONF_DIR:-/etc/glance} GLANCE_METADEF_DIR=$GLANCE_CONF_DIR/metadefs GLANCE_REGISTRY_CONF=$GLANCE_CONF_DIR/glance-registry.conf GLANCE_API_CONF=$GLANCE_CONF_DIR/glance-api.conf -GLANCE_SEARCH_CONF=$GLANCE_CONF_DIR/glance-search.conf GLANCE_REGISTRY_PASTE_INI=$GLANCE_CONF_DIR/glance-registry-paste.ini GLANCE_API_PASTE_INI=$GLANCE_CONF_DIR/glance-api-paste.ini -GLANCE_SEARCH_PASTE_INI=$GLANCE_CONF_DIR/glance-search-paste.ini GLANCE_CACHE_CONF=$GLANCE_CONF_DIR/glance-cache.conf GLANCE_POLICY_JSON=$GLANCE_CONF_DIR/policy.json GLANCE_SCHEMA_JSON=$GLANCE_CONF_DIR/schema-image.json +GLANCE_SWIFT_STORE_CONF=$GLANCE_CONF_DIR/glance-swift-store.conf +GLANCE_IMAGE_IMPORT_CONF=$GLANCE_CONF_DIR/glance-image-import.conf +GLANCE_V1_ENABLED=${GLANCE_V1_ENABLED:-False} -if is_ssl_enabled_service "glance" || is_service_enabled tls-proxy; then +if is_service_enabled tls-proxy; then GLANCE_SERVICE_PROTOCOL="https" fi # Glance connection info. Note the port must be specified. GLANCE_SERVICE_HOST=${GLANCE_SERVICE_HOST:-$SERVICE_HOST} +GLANCE_SERVICE_LISTEN_ADDRESS=${GLANCE_SERVICE_LISTEN_ADDRESS:-$(ipv6_unquote $SERVICE_LISTEN_ADDRESS)} GLANCE_SERVICE_PORT=${GLANCE_SERVICE_PORT:-9292} GLANCE_SERVICE_PORT_INT=${GLANCE_SERVICE_PORT_INT:-19292} GLANCE_HOSTPORT=${GLANCE_HOSTPORT:-$GLANCE_SERVICE_HOST:$GLANCE_SERVICE_PORT} GLANCE_SERVICE_PROTOCOL=${GLANCE_SERVICE_PROTOCOL:-$SERVICE_PROTOCOL} GLANCE_REGISTRY_PORT=${GLANCE_REGISTRY_PORT:-9191} GLANCE_REGISTRY_PORT_INT=${GLANCE_REGISTRY_PORT_INT:-19191} -GLANCE_SEARCH_PORT=${GLANCE_SEARCH_PORT:-9393} -GLANCE_SEARCH_PORT_INT=${GLANCE_SEARCH_PORT_INT:-19393} -GLANCE_SEARCH_HOSTPORT=${GLANCE_SEARCH_HOSTPORT:-$GLANCE_SERVICE_HOST:$GLANCE_SEARCH_PORT} - -# Tell Tempest this project is present -TEMPEST_SERVICES+=,glance +GLANCE_UWSGI=$GLANCE_BIN_DIR/glance-wsgi-api +GLANCE_UWSGI_CONF=$GLANCE_CONF_DIR/glance-uwsgi.ini +# If wsgi mode is uwsgi run glance under uwsgi, else default to eventlet +# TODO(mtreinish): Remove the eventlet path here and in all the similar +# conditionals below after the Pike release +if [[ "$WSGI_MODE" == "uwsgi" ]]; then + GLANCE_URL="$GLANCE_SERVICE_PROTOCOL://$GLANCE_SERVICE_HOST/image" +else + GLANCE_URL="$GLANCE_SERVICE_PROTOCOL://$GLANCE_HOSTPORT" +fi # Functions # --------- @@ -82,6 +89,7 @@ TEMPEST_SERVICES+=,glance # Test if any Glance services are enabled # is_glance_enabled function is_glance_enabled { + [[ ,${DISABLED_SERVICES} =~ ,"glance" ]] && return 1 [[ ,${ENABLED_SERVICES} =~ ,"g-" ]] && return 0 return 1 } @@ -92,42 +100,40 @@ function cleanup_glance { # kill instances (nova) # delete image files (glance) sudo rm -rf $GLANCE_CACHE_DIR $GLANCE_IMAGE_DIR $GLANCE_AUTH_CACHE_DIR - - if is_service_enabled g-search; then - ${TOP_DIR}/pkg/elasticsearch.sh stop - fi } # configure_glance() - Set config files, create data dirs, etc function configure_glance { sudo install -d -o $STACK_USER $GLANCE_CONF_DIR $GLANCE_METADEF_DIR - # Copy over our glance configurations and update them - cp $GLANCE_DIR/etc/glance-registry.conf $GLANCE_REGISTRY_CONF + # We run this here as this configures cache dirs for the auth middleware + # which is used in the api server and not in the registry. The api + # Server is configured through this function and not init_glance. + create_glance_cache_dir + + # Set non-default configuration options for registry iniset $GLANCE_REGISTRY_CONF DEFAULT debug $ENABLE_DEBUG_LOG_LEVEL - inicomment $GLANCE_REGISTRY_CONF DEFAULT log_file - local dburl=`database_connection_url glance` - iniset $GLANCE_REGISTRY_CONF DEFAULT sql_connection $dburl + iniset $GLANCE_REGISTRY_CONF DEFAULT bind_host $GLANCE_SERVICE_LISTEN_ADDRESS + iniset $GLANCE_REGISTRY_CONF DEFAULT workers $API_WORKERS + local dburl + dburl=`database_connection_url glance` + iniset $GLANCE_REGISTRY_CONF database connection $dburl iniset $GLANCE_REGISTRY_CONF DEFAULT use_syslog $SYSLOG - iniset $GLANCE_REGISTRY_CONF DEFAULT workers "$API_WORKERS" iniset $GLANCE_REGISTRY_CONF paste_deploy flavor keystone configure_auth_token_middleware $GLANCE_REGISTRY_CONF glance $GLANCE_AUTH_CACHE_DIR/registry - if is_service_enabled qpid || [ -n "$RABBIT_HOST" ] && [ -n "$RABBIT_PASSWORD" ]; then - iniset $GLANCE_REGISTRY_CONF DEFAULT notification_driver messaging - fi + iniset $GLANCE_REGISTRY_CONF oslo_messaging_notifications driver messagingv2 iniset_rpc_backend glance $GLANCE_REGISTRY_CONF + iniset $GLANCE_REGISTRY_CONF DEFAULT graceful_shutdown_timeout "$SERVICE_GRACEFUL_SHUTDOWN_TIMEOUT" - cp $GLANCE_DIR/etc/glance-api.conf $GLANCE_API_CONF + # Set non-default configuration options for the API server iniset $GLANCE_API_CONF DEFAULT debug $ENABLE_DEBUG_LOG_LEVEL - inicomment $GLANCE_API_CONF DEFAULT log_file - iniset $GLANCE_API_CONF DEFAULT sql_connection $dburl + iniset $GLANCE_API_CONF database connection $dburl iniset $GLANCE_API_CONF DEFAULT use_syslog $SYSLOG iniset $GLANCE_API_CONF DEFAULT image_cache_dir $GLANCE_CACHE_DIR/ + iniset $GLANCE_API_CONF DEFAULT lock_path $GLANCE_LOCK_DIR iniset $GLANCE_API_CONF paste_deploy flavor keystone+cachemanagement configure_auth_token_middleware $GLANCE_API_CONF glance $GLANCE_AUTH_CACHE_DIR/api - if is_service_enabled qpid || [ -n "$RABBIT_HOST" ] && [ -n "$RABBIT_PASSWORD" ]; then - iniset $GLANCE_API_CONF DEFAULT notification_driver messaging - fi + iniset $GLANCE_API_CONF oslo_messaging_notifications driver messagingv2 iniset_rpc_backend glance $GLANCE_API_CONF if [ "$VIRT_DRIVER" = 'xenserver' ]; then iniset $GLANCE_API_CONF DEFAULT container_formats "ami,ari,aki,bare,ovf,tgz" @@ -137,74 +143,96 @@ function configure_glance { iniset $GLANCE_API_CONF DEFAULT disk_formats "ami,ari,aki,vhd,vmdk,raw,qcow2,vdi,iso,ploop" fi + # NOTE(flaper87): To uncomment as soon as all services consuming Glance are + # able to consume V2 entirely. + if [ "$GLANCE_V1_ENABLED" != "True" ]; then + iniset $GLANCE_API_CONF DEFAULT enable_v1_api False + fi + # Store specific configs iniset $GLANCE_API_CONF glance_store filesystem_store_datadir $GLANCE_IMAGE_DIR/ + iniset $GLANCE_API_CONF DEFAULT registry_host $(ipv6_unquote $GLANCE_SERVICE_HOST) - iniset $GLANCE_API_CONF DEFAULT workers "$API_WORKERS" + # CORS feature support - to allow calls from Horizon by default + if [ -n "$GLANCE_CORS_ALLOWED_ORIGIN" ]; then + iniset $GLANCE_API_CONF cors allowed_origin "$GLANCE_CORS_ALLOWED_ORIGIN" + else + iniset $GLANCE_API_CONF cors allowed_origin "http://$SERVICE_HOST" + fi # Store the images in swift if enabled. if is_service_enabled s-proxy; then iniset $GLANCE_API_CONF glance_store default_store swift - iniset $GLANCE_API_CONF glance_store swift_store_auth_address $KEYSTONE_SERVICE_URI/v2.0/ - iniset $GLANCE_API_CONF glance_store swift_store_user $SERVICE_TENANT_NAME:glance-swift - iniset $GLANCE_API_CONF glance_store swift_store_key $SERVICE_PASSWORD iniset $GLANCE_API_CONF glance_store swift_store_create_container_on_put True + if python3_enabled; then + iniset $GLANCE_API_CONF glance_store swift_store_auth_insecure True + fi + + iniset $GLANCE_API_CONF glance_store swift_store_config_file $GLANCE_SWIFT_STORE_CONF + iniset $GLANCE_API_CONF glance_store default_swift_reference ref1 iniset $GLANCE_API_CONF glance_store stores "file, http, swift" + iniset $GLANCE_API_CONF DEFAULT graceful_shutdown_timeout "$SERVICE_GRACEFUL_SHUTDOWN_TIMEOUT" + + iniset $GLANCE_SWIFT_STORE_CONF ref1 user $SERVICE_PROJECT_NAME:glance-swift + + iniset $GLANCE_SWIFT_STORE_CONF ref1 key $SERVICE_PASSWORD + if python3_enabled; then + # NOTE(dims): Currently the glance_store+swift does not support either an insecure flag + # or ability to specify the CACERT. So fallback to http:// url + iniset $GLANCE_SWIFT_STORE_CONF ref1 auth_address ${KEYSTONE_SERVICE_URI/https/http}/v3 + else + iniset $GLANCE_SWIFT_STORE_CONF ref1 auth_address $KEYSTONE_SERVICE_URI/v3 + fi + iniset $GLANCE_SWIFT_STORE_CONF ref1 auth_version 3 fi + # We need to tell glance what it's public endpoint is so that the version + # discovery document will be correct + iniset $GLANCE_API_CONF DEFAULT public_endpoint $GLANCE_URL + if is_service_enabled tls-proxy; then iniset $GLANCE_API_CONF DEFAULT bind_port $GLANCE_SERVICE_PORT_INT iniset $GLANCE_REGISTRY_CONF DEFAULT bind_port $GLANCE_REGISTRY_PORT_INT - fi - - # Register SSL certificates if provided - if is_ssl_enabled_service glance; then - ensure_certificates GLANCE - - iniset $GLANCE_API_CONF DEFAULT cert_file "$GLANCE_SSL_CERT" - iniset $GLANCE_API_CONF DEFAULT key_file "$GLANCE_SSL_KEY" - iniset $GLANCE_REGISTRY_CONF DEFAULT cert_file "$GLANCE_SSL_CERT" - iniset $GLANCE_REGISTRY_CONF DEFAULT key_file "$GLANCE_SSL_KEY" + iniset $GLANCE_API_CONF keystone_authtoken identity_uri $KEYSTONE_AUTH_URI + iniset $GLANCE_REGISTRY_CONF keystone_authtoken identity_uri $KEYSTONE_AUTH_URI fi - if is_ssl_enabled_service glance || is_service_enabled tls-proxy; then + if is_service_enabled tls-proxy; then iniset $GLANCE_API_CONF DEFAULT registry_client_protocol https fi # Format logging - if [ "$LOG_COLOR" == "True" ] && [ "$SYSLOG" == "False" ]; then - setup_colorized_logging $GLANCE_API_CONF DEFAULT tenant user - setup_colorized_logging $GLANCE_REGISTRY_CONF DEFAULT tenant user - fi + setup_logging $GLANCE_API_CONF + setup_logging $GLANCE_REGISTRY_CONF cp -p $GLANCE_DIR/etc/glance-registry-paste.ini $GLANCE_REGISTRY_PASTE_INI - cp -p $GLANCE_DIR/etc/glance-api-paste.ini $GLANCE_API_PASTE_INI - cp $GLANCE_DIR/etc/glance-cache.conf $GLANCE_CACHE_CONF + # Set non-default configuration options for the glance-cache iniset $GLANCE_CACHE_CONF DEFAULT debug $ENABLE_DEBUG_LOG_LEVEL - inicomment $GLANCE_CACHE_CONF DEFAULT log_file iniset $GLANCE_CACHE_CONF DEFAULT use_syslog $SYSLOG iniset $GLANCE_CACHE_CONF DEFAULT image_cache_dir $GLANCE_CACHE_DIR/ - iniuncomment $GLANCE_CACHE_CONF DEFAULT auth_url - iniset $GLANCE_CACHE_CONF DEFAULT auth_url $KEYSTONE_AUTH_URI/v2.0 - iniuncomment $GLANCE_CACHE_CONF DEFAULT auth_tenant_name - iniset $GLANCE_CACHE_CONF DEFAULT admin_tenant_name $SERVICE_TENANT_NAME - iniuncomment $GLANCE_CACHE_CONF DEFAULT auth_user + iniset $GLANCE_CACHE_CONF DEFAULT auth_url $KEYSTONE_AUTH_URI + iniset $GLANCE_CACHE_CONF DEFAULT admin_tenant_name $SERVICE_PROJECT_NAME iniset $GLANCE_CACHE_CONF DEFAULT admin_user glance - iniuncomment $GLANCE_CACHE_CONF DEFAULT auth_password iniset $GLANCE_CACHE_CONF DEFAULT admin_password $SERVICE_PASSWORD + iniset $GLANCE_CACHE_CONF DEFAULT registry_host $(ipv6_unquote $GLANCE_SERVICE_HOST) # Store specific confs iniset $GLANCE_CACHE_CONF glance_store filesystem_store_datadir $GLANCE_IMAGE_DIR/ + # Set default configuration options for the glance-image-import + iniset $GLANCE_IMAGE_IMPORT_CONF image_import_opts image_import_plugins [] + iniset $GLANCE_IMAGE_IMPORT_CONF inject_metadata_properties ignore_user_roles admin + iniset $GLANCE_IMAGE_IMPORT_CONF inject_metadata_properties inject + cp -p $GLANCE_DIR/etc/policy.json $GLANCE_POLICY_JSON cp -p $GLANCE_DIR/etc/schema-image.json $GLANCE_SCHEMA_JSON cp -p $GLANCE_DIR/etc/metadefs/*.json $GLANCE_METADEF_DIR - if is_ssl_enabled_service "cinder" || is_service_enabled tls-proxy; then + if is_service_enabled tls-proxy; then CINDER_SERVICE_HOST=${CINDER_SERVICE_HOST:-$SERVICE_HOST} CINDER_SERVICE_PORT=${CINDER_SERVICE_PORT:-8776} @@ -212,27 +240,11 @@ function configure_glance { iniset $GLANCE_CACHE_CONF DEFAULT cinder_endpoint_template "https://$CINDER_SERVICE_HOST:$CINDER_SERVICE_PORT/v1/%(project_id)s" fi - # Configure search - if is_service_enabled g-search; then - cp $GLANCE_DIR/etc/glance-search.conf $GLANCE_SEARCH_CONF - iniset $GLANCE_SEARCH_CONF DEFAULT debug $ENABLE_DEBUG_LOG_LEVEL - inicomment $GLANCE_SEARCH_CONF DEFAULT log_file - iniset $GLANCE_SEARCH_CONF DEFAULT use_syslog $SYSLOG - iniset $GLANCE_SEARCH_CONF DEFAULT sql_connection $dburl - iniset $GLANCE_SEARCH_CONF paste_deploy flavor keystone - configure_auth_token_middleware $GLANCE_SEARCH_CONF glance $GLANCE_AUTH_CACHE_DIR/search - - if is_service_enabled tls-proxy; then - iniset $GLANCE_SEARCH_CONF DEFAULT bind_port $GLANCE_SEARCH_PORT_INT - fi - # Register SSL certificates if provided - if is_ssl_enabled_service glance; then - ensure_certificates GLANCE - iniset $GLANCE_SEARCH_CONF DEFAULT cert_file "$GLANCE_SSL_CERT" - iniset $GLANCE_SEARCH_CONF DEFAULT key_file "$GLANCE_SSL_KEY" - fi - - cp $GLANCE_DIR/etc/glance-search-paste.ini $GLANCE_SEARCH_PASTE_INI + if [[ "$WSGI_MODE" == "uwsgi" ]]; then + write_local_uwsgi_http_config "$GLANCE_UWSGI_CONF" "$GLANCE_UWSGI" "/image" + else + iniset $GLANCE_API_CONF DEFAULT bind_host $GLANCE_SERVICE_LISTEN_ADDRESS + iniset $GLANCE_API_CONF DEFAULT workers "$API_WORKERS" fi } @@ -240,9 +252,9 @@ function configure_glance { # Project User Roles # --------------------------------------------------------------------- -# SERVICE_TENANT_NAME glance service -# SERVICE_TENANT_NAME glance-swift ResellerAdmin (if Swift is enabled) -# SERVICE_TENANT_NAME glance-search search (if Search is enabled) +# SERVICE_PROJECT_NAME glance service +# SERVICE_PROJECT_NAME glance-swift ResellerAdmin (if Swift is enabled) +# SERVICE_PROJECT_NAME glance-search search (if Search is enabled) function create_glance_accounts { if is_service_enabled g-api; then @@ -251,44 +263,27 @@ function create_glance_accounts { # required for swift access if is_service_enabled s-proxy; then - - local glance_swift_user=$(get_or_create_user "glance-swift" \ - "$SERVICE_PASSWORD" "glance-swift@example.com") - get_or_add_user_project_role "ResellerAdmin" $glance_swift_user $SERVICE_TENANT_NAME + create_service_user "glance-swift" "ResellerAdmin" fi - if [[ "$KEYSTONE_CATALOG_BACKEND" = 'sql' ]]; then + get_or_create_service "glance" "image" "Glance Image Service" + get_or_create_endpoint \ + "image" \ + "$REGION_NAME" \ + "$GLANCE_URL" - local glance_service=$(get_or_create_service "glance" \ - "image" "Glance Image Service") - get_or_create_endpoint $glance_service \ - "$REGION_NAME" \ - "$GLANCE_SERVICE_PROTOCOL://$GLANCE_HOSTPORT" \ - "$GLANCE_SERVICE_PROTOCOL://$GLANCE_HOSTPORT" \ - "$GLANCE_SERVICE_PROTOCOL://$GLANCE_HOSTPORT" - fi - fi - - # Add glance-search service and endpoints - if is_service_enabled g-search; then - if [[ "$KEYSTONE_CATALOG_BACKEND" = 'sql' ]]; then - local glance_search_service=$(get_or_create_service "glance-search" \ - "search" "EXPERIMENTAL - Glance Graffiti Search Service") - - get_or_create_endpoint $glance_search_service \ - "$REGION_NAME" \ - "$GLANCE_SERVICE_PROTOCOL://$GLANCE_SEARCH_HOSTPORT" \ - "$GLANCE_SERVICE_PROTOCOL://$GLANCE_SEARCH_HOSTPORT" \ - "$GLANCE_SERVICE_PROTOCOL://$GLANCE_SEARCH_HOSTPORT" - fi + # Note(frickler): Crude workaround for https://bugs.launchpad.net/glance-store/+bug/1620999 + service_domain_id=$(get_or_create_domain $SERVICE_DOMAIN_NAME) + iniset $GLANCE_SWIFT_STORE_CONF ref1 project_domain_id $service_domain_id + iniset $GLANCE_SWIFT_STORE_CONF ref1 user_domain_id $service_domain_id fi } -# create_glance_cache_dir() - Part of the init_glance() process +# create_glance_cache_dir() - Part of the configure_glance() process function create_glance_cache_dir { # Create cache dir - sudo install -d -o $STACK_USER $GLANCE_AUTH_CACHE_DIR/api $GLANCE_AUTH_CACHE_DIR/registry $GLANCE_AUTH_CACHE_DIR/search - rm -f $GLANCE_AUTH_CACHE_DIR/api/* $GLANCE_AUTH_CACHE_DIR/registry/* $GLANCE_AUTH_CACHE_DIR/search/* + sudo install -d -o $STACK_USER $GLANCE_AUTH_CACHE_DIR/api $GLANCE_AUTH_CACHE_DIR/registry $GLANCE_AUTH_CACHE_DIR/search $GLANCE_AUTH_CACHE_DIR/artifact + rm -f $GLANCE_AUTH_CACHE_DIR/api/* $GLANCE_AUTH_CACHE_DIR/registry/* $GLANCE_AUTH_CACHE_DIR/search/* $GLANCE_AUTH_CACHE_DIR/artifact/* } # init_glance() - Initialize databases, etc. @@ -304,19 +299,13 @@ function init_glance { # (Re)create glance database recreate_database glance + time_start "dbsync" # Migrate glance database - $GLANCE_BIN_DIR/glance-manage db_sync + $GLANCE_BIN_DIR/glance-manage --config-file $GLANCE_CONF_DIR/glance-api.conf db_sync # Load metadata definitions - $GLANCE_BIN_DIR/glance-manage db_load_metadefs - - create_glance_cache_dir - - # Init glance search by exporting found metadefs/images to elasticsearch - if is_service_enabled g-search; then - ${TOP_DIR}/pkg/elasticsearch.sh start - $GLANCE_BIN_DIR/glance-index - fi + $GLANCE_BIN_DIR/glance-manage --config-file $GLANCE_CONF_DIR/glance-api.conf db_load_metadefs + time_stop "dbsync" } # install_glanceclient() - Collect source and prepare @@ -339,58 +328,40 @@ function install_glance { git_clone $GLANCE_REPO $GLANCE_DIR $GLANCE_BRANCH - if is_service_enabled g-search; then - ${TOP_DIR}/pkg/elasticsearch.sh download - ${TOP_DIR}/pkg/elasticsearch.sh install - fi - setup_develop $GLANCE_DIR } -# start_glance() - Start running processes, including screen +# start_glance() - Start running processes function start_glance { local service_protocol=$GLANCE_SERVICE_PROTOCOL if is_service_enabled tls-proxy; then - start_tls_proxy '*' $GLANCE_SERVICE_PORT $GLANCE_SERVICE_HOST $GLANCE_SERVICE_PORT_INT & - start_tls_proxy '*' $GLANCE_REGISTRY_PORT $GLANCE_SERVICE_HOST $GLANCE_REGISTRY_PORT_INT & - - # Handle g-search - if is_service_enabled g-search; then - start_tls_proxy '*' $GLANCE_SEARCH_PORT $GLANCE_SERVICE_HOST $GLANCE_SEARCH_PORT_INT & + if [[ "$WSGI_MODE" != "uwsgi" ]]; then + start_tls_proxy glance-service '*' $GLANCE_SERVICE_PORT $GLANCE_SERVICE_HOST $GLANCE_SERVICE_PORT_INT fi + start_tls_proxy glance-registry '*' $GLANCE_REGISTRY_PORT $GLANCE_SERVICE_HOST $GLANCE_REGISTRY_PORT_INT fi run_process g-reg "$GLANCE_BIN_DIR/glance-registry --config-file=$GLANCE_CONF_DIR/glance-registry.conf" - run_process g-api "$GLANCE_BIN_DIR/glance-api --config-file=$GLANCE_CONF_DIR/glance-api.conf" - - echo "Waiting for g-api ($GLANCE_HOSTPORT) to start..." - if ! wait_for_service $SERVICE_TIMEOUT $GLANCE_SERVICE_PROTOCOL://$GLANCE_HOSTPORT; then - die $LINENO "g-api did not start" + if [[ "$WSGI_MODE" == "uwsgi" ]]; then + run_process g-api "$GLANCE_BIN_DIR/uwsgi --procname-prefix glance-api --ini $GLANCE_UWSGI_CONF" + else + run_process g-api "$GLANCE_BIN_DIR/glance-api --config-file=$GLANCE_CONF_DIR/glance-api.conf" fi - # Start g-search after g-reg/g-api - if is_service_enabled g-search; then - run_process g-search "$GLANCE_BIN_DIR/glance-search --config-file=$GLANCE_CONF_DIR/glance-search.conf" - echo "Waiting for g-search ($GLANCE_SEARCH_HOSTPORT) to start..." - if ! wait_for_service $SERVICE_TIMEOUT $GLANCE_SERVICE_PROTOCOL://$GLANCE_SEARCH_HOSTPORT; then - die $LINENO "g-search did not start" - fi + echo "Waiting for g-api ($GLANCE_SERVICE_HOST) to start..." + if ! wait_for_service $SERVICE_TIMEOUT $GLANCE_URL; then + die $LINENO "g-api did not start" fi } # stop_glance() - Stop running processes function stop_glance { - # Kill the Glance screen windows stop_process g-api stop_process g-reg - - if is_service_enabled g-search; then - stop_process g-search - fi } # Restore xtrace -$XTRACE +$_XTRACE_GLANCE # Tell emacs to use shell-script-mode ## Local variables: diff --git a/lib/heat b/lib/heat deleted file mode 100644 index 5cb0dbf6d9..0000000000 --- a/lib/heat +++ /dev/null @@ -1,347 +0,0 @@ -#!/bin/bash -# -# lib/heat -# Install and start **Heat** service - -# To enable, add the following to localrc -# -# ENABLED_SERVICES+=,heat,h-api,h-api-cfn,h-api-cw,h-eng - -# Dependencies: -# (none) - -# stack.sh -# --------- -# - install_heatclient -# - install_heat -# - configure_heatclient -# - configure_heat -# - init_heat -# - start_heat -# - stop_heat -# - cleanup_heat - -# Save trace setting -XTRACE=$(set +o | grep xtrace) -set +o xtrace - - -# Defaults -# -------- - -# set up default directories -GITDIR["python-heatclient"]=$DEST/python-heatclient - -HEAT_DIR=$DEST/heat -HEAT_CFNTOOLS_DIR=$DEST/heat-cfntools -HEAT_TEMPLATES_REPO_DIR=$DEST/heat-templates -OCC_DIR=$DEST/os-collect-config -DIB_UTILS_DIR=$DEST/dib-utils -ORC_DIR=$DEST/os-refresh-config -OAC_DIR=$DEST/os-apply-config - -HEAT_PIP_REPO=$DATA_DIR/heat-pip-repo -HEAT_PIP_REPO_PORT=${HEAT_PIP_REPO_PORT:-8899} - -HEAT_AUTH_CACHE_DIR=${HEAT_AUTH_CACHE_DIR:-/var/cache/heat} -HEAT_STANDALONE=$(trueorfalse False HEAT_STANDALONE) -HEAT_ENABLE_ADOPT_ABANDON=$(trueorfalse False HEAT_ENABLE_ADOPT_ABANDON) -HEAT_CONF_DIR=/etc/heat -HEAT_CONF=$HEAT_CONF_DIR/heat.conf -HEAT_ENV_DIR=$HEAT_CONF_DIR/environment.d -HEAT_TEMPLATES_DIR=$HEAT_CONF_DIR/templates -HEAT_API_HOST=${HEAT_API_HOST:-$HOST_IP} -HEAT_API_PORT=${HEAT_API_PORT:-8004} - - -# other default options -if [[ "$HEAT_STANDALONE" = "True" ]]; then - # for standalone, use defaults which require no service user - HEAT_STACK_DOMAIN=`trueorfalse False $HEAT_STACK_DOMAIN` - HEAT_DEFERRED_AUTH=${HEAT_DEFERRED_AUTH:-password} -else - HEAT_STACK_DOMAIN=`trueorfalse True $HEAT_STACK_DOMAIN` - HEAT_DEFERRED_AUTH=${HEAT_DEFERRED_AUTH:-trusts} -fi - -# Tell Tempest this project is present -TEMPEST_SERVICES+=,heat - - -# Functions -# --------- - -# Test if any Heat services are enabled -# is_heat_enabled -function is_heat_enabled { - [[ ,${ENABLED_SERVICES} =~ ,"h-" ]] && return 0 - return 1 -} - -# cleanup_heat() - Remove residual data files, anything left over from previous -# runs that a clean run would need to clean up -function cleanup_heat { - sudo rm -rf $HEAT_AUTH_CACHE_DIR - sudo rm -rf $HEAT_ENV_DIR - sudo rm -rf $HEAT_TEMPLATES_DIR - sudo rm -rf $HEAT_CONF_DIR -} - -# configure_heat() - Set config files, create data dirs, etc -function configure_heat { - - sudo install -d -o $STACK_USER $HEAT_CONF_DIR - # remove old config files - rm -f $HEAT_CONF_DIR/heat-*.conf - - HEAT_API_CFN_HOST=${HEAT_API_CFN_HOST:-$HOST_IP} - HEAT_API_CFN_PORT=${HEAT_API_CFN_PORT:-8000} - HEAT_ENGINE_HOST=${HEAT_ENGINE_HOST:-$SERVICE_HOST} - HEAT_ENGINE_PORT=${HEAT_ENGINE_PORT:-8001} - HEAT_API_CW_HOST=${HEAT_API_CW_HOST:-$HOST_IP} - HEAT_API_CW_PORT=${HEAT_API_CW_PORT:-8003} - HEAT_API_PASTE_FILE=$HEAT_CONF_DIR/api-paste.ini - HEAT_POLICY_FILE=$HEAT_CONF_DIR/policy.json - - cp $HEAT_DIR/etc/heat/api-paste.ini $HEAT_API_PASTE_FILE - cp $HEAT_DIR/etc/heat/policy.json $HEAT_POLICY_FILE - - # common options - iniset_rpc_backend heat $HEAT_CONF - iniset $HEAT_CONF DEFAULT heat_metadata_server_url http://$HEAT_API_CFN_HOST:$HEAT_API_CFN_PORT - iniset $HEAT_CONF DEFAULT heat_waitcondition_server_url http://$HEAT_API_CFN_HOST:$HEAT_API_CFN_PORT/v1/waitcondition - iniset $HEAT_CONF DEFAULT heat_watch_server_url http://$HEAT_API_CW_HOST:$HEAT_API_CW_PORT - iniset $HEAT_CONF database connection `database_connection_url heat` - iniset $HEAT_CONF DEFAULT auth_encryption_key $(generate_hex_string 16) - - iniset $HEAT_CONF DEFAULT region_name_for_services "$REGION_NAME" - - # logging - iniset $HEAT_CONF DEFAULT debug $ENABLE_DEBUG_LOG_LEVEL - iniset $HEAT_CONF DEFAULT use_syslog $SYSLOG - if [ "$LOG_COLOR" == "True" ] && [ "$SYSLOG" == "False" ]; then - # Add color to logging output - setup_colorized_logging $HEAT_CONF DEFAULT tenant user - fi - - iniset $HEAT_CONF DEFAULT deferred_auth_method $HEAT_DEFERRED_AUTH - - # NOTE(jamielennox): heat re-uses specific values from the - # keystone_authtoken middleware group and so currently fails when using the - # auth plugin setup. This should be fixed in heat. Heat is also the only - # service that requires the auth_uri to include a /v2.0. Remove this custom - # setup when bug #1300246 is resolved. - iniset $HEAT_CONF keystone_authtoken auth_uri $KEYSTONE_SERVICE_URI/v2.0 - if [[ "$HEAT_STANDALONE" = "True" ]]; then - iniset $HEAT_CONF paste_deploy flavor standalone - iniset $HEAT_CONF clients_heat url "http://$HEAT_API_HOST:$HEAT_API_PORT/v1/%(tenant_id)s" - else - iniset $HEAT_CONF keystone_authtoken identity_uri $KEYSTONE_AUTH_URI - iniset $HEAT_CONF keystone_authtoken admin_user heat - iniset $HEAT_CONF keystone_authtoken admin_password $SERVICE_PASSWORD - iniset $HEAT_CONF keystone_authtoken admin_tenant_name $SERVICE_TENANT_NAME - iniset $HEAT_CONF keystone_authtoken cafile $SSL_BUNDLE_FILE - iniset $HEAT_CONF keystone_authtoken signing_dir $HEAT_AUTH_CACHE_DIR - fi - - # ec2authtoken - iniset $HEAT_CONF ec2authtoken auth_uri $KEYSTONE_SERVICE_URI/v2.0 - - # OpenStack API - iniset $HEAT_CONF heat_api bind_port $HEAT_API_PORT - iniset $HEAT_CONF heat_api workers "$API_WORKERS" - - # Cloudformation API - iniset $HEAT_CONF heat_api_cfn bind_port $HEAT_API_CFN_PORT - - # Cloudwatch API - iniset $HEAT_CONF heat_api_cloudwatch bind_port $HEAT_API_CW_PORT - - if is_ssl_enabled_service "key" || is_service_enabled tls-proxy; then - iniset $HEAT_CONF clients_keystone ca_file $SSL_BUNDLE_FILE - fi - - if is_ssl_enabled_service "nova" || is_service_enabled tls-proxy; then - iniset $HEAT_CONF clients_nova ca_file $SSL_BUNDLE_FILE - fi - - if is_ssl_enabled_service "cinder" || is_service_enabled tls-proxy; then - iniset $HEAT_CONF clients_cinder ca_file $SSL_BUNDLE_FILE - fi - - if [[ "$HEAT_ENABLE_ADOPT_ABANDON" = "True" ]]; then - iniset $HEAT_CONF DEFAULT enable_stack_adopt true - iniset $HEAT_CONF DEFAULT enable_stack_abandon true - fi - - sudo install -d -o $STACK_USER $HEAT_ENV_DIR $HEAT_TEMPLATES_DIR - - # copy the default environment - cp $HEAT_DIR/etc/heat/environment.d/* $HEAT_ENV_DIR/ - - # copy the default templates - cp $HEAT_DIR/etc/heat/templates/* $HEAT_TEMPLATES_DIR/ - -} - -# init_heat() - Initialize database -function init_heat { - - # (re)create heat database - recreate_database heat - - $HEAT_DIR/bin/heat-manage db_sync - create_heat_cache_dir -} - -# create_heat_cache_dir() - Part of the init_heat() process -function create_heat_cache_dir { - # Create cache dirs - sudo install -d -o $STACK_USER $HEAT_AUTH_CACHE_DIR -} - -# install_heatclient() - Collect source and prepare -function install_heatclient { - if use_library_from_git "python-heatclient"; then - git_clone_by_name "python-heatclient" - setup_dev_lib "python-heatclient" - sudo install -D -m 0644 -o $STACK_USER {${GITDIR["python-heatclient"]}/tools/,/etc/bash_completion.d/}heat.bash_completion - fi -} - -# install_heat() - Collect source and prepare -function install_heat { - git_clone $HEAT_REPO $HEAT_DIR $HEAT_BRANCH - setup_develop $HEAT_DIR -} - -# install_heat_other() - Collect source and prepare -function install_heat_other { - git_clone $HEAT_CFNTOOLS_REPO $HEAT_CFNTOOLS_DIR $HEAT_CFNTOOLS_BRANCH - git_clone $HEAT_TEMPLATES_REPO $HEAT_TEMPLATES_REPO_DIR $HEAT_TEMPLATES_BRANCH - git_clone $OAC_REPO $OAC_DIR $OAC_BRANCH - git_clone $OCC_REPO $OCC_DIR $OCC_BRANCH - git_clone $ORC_REPO $ORC_DIR $ORC_BRANCH - git_clone $DIB_UTILS_REPO $DIB_UTILS_DIR $DIB_UTILS_BRANCH -} - -# start_heat() - Start running processes, including screen -function start_heat { - run_process h-eng "$HEAT_DIR/bin/heat-engine --config-file=$HEAT_CONF" - run_process h-api "$HEAT_DIR/bin/heat-api --config-file=$HEAT_CONF" - run_process h-api-cfn "$HEAT_DIR/bin/heat-api-cfn --config-file=$HEAT_CONF" - run_process h-api-cw "$HEAT_DIR/bin/heat-api-cloudwatch --config-file=$HEAT_CONF" -} - -# stop_heat() - Stop running processes -function stop_heat { - # Kill the screen windows - local serv - for serv in h-eng h-api h-api-cfn h-api-cw; do - stop_process $serv - done -} - -# create_heat_accounts() - Set up common required heat accounts -function create_heat_accounts { - if [[ "$HEAT_STANDALONE" != "True" ]]; then - - create_service_user "heat" "admin" - - if [[ "$KEYSTONE_CATALOG_BACKEND" = 'sql' ]]; then - - local heat_service=$(get_or_create_service "heat" \ - "orchestration" "Heat Orchestration Service") - get_or_create_endpoint $heat_service \ - "$REGION_NAME" \ - "$SERVICE_PROTOCOL://$HEAT_API_HOST:$HEAT_API_PORT/v1/\$(tenant_id)s" \ - "$SERVICE_PROTOCOL://$HEAT_API_HOST:$HEAT_API_PORT/v1/\$(tenant_id)s" \ - "$SERVICE_PROTOCOL://$HEAT_API_HOST:$HEAT_API_PORT/v1/\$(tenant_id)s" - - local heat_cfn_service=$(get_or_create_service "heat-cfn" \ - "cloudformation" "Heat CloudFormation Service") - get_or_create_endpoint $heat_cfn_service \ - "$REGION_NAME" \ - "$SERVICE_PROTOCOL://$HEAT_API_CFN_HOST:$HEAT_API_CFN_PORT/v1" \ - "$SERVICE_PROTOCOL://$HEAT_API_CFN_HOST:$HEAT_API_CFN_PORT/v1" \ - "$SERVICE_PROTOCOL://$HEAT_API_CFN_HOST:$HEAT_API_CFN_PORT/v1" - fi - - # heat_stack_user role is for users created by Heat - get_or_create_role "heat_stack_user" - fi - - if [[ "$HEAT_STACK_DOMAIN" == "True" ]]; then - # Note we have to pass token/endpoint here because the current endpoint and - # version negotiation in OSC means just --os-identity-api-version=3 won't work - D_ID=$(openstack --os-token $OS_TOKEN --os-url=$KEYSTONE_SERVICE_URI_V3 \ - --os-identity-api-version=3 domain list | grep ' heat ' | get_field 1) - - if [[ -z "$D_ID" ]]; then - D_ID=$(openstack --os-token $OS_TOKEN --os-url=$KEYSTONE_SERVICE_URI_V3 \ - --os-identity-api-version=3 domain create heat \ - --description "Owns users and projects created by heat" \ - | grep ' id ' | get_field 2) - iniset $HEAT_CONF DEFAULT stack_user_domain_id ${D_ID} - - openstack --os-token $OS_TOKEN --os-url=$KEYSTONE_SERVICE_URI_V3 \ - --os-identity-api-version=3 user create --password $SERVICE_PASSWORD \ - --domain $D_ID heat_domain_admin \ - --description "Manages users and projects created by heat" - openstack --os-token $OS_TOKEN --os-url=$KEYSTONE_SERVICE_URI_V3 \ - --os-identity-api-version=3 role add \ - --user heat_domain_admin --domain ${D_ID} admin - iniset $HEAT_CONF DEFAULT stack_domain_admin heat_domain_admin - iniset $HEAT_CONF DEFAULT stack_domain_admin_password $SERVICE_PASSWORD - fi - fi -} - -# build_heat_pip_mirror() - Build a pip mirror containing heat agent projects -function build_heat_pip_mirror { - local project_dirs="$OCC_DIR $OAC_DIR $ORC_DIR $HEAT_CFNTOOLS_DIR $DIB_UTILS_DIR" - local projpath proj package - - rm -rf $HEAT_PIP_REPO - mkdir -p $HEAT_PIP_REPO - - echo "" > $HEAT_PIP_REPO/index.html - for projpath in $project_dirs; do - proj=$(basename $projpath) - mkdir -p $HEAT_PIP_REPO/$proj - pushd $projpath - rm -rf dist - python setup.py sdist - pushd dist - package=$(ls *) - mv $package $HEAT_PIP_REPO/$proj/$package - popd - - echo "$package" > $HEAT_PIP_REPO/$proj/index.html - echo "$proj
" >> $HEAT_PIP_REPO/index.html - - popd - done - - echo "" >> $HEAT_PIP_REPO/index.html - - local heat_pip_repo_apache_conf=$(apache_site_config_for heat_pip_repo) - - sudo cp $FILES/apache-heat-pip-repo.template $heat_pip_repo_apache_conf - sudo sed -e " - s|%HEAT_PIP_REPO%|$HEAT_PIP_REPO|g; - s|%HEAT_PIP_REPO_PORT%|$HEAT_PIP_REPO_PORT|g; - s|%APACHE_NAME%|$APACHE_NAME|g; - " -i $heat_pip_repo_apache_conf - enable_apache_site heat_pip_repo - restart_apache_server - sudo iptables -I INPUT -d $HOST_IP -p tcp --dport $HEAT_PIP_REPO_PORT -j ACCEPT || true -} - -# Restore xtrace -$XTRACE - -# Tell emacs to use shell-script-mode -## Local variables: -## mode: shell-script -## End: diff --git a/lib/horizon b/lib/horizon index f953f5cc01..293a627c78 100644 --- a/lib/horizon +++ b/lib/horizon @@ -19,26 +19,19 @@ # - cleanup_horizon # Save trace setting -XTRACE=$(set +o | grep xtrace) +_XTRACE_HORIZON=$(set +o | grep xtrace) set +o xtrace # Defaults # -------- -# Set up default directories -GITDIR["django_openstack_auth"]=$DEST/django_openstack_auth - HORIZON_DIR=$DEST/horizon # local_settings.py is used to customize Dashboard settings. # The example file in Horizon repo is used by default. HORIZON_SETTINGS=${HORIZON_SETTINGS:-$HORIZON_DIR/openstack_dashboard/local/local_settings.py.example} -# Tell Tempest this project is present -TEMPEST_SERVICES+=,horizon - - # Functions # --------- @@ -53,7 +46,8 @@ function _horizon_config_set { sed -e "/^$option/d" -i $local_settings echo -e "\n$option=$value" >> $file elif grep -q "^$section" $file; then - local line=$(sed -ne "/^$section/,/^}/ { /^ *'$option':/ p; }" $file) + local line + line=$(sed -ne "/^$section/,/^}/ { /^ *'$option':/ p; }" $file) if [ -n "$line" ]; then sed -i -e "/^$section/,/^}/ s/^\( *'$option'\) *:.*$/\1: $value,/" $file else @@ -72,8 +66,8 @@ function _horizon_config_set { # cleanup_horizon() - Remove residual data files, anything left over from previous # runs that a clean run would need to clean up function cleanup_horizon { - local horizon_conf=$(apache_site_config_for horizon) - sudo rm -f $horizon_conf + disable_apache_site horizon + sudo rm -f $(apache_site_config_for horizon) } # configure_horizon() - Set config files, create data dirs, etc @@ -84,51 +78,65 @@ function configure_horizon { # Horizon is installed as develop mode, so we can compile here. # Message catalog compilation is handled by Django admin script, # so compiling them after the installation avoids Django installation twice. - (cd $HORIZON_DIR; ./run_tests.sh -N --compilemessages) -} + (cd $HORIZON_DIR; $PYTHON manage.py compilemessages) -# init_horizon() - Initialize databases, etc. -function init_horizon { # ``local_settings.py`` is used to override horizon default settings. local local_settings=$HORIZON_DIR/openstack_dashboard/local/local_settings.py cp $HORIZON_SETTINGS $local_settings + _horizon_config_set $local_settings "" WEBROOT \"$HORIZON_APACHE_ROOT/\" + _horizon_config_set $local_settings "" COMPRESS_OFFLINE True - _horizon_config_set $local_settings "" OPENSTACK_KEYSTONE_DEFAULT_ROLE \"Member\" + _horizon_config_set $local_settings "" OPENSTACK_KEYSTONE_DEFAULT_ROLE \"member\" _horizon_config_set $local_settings "" OPENSTACK_HOST \"${KEYSTONE_SERVICE_HOST}\" - _horizon_config_set $local_settings "" OPENSTACK_KEYSTONE_URL "\"${KEYSTONE_SERVICE_PROTOCOL}://${KEYSTONE_SERVICE_HOST}:${KEYSTONE_SERVICE_PORT}/v2.0\"" + + _horizon_config_set $local_settings "" OPENSTACK_API_VERSIONS {\"identity\":3} + _horizon_config_set $local_settings "" OPENSTACK_KEYSTONE_URL "\"${KEYSTONE_SERVICE_URI}/v3\"" + + # note(trebskit): if HOST_IP points at non-localhost ip address, horizon cannot be accessed + # from outside the virtual machine. This fixes is meant primarily for local development + # purpose + _horizon_config_set $local_settings "" ALLOWED_HOSTS [\"*\"] if [ -f $SSL_BUNDLE_FILE ]; then _horizon_config_set $local_settings "" OPENSTACK_SSL_CACERT \"${SSL_BUNDLE_FILE}\" fi + if is_service_enabled ldap; then + _horizon_config_set $local_settings "" OPENSTACK_KEYSTONE_MULTIDOMAIN_SUPPORT "True" + fi + # Create an empty directory that apache uses as docroot sudo mkdir -p $HORIZON_DIR/.blackhole - local horizon_conf=$(apache_site_config_for horizon) + local horizon_conf + horizon_conf=$(apache_site_config_for horizon) # Configure apache to run horizon + # Set up the django horizon application to serve via apache/wsgi sudo sh -c "sed -e \" s,%USER%,$APACHE_USER,g; s,%GROUP%,$APACHE_GROUP,g; s,%HORIZON_DIR%,$HORIZON_DIR,g; s,%APACHE_NAME%,$APACHE_NAME,g; s,%DEST%,$DEST,g; + s,%WEBROOT%,$HORIZON_APACHE_ROOT,g; \" $FILES/apache-horizon.template >$horizon_conf" if is_ubuntu; then disable_apache_site 000-default sudo touch $horizon_conf - elif is_fedora; then - sudo sed '/^Listen/s/^.*$/Listen 0.0.0.0:80/' -i /etc/httpd/conf/httpd.conf - elif is_suse; then + elif is_fedora || is_suse; then : # nothing to do else exit_distro_not_supported "horizon apache configuration" fi enable_apache_site horizon +} +# init_horizon() - Initialize databases, etc. +function init_horizon { # Remove old log files that could mess with how DevStack detects whether Horizon # has been successfully started (see start_horizon() and functions::screen_it()) # and run_process @@ -142,25 +150,12 @@ function init_horizon { django_admin=django-admin.py fi + # These need to be run after horizon plugins are configured. DJANGO_SETTINGS_MODULE=openstack_dashboard.settings $django_admin collectstatic --noinput DJANGO_SETTINGS_MODULE=openstack_dashboard.settings $django_admin compress --force } -# install_django_openstack_auth() - Collect source and prepare -function install_django_openstack_auth { - if use_library_from_git "django_openstack_auth"; then - local dir=${GITDIR["django_openstack_auth"]} - git_clone_by_name "django_openstack_auth" - # Compile message catalogs before installation - _prepare_message_catalog_compilation - (cd $dir; python setup.py compile_catalog) - setup_dev_lib "django_openstack_auth" - fi - # if we aren't using this library from git, then we just let it - # get dragged in by the horizon setup. -} - # install_horizon() - Collect source and prepare function install_horizon { # Apache installation, because we mark it NOPRIME @@ -169,26 +164,18 @@ function install_horizon { git_clone $HORIZON_REPO $HORIZON_DIR $HORIZON_BRANCH } -# start_horizon() - Start running processes, including screen +# start_horizon() - Start running processes function start_horizon { restart_apache_server - tail_log horizon /var/log/$APACHE_NAME/horizon_error.log } -# stop_horizon() - Stop running processes (non-screen) +# stop_horizon() - Stop running processes function stop_horizon { stop_apache_server } -# NOTE: It can be moved to common functions, but it is only used by compilation -# of django_openstack_auth catalogs at the moment. -function _prepare_message_catalog_compilation { - pip_install_gr Babel -} - - # Restore xtrace -$XTRACE +$_XTRACE_HORIZON # Tell emacs to use shell-script-mode ## Local variables: diff --git a/lib/infra b/lib/infra index c825b4ee56..cf003cce01 100644 --- a/lib/infra +++ b/lib/infra @@ -15,27 +15,33 @@ # - install_infra # Save trace setting -XTRACE=$(set +o | grep xtrace) +_XTRACE_INFRA=$(set +o | grep xtrace) set +o xtrace # Defaults # -------- GITDIR["pbr"]=$DEST/pbr -REQUIREMENTS_DIR=$DEST/requirements # Entry Points # ------------ # install_infra() - Collect source and prepare function install_infra { - # bring down global requirements - git_clone $REQUIREMENTS_REPO $REQUIREMENTS_DIR $REQUIREMENTS_BRANCH + local PIP_VIRTUAL_ENV="$REQUIREMENTS_DIR/.venv" + [ ! -d $PIP_VIRTUAL_ENV ] && virtualenv $PIP_VIRTUAL_ENV + # We don't care about testing git pbr in the requirements venv. + PIP_VIRTUAL_ENV=$PIP_VIRTUAL_ENV pip_install -U pbr + PIP_VIRTUAL_ENV=$PIP_VIRTUAL_ENV pip_install $REQUIREMENTS_DIR + + # Unset the PIP_VIRTUAL_ENV so that PBR does not end up trapped + # down the VENV well + unset PIP_VIRTUAL_ENV # Install pbr if use_library_from_git "pbr"; then git_clone_by_name "pbr" - setup_lib "pbr" + setup_dev_lib "pbr" else # Always upgrade pbr to latest version as we may have pulled it # in via system packages. @@ -44,7 +50,7 @@ function install_infra { } # Restore xtrace -$XTRACE +$_XTRACE_INFRA # Tell emacs to use shell-script-mode ## Local variables: diff --git a/lib/ironic b/lib/ironic deleted file mode 100644 index 4a37f0aafa..0000000000 --- a/lib/ironic +++ /dev/null @@ -1,837 +0,0 @@ -#!/bin/bash -# -# lib/ironic -# Functions to control the configuration and operation of the **Ironic** service - -# Dependencies: -# -# - ``functions`` file -# - ``DEST``, ``DATA_DIR``, ``STACK_USER`` must be defined -# - ``SERVICE_{TENANT_NAME|PASSWORD}`` must be defined -# - ``SERVICE_HOST`` -# - ``KEYSTONE_TOKEN_FORMAT`` must be defined - -# ``stack.sh`` calls the entry points in this order: -# -# - install_ironic -# - install_ironicclient -# - init_ironic -# - start_ironic -# - stop_ironic -# - cleanup_ironic - -# Save trace and pipefail settings -XTRACE=$(set +o | grep xtrace) -PIPEFAIL=$(set +o | grep pipefail) -set +o xtrace -set +o pipefail - -# Defaults -# -------- - -# Set up default directories -GITDIR["python-ironicclient"]=$DEST/python-ironicclient - -IRONIC_DIR=$DEST/ironic -IRONIC_PYTHON_AGENT_DIR=$DEST/ironic-python-agent -IRONIC_DATA_DIR=$DATA_DIR/ironic -IRONIC_STATE_PATH=/var/lib/ironic -IRONIC_AUTH_CACHE_DIR=${IRONIC_AUTH_CACHE_DIR:-/var/cache/ironic} -IRONIC_CONF_DIR=${IRONIC_CONF_DIR:-/etc/ironic} -IRONIC_CONF_FILE=$IRONIC_CONF_DIR/ironic.conf -IRONIC_ROOTWRAP_CONF=$IRONIC_CONF_DIR/rootwrap.conf -IRONIC_POLICY_JSON=$IRONIC_CONF_DIR/policy.json - -# Deploy callback timeout can be changed from its default (1800), if required. -IRONIC_CALLBACK_TIMEOUT=${IRONIC_CALLBACK_TIMEOUT:-} - -# Deploy to hardware platform -IRONIC_HW_NODE_CPU=${IRONIC_HW_NODE_CPU:-1} -IRONIC_HW_NODE_RAM=${IRONIC_HW_NODE_RAM:-512} -IRONIC_HW_NODE_DISK=${IRONIC_HW_NODE_DISK:-10} -IRONIC_HW_EPHEMERAL_DISK=${IRONIC_HW_EPHEMERAL_DISK:-0} -# The file is composed of multiple lines, each line includes four field -# separated by white space: IPMI address, MAC address, IPMI username -# and IPMI password. -# -# 192.168.110.107 00:1e:67:57:50:4c root otc123 -IRONIC_IPMIINFO_FILE=${IRONIC_IPMIINFO_FILE:-$IRONIC_DATA_DIR/hardware_info} - -# Set up defaults for functional / integration testing -IRONIC_SCRIPTS_DIR=${IRONIC_SCRIPTS_DIR:-$TOP_DIR/tools/ironic/scripts} -IRONIC_TEMPLATES_DIR=${IRONIC_TEMPLATES_DIR:-$TOP_DIR/tools/ironic/templates} -IRONIC_BAREMETAL_BASIC_OPS=$(trueorfalse False IRONIC_BAREMETAL_BASIC_OPS) -IRONIC_ENABLED_DRIVERS=${IRONIC_ENABLED_DRIVERS:-fake,pxe_ssh,pxe_ipmitool} -IRONIC_SSH_USERNAME=${IRONIC_SSH_USERNAME:-`whoami`} -IRONIC_SSH_TIMEOUT=${IRONIC_SSH_TIMEOUT:-15} -IRONIC_SSH_KEY_DIR=${IRONIC_SSH_KEY_DIR:-$IRONIC_DATA_DIR/ssh_keys} -IRONIC_SSH_KEY_FILENAME=${IRONIC_SSH_KEY_FILENAME:-ironic_key} -IRONIC_KEY_FILE=${IRONIC_KEY_FILE:-$IRONIC_SSH_KEY_DIR/$IRONIC_SSH_KEY_FILENAME} -IRONIC_SSH_VIRT_TYPE=${IRONIC_SSH_VIRT_TYPE:-virsh} -IRONIC_TFTPBOOT_DIR=${IRONIC_TFTPBOOT_DIR:-$IRONIC_DATA_DIR/tftpboot} -IRONIC_TFTPSERVER_IP=${IRONIC_TFTPSERVER_IP:-$HOST_IP} -IRONIC_VM_SSH_PORT=${IRONIC_VM_SSH_PORT:-22} -IRONIC_VM_SSH_ADDRESS=${IRONIC_VM_SSH_ADDRESS:-$HOST_IP} -IRONIC_VM_COUNT=${IRONIC_VM_COUNT:-1} -IRONIC_VM_SPECS_CPU=${IRONIC_VM_SPECS_CPU:-1} -IRONIC_VM_SPECS_RAM=${IRONIC_VM_SPECS_RAM:-512} -IRONIC_VM_SPECS_DISK=${IRONIC_VM_SPECS_DISK:-10} -IRONIC_VM_EPHEMERAL_DISK=${IRONIC_VM_EPHEMERAL_DISK:-0} -IRONIC_VM_EMULATOR=${IRONIC_VM_EMULATOR:-/usr/bin/qemu-system-x86_64} -IRONIC_VM_NETWORK_BRIDGE=${IRONIC_VM_NETWORK_BRIDGE:-brbm} -IRONIC_VM_NETWORK_RANGE=${IRONIC_VM_NETWORK_RANGE:-192.0.2.0/24} -IRONIC_VM_MACS_CSV_FILE=${IRONIC_VM_MACS_CSV_FILE:-$IRONIC_DATA_DIR/ironic_macs.csv} -IRONIC_AUTHORIZED_KEYS_FILE=${IRONIC_AUTHORIZED_KEYS_FILE:-$HOME/.ssh/authorized_keys} - -# By default, baremetal VMs will console output to file. -IRONIC_VM_LOG_CONSOLE=${IRONIC_VM_LOG_CONSOLE:-True} -IRONIC_VM_LOG_DIR=${IRONIC_VM_LOG_DIR:-$IRONIC_DATA_DIR/logs/} - -# Use DIB to create deploy ramdisk and kernel. -IRONIC_BUILD_DEPLOY_RAMDISK=$(trueorfalse True IRONIC_BUILD_DEPLOY_RAMDISK) -# If not use DIB, these files are used as deploy ramdisk/kernel. -# (The value must be a absolute path) -IRONIC_DEPLOY_RAMDISK=${IRONIC_DEPLOY_RAMDISK:-} -IRONIC_DEPLOY_KERNEL=${IRONIC_DEPLOY_KERNEL:-} -IRONIC_DEPLOY_ELEMENT=${IRONIC_DEPLOY_ELEMENT:-deploy-ironic} - -IRONIC_AGENT_KERNEL_URL=${IRONIC_AGENT_KERNEL_URL:-http://tarballs.openstack.org/ironic-python-agent/coreos/files/coreos_production_pxe.vmlinuz} -IRONIC_AGENT_RAMDISK_URL=${IRONIC_AGENT_RAMDISK_URL:-http://tarballs.openstack.org/ironic-python-agent/coreos/files/coreos_production_pxe_image-oem.cpio.gz} - -# Which deploy driver to use - valid choices right now -# are ``pxe_ssh``, ``pxe_ipmitool``, ``agent_ssh`` and ``agent_ipmitool``. -IRONIC_DEPLOY_DRIVER=${IRONIC_DEPLOY_DRIVER:-pxe_ssh} - -# TODO(agordeev): replace 'ubuntu' with host distro name getting -IRONIC_DEPLOY_FLAVOR=${IRONIC_DEPLOY_FLAVOR:-ubuntu $IRONIC_DEPLOY_ELEMENT} - -# Support entry points installation of console scripts -IRONIC_BIN_DIR=$(get_python_exec_prefix) - -# Ironic connection info. Note the port must be specified. -IRONIC_SERVICE_PROTOCOL=http -IRONIC_SERVICE_PORT=${IRONIC_SERVICE_PORT:-6385} -IRONIC_HOSTPORT=${IRONIC_HOSTPORT:-$SERVICE_HOST:$IRONIC_SERVICE_PORT} - -# Tell Tempest this project is present -TEMPEST_SERVICES+=,ironic - -# Enable iPXE -IRONIC_IPXE_ENABLED=$(trueorfalse False IRONIC_IPXE_ENABLED) -IRONIC_HTTP_DIR=${IRONIC_HTTP_DIR:-$IRONIC_DATA_DIR/httpboot} -IRONIC_HTTP_SERVER=${IRONIC_HTTP_SERVER:-$HOST_IP} -IRONIC_HTTP_PORT=${IRONIC_HTTP_PORT:-8088} - -# NOTE(lucasagomes): This flag is used to differentiate the nodes that -# uses IPA as their deploy ramdisk from nodes that uses the agent_* drivers -# (which also uses IPA but depends on Swift Temp URLs to work). At present, -# all drivers that uses the iSCSI approach for their deployment supports -# using both, IPA or bash ramdisks for the deployment. In the future we -# want to remove the support for the bash ramdisk in favor of IPA, once -# we get there this flag can be removed, and all conditionals that uses -# it should just run by default. -IRONIC_DEPLOY_DRIVER_ISCSI_WITH_IPA=$(trueorfalse False IRONIC_DEPLOY_DRIVER_ISCSI_WITH_IPA) - -# get_pxe_boot_file() - Get the PXE/iPXE boot file path -function get_pxe_boot_file { - local relpath=syslinux/pxelinux.0 - if [[ "$IRONIC_IPXE_ENABLED" == "True" ]] ; then - relpath=ipxe/undionly.kpxe - fi - - local pxe_boot_file - if is_ubuntu; then - pxe_boot_file=/usr/lib/$relpath - elif is_fedora || is_suse; then - pxe_boot_file=/usr/share/$relpath - fi - - echo $pxe_boot_file -} - -# PXE boot image -IRONIC_PXE_BOOT_IMAGE=${IRONIC_PXE_BOOT_IMAGE:-$(get_pxe_boot_file)} - - -# Functions -# --------- - -# Test if any Ironic services are enabled -# is_ironic_enabled -function is_ironic_enabled { - [[ ,${ENABLED_SERVICES} =~ ,"ir-" ]] && return 0 - return 1 -} - -function is_ironic_hardware { - is_ironic_enabled && [[ -n "${IRONIC_DEPLOY_DRIVER##*_ssh}" ]] && return 0 - return 1 -} - -function is_deployed_by_agent { - [[ -z "${IRONIC_DEPLOY_DRIVER%%agent*}" ]] && return 0 - return 1 -} - -function is_deployed_with_ipa_ramdisk { - is_deployed_by_agent || [[ "$IRONIC_DEPLOY_DRIVER_ISCSI_WITH_IPA" == "True" ]] && return 0 - return 1 -} - -# install_ironic() - Collect source and prepare -function install_ironic { - # make sure all needed service were enabled - local req_services="key" - if [[ "$VIRT_DRIVER" == "ironic" ]]; then - req_services+=" nova glance neutron" - fi - for srv in $req_services; do - if ! is_service_enabled "$srv"; then - die $LINENO "$srv should be enabled for Ironic." - fi - done - git_clone $IRONIC_REPO $IRONIC_DIR $IRONIC_BRANCH - setup_develop $IRONIC_DIR - - if [[ "$IRONIC_IPXE_ENABLED" == "True" ]] ; then - install_apache_wsgi - fi -} - -# install_ironicclient() - Collect sources and prepare -function install_ironicclient { - if use_library_from_git "python-ironicclient"; then - git_clone_by_name "python-ironicclient" - setup_dev_lib "python-ironicclient" - sudo install -D -m 0644 -o $STACK_USER {${GITDIR["python-ironicclient"]}/tools/,/etc/bash_completion.d/}ironic.bash_completion - else - # nothing actually "requires" ironicclient, so force instally from pypi - pip_install_gr python-ironicclient - fi -} - -# _cleanup_ironic_apache_wsgi() - Remove wsgi files, disable and remove apache vhost file -function _cleanup_ironic_apache_wsgi { - sudo rm -rf $IRONIC_HTTP_DIR - disable_apache_site ironic - sudo rm -f $(apache_site_config_for ironic) - restart_apache_server -} - -# _config_ironic_apache_wsgi() - Set WSGI config files of Ironic -function _config_ironic_apache_wsgi { - local ironic_apache_conf=$(apache_site_config_for ironic) - sudo cp $FILES/apache-ironic.template $ironic_apache_conf - sudo sed -e " - s|%PUBLICPORT%|$IRONIC_HTTP_PORT|g; - s|%HTTPROOT%|$IRONIC_HTTP_DIR|g; - " -i $ironic_apache_conf - enable_apache_site ironic -} - -# cleanup_ironic() - Remove residual data files, anything left over from previous -# runs that would need to clean up. -function cleanup_ironic { - sudo rm -rf $IRONIC_AUTH_CACHE_DIR $IRONIC_CONF_DIR -} - -# configure_ironic_dirs() - Create all directories required by Ironic and -# associated services. -function configure_ironic_dirs { - sudo install -d -o $STACK_USER $IRONIC_CONF_DIR $STACK_USER $IRONIC_DATA_DIR \ - $IRONIC_STATE_PATH $IRONIC_TFTPBOOT_DIR $IRONIC_TFTPBOOT_DIR/pxelinux.cfg - sudo chown -R $STACK_USER:$LIBVIRT_GROUP $IRONIC_TFTPBOOT_DIR - - if [[ "$IRONIC_IPXE_ENABLED" == "True" ]] ; then - sudo install -d -o $STACK_USER -g $LIBVIRT_GROUP $IRONIC_HTTP_DIR - fi - - if [ ! -f $IRONIC_PXE_BOOT_IMAGE ]; then - die $LINENO "PXE boot file $IRONIC_PXE_BOOT_IMAGE not found." - fi - - # Copy PXE binary - if [[ "$IRONIC_IPXE_ENABLED" == "True" ]] ; then - cp $IRONIC_PXE_BOOT_IMAGE $IRONIC_TFTPBOOT_DIR - else - # Syslinux >= 5.00 pxelinux.0 binary is not "stand-alone" anymore, - # it depends on some c32 modules to work correctly. - # More info: http://www.syslinux.org/wiki/index.php/Library_modules - cp -aR $(dirname $IRONIC_PXE_BOOT_IMAGE)/*.{c32,0} $IRONIC_TFTPBOOT_DIR - fi -} - -# configure_ironic() - Set config files, create data dirs, etc -function configure_ironic { - configure_ironic_dirs - - # Copy over ironic configuration file and configure common parameters. - cp $IRONIC_DIR/etc/ironic/ironic.conf.sample $IRONIC_CONF_FILE - iniset $IRONIC_CONF_FILE DEFAULT debug True - inicomment $IRONIC_CONF_FILE DEFAULT log_file - iniset $IRONIC_CONF_FILE database connection `database_connection_url ironic` - iniset $IRONIC_CONF_FILE DEFAULT state_path $IRONIC_STATE_PATH - iniset $IRONIC_CONF_FILE DEFAULT use_syslog $SYSLOG - # Configure Ironic conductor, if it was enabled. - if is_service_enabled ir-cond; then - configure_ironic_conductor - fi - - # Configure Ironic API, if it was enabled. - if is_service_enabled ir-api; then - configure_ironic_api - fi - - # Format logging - if [ "$LOG_COLOR" == "True" ] && [ "$SYSLOG" == "False" ]; then - setup_colorized_logging $IRONIC_CONF_FILE DEFAULT - fi - - if [[ "$IRONIC_IPXE_ENABLED" == "True" ]]; then - _config_ironic_apache_wsgi - fi -} - -# configure_ironic_api() - Is used by configure_ironic(). Performs -# API specific configuration. -function configure_ironic_api { - iniset $IRONIC_CONF_FILE DEFAULT auth_strategy keystone - iniset $IRONIC_CONF_FILE oslo_policy policy_file $IRONIC_POLICY_JSON - - # TODO(Yuki Nishiwaki): This is a temporary work-around until Ironic is fixed(bug#1422632). - # These codes need to be changed to use the function of configure_auth_token_middleware - # after Ironic conforms to the new auth plugin. - iniset $IRONIC_CONF_FILE keystone_authtoken identity_uri $KEYSTONE_AUTH_URI - iniset $IRONIC_CONF_FILE keystone_authtoken auth_uri $KEYSTONE_SERVICE_URI/v2.0 - iniset $IRONIC_CONF_FILE keystone_authtoken admin_user ironic - iniset $IRONIC_CONF_FILE keystone_authtoken admin_password $SERVICE_PASSWORD - iniset $IRONIC_CONF_FILE keystone_authtoken admin_tenant_name $SERVICE_TENANT_NAME - iniset $IRONIC_CONF_FILE keystone_authtoken cafile $SSL_BUNDLE_FILE - iniset $IRONIC_CONF_FILE keystone_authtoken signing_dir $IRONIC_AUTH_CACHE_DIR/api - - iniset_rpc_backend ironic $IRONIC_CONF_FILE - iniset $IRONIC_CONF_FILE api port $IRONIC_SERVICE_PORT - - cp -p $IRONIC_DIR/etc/ironic/policy.json $IRONIC_POLICY_JSON -} - -# configure_ironic_conductor() - Is used by configure_ironic(). -# Sets conductor specific settings. -function configure_ironic_conductor { - cp $IRONIC_DIR/etc/ironic/rootwrap.conf $IRONIC_ROOTWRAP_CONF - cp -r $IRONIC_DIR/etc/ironic/rootwrap.d $IRONIC_CONF_DIR - local ironic_rootwrap=$(get_rootwrap_location ironic) - local rootwrap_isudoer_cmd="$ironic_rootwrap $IRONIC_CONF_DIR/rootwrap.conf *" - - # Set up the rootwrap sudoers for ironic - local tempfile=`mktemp` - echo "$STACK_USER ALL=(root) NOPASSWD: $rootwrap_isudoer_cmd" >$tempfile - chmod 0440 $tempfile - sudo chown root:root $tempfile - sudo mv $tempfile /etc/sudoers.d/ironic-rootwrap - - iniset $IRONIC_CONF_FILE DEFAULT rootwrap_config $IRONIC_ROOTWRAP_CONF - iniset $IRONIC_CONF_FILE DEFAULT enabled_drivers $IRONIC_ENABLED_DRIVERS - iniset $IRONIC_CONF_FILE conductor api_url $IRONIC_SERVICE_PROTOCOL://$HOST_IP:$IRONIC_SERVICE_PORT - if [[ -n "$IRONIC_CALLBACK_TIMEOUT" ]]; then - iniset $IRONIC_CONF_FILE conductor deploy_callback_timeout $IRONIC_CALLBACK_TIMEOUT - fi - iniset $IRONIC_CONF_FILE pxe tftp_server $IRONIC_TFTPSERVER_IP - iniset $IRONIC_CONF_FILE pxe tftp_root $IRONIC_TFTPBOOT_DIR - iniset $IRONIC_CONF_FILE pxe tftp_master_path $IRONIC_TFTPBOOT_DIR/master_images - - local pxe_params="" - if [[ "$IRONIC_VM_LOG_CONSOLE" == "True" ]] ; then - pxe_params+="nofb nomodeset vga=normal console=ttyS0" - if is_deployed_with_ipa_ramdisk; then - pxe_params+=" systemd.journald.forward_to_console=yes" - fi - fi - # When booting with less than 1GB, we need to switch from default tmpfs - # to ramfs for ramdisks to decompress successfully. - if (is_ironic_hardware && [[ "$IRONIC_HW_NODE_RAM" -lt 1024 ]]) || - (! is_ironic_hardware && [[ "$IRONIC_VM_SPECS_RAM" -lt 1024 ]]); then - pxe_params+=" rootfstype=ramfs" - fi - if [[ -n "$pxe_params" ]]; then - iniset $IRONIC_CONF_FILE pxe pxe_append_params "$pxe_params" - fi - - if is_deployed_by_agent; then - if [[ "$SWIFT_ENABLE_TEMPURLS" == "True" ]] ; then - iniset $IRONIC_CONF_FILE glance swift_temp_url_key $SWIFT_TEMPURL_KEY - else - die $LINENO "SWIFT_ENABLE_TEMPURLS must be True to use agent_ssh driver in Ironic." - fi - iniset $IRONIC_CONF_FILE glance swift_endpoint_url http://${HOST_IP}:${SWIFT_DEFAULT_BIND_PORT:-8080} - iniset $IRONIC_CONF_FILE glance swift_api_version v1 - local tenant_id=$(get_or_create_project $SERVICE_TENANT_NAME) - iniset $IRONIC_CONF_FILE glance swift_account AUTH_${tenant_id} - iniset $IRONIC_CONF_FILE glance swift_container glance - iniset $IRONIC_CONF_FILE glance swift_temp_url_duration 3600 - iniset $IRONIC_CONF_FILE agent heartbeat_timeout 30 - iniset $IRONIC_CONF_FILE agent agent_erase_devices_priority 0 - fi - - if [[ "$IRONIC_IPXE_ENABLED" == "True" ]] ; then - local pxebin=`basename $IRONIC_PXE_BOOT_IMAGE` - iniset $IRONIC_CONF_FILE pxe ipxe_enabled True - iniset $IRONIC_CONF_FILE pxe pxe_config_template '\$pybasedir/drivers/modules/ipxe_config.template' - iniset $IRONIC_CONF_FILE pxe pxe_bootfile_name $pxebin - iniset $IRONIC_CONF_FILE pxe http_root $IRONIC_HTTP_DIR - iniset $IRONIC_CONF_FILE pxe http_url "http://$IRONIC_HTTP_SERVER:$IRONIC_HTTP_PORT" - fi -} - -# create_ironic_cache_dir() - Part of the init_ironic() process -function create_ironic_cache_dir { - # Create cache dir - sudo mkdir -p $IRONIC_AUTH_CACHE_DIR/api - sudo chown $STACK_USER $IRONIC_AUTH_CACHE_DIR/api - rm -f $IRONIC_AUTH_CACHE_DIR/api/* - sudo mkdir -p $IRONIC_AUTH_CACHE_DIR/registry - sudo chown $STACK_USER $IRONIC_AUTH_CACHE_DIR/registry - rm -f $IRONIC_AUTH_CACHE_DIR/registry/* -} - -# create_ironic_accounts() - Set up common required ironic accounts - -# Tenant User Roles -# ------------------------------------------------------------------ -# service ironic admin # if enabled -function create_ironic_accounts { - - # Ironic - if [[ "$ENABLED_SERVICES" =~ "ir-api" ]]; then - # Get ironic user if exists - - # NOTE(Shrews): This user MUST have admin level privileges! - create_service_user "ironic" "admin" - - if [[ "$KEYSTONE_CATALOG_BACKEND" = 'sql' ]]; then - - local ironic_service=$(get_or_create_service "ironic" \ - "baremetal" "Ironic baremetal provisioning service") - get_or_create_endpoint $ironic_service \ - "$REGION_NAME" \ - "$IRONIC_SERVICE_PROTOCOL://$IRONIC_HOSTPORT" \ - "$IRONIC_SERVICE_PROTOCOL://$IRONIC_HOSTPORT" \ - "$IRONIC_SERVICE_PROTOCOL://$IRONIC_HOSTPORT" - fi - fi -} - - -# init_ironic() - Initialize databases, etc. -function init_ironic { - # Save private network as cleaning network - local cleaning_network_uuid - cleaning_network_uuid=$(neutron net-list | grep private | get_field 1) - iniset $IRONIC_CONF_FILE neutron cleaning_network_uuid ${cleaning_network_uuid} - - # (Re)create ironic database - recreate_database ironic - - # Migrate ironic database - $IRONIC_BIN_DIR/ironic-dbsync --config-file=$IRONIC_CONF_FILE - - create_ironic_cache_dir -} - -# _ironic_bm_vm_names() - Generates list of names for baremetal VMs. -function _ironic_bm_vm_names { - local idx - local num_vms=$(($IRONIC_VM_COUNT - 1)) - for idx in $(seq 0 $num_vms); do - echo "baremetal${IRONIC_VM_NETWORK_BRIDGE}_${idx}" - done -} - -# start_ironic() - Start running processes, including screen -function start_ironic { - # Start Ironic API server, if enabled. - if is_service_enabled ir-api; then - start_ironic_api - fi - - # Start Ironic conductor, if enabled. - if is_service_enabled ir-cond; then - start_ironic_conductor - fi - - # Start Apache if iPXE is enabled - if [[ "$IRONIC_IPXE_ENABLED" == "True" ]] ; then - restart_apache_server - fi -} - -# start_ironic_api() - Used by start_ironic(). -# Starts Ironic API server. -function start_ironic_api { - run_process ir-api "$IRONIC_BIN_DIR/ironic-api --config-file=$IRONIC_CONF_FILE" - echo "Waiting for ir-api ($IRONIC_HOSTPORT) to start..." - if ! timeout $SERVICE_TIMEOUT sh -c "while ! wget --no-proxy -q -O- $IRONIC_SERVICE_PROTOCOL://$IRONIC_HOSTPORT; do sleep 1; done"; then - die $LINENO "ir-api did not start" - fi -} - -# start_ironic_conductor() - Used by start_ironic(). -# Starts Ironic conductor. -function start_ironic_conductor { - run_process ir-cond "$IRONIC_BIN_DIR/ironic-conductor --config-file=$IRONIC_CONF_FILE" - # TODO(romcheg): Find a way to check whether the conductor has started. -} - -# stop_ironic() - Stop running processes -function stop_ironic { - stop_process ir-api - stop_process ir-cond - - # Cleanup the WSGI files - if [[ "$IRONIC_IPXE_ENABLED" == "True" ]] ; then - _cleanup_ironic_apache_wsgi - fi -} - -function create_ovs_taps { - local ironic_net_id=$(neutron net-list | grep private | get_field 1) - - # Work around: No netns exists on host until a Neutron port is created. We - # need to create one in Neutron to know what netns to tap into prior to the - # first node booting. - local port_id=$(neutron port-create private | grep " id " | get_field 2) - - # intentional sleep to make sure the tag has been set to port - sleep 10 - - if [[ "$Q_USE_NAMESPACE" = "True" ]]; then - local tapdev=$(sudo ip netns exec qdhcp-${ironic_net_id} ip link list | grep " tap" | cut -d':' -f2 | cut -b2-) - else - local tapdev=$(sudo ip link list | grep " tap" | cut -d':' -f2 | cut -b2-) - fi - local tag_id=$(sudo ovs-vsctl show |grep ${tapdev} -A1 -m1 | grep tag | cut -d':' -f2 | cut -b2-) - - # make sure veth pair is not existing, otherwise delete its links - sudo ip link show ovs-tap1 && sudo ip link delete ovs-tap1 - sudo ip link show brbm-tap1 && sudo ip link delete brbm-tap1 - # create veth pair for future interconnection between br-int and brbm - sudo ip link add brbm-tap1 type veth peer name ovs-tap1 - sudo ip link set dev brbm-tap1 up - sudo ip link set dev ovs-tap1 up - - sudo ovs-vsctl -- --if-exists del-port ovs-tap1 -- add-port br-int ovs-tap1 tag=$tag_id - sudo ovs-vsctl -- --if-exists del-port brbm-tap1 -- add-port $IRONIC_VM_NETWORK_BRIDGE brbm-tap1 - - # Remove the port needed only for workaround. - neutron port-delete $port_id - - # Finally, share the fixed tenant network across all tenants. This allows the host - # to serve TFTP to a single network namespace via the tap device created above. - neutron net-update $ironic_net_id --shared true -} - -function create_bridge_and_vms { - # Call libvirt setup scripts in a new shell to ensure any new group membership - sudo su $STACK_USER -c "$IRONIC_SCRIPTS_DIR/setup-network" - if [[ "$IRONIC_VM_LOG_CONSOLE" == "True" ]] ; then - local log_arg="$IRONIC_VM_LOG_DIR" - else - local log_arg="" - fi - local vm_name - for vm_name in $(_ironic_bm_vm_names); do - sudo su $STACK_USER -c "$IRONIC_SCRIPTS_DIR/create-node $vm_name \ - $IRONIC_VM_SPECS_CPU $IRONIC_VM_SPECS_RAM $IRONIC_VM_SPECS_DISK \ - amd64 $IRONIC_VM_NETWORK_BRIDGE $IRONIC_VM_EMULATOR \ - $log_arg" >> $IRONIC_VM_MACS_CSV_FILE - done - create_ovs_taps -} - -function wait_for_nova_resources { - # After nodes have been enrolled, we need to wait for both ironic and - # nova's periodic tasks to populate the resource tracker with available - # nodes and resources. Wait up to 2 minutes for a given resource before - # timing out. - local resource=$1 - local expected_count=$2 - echo_summary "Waiting 2 minutes for Nova resource tracker to pick up $resource >= $expected_count" - for i in $(seq 1 120); do - if [ $(nova hypervisor-stats | grep " $resource " | get_field 2) -ge $expected_count ]; then - return 0 - fi - sleep 1 - done - die $LINENO "Timed out waiting for Nova hypervisor-stats $resource >= $expected_count" -} - -function enroll_nodes { - local chassis_id=$(ironic chassis-create -d "ironic test chassis" | grep " uuid " | get_field 2) - - if [[ "$IRONIC_DEPLOY_DRIVER" == "pxe_ssh" ]] ; then - local _IRONIC_DEPLOY_KERNEL_KEY=pxe_deploy_kernel - local _IRONIC_DEPLOY_RAMDISK_KEY=pxe_deploy_ramdisk - elif is_deployed_by_agent; then - local _IRONIC_DEPLOY_KERNEL_KEY=deploy_kernel - local _IRONIC_DEPLOY_RAMDISK_KEY=deploy_ramdisk - fi - - if ! is_ironic_hardware; then - local ironic_node_cpu=$IRONIC_VM_SPECS_CPU - local ironic_node_ram=$IRONIC_VM_SPECS_RAM - local ironic_node_disk=$IRONIC_VM_SPECS_DISK - local ironic_ephemeral_disk=$IRONIC_VM_EPHEMERAL_DISK - local ironic_hwinfo_file=$IRONIC_VM_MACS_CSV_FILE - local node_options="\ - -i $_IRONIC_DEPLOY_KERNEL_KEY=$IRONIC_DEPLOY_KERNEL_ID \ - -i $_IRONIC_DEPLOY_RAMDISK_KEY=$IRONIC_DEPLOY_RAMDISK_ID \ - -i ssh_virt_type=$IRONIC_SSH_VIRT_TYPE \ - -i ssh_address=$IRONIC_VM_SSH_ADDRESS \ - -i ssh_port=$IRONIC_VM_SSH_PORT \ - -i ssh_username=$IRONIC_SSH_USERNAME \ - -i ssh_key_filename=$IRONIC_KEY_FILE" - else - local ironic_node_cpu=$IRONIC_HW_NODE_CPU - local ironic_node_ram=$IRONIC_HW_NODE_RAM - local ironic_node_disk=$IRONIC_HW_NODE_DISK - local ironic_ephemeral_disk=$IRONIC_HW_EPHEMERAL_DISK - if [[ -z "${IRONIC_DEPLOY_DRIVER##*_ipmitool}" ]]; then - local ironic_hwinfo_file=$IRONIC_IPMIINFO_FILE - fi - fi - - local total_nodes=0 - local total_cpus=0 - while read hardware_info; do - if ! is_ironic_hardware; then - local mac_address=$hardware_info - elif [[ -z "${IRONIC_DEPLOY_DRIVER##*_ipmitool}" ]]; then - local ipmi_address=$(echo $hardware_info |awk '{print $1}') - local mac_address=$(echo $hardware_info |awk '{print $2}') - local ironic_ipmi_username=$(echo $hardware_info |awk '{print $3}') - local ironic_ipmi_passwd=$(echo $hardware_info |awk '{print $4}') - # Currently we require all hardware platform have same CPU/RAM/DISK info - # in future, this can be enhanced to support different type, and then - # we create the bare metal flavor with minimum value - local node_options="-i ipmi_address=$ipmi_address -i ipmi_password=$ironic_ipmi_passwd\ - -i ipmi_username=$ironic_ipmi_username" - node_options+=" -i $_IRONIC_DEPLOY_KERNEL_KEY=$IRONIC_DEPLOY_KERNEL_ID" - node_options+=" -i $_IRONIC_DEPLOY_RAMDISK_KEY=$IRONIC_DEPLOY_RAMDISK_ID" - fi - - local node_id=$(ironic node-create --chassis_uuid $chassis_id \ - --driver $IRONIC_DEPLOY_DRIVER \ - -p cpus=$ironic_node_cpu\ - -p memory_mb=$ironic_node_ram\ - -p local_gb=$ironic_node_disk\ - -p cpu_arch=x86_64 \ - $node_options \ - | grep " uuid " | get_field 2) - - ironic port-create --address $mac_address --node $node_id - - total_nodes=$((total_nodes+1)) - total_cpus=$((total_cpus+$ironic_node_cpu)) - done < $ironic_hwinfo_file - - # create the nova flavor - # NOTE(adam_g): Attempting to use an autogenerated UUID for flavor id here uncovered - # bug (LP: #1333852) in Trove. This can be changed to use an auto flavor id when the - # bug is fixed in Juno. - local adjusted_disk=$(($ironic_node_disk - $ironic_ephemeral_disk)) - nova flavor-create --ephemeral $ironic_ephemeral_disk baremetal 551 $ironic_node_ram $adjusted_disk $ironic_node_cpu - - nova flavor-key baremetal set "cpu_arch"="x86_64" - - if [ "$VIRT_DRIVER" == "ironic" ]; then - wait_for_nova_resources "count" $total_nodes - wait_for_nova_resources "vcpus" $total_cpus - fi -} - -function configure_iptables { - # enable tftp natting for allowing connections to HOST_IP's tftp server - sudo modprobe nf_conntrack_tftp - sudo modprobe nf_nat_tftp - # nodes boot from TFTP and callback to the API server listening on $HOST_IP - sudo iptables -I INPUT -d $HOST_IP -p udp --dport 69 -j ACCEPT || true - sudo iptables -I INPUT -d $HOST_IP -p tcp --dport $IRONIC_SERVICE_PORT -j ACCEPT || true - if is_deployed_by_agent; then - # agent ramdisk gets instance image from swift - sudo iptables -I INPUT -d $HOST_IP -p tcp --dport ${SWIFT_DEFAULT_BIND_PORT:-8080} -j ACCEPT || true - fi -} - -function configure_tftpd { - # stop tftpd and setup serving via xinetd - stop_service tftpd-hpa || true - [ -f /etc/init/tftpd-hpa.conf ] && echo "manual" | sudo tee /etc/init/tftpd-hpa.override - sudo cp $IRONIC_TEMPLATES_DIR/tftpd-xinetd.template /etc/xinetd.d/tftp - sudo sed -e "s|%TFTPBOOT_DIR%|$IRONIC_TFTPBOOT_DIR|g" -i /etc/xinetd.d/tftp - - # setup tftp file mapping to satisfy requests at the root (booting) and - # /tftpboot/ sub-dir (as per deploy-ironic elements) - echo "r ^([^/]) $IRONIC_TFTPBOOT_DIR/\1" >$IRONIC_TFTPBOOT_DIR/map-file - echo "r ^(/tftpboot/) $IRONIC_TFTPBOOT_DIR/\2" >>$IRONIC_TFTPBOOT_DIR/map-file - - chmod -R 0755 $IRONIC_TFTPBOOT_DIR - restart_service xinetd -} - -function configure_ironic_ssh_keypair { - if [[ ! -d $HOME/.ssh ]]; then - mkdir -p $HOME/.ssh - chmod 700 $HOME/.ssh - fi - if [[ ! -e $IRONIC_KEY_FILE ]]; then - if [[ ! -d $(dirname $IRONIC_KEY_FILE) ]]; then - mkdir -p $(dirname $IRONIC_KEY_FILE) - fi - echo -e 'n\n' | ssh-keygen -q -t rsa -P '' -f $IRONIC_KEY_FILE - fi - cat $IRONIC_KEY_FILE.pub | tee -a $IRONIC_AUTHORIZED_KEYS_FILE -} - -function ironic_ssh_check { - local key_file=$1 - local floating_ip=$2 - local port=$3 - local default_instance_user=$4 - local active_timeout=$5 - if ! timeout $active_timeout sh -c "while ! ssh -p $port -o StrictHostKeyChecking=no -i $key_file ${default_instance_user}@$floating_ip echo success; do sleep 1; done"; then - die $LINENO "server didn't become ssh-able!" - fi -} - -function configure_ironic_auxiliary { - configure_ironic_ssh_keypair - ironic_ssh_check $IRONIC_KEY_FILE $IRONIC_VM_SSH_ADDRESS $IRONIC_VM_SSH_PORT $IRONIC_SSH_USERNAME $IRONIC_SSH_TIMEOUT -} - -function build_ipa_coreos_ramdisk { - echo "Building ironic-python-agent deploy ramdisk" - local kernel_path=$1 - local ramdisk_path=$2 - git_clone $IRONIC_PYTHON_AGENT_REPO $IRONIC_PYTHON_AGENT_DIR $IRONIC_PYTHON_AGENT_BRANCH - cd $IRONIC_PYTHON_AGENT_DIR - imagebuild/coreos/build_coreos_image.sh - cp imagebuild/coreos/UPLOAD/coreos_production_pxe_image-oem.cpio.gz $ramdisk_path - cp imagebuild/coreos/UPLOAD/coreos_production_pxe.vmlinuz $kernel_path - sudo rm -rf UPLOAD - cd - -} - -# build deploy kernel+ramdisk, then upload them to glance -# this function sets ``IRONIC_DEPLOY_KERNEL_ID``, ``IRONIC_DEPLOY_RAMDISK_ID`` -function upload_baremetal_ironic_deploy { - declare -g IRONIC_DEPLOY_KERNEL_ID IRONIC_DEPLOY_RAMDISK_ID - echo_summary "Creating and uploading baremetal images for ironic" - - # install diskimage-builder - if [[ $(type -P ramdisk-image-create) == "" ]]; then - pip_install_gr "diskimage-builder" - fi - - if [ -z "$IRONIC_DEPLOY_KERNEL" -o -z "$IRONIC_DEPLOY_RAMDISK" ]; then - local IRONIC_DEPLOY_KERNEL_PATH=$TOP_DIR/files/ir-deploy-$IRONIC_DEPLOY_DRIVER.kernel - local IRONIC_DEPLOY_RAMDISK_PATH=$TOP_DIR/files/ir-deploy-$IRONIC_DEPLOY_DRIVER.initramfs - else - local IRONIC_DEPLOY_KERNEL_PATH=$IRONIC_DEPLOY_KERNEL - local IRONIC_DEPLOY_RAMDISK_PATH=$IRONIC_DEPLOY_RAMDISK - fi - - if [ ! -e "$IRONIC_DEPLOY_RAMDISK_PATH" -o ! -e "$IRONIC_DEPLOY_KERNEL_PATH" ]; then - # files don't exist, need to build them - if [ "$IRONIC_BUILD_DEPLOY_RAMDISK" = "True" ]; then - # we can build them only if we're not offline - if [ "$OFFLINE" != "True" ]; then - if is_deployed_with_ipa_ramdisk; then - build_ipa_coreos_ramdisk $IRONIC_DEPLOY_KERNEL_PATH $IRONIC_DEPLOY_RAMDISK_PATH - else - ramdisk-image-create $IRONIC_DEPLOY_FLAVOR \ - -o $TOP_DIR/files/ir-deploy-$IRONIC_DEPLOY_DRIVER - fi - else - die $LINENO "Deploy kernel+ramdisk files don't exist and cannot be build in OFFLINE mode" - fi - else - if is_deployed_with_ipa_ramdisk; then - # download the agent image tarball - wget "$IRONIC_AGENT_KERNEL_URL" -O $IRONIC_DEPLOY_KERNEL_PATH - wget "$IRONIC_AGENT_RAMDISK_URL" -O $IRONIC_DEPLOY_RAMDISK_PATH - else - die $LINENO "Deploy kernel+ramdisk files don't exist and their building was disabled explicitly by IRONIC_BUILD_DEPLOY_RAMDISK" - fi - fi - fi - - local token=$(openstack token issue -c id -f value) - die_if_not_set $LINENO token "Keystone fail to get token" - - # load them into glance - IRONIC_DEPLOY_KERNEL_ID=$(openstack \ - --os-token $token \ - --os-url http://$GLANCE_HOSTPORT \ - image create \ - $(basename $IRONIC_DEPLOY_KERNEL_PATH) \ - --public --disk-format=aki \ - --container-format=aki \ - < $IRONIC_DEPLOY_KERNEL_PATH | grep ' id ' | get_field 2) - IRONIC_DEPLOY_RAMDISK_ID=$(openstack \ - --os-token $token \ - --os-url http://$GLANCE_HOSTPORT \ - image create \ - $(basename $IRONIC_DEPLOY_RAMDISK_PATH) \ - --public --disk-format=ari \ - --container-format=ari \ - < $IRONIC_DEPLOY_RAMDISK_PATH | grep ' id ' | get_field 2) -} - -function prepare_baremetal_basic_ops { - if ! is_ironic_hardware; then - configure_ironic_auxiliary - fi - upload_baremetal_ironic_deploy - if ! is_ironic_hardware; then - create_bridge_and_vms - fi - enroll_nodes - configure_tftpd - configure_iptables -} - -function cleanup_baremetal_basic_ops { - rm -f $IRONIC_VM_MACS_CSV_FILE - if [ -f $IRONIC_KEY_FILE ]; then - local key=$(cat $IRONIC_KEY_FILE.pub) - # remove public key from authorized_keys - grep -v "$key" $IRONIC_AUTHORIZED_KEYS_FILE > temp && mv temp $IRONIC_AUTHORIZED_KEYS_FILE - chmod 0600 $IRONIC_AUTHORIZED_KEYS_FILE - fi - sudo rm -rf $IRONIC_DATA_DIR $IRONIC_STATE_PATH - - local vm_name - for vm_name in $(_ironic_bm_vm_names); do - sudo su $STACK_USER -c "$IRONIC_SCRIPTS_DIR/cleanup-node $vm_name $IRONIC_VM_NETWORK_BRIDGE" - done - - sudo rm -rf /etc/xinetd.d/tftp /etc/init/tftpd-hpa.override - restart_service xinetd - sudo iptables -D INPUT -d $HOST_IP -p udp --dport 69 -j ACCEPT || true - sudo iptables -D INPUT -d $HOST_IP -p tcp --dport $IRONIC_SERVICE_PORT -j ACCEPT || true - if is_deployed_by_agent; then - # agent ramdisk gets instance image from swift - sudo iptables -D INPUT -d $HOST_IP -p tcp --dport ${SWIFT_DEFAULT_BIND_PORT:-8080} -j ACCEPT || true - fi - sudo rmmod nf_conntrack_tftp || true - sudo rmmod nf_nat_tftp || true -} - -# Restore xtrace + pipefail -$XTRACE -$PIPEFAIL - -# Tell emacs to use shell-script-mode -## Local variables: -## mode: shell-script -## End: diff --git a/lib/keystone b/lib/keystone index 0f369af71d..02e28222b7 100644 --- a/lib/keystone +++ b/lib/keystone @@ -12,7 +12,6 @@ # - ``IDENTITY_API_VERSION`` # - ``BASE_SQL_CONN`` # - ``SERVICE_HOST``, ``SERVICE_PROTOCOL`` -# - ``SERVICE_TOKEN`` # - ``S3_SERVICE_PORT`` (template backend only) # ``stack.sh`` calls the entry points in this order: @@ -22,19 +21,20 @@ # - _config_keystone_apache_wsgi # - init_keystone # - start_keystone +# - bootstrap_keystone # - create_keystone_accounts # - stop_keystone # - cleanup_keystone -# - _cleanup_keystone_apache_wsgi # Save trace setting -XTRACE=$(set +o | grep xtrace) +_XTRACE_KEYSTONE=$(set +o | grep xtrace) set +o xtrace # Defaults # -------- # Set up default directories +GITDIR["keystoneauth"]=$DEST/keystoneauth GITDIR["python-keystoneclient"]=$DEST/python-keystoneclient GITDIR["keystonemiddleware"]=$DEST/keystonemiddleware KEYSTONE_DIR=$DEST/keystone @@ -49,37 +49,36 @@ fi KEYSTONE_CONF_DIR=${KEYSTONE_CONF_DIR:-/etc/keystone} KEYSTONE_CONF=$KEYSTONE_CONF_DIR/keystone.conf -KEYSTONE_PASTE_INI=${KEYSTONE_PASTE_INI:-$KEYSTONE_CONF_DIR/keystone-paste.ini} -KEYSTONE_AUTH_CACHE_DIR=${KEYSTONE_AUTH_CACHE_DIR:-/var/cache/keystone} -if is_suse; then - KEYSTONE_WSGI_DIR=${KEYSTONE_WSGI_DIR:-/srv/www/htdocs/keystone} +KEYSTONE_PUBLIC_UWSGI_CONF=$KEYSTONE_CONF_DIR/keystone-uwsgi-public.ini +KEYSTONE_ADMIN_UWSGI_CONF=$KEYSTONE_CONF_DIR/keystone-uwsgi-admin.ini +KEYSTONE_PUBLIC_UWSGI=$KEYSTONE_BIN_DIR/keystone-wsgi-public +KEYSTONE_ADMIN_UWSGI=$KEYSTONE_BIN_DIR/keystone-wsgi-admin + +# KEYSTONE_DEPLOY defines how keystone is deployed, allowed values: +# - mod_wsgi : Run keystone under Apache HTTPd mod_wsgi +# - uwsgi : Run keystone under uwsgi +if [[ "$WSGI_MODE" == "uwsgi" ]]; then + KEYSTONE_DEPLOY=uwsgi else - KEYSTONE_WSGI_DIR=${KEYSTONE_WSGI_DIR:-/var/www/keystone} + KEYSTONE_DEPLOY=mod_wsgi fi -# Set up additional extensions, such as oauth1, federation -# Example of KEYSTONE_EXTENSIONS=oauth1,federation -KEYSTONE_EXTENSIONS=${KEYSTONE_EXTENSIONS:-} - -# Toggle for deploying Keystone under HTTPD + mod_wsgi -KEYSTONE_USE_MOD_WSGI=${KEYSTONE_USE_MOD_WSGI:-${ENABLE_HTTPD_MOD_WSGI_SERVICES}} - -# Select the backend for Keystone's service catalog -KEYSTONE_CATALOG_BACKEND=${KEYSTONE_CATALOG_BACKEND:-sql} -KEYSTONE_CATALOG=$KEYSTONE_CONF_DIR/default_catalog.templates - -# Select the backend for Tokens -KEYSTONE_TOKEN_BACKEND=${KEYSTONE_TOKEN_BACKEND:-sql} - -# Select the backend for Identity +# Select the Identity backend driver KEYSTONE_IDENTITY_BACKEND=${KEYSTONE_IDENTITY_BACKEND:-sql} -# Select the backend for Assignment +# Select the Assignment backend driver KEYSTONE_ASSIGNMENT_BACKEND=${KEYSTONE_ASSIGNMENT_BACKEND:-sql} -# Select Keystone's token format -# Choose from 'UUID', 'PKI', or 'PKIZ' -KEYSTONE_TOKEN_FORMAT=${KEYSTONE_TOKEN_FORMAT:-} +# Select the Role backend driver +KEYSTONE_ROLE_BACKEND=${KEYSTONE_ROLE_BACKEND:-sql} + +# Select the Resource backend driver +KEYSTONE_RESOURCE_BACKEND=${KEYSTONE_RESOURCE_BACKEND:-sql} + +# Select Keystone's token provider (and format) +# Refer keystone doc for supported token provider: +# https://docs.openstack.org/keystone/latest/admin/token-provider.html +KEYSTONE_TOKEN_FORMAT=${KEYSTONE_TOKEN_FORMAT:-fernet} KEYSTONE_TOKEN_FORMAT=$(echo ${KEYSTONE_TOKEN_FORMAT} | tr '[:upper:]' '[:lower:]') # Set Keystone interface configuration @@ -96,29 +95,41 @@ KEYSTONE_SERVICE_PROTOCOL=${KEYSTONE_SERVICE_PROTOCOL:-$SERVICE_PROTOCOL} # Bind hosts KEYSTONE_ADMIN_BIND_HOST=${KEYSTONE_ADMIN_BIND_HOST:-$KEYSTONE_SERVICE_HOST} -# Set the tenant for service accounts in Keystone -SERVICE_TENANT_NAME=${SERVICE_TENANT_NAME:-service} -# valid identity backends as per dir keystone/identity/backends -KEYSTONE_VALID_IDENTITY_BACKENDS=kvs,ldap,pam,sql +# Set the project for service accounts in Keystone +SERVICE_DOMAIN_NAME=${SERVICE_DOMAIN_NAME:-Default} +SERVICE_PROJECT_NAME=${SERVICE_PROJECT_NAME:-service} -# valid assignment backends as per dir keystone/identity/backends -KEYSTONE_VALID_ASSIGNMENT_BACKENDS=kvs,ldap,sql +# Note 2016-03 : SERVICE_TENANT_NAME is kept for backwards +# compatibility; we should be using SERVICE_PROJECT_NAME now +SERVICE_TENANT_NAME=${SERVICE_PROJECT_NAME:-service} # if we are running with SSL use https protocols -if is_ssl_enabled_service "key" || is_service_enabled tls-proxy; then +if is_service_enabled tls-proxy; then KEYSTONE_AUTH_PROTOCOL="https" KEYSTONE_SERVICE_PROTOCOL="https" fi -# complete URIs -KEYSTONE_AUTH_URI=${KEYSTONE_AUTH_PROTOCOL}://${KEYSTONE_AUTH_HOST}:${KEYSTONE_AUTH_PORT} -KEYSTONE_SERVICE_URI=${KEYSTONE_SERVICE_PROTOCOL}://${KEYSTONE_SERVICE_HOST}:${KEYSTONE_SERVICE_PORT} +KEYSTONE_SERVICE_URI=${KEYSTONE_SERVICE_PROTOCOL}://${KEYSTONE_SERVICE_HOST}/identity +# for compat +KEYSTONE_AUTH_URI=$KEYSTONE_SERVICE_URI # V3 URIs KEYSTONE_AUTH_URI_V3=$KEYSTONE_AUTH_URI/v3 KEYSTONE_SERVICE_URI_V3=$KEYSTONE_SERVICE_URI/v3 +# Security compliance +KEYSTONE_SECURITY_COMPLIANCE_ENABLED=${KEYSTONE_SECURITY_COMPLIANCE_ENABLED:-True} +KEYSTONE_LOCKOUT_FAILURE_ATTEMPTS=${KEYSTONE_LOCKOUT_FAILURE_ATTEMPTS:-2} +KEYSTONE_LOCKOUT_DURATION=${KEYSTONE_LOCKOUT_DURATION:-10} +KEYSTONE_UNIQUE_LAST_PASSWORD_COUNT=${KEYSTONE_UNIQUE_LAST_PASSWORD_COUNT:-2} + +# Number of bcrypt hashing rounds, increasing number exponentially increases required +# resources to generate password hash. This is very effective way to protect from +# bruteforce attacks. 4 is minimal value that can be specified for bcrypt and +# it works way faster than default 12. Minimal value is great for CI and development +# however may not be suitable for real production. +KEYSTONE_PASSWORD_HASH_ROUNDS=${KEYSTONE_PASSWORD_HASH_ROUNDS:-4} # Functions # --------- @@ -126,6 +137,7 @@ KEYSTONE_SERVICE_URI_V3=$KEYSTONE_SERVICE_URI/v3 # Test if Keystone is enabled # is_keystone_enabled function is_keystone_enabled { + [[ ,${DISABLED_SERVICES} =~ ,"keystone" ]] && return 1 [[ ,${ENABLED_SERVICES}, =~ ,"key", ]] && return 0 return 1 } @@ -133,20 +145,25 @@ function is_keystone_enabled { # cleanup_keystone() - Remove residual data files, anything left over from previous # runs that a clean run would need to clean up function cleanup_keystone { - _cleanup_keystone_apache_wsgi -} - -# _cleanup_keystone_apache_wsgi() - Remove wsgi files, disable and remove apache vhost file -function _cleanup_keystone_apache_wsgi { - sudo rm -f $KEYSTONE_WSGI_DIR/* - sudo rm -f $(apache_site_config_for keystone) + if [ "$KEYSTONE_DEPLOY" == "mod_wsgi" ]; then + # These files will be created if we are running WSGI_MODE="mod_wsgi" + disable_apache_site keystone + sudo rm -f $(apache_site_config_for keystone) + else + stop_process "keystone" + # TODO: remove admin at pike-2 + remove_uwsgi_config "$KEYSTONE_PUBLIC_UWSGI_CONF" "$KEYSTONE_PUBLIC_UWSGI" + remove_uwsgi_config "$KEYSTONE_ADMIN_UWSGI_CONF" "$KEYSTONE_ADMIN_UWSGI" + sudo rm -f $(apache_site_config_for keystone-wsgi-public) + sudo rm -f $(apache_site_config_for keystone-wsgi-admin) + fi } # _config_keystone_apache_wsgi() - Set WSGI config files of Keystone function _config_keystone_apache_wsgi { - sudo mkdir -p $KEYSTONE_WSGI_DIR - - local keystone_apache_conf=$(apache_site_config_for keystone) + local keystone_apache_conf + keystone_apache_conf=$(apache_site_config_for keystone) + keystone_ssl_listen="#" local keystone_ssl="" local keystone_certfile="" local keystone_keyfile="" @@ -154,11 +171,6 @@ function _config_keystone_apache_wsgi { local keystone_auth_port=$KEYSTONE_AUTH_PORT local venv_path="" - if is_ssl_enabled_service key; then - keystone_ssl="SSLEngine On" - keystone_certfile="SSLCertificateFile $KEYSTONE_SSL_CERT" - keystone_keyfile="SSLCertificateKeyFile $KEYSTONE_SSL_KEY" - fi if is_service_enabled tls-proxy; then keystone_service_port=$KEYSTONE_SERVICE_PORT_INT keystone_auth_port=$KEYSTONE_AUTH_PORT_INT @@ -167,22 +179,18 @@ function _config_keystone_apache_wsgi { venv_path="python-path=${PROJECT_VENV["keystone"]}/lib/$(python_version)/site-packages" fi - # copy proxy vhost and wsgi file - sudo cp $KEYSTONE_DIR/httpd/keystone.py $KEYSTONE_WSGI_DIR/main - sudo cp $KEYSTONE_DIR/httpd/keystone.py $KEYSTONE_WSGI_DIR/admin - sudo cp $FILES/apache-keystone.template $keystone_apache_conf sudo sed -e " s|%PUBLICPORT%|$keystone_service_port|g; s|%ADMINPORT%|$keystone_auth_port|g; s|%APACHE_NAME%|$APACHE_NAME|g; - s|%PUBLICWSGI%|$KEYSTONE_WSGI_DIR/main|g; - s|%ADMINWSGI%|$KEYSTONE_WSGI_DIR/admin|g; + s|%SSLLISTEN%|$keystone_ssl_listen|g; s|%SSLENGINE%|$keystone_ssl|g; s|%SSLCERTFILE%|$keystone_certfile|g; s|%SSLKEYFILE%|$keystone_keyfile|g; s|%USER%|$STACK_USER|g; s|%VIRTUALENV%|$venv_path|g + s|%KEYSTONE_BIN%|$KEYSTONE_BIN_DIR|g " -i $keystone_apache_conf } @@ -191,118 +199,49 @@ function configure_keystone { sudo install -d -o $STACK_USER $KEYSTONE_CONF_DIR if [[ "$KEYSTONE_CONF_DIR" != "$KEYSTONE_DIR/etc" ]]; then - install -m 600 $KEYSTONE_DIR/etc/keystone.conf.sample $KEYSTONE_CONF - cp -p $KEYSTONE_DIR/etc/policy.json $KEYSTONE_CONF_DIR - if [[ -f "$KEYSTONE_DIR/etc/keystone-paste.ini" ]]; then - cp -p "$KEYSTONE_DIR/etc/keystone-paste.ini" "$KEYSTONE_PASTE_INI" - fi - fi - if [[ -f "$KEYSTONE_PASTE_INI" ]]; then - iniset "$KEYSTONE_CONF" paste_deploy config_file "$KEYSTONE_PASTE_INI" - else - # compatibility with mixed cfg and paste.deploy configuration - KEYSTONE_PASTE_INI="$KEYSTONE_CONF" + install -m 600 /dev/null $KEYSTONE_CONF fi - - configure_keystone_extensions - - # Rewrite stock ``keystone.conf`` - + # Populate ``keystone.conf`` if is_service_enabled ldap; then - #Set all needed ldap values - iniset $KEYSTONE_CONF ldap password $LDAP_PASSWORD - iniset $KEYSTONE_CONF ldap user $LDAP_MANAGER_DN - iniset $KEYSTONE_CONF ldap suffix $LDAP_BASE_DN - iniset $KEYSTONE_CONF ldap use_dumb_member "True" - iniset $KEYSTONE_CONF ldap user_attribute_ignore "enabled,email,tenants,default_project_id" - iniset $KEYSTONE_CONF ldap tenant_attribute_ignore "enabled" - iniset $KEYSTONE_CONF ldap tenant_domain_id_attribute "businessCategory" - iniset $KEYSTONE_CONF ldap tenant_desc_attribute "description" - iniset $KEYSTONE_CONF ldap tenant_tree_dn "ou=Projects,$LDAP_BASE_DN" - iniset $KEYSTONE_CONF ldap user_domain_id_attribute "businessCategory" - iniset $KEYSTONE_CONF ldap user_tree_dn "ou=Users,$LDAP_BASE_DN" - iniset $KEYSTONE_CONF DEFAULT member_role_id "9fe2ff9ee4384b1894a90878d3e92bab" - iniset $KEYSTONE_CONF DEFAULT member_role_name "_member_" + iniset $KEYSTONE_CONF identity domain_config_dir "$KEYSTONE_CONF_DIR/domains" + iniset $KEYSTONE_CONF identity domain_specific_drivers_enabled "True" fi + iniset $KEYSTONE_CONF identity driver "$KEYSTONE_IDENTITY_BACKEND" + iniset $KEYSTONE_CONF identity password_hash_rounds $KEYSTONE_PASSWORD_HASH_ROUNDS + iniset $KEYSTONE_CONF assignment driver "$KEYSTONE_ASSIGNMENT_BACKEND" + iniset $KEYSTONE_CONF role driver "$KEYSTONE_ROLE_BACKEND" + iniset $KEYSTONE_CONF resource driver "$KEYSTONE_RESOURCE_BACKEND" - # check if identity backend is valid - if [[ "$KEYSTONE_VALID_IDENTITY_BACKENDS" =~ "$KEYSTONE_IDENTITY_BACKEND" ]]; then - iniset $KEYSTONE_CONF identity driver "keystone.identity.backends.$KEYSTONE_IDENTITY_BACKEND.Identity" - fi + # Enable caching + iniset $KEYSTONE_CONF cache enabled "True" + iniset $KEYSTONE_CONF cache backend "dogpile.cache.memcached" + iniset $KEYSTONE_CONF cache memcache_servers localhost:11211 - # check if assignment backend is valid - if [[ "$KEYSTONE_VALID_ASSIGNMENT_BACKENDS" =~ "$KEYSTONE_ASSIGNMENT_BACKEND" ]]; then - iniset $KEYSTONE_CONF assignment driver "keystone.assignment.backends.$KEYSTONE_ASSIGNMENT_BACKEND.Assignment" - fi + iniset_rpc_backend keystone $KEYSTONE_CONF oslo_messaging_notifications - iniset_rpc_backend keystone $KEYSTONE_CONF - - iniset $KEYSTONE_CONF eventlet_server admin_bind_host "$KEYSTONE_ADMIN_BIND_HOST" - - # Register SSL certificates if provided - if is_ssl_enabled_service key; then - ensure_certificates KEYSTONE - - iniset $KEYSTONE_CONF eventlet_server_ssl enable True - iniset $KEYSTONE_CONF eventlet_server_ssl certfile $KEYSTONE_SSL_CERT - iniset $KEYSTONE_CONF eventlet_server_ssl keyfile $KEYSTONE_SSL_KEY - fi + local service_port=$KEYSTONE_SERVICE_PORT + local auth_port=$KEYSTONE_AUTH_PORT if is_service_enabled tls-proxy; then # Set the service ports for a proxy to take the originals - iniset $KEYSTONE_CONF eventlet_server public_port $KEYSTONE_SERVICE_PORT_INT - iniset $KEYSTONE_CONF eventlet_server admin_port $KEYSTONE_AUTH_PORT_INT + service_port=$KEYSTONE_SERVICE_PORT_INT + auth_port=$KEYSTONE_AUTH_PORT_INT fi - iniset $KEYSTONE_CONF DEFAULT admin_token "$SERVICE_TOKEN" + # Override the endpoints advertised by keystone (the public_endpoint and + # admin_endpoint) so that clients use the correct endpoint. By default, the + # keystone server uses the public_port and admin_port which isn't going to + # work when you want to use a different port (in the case of proxy), or you + # don't want the port (in the case of putting keystone on a path in + # apache). + iniset $KEYSTONE_CONF DEFAULT public_endpoint $KEYSTONE_SERVICE_URI + iniset $KEYSTONE_CONF DEFAULT admin_endpoint $KEYSTONE_AUTH_URI if [[ "$KEYSTONE_TOKEN_FORMAT" != "" ]]; then - iniset $KEYSTONE_CONF token provider keystone.token.providers.$KEYSTONE_TOKEN_FORMAT.Provider + iniset $KEYSTONE_CONF token provider $KEYSTONE_TOKEN_FORMAT fi iniset $KEYSTONE_CONF database connection `database_connection_url keystone` - iniset $KEYSTONE_CONF ec2 driver "keystone.contrib.ec2.backends.sql.Ec2" - - if [[ "$KEYSTONE_TOKEN_BACKEND" = "sql" ]]; then - iniset $KEYSTONE_CONF token driver keystone.token.persistence.backends.sql.Token - elif [[ "$KEYSTONE_TOKEN_BACKEND" = "memcache" ]]; then - iniset $KEYSTONE_CONF token driver keystone.token.persistence.backends.memcache.Token - else - iniset $KEYSTONE_CONF token driver keystone.token.persistence.backends.kvs.Token - fi - - if [[ "$KEYSTONE_CATALOG_BACKEND" = "sql" ]]; then - # Configure ``keystone.conf`` to use sql - iniset $KEYSTONE_CONF catalog driver keystone.catalog.backends.sql.Catalog - inicomment $KEYSTONE_CONF catalog template_file - else - cp -p $FILES/default_catalog.templates $KEYSTONE_CATALOG - - # Add swift endpoints to service catalog if swift is enabled - if is_service_enabled s-proxy; then - echo "catalog.RegionOne.object_store.publicURL = http://%SERVICE_HOST%:8080/v1/AUTH_\$(tenant_id)s" >> $KEYSTONE_CATALOG - echo "catalog.RegionOne.object_store.adminURL = http://%SERVICE_HOST%:8080/" >> $KEYSTONE_CATALOG - echo "catalog.RegionOne.object_store.internalURL = http://%SERVICE_HOST%:8080/v1/AUTH_\$(tenant_id)s" >> $KEYSTONE_CATALOG - echo "catalog.RegionOne.object_store.name = Swift Service" >> $KEYSTONE_CATALOG - fi - - # Add neutron endpoints to service catalog if neutron is enabled - if is_service_enabled neutron; then - echo "catalog.RegionOne.network.publicURL = http://%SERVICE_HOST%:$Q_PORT/" >> $KEYSTONE_CATALOG - echo "catalog.RegionOne.network.adminURL = http://%SERVICE_HOST%:$Q_PORT/" >> $KEYSTONE_CATALOG - echo "catalog.RegionOne.network.internalURL = http://%SERVICE_HOST%:$Q_PORT/" >> $KEYSTONE_CATALOG - echo "catalog.RegionOne.network.name = Neutron Service" >> $KEYSTONE_CATALOG - fi - - sed -e " - s,%SERVICE_HOST%,$SERVICE_HOST,g; - s,%S3_SERVICE_PORT%,$S3_SERVICE_PORT,g; - " -i $KEYSTONE_CATALOG - - # Configure ``keystone.conf`` to use templates - iniset $KEYSTONE_CONF catalog driver "keystone.catalog.backends.templated.Catalog" - iniset $KEYSTONE_CONF catalog template_file "$KEYSTONE_CATALOG" - fi # Set up logging if [ "$SYSLOG" != "False" ]; then @@ -310,125 +249,135 @@ function configure_keystone { fi # Format logging - if [ "$LOG_COLOR" == "True" ] && [ "$SYSLOG" == "False" ] && [ "$KEYSTONE_USE_MOD_WSGI" == "False" ] ; then - setup_colorized_logging $KEYSTONE_CONF DEFAULT - fi + setup_logging $KEYSTONE_CONF iniset $KEYSTONE_CONF DEFAULT debug $ENABLE_DEBUG_LOG_LEVEL - if [ "$KEYSTONE_USE_MOD_WSGI" == "True" ]; then - # Eliminate the %(asctime)s.%(msecs)03d from the log format strings - iniset $KEYSTONE_CONF DEFAULT logging_context_format_string "%(process)d %(levelname)s %(name)s [%(request_id)s %(user_identity)s] %(instance)s%(message)s" - iniset $KEYSTONE_CONF DEFAULT logging_default_format_string "%(process)d %(levelname)s %(name)s [-] %(instance)s%(message)s" - iniset $KEYSTONE_CONF DEFAULT logging_debug_format_suffix "%(funcName)s %(pathname)s:%(lineno)d" - iniset $KEYSTONE_CONF DEFAULT logging_exception_prefix "%(process)d TRACE %(name)s %(instance)s" + if [ "$KEYSTONE_DEPLOY" == "mod_wsgi" ]; then + iniset $KEYSTONE_CONF DEFAULT logging_exception_prefix "%(asctime)s.%(msecs)03d %(process)d TRACE %(name)s %(instance)s" _config_keystone_apache_wsgi + else # uwsgi + write_uwsgi_config "$KEYSTONE_PUBLIC_UWSGI_CONF" "$KEYSTONE_PUBLIC_UWSGI" "/identity" + write_uwsgi_config "$KEYSTONE_ADMIN_UWSGI_CONF" "$KEYSTONE_ADMIN_UWSGI" "/identity_admin" fi iniset $KEYSTONE_CONF DEFAULT max_token_size 16384 - iniset $KEYSTONE_CONF eventlet_server admin_workers "$API_WORKERS" - # Public workers will use the server default, typically number of CPU. -} + iniset $KEYSTONE_CONF fernet_tokens key_repository "$KEYSTONE_CONF_DIR/fernet-keys/" + + iniset $KEYSTONE_CONF credential key_repository "$KEYSTONE_CONF_DIR/credential-keys/" -function configure_keystone_extensions { - # Add keystone extension into keystone v3 application pipeline - local extension_value - local api_v3 - local extension - local api_v3_extension - for extension_value in ${KEYSTONE_EXTENSIONS//,/ }; do - if [[ -z "${extension_value}" ]]; then - continue - fi - api_v3=$(iniget $KEYSTONE_PASTE_INI pipeline:api_v3 pipeline) - extension=$(echo $api_v3 | sed -ne "/${extension_value}/ p;" ) - if [[ -z $extension ]]; then - api_v3_extension=$(echo $api_v3 | sed -ne "s/service_v3/${extension_value}_extension service_v3/p;" ) - iniset $KEYSTONE_PASTE_INI pipeline:api_v3 pipeline "$api_v3_extension" - fi - done + # Configure the project created by the 'keystone-manage bootstrap' as the cloud-admin project. + # The users from this project are globally admin as before, but it also + # allows policy changes in order to clarify the adminess scope. + #iniset $KEYSTONE_CONF resource admin_project_domain_name Default + #iniset $KEYSTONE_CONF resource admin_project_name admin + + if [[ "$KEYSTONE_SECURITY_COMPLIANCE_ENABLED" = True ]]; then + iniset $KEYSTONE_CONF security_compliance lockout_failure_attempts $KEYSTONE_LOCKOUT_FAILURE_ATTEMPTS + iniset $KEYSTONE_CONF security_compliance lockout_duration $KEYSTONE_LOCKOUT_DURATION + iniset $KEYSTONE_CONF security_compliance unique_last_password_count $KEYSTONE_UNIQUE_LAST_PASSWORD_COUNT + fi } # create_keystone_accounts() - Sets up common required keystone accounts -# Tenant User Roles +# Project User Roles # ------------------------------------------------------------------ # admin admin admin # service -- -- # -- -- service # -- -- ResellerAdmin -# -- -- Member +# -- -- member # demo admin admin -# demo demo Member, anotherrole -# invisible_to_admin demo Member +# demo demo member, anotherrole +# alt_demo admin admin +# alt_demo alt_demo member, anotherrole +# invisible_to_admin demo member -# Group Users Roles Tenant +# Group Users Roles Project # ------------------------------------------------------------------ -# admins admin admin admin -# nonadmin demo Member, anotherrole demo +# admins admin admin admin +# nonadmins demo, alt_demo member, anotherrole demo, alt_demo # Migrated from keystone_data.sh function create_keystone_accounts { - # admin - local admin_tenant=$(get_or_create_project "admin") - local admin_user=$(get_or_create_user "admin" "$ADMIN_PASSWORD") - local admin_role=$(get_or_create_role "admin") - get_or_add_user_project_role $admin_role $admin_user $admin_tenant + # The keystone bootstrapping process (performed via keystone-manage + # bootstrap) creates an admin user, admin role, member role, and admin + # project. As a sanity check we exercise the CLI to retrieve the IDs for + # these values. + local admin_project + admin_project=$(openstack project show "admin" -f value -c id) + local admin_user + admin_user=$(openstack user show "admin" -f value -c id) + local admin_role="admin" + local member_role="member" + + get_or_add_user_domain_role $admin_role $admin_user default # Create service project/role - get_or_create_project "$SERVICE_TENANT_NAME" + get_or_create_domain "$SERVICE_DOMAIN_NAME" + get_or_create_project "$SERVICE_PROJECT_NAME" "$SERVICE_DOMAIN_NAME" # Service role, so service users do not have to be admins get_or_create_role service # The ResellerAdmin role is used by Nova and Ceilometer so we need to keep it. - # The admin role in swift allows a user to act as an admin for their tenant, - # but ResellerAdmin is needed for a user to act as any tenant. The name of this + # The admin role in swift allows a user to act as an admin for their project, + # but ResellerAdmin is needed for a user to act as any project. The name of this # role is also configurable in swift-proxy.conf get_or_create_role ResellerAdmin - # The Member role is used by Horizon and Swift so we need to keep it: - local member_role=$(get_or_create_role "Member") - # another_role demonstrates that an arbitrary role may be created and used # TODO(sleepsonthefloor): show how this can be used for rbac in the future! - local another_role=$(get_or_create_role "anotherrole") + local another_role="anotherrole" + get_or_create_role $another_role - # invisible tenant - admin can't see this one - local invis_tenant=$(get_or_create_project "invisible_to_admin") + # invisible project - admin can't see this one + local invis_project + invis_project=$(get_or_create_project "invisible_to_admin" default) # demo - local demo_tenant=$(get_or_create_project "demo") - local demo_user=$(get_or_create_user "demo" \ - "$ADMIN_PASSWORD" "demo@example.com") - - get_or_add_user_project_role $member_role $demo_user $demo_tenant - get_or_add_user_project_role $admin_role $admin_user $demo_tenant - get_or_add_user_project_role $another_role $demo_user $demo_tenant - get_or_add_user_project_role $member_role $demo_user $invis_tenant - - local admin_group=$(get_or_create_group "admins" \ + local demo_project + demo_project=$(get_or_create_project "demo" default) + local demo_user + demo_user=$(get_or_create_user "demo" \ + "$ADMIN_PASSWORD" "default" "demo@example.com") + + get_or_add_user_project_role $member_role $demo_user $demo_project + get_or_add_user_project_role $admin_role $admin_user $demo_project + get_or_add_user_project_role $another_role $demo_user $demo_project + get_or_add_user_project_role $member_role $demo_user $invis_project + + # alt_demo + local alt_demo_project + alt_demo_project=$(get_or_create_project "alt_demo" default) + local alt_demo_user + alt_demo_user=$(get_or_create_user "alt_demo" \ + "$ADMIN_PASSWORD" "default" "alt_demo@example.com") + + get_or_add_user_project_role $member_role $alt_demo_user $alt_demo_project + get_or_add_user_project_role $admin_role $admin_user $alt_demo_project + get_or_add_user_project_role $another_role $alt_demo_user $alt_demo_project + + # groups + local admin_group + admin_group=$(get_or_create_group "admins" \ "default" "openstack admin group") - local non_admin_group=$(get_or_create_group "nonadmins" \ + local non_admin_group + non_admin_group=$(get_or_create_group "nonadmins" \ "default" "non-admin group") - get_or_add_group_project_role $member_role $non_admin_group $demo_tenant - get_or_add_group_project_role $another_role $non_admin_group $demo_tenant - get_or_add_group_project_role $admin_role $admin_group $admin_tenant + get_or_add_group_project_role $member_role $non_admin_group $demo_project + get_or_add_group_project_role $another_role $non_admin_group $demo_project + get_or_add_group_project_role $member_role $non_admin_group $alt_demo_project + get_or_add_group_project_role $another_role $non_admin_group $alt_demo_project + get_or_add_group_project_role $admin_role $admin_group $admin_project - # Keystone - if [[ "$KEYSTONE_CATALOG_BACKEND" = 'sql' ]]; then - - KEYSTONE_SERVICE=$(get_or_create_service "keystone" \ - "identity" "Keystone Identity Service") - get_or_create_endpoint $KEYSTONE_SERVICE \ - "$REGION_NAME" \ - "$KEYSTONE_SERVICE_PROTOCOL://$KEYSTONE_SERVICE_HOST:$KEYSTONE_SERVICE_PORT/v$IDENTITY_API_VERSION" \ - "$KEYSTONE_AUTH_PROTOCOL://$KEYSTONE_AUTH_HOST:$KEYSTONE_AUTH_PORT/v$IDENTITY_API_VERSION" \ - "$KEYSTONE_SERVICE_PROTOCOL://$KEYSTONE_SERVICE_HOST:$KEYSTONE_SERVICE_PORT/v$IDENTITY_API_VERSION" + if is_service_enabled ldap; then + create_ldap_domain fi } @@ -436,14 +385,16 @@ function create_keystone_accounts { # # create_service_user [role] # -# The role defaults to the service role. It is allowed to be provided as optional as historically +# We always add the service role, other roles are also allowed to be added as historically # a lot of projects have configured themselves with the admin or other role here if they are # using this user for other purposes beyond simply auth_token middleware. function create_service_user { - local role=${2:-service} + get_or_create_user "$1" "$SERVICE_PASSWORD" "$SERVICE_DOMAIN_NAME" + get_or_add_user_project_role service "$1" "$SERVICE_PROJECT_NAME" "$SERVICE_DOMAIN_NAME" "$SERVICE_DOMAIN_NAME" - local user=$(get_or_create_user "$1" "$SERVICE_PASSWORD") - get_or_add_user_project_role "$role" "$user" "$SERVICE_TENANT_NAME" + if [[ -n "$2" ]]; then + get_or_add_user_project_role "$2" "$1" "$SERVICE_PROJECT_NAME" "$SERVICE_DOMAIN_NAME" "$SERVICE_DOMAIN_NAME" + fi } # Configure the service to use the auth token middleware. @@ -459,17 +410,17 @@ function configure_auth_token_middleware { local signing_dir=$3 local section=${4:-keystone_authtoken} - iniset $conf_file $section auth_plugin password - iniset $conf_file $section auth_url $KEYSTONE_AUTH_URI + iniset $conf_file $section auth_type password + iniset $conf_file $section auth_url $KEYSTONE_SERVICE_URI iniset $conf_file $section username $admin_user iniset $conf_file $section password $SERVICE_PASSWORD - iniset $conf_file $section user_domain_id default - iniset $conf_file $section project_name $SERVICE_TENANT_NAME - iniset $conf_file $section project_domain_id default + iniset $conf_file $section user_domain_name "$SERVICE_DOMAIN_NAME" + iniset $conf_file $section project_name $SERVICE_PROJECT_NAME + iniset $conf_file $section project_domain_name "$SERVICE_DOMAIN_NAME" - iniset $conf_file $section auth_uri $KEYSTONE_SERVICE_URI iniset $conf_file $section cafile $SSL_BUNDLE_FILE iniset $conf_file $section signing_dir $signing_dir + iniset $conf_file $section memcached_servers localhost:11211 } # init_keystone() - Initialize databases, etc. @@ -478,28 +429,30 @@ function init_keystone { init_ldap fi - # (Re)create keystone database - recreate_database keystone + if [[ "$RECREATE_KEYSTONE_DB" == True ]]; then + # (Re)create keystone database + recreate_database keystone + fi + time_start "dbsync" # Initialize keystone database - $KEYSTONE_BIN_DIR/keystone-manage db_sync - - local extension_value - for extension_value in ${KEYSTONE_EXTENSIONS//,/ }; do - if [[ -z "${extension_value}" ]]; then - continue - fi - $KEYSTONE_BIN_DIR/keystone-manage db_sync --extension "${extension_value}" - done - - if [[ "$KEYSTONE_TOKEN_FORMAT" != "uuid" ]]; then - # Set up certificates - rm -rf $KEYSTONE_CONF_DIR/ssl - $KEYSTONE_BIN_DIR/keystone-manage pki_setup - - # Create cache dir - sudo install -d -o $STACK_USER $KEYSTONE_AUTH_CACHE_DIR - rm -f $KEYSTONE_AUTH_CACHE_DIR/* + $KEYSTONE_BIN_DIR/keystone-manage --config-file $KEYSTONE_CONF db_sync + time_stop "dbsync" + + if [[ "$KEYSTONE_TOKEN_FORMAT" == "fernet" ]]; then + rm -rf "$KEYSTONE_CONF_DIR/fernet-keys/" + $KEYSTONE_BIN_DIR/keystone-manage --config-file $KEYSTONE_CONF fernet_setup + fi + rm -rf "$KEYSTONE_CONF_DIR/credential-keys/" + $KEYSTONE_BIN_DIR/keystone-manage --config-file $KEYSTONE_CONF credential_setup + +} + +# install_keystoneauth() - Collect source and prepare +function install_keystoneauth { + if use_library_from_git "keystoneauth"; then + git_clone_by_name "keystoneauth" + setup_dev_lib "keystoneauth" fi } @@ -508,7 +461,6 @@ function install_keystoneclient { if use_library_from_git "python-keystoneclient"; then git_clone_by_name "python-keystoneclient" setup_dev_lib "python-keystoneclient" - sudo install -D -m 0644 -o $STACK_USER {${GITDIR["python-keystoneclient"]}/tools/,/etc/bash_completion.d/}keystone.bash_completion fi } @@ -523,6 +475,9 @@ function install_keystonemiddleware { # When not installing from repo, keystonemiddleware is still needed... pip_install_gr keystonemiddleware fi + # Install the memcache library so keystonemiddleware can cache tokens in a + # shared location. + pip_install_gr python-memcached } # install_keystone() - Collect source and prepare @@ -531,28 +486,22 @@ function install_keystone { if is_service_enabled ldap; then install_ldap fi - if [[ "$KEYSTONE_TOKEN_BACKEND" = "memcache" ]]; then - # Install memcached and the memcache Python library that keystone uses. - # Unfortunately the Python library goes by different names in the .deb - # and .rpm circles. - install_package memcached - if is_ubuntu; then - install_package python-memcache - else - install_package python-memcached - fi - fi + git_clone $KEYSTONE_REPO $KEYSTONE_DIR $KEYSTONE_BRANCH setup_develop $KEYSTONE_DIR - if [ "$KEYSTONE_USE_MOD_WSGI" == "True" ]; then + + if is_service_enabled ldap; then + setup_develop $KEYSTONE_DIR ldap + fi + + if [ "$KEYSTONE_DEPLOY" == "mod_wsgi" ]; then install_apache_wsgi - if is_ssl_enabled_service "key"; then - enable_mod_ssl - fi + elif [ "$KEYSTONE_DEPLOY" == "uwsgi" ]; then + pip_install uwsgi fi } -# start_keystone() - Start running processes, including screen +# start_keystone() - Start running processes function start_keystone { # Get right service port for testing local service_port=$KEYSTONE_SERVICE_PORT @@ -562,44 +511,120 @@ function start_keystone { auth_protocol="http" fi - if [ "$KEYSTONE_USE_MOD_WSGI" == "True" ]; then + if [ "$KEYSTONE_DEPLOY" == "mod_wsgi" ]; then enable_apache_site keystone restart_apache_server - tail_log key /var/log/$APACHE_NAME/keystone.log - tail_log key-access /var/log/$APACHE_NAME/keystone_access.log - else - # Start Keystone in a screen window - run_process key "$KEYSTONE_BIN_DIR/keystone-all --config-file $KEYSTONE_CONF" + else # uwsgi + run_process keystone "$KEYSTONE_BIN_DIR/uwsgi --procname-prefix keystone --ini $KEYSTONE_PUBLIC_UWSGI_CONF" "" fi echo "Waiting for keystone to start..." # Check that the keystone service is running. Even if the tls tunnel # should be enabled, make sure the internal port is checked using # unencryted traffic at this point. - if ! wait_for_service $SERVICE_TIMEOUT $auth_protocol://$KEYSTONE_SERVICE_HOST:$service_port/v$IDENTITY_API_VERSION/; then + # If running in Apache, use the path rather than port. + + local service_uri=$auth_protocol://$KEYSTONE_SERVICE_HOST/identity/v$IDENTITY_API_VERSION/ + + if ! wait_for_service $SERVICE_TIMEOUT $service_uri; then die $LINENO "keystone did not start" fi # Start proxies if enabled if is_service_enabled tls-proxy; then - start_tls_proxy '*' $KEYSTONE_SERVICE_PORT $KEYSTONE_SERVICE_HOST $KEYSTONE_SERVICE_PORT_INT & - start_tls_proxy '*' $KEYSTONE_AUTH_PORT $KEYSTONE_AUTH_HOST $KEYSTONE_AUTH_PORT_INT & + start_tls_proxy keystone-service '*' $KEYSTONE_SERVICE_PORT $KEYSTONE_SERVICE_HOST $KEYSTONE_SERVICE_PORT_INT + start_tls_proxy keystone-auth '*' $KEYSTONE_AUTH_PORT $KEYSTONE_AUTH_HOST $KEYSTONE_AUTH_PORT_INT fi + + # (re)start memcached to make sure we have a clean memcache. + restart_service memcached } # stop_keystone() - Stop running processes function stop_keystone { - if [ "$KEYSTONE_USE_MOD_WSGI" == "True" ]; then + if [ "$KEYSTONE_DEPLOY" == "mod_wsgi" ]; then disable_apache_site keystone restart_apache_server + else + stop_process keystone fi - # Kill the Keystone screen window - stop_process key } +# bootstrap_keystone() - Initialize user, role and project +# This function uses the following GLOBAL variables: +# - ``KEYSTONE_BIN_DIR`` +# - ``ADMIN_PASSWORD`` +# - ``IDENTITY_API_VERSION`` +# - ``KEYSTONE_AUTH_URI`` +# - ``REGION_NAME`` +# - ``KEYSTONE_SERVICE_PROTOCOL`` +# - ``KEYSTONE_SERVICE_HOST`` +# - ``KEYSTONE_SERVICE_PORT`` +function bootstrap_keystone { + $KEYSTONE_BIN_DIR/keystone-manage bootstrap \ + --bootstrap-username admin \ + --bootstrap-password "$ADMIN_PASSWORD" \ + --bootstrap-project-name admin \ + --bootstrap-role-name admin \ + --bootstrap-service-name keystone \ + --bootstrap-region-id "$REGION_NAME" \ + --bootstrap-admin-url "$KEYSTONE_AUTH_URI" \ + --bootstrap-public-url "$KEYSTONE_SERVICE_URI" +} + +# create_ldap_domain() - Create domain file and initialize domain with a user +function create_ldap_domain { + # Creates domain Users + openstack --os-identity-api-version=3 domain create --description "LDAP domain" Users + + # Create domain file inside etc/keystone/domains + KEYSTONE_LDAP_DOMAIN_FILE=$KEYSTONE_CONF_DIR/domains/keystone.Users.conf + mkdir -p "$KEYSTONE_CONF_DIR/domains" + touch "$KEYSTONE_LDAP_DOMAIN_FILE" + + # Set identity driver 'ldap' + iniset $KEYSTONE_LDAP_DOMAIN_FILE identity driver "ldap" + + # LDAP settings for Users domain + iniset $KEYSTONE_LDAP_DOMAIN_FILE ldap user_tree_dn "ou=Users,$LDAP_BASE_DN" + iniset $KEYSTONE_LDAP_DOMAIN_FILE ldap user_objectclass "inetOrgPerson" + iniset $KEYSTONE_LDAP_DOMAIN_FILE ldap user_name_attribute "cn" + iniset $KEYSTONE_LDAP_DOMAIN_FILE ldap user_mail_attribute "mail" + iniset $KEYSTONE_LDAP_DOMAIN_FILE ldap user_id_attribute "uid" + iniset $KEYSTONE_LDAP_DOMAIN_FILE ldap user "cn=Manager,dc=openstack,dc=org" + iniset $KEYSTONE_LDAP_DOMAIN_FILE ldap url "ldap://localhost" + iniset $KEYSTONE_LDAP_DOMAIN_FILE ldap suffix $LDAP_BASE_DN + iniset $KEYSTONE_LDAP_DOMAIN_FILE ldap password $LDAP_PASSWORD + iniset $KEYSTONE_LDAP_DOMAIN_FILE ldap group_tree_dn "ou=Groups,$LDAP_BASE_DN" + iniset $KEYSTONE_LDAP_DOMAIN_FILE ldap group_objectclass "groupOfNames" + iniset $KEYSTONE_LDAP_DOMAIN_FILE ldap group_name_attribute "cn" + iniset $KEYSTONE_LDAP_DOMAIN_FILE ldap group_id_attribute "cn" + + # Restart apache and identity services to associate domain and conf file + sudo service apache2 reload + sudo systemctl restart devstack@keystone + + # Create LDAP user.ldif and add user to LDAP backend + local tmp_ldap_dir + tmp_ldap_dir=$(mktemp -d -t ldap.$$.XXXXXXXXXX) + + _ldap_varsubst $FILES/ldap/user.ldif.in $slappass >$tmp_ldap_dir/user.ldif + sudo ldapadd -x -w $LDAP_PASSWORD -D "$LDAP_MANAGER_DN" -H $LDAP_URL -c -f $tmp_ldap_dir/user.ldif + rm -rf $tmp_ldap_dir + + local admin_project + admin_project=$(get_or_create_project "admin" default) + local ldap_user + ldap_user=$(openstack user show --domain=Users demo -f value -c id) + local admin_role="admin" + get_or_create_role $admin_role + + # Grant demo LDAP user access to project and role + get_or_add_user_project_role $admin_role $ldap_user $admin_project +} # Restore xtrace -$XTRACE +$_XTRACE_KEYSTONE # Tell emacs to use shell-script-mode ## Local variables: diff --git a/lib/ldap b/lib/ldap index d2dbc3b728..5a53d0eaee 100644 --- a/lib/ldap +++ b/lib/ldap @@ -8,7 +8,7 @@ # - install_ldap() # Save trace setting -XTRACE=$(set +o | grep xtrace) +_XTRACE_LDAP=$(set +o | grep xtrace) set +o xtrace @@ -82,7 +82,8 @@ function cleanup_ldap { function init_ldap { local keystone_ldif - local tmp_ldap_dir=$(mktemp -d -t ldap.$$.XXXXXXXXXX) + local tmp_ldap_dir + tmp_ldap_dir=$(mktemp -d -t ldap.$$.XXXXXXXXXX) # Remove data but not schemas clear_ldap_state @@ -113,12 +114,12 @@ function install_ldap { echo "Installing LDAP inside function" echo "os_VENDOR is $os_VENDOR" - local tmp_ldap_dir=$(mktemp -d -t ldap.$$.XXXXXXXXXX) + local tmp_ldap_dir + tmp_ldap_dir=$(mktemp -d -t ldap.$$.XXXXXXXXXX) printf "installing OpenLDAP" if is_ubuntu; then - # Ubuntu automatically starts LDAP so no need to call start_ldap() - : + configure_ldap elif is_fedora; then start_ldap elif is_suse; then @@ -129,7 +130,8 @@ function install_ldap { fi echo "LDAP_PASSWORD is $LDAP_PASSWORD" - local slappass=$(slappasswd -s $LDAP_PASSWORD) + local slappass + slappass=$(slappasswd -s $LDAP_PASSWORD) printf "LDAP secret is $slappass\n" # Create manager.ldif and add to olcdb @@ -142,11 +144,30 @@ function install_ldap { sudo ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/openldap/schema/inetorgperson.ldif fi - pip_install_gr ldappool - rm -rf $tmp_ldap_dir } +# configure_ldap() - Configure LDAP - reconfigure slapd +function configure_ldap { + sudo debconf-set-selections </dev/null)" ]]; then @@ -78,7 +88,7 @@ function clean_lvm_volume_group { } -# _create_volume_group creates default volume group +# _create_lvm_volume_group creates default volume group # # Usage: _create_lvm_volume_group() $vg $size function _create_lvm_volume_group { @@ -89,7 +99,15 @@ function _create_lvm_volume_group { if ! sudo vgs $vg; then # Only create if the file doesn't already exists [[ -f $backing_file ]] || truncate -s $size $backing_file - local vg_dev=`sudo losetup -f --show $backing_file` + + local directio="" + # Check to see if we can do direct-io + if losetup -h | grep -q direct-io; then + directio="--direct-io=on" + fi + + local vg_dev + vg_dev=$(sudo losetup -f --show $directio $backing_file) # Only create volume group if it doesn't already exist if ! sudo vgs $vg; then @@ -101,7 +119,7 @@ function _create_lvm_volume_group { # init_lvm_volume_group() initializes the volume group creating the backing # file if necessary # -# Usage: init_lvm_volume_group() $vg +# Usage: init_lvm_volume_group() $vg $size function init_lvm_volume_group { local vg=$1 local size=$2 @@ -122,7 +140,7 @@ function init_lvm_volume_group { if [ "$CINDER_ISCSI_HELPER" = "lioadm" ]; then sudo cinder-rtstool get-targets | sudo xargs -rn 1 cinder-rtstool delete else - sudo tgtadm --op show --mode target | grep Target | cut -f3 -d ' ' | sudo xargs -n1 tgt-admin --delete || true + sudo tgtadm --op show --mode target | awk '/Target/ {print $3}' | sudo xargs -r -n1 tgt-admin --delete fi _clean_lvm_volume_group $vg } @@ -180,7 +198,7 @@ function set_lvm_filter { } # Restore xtrace -$MY_XTRACE +$_XTRACE_LVM # mode: shell-script # End: diff --git a/lib/neutron b/lib/neutron new file mode 100644 index 0000000000..62f7366e7e --- /dev/null +++ b/lib/neutron @@ -0,0 +1,730 @@ +#!/bin/bash +# +# lib/neutron +# Install and start **Neutron** network services + +# Dependencies: +# +# ``functions`` file +# ``DEST`` must be defined + +# ``stack.sh`` calls the entry points in this order: +# +# - is_XXXX_enabled +# - install_XXXX +# - configure_XXXX +# - init_XXXX +# - start_XXXX +# - stop_XXXX +# - cleanup_XXXX + +# Save trace setting +XTRACE=$(set +o | grep xtrace) +set +o xtrace + +# Defaults +# -------- + +# Set up default directories +GITDIR["python-neutronclient"]=$DEST/python-neutronclient + +# NEUTRON_DEPLOY_MOD_WSGI defines how neutron is deployed, allowed values: +# - False (default) : Run neutron under Eventlet +# - True : Run neutron under uwsgi +# TODO(annp): Switching to uwsgi in next cycle if things turn out to be stable +# enough +NEUTRON_DEPLOY_MOD_WSGI=${NEUTRON_DEPLOY_MOD_WSGI:-False} +NEUTRON_AGENT=${NEUTRON_AGENT:-openvswitch} +NEUTRON_DIR=$DEST/neutron +NEUTRON_AUTH_CACHE_DIR=${NEUTRON_AUTH_CACHE_DIR:-/var/cache/neutron} + +NEUTRON_DISTRIBUTED_ROUTING=$(trueorfalse False NEUTRON_DISTRIBUTED_ROUTING) +# Distributed Virtual Router (DVR) configuration +# Can be: +# - ``legacy`` - No DVR functionality +# - ``dvr_snat`` - Controller or single node DVR +# - ``dvr`` - Compute node in multi-node DVR +# - ``dvr_no_external`` - Compute node in multi-node DVR, no external network +# +# Default is 'dvr_snat' since it can handle both DVR and legacy routers +NEUTRON_DVR_MODE=${NEUTRON_DVR_MODE:-dvr_snat} + +NEUTRON_BIN_DIR=$(get_python_exec_prefix) +NEUTRON_DHCP_BINARY="neutron-dhcp-agent" + +NEUTRON_CONF_DIR=/etc/neutron +NEUTRON_CONF=$NEUTRON_CONF_DIR/neutron.conf +NEUTRON_META_CONF=$NEUTRON_CONF_DIR/metadata_agent.ini + +NEUTRON_DHCP_CONF=$NEUTRON_CONF_DIR/dhcp_agent.ini +NEUTRON_L3_CONF=$NEUTRON_CONF_DIR/l3_agent.ini +NEUTRON_AGENT_CONF=$NEUTRON_CONF_DIR/ +NEUTRON_CREATE_INITIAL_NETWORKS=${NEUTRON_CREATE_INITIAL_NETWORKS:-True} + +NEUTRON_STATE_PATH=${NEUTRON_STATE_PATH:=$DATA_DIR/neutron} +NEUTRON_AUTH_CACHE_DIR=${NEUTRON_AUTH_CACHE_DIR:-/var/cache/neutron} + +NEUTRON_UWSGI_CONF=$NEUTRON_CONF_DIR/neutron-api-uwsgi.ini + +# By default, use the ML2 plugin +NEUTRON_CORE_PLUGIN=${NEUTRON_CORE_PLUGIN:-ml2} +NEUTRON_CORE_PLUGIN_CONF_FILENAME=${NEUTRON_CORE_PLUGIN_CONF_FILENAME:-ml2_conf.ini} +NEUTRON_CORE_PLUGIN_CONF_PATH=$NEUTRON_CONF_DIR/plugins/$NEUTRON_CORE_PLUGIN +NEUTRON_CORE_PLUGIN_CONF=$NEUTRON_CORE_PLUGIN_CONF_PATH/$NEUTRON_CORE_PLUGIN_CONF_FILENAME + +NEUTRON_METERING_AGENT_CONF_FILENAME=${NEUTRON_METERING_AGENT_CONF_FILENAME:-metering_agent.ini} +NEUTRON_METERING_AGENT_CONF=$NEUTRON_CONF_DIR/$NEUTRON_METERING_AGENT_CONF_FILENAME + +NEUTRON_AGENT_BINARY=${NEUTRON_AGENT_BINARY:-neutron-$NEUTRON_AGENT-agent} +NEUTRON_L3_BINARY=${NEUTRON_L3_BINARY:-neutron-l3-agent} +NEUTRON_META_BINARY=${NEUTRON_META_BINARY:-neutron-metadata-agent} +NEUTRON_METERING_BINARY=${NEUTRON_METERING_BINARY:-neutron-metering-agent} + +# Public facing bits +if is_service_enabled tls-proxy; then + NEUTRON_SERVICE_PROTOCOL="https" +fi +NEUTRON_SERVICE_HOST=${NEUTRON_SERVICE_HOST:-$SERVICE_HOST} +NEUTRON_SERVICE_PORT=${NEUTRON_SERVICE_PORT:-9696} +NEUTRON_SERVICE_PORT_INT=${NEUTRON_SERVICE_PORT_INT:-19696} +NEUTRON_SERVICE_PROTOCOL=${NEUTRON_SERVICE_PROTOCOL:-$SERVICE_PROTOCOL} + +NEUTRON_AUTH_STRATEGY=${NEUTRON_AUTH_STRATEGY:-keystone} +NEUTRON_ROOTWRAP=$(get_rootwrap_location neutron) +NEUTRON_ROOTWRAP_CONF_FILE=$NEUTRON_CONF_DIR/rootwrap.conf +NEUTRON_ROOTWRAP_CMD="$NEUTRON_ROOTWRAP $NEUTRON_ROOTWRAP_CONF_FILE" +NEUTRON_ROOTWRAP_DAEMON_CMD="$NEUTRON_ROOTWRAP-daemon $NEUTRON_ROOTWRAP_CONF_FILE" + +# This is needed because _neutron_ovs_base_configure_l3_agent will set +# external_network_bridge +Q_USE_PROVIDERNET_FOR_PUBLIC=${Q_USE_PROVIDERNET_FOR_PUBLIC:-True} +# This is needed because _neutron_ovs_base_configure_l3_agent uses it to create +# an external network bridge +PUBLIC_BRIDGE=${PUBLIC_BRIDGE:-br-ex} +PUBLIC_BRIDGE_MTU=${PUBLIC_BRIDGE_MTU:-1500} + +# Additional neutron api config files +declare -a -g _NEUTRON_SERVER_EXTRA_CONF_FILES_ABS + +# Functions +# --------- + +# Test if any Neutron services are enabled +# is_neutron_enabled +function is_neutron_enabled { + [[ ,${DISABLED_SERVICES} =~ ,"neutron" ]] && return 1 + [[ ,${ENABLED_SERVICES} =~ ,"neutron-" || ,${ENABLED_SERVICES} =~ ,"q-" ]] && return 0 + return 1 +} + +# Test if any Neutron services are enabled +# is_neutron_enabled +function is_neutron_legacy_enabled { + [[ ,${DISABLED_SERVICES} =~ ,"neutron" ]] && return 1 + [[ ,${ENABLED_SERVICES} =~ ,"q-" ]] && return 0 + return 1 +} + +if is_neutron_legacy_enabled; then + source $TOP_DIR/lib/neutron-legacy +fi + +# cleanup_neutron() - Remove residual data files, anything left over from previous +# runs that a clean run would need to clean up +function cleanup_neutron_new { + source $TOP_DIR/lib/neutron_plugins/${NEUTRON_AGENT}_agent + if is_neutron_ovs_base_plugin; then + neutron_ovs_base_cleanup + fi + + if [[ $NEUTRON_AGENT == "linuxbridge" ]]; then + neutron_lb_cleanup + fi + # delete all namespaces created by neutron + for ns in $(sudo ip netns list | grep -o -E '(qdhcp|qrouter|qlbaas|fip|snat)-[0-9a-f-]*'); do + sudo ip netns delete ${ns} + done +} + +# configure_root_helper_options() - Configure agent rootwrap helper options +function configure_root_helper_options { + local conffile=$1 + iniset $conffile agent root_helper "sudo $NEUTRON_ROOTWRAP_CMD" + iniset $conffile agent root_helper_daemon "sudo $NEUTRON_ROOTWRAP_DAEMON_CMD" +} + +# configure_neutron() - Set config files, create data dirs, etc +function configure_neutron_new { + sudo install -d -o $STACK_USER $NEUTRON_CONF_DIR + + (cd $NEUTRON_DIR && exec ./tools/generate_config_file_samples.sh) + + cp $NEUTRON_DIR/etc/neutron.conf.sample $NEUTRON_CONF + + configure_neutron_rootwrap + + mkdir -p $NEUTRON_CORE_PLUGIN_CONF_PATH + + # NOTE(yamamoto): A decomposed plugin should prepare the config file in + # its devstack plugin. + if [ -f $NEUTRON_DIR/etc/neutron/plugins/$NEUTRON_CORE_PLUGIN/$NEUTRON_CORE_PLUGIN_CONF_FILENAME.sample ]; then + cp $NEUTRON_DIR/etc/neutron/plugins/$NEUTRON_CORE_PLUGIN/$NEUTRON_CORE_PLUGIN_CONF_FILENAME.sample $NEUTRON_CORE_PLUGIN_CONF + fi + + iniset $NEUTRON_CONF database connection `database_connection_url neutron` + iniset $NEUTRON_CONF DEFAULT state_path $NEUTRON_STATE_PATH + iniset $NEUTRON_CONF oslo_concurrency lock_path $NEUTRON_STATE_PATH/lock + iniset $NEUTRON_CONF DEFAULT use_syslog $SYSLOG + + iniset $NEUTRON_CONF DEFAULT debug $ENABLE_DEBUG_LOG_LEVEL + + iniset_rpc_backend neutron $NEUTRON_CONF + + # Neutron API server & Neutron plugin + if is_service_enabled neutron-api; then + local policy_file=$NEUTRON_CONF_DIR/policy.json + # Allow neutron user to administer neutron to match neutron account + # NOTE(amotoki): This is required for nova works correctly with neutron. + if [ -f $NEUTRON_DIR/etc/policy.json ]; then + cp $NEUTRON_DIR/etc/policy.json $policy_file + sed -i 's/"context_is_admin": "role:admin"/"context_is_admin": "role:admin or user_name:neutron"/g' $policy_file + else + echo '{"context_is_admin": "role:admin or user_name:neutron"}' > $policy_file + fi + + cp $NEUTRON_DIR/etc/api-paste.ini $NEUTRON_CONF_DIR/api-paste.ini + + iniset $NEUTRON_CONF DEFAULT core_plugin $NEUTRON_CORE_PLUGIN + + iniset $NEUTRON_CONF DEFAULT policy_file $policy_file + iniset $NEUTRON_CONF DEFAULT allow_overlapping_ips True + iniset $NEUTRON_CONF DEFAULT router_distributed $NEUTRON_DISTRIBUTED_ROUTING + + iniset $NEUTRON_CONF DEFAULT auth_strategy $NEUTRON_AUTH_STRATEGY + configure_auth_token_middleware $NEUTRON_CONF neutron $NEUTRON_AUTH_CACHE_DIR keystone_authtoken + configure_auth_token_middleware $NEUTRON_CONF nova $NEUTRON_AUTH_CACHE_DIR nova + + # Configure VXLAN + # TODO(sc68cal) not hardcode? + iniset $NEUTRON_CORE_PLUGIN_CONF ml2 tenant_network_types vxlan + + local mech_drivers="openvswitch" + if [[ "$NEUTRON_DISTRIBUTED_ROUTING" = "True" ]]; then + mech_drivers+=",l2population" + else + mech_drivers+=",linuxbridge" + fi + iniset $NEUTRON_CORE_PLUGIN_CONF ml2 mechanism_drivers $mech_drivers + + iniset $NEUTRON_CORE_PLUGIN_CONF ml2_type_vxlan vni_ranges 1001:2000 + iniset $NEUTRON_CORE_PLUGIN_CONF ml2_type_flat flat_networks public + if [[ "$NEUTRON_PORT_SECURITY" = "True" ]]; then + neutron_ml2_extension_driver_add port_security + fi + fi + + # Neutron OVS or LB agent + if is_service_enabled neutron-agent; then + iniset $NEUTRON_CORE_PLUGIN_CONF agent tunnel_types vxlan + iniset $NEUTRON_CORE_PLUGIN_CONF DEFAULT debug $ENABLE_DEBUG_LOG_LEVEL + configure_root_helper_options $NEUTRON_CORE_PLUGIN_CONF + + # Configure the neutron agent + if [[ $NEUTRON_AGENT == "linuxbridge" ]]; then + iniset $NEUTRON_CORE_PLUGIN_CONF securitygroup firewall_driver iptables + iniset $NEUTRON_CORE_PLUGIN_CONF vxlan local_ip $HOST_IP + elif [[ $NEUTRON_AGENT == "openvswitch" ]]; then + iniset $NEUTRON_CORE_PLUGIN_CONF securitygroup firewall_driver openvswitch + iniset $NEUTRON_CORE_PLUGIN_CONF ovs local_ip $HOST_IP + + if [[ "$NEUTRON_DISTRIBUTED_ROUTING" = "True" ]]; then + iniset $NEUTRON_CORE_PLUGIN_CONF agent l2_population True + iniset $NEUTRON_CORE_PLUGIN_CONF agent enable_distributed_routing True + fi + fi + + if ! running_in_container; then + enable_kernel_bridge_firewall + fi + fi + + # DHCP Agent + if is_service_enabled neutron-dhcp; then + cp $NEUTRON_DIR/etc/dhcp_agent.ini.sample $NEUTRON_DHCP_CONF + + iniset $NEUTRON_DHCP_CONF DEFAULT debug $ENABLE_DEBUG_LOG_LEVEL + # make it so we have working DNS from guests + iniset $NEUTRON_DHCP_CONF DEFAULT dnsmasq_local_resolv True + + configure_root_helper_options $NEUTRON_DHCP_CONF + iniset $NEUTRON_DHCP_CONF DEFAULT interface_driver $NEUTRON_AGENT + neutron_plugin_configure_dhcp_agent $NEUTRON_DHCP_CONF + fi + + if is_service_enabled neutron-l3; then + cp $NEUTRON_DIR/etc/l3_agent.ini.sample $NEUTRON_L3_CONF + iniset $NEUTRON_L3_CONF DEFAULT interface_driver $NEUTRON_AGENT + neutron_service_plugin_class_add router + configure_root_helper_options $NEUTRON_L3_CONF + iniset $NEUTRON_L3_CONF DEFAULT debug $ENABLE_DEBUG_LOG_LEVEL + neutron_plugin_configure_l3_agent $NEUTRON_L3_CONF + + # Configure the neutron agent to serve external network ports + if [[ $NEUTRON_AGENT == "linuxbridge" ]]; then + iniset $NEUTRON_CORE_PLUGIN_CONF linux_bridge bridge_mappings "$PUBLIC_NETWORK_NAME:$PUBLIC_BRIDGE" + else + iniset $NEUTRON_CORE_PLUGIN_CONF ovs bridge_mappings "$PUBLIC_NETWORK_NAME:$PUBLIC_BRIDGE" + fi + + if [[ "$NEUTRON_DISTRIBUTED_ROUTING" = "True" ]]; then + iniset $NEUTRON_L3_CONF DEFAULT agent_mode $NEUTRON_DVR_MODE + fi + fi + + # Metadata + if is_service_enabled neutron-metadata-agent; then + cp $NEUTRON_DIR/etc/metadata_agent.ini.sample $NEUTRON_META_CONF + + iniset $NEUTRON_META_CONF DEFAULT debug $ENABLE_DEBUG_LOG_LEVEL + iniset $NEUTRON_META_CONF DEFAULT nova_metadata_host $SERVICE_HOST + iniset $NEUTRON_META_CONF DEFAULT metadata_workers $API_WORKERS + # TODO(ihrachys) do we really need to set rootwrap for metadata agent? + configure_root_helper_options $NEUTRON_META_CONF + + # TODO(dtroyer): remove the v2.0 hard code below + iniset $NEUTRON_META_CONF DEFAULT auth_url $KEYSTONE_SERVICE_URI + configure_auth_token_middleware $NEUTRON_META_CONF neutron $NEUTRON_AUTH_CACHE_DIR DEFAULT + fi + + # Format logging + setup_logging $NEUTRON_CONF + + if is_service_enabled tls-proxy && [ "$NEUTRON_DEPLOY_MOD_WSGI" == "False" ]; then + # Set the service port for a proxy to take the original + iniset $NEUTRON_CONF DEFAULT bind_port "$NEUTRON_SERVICE_PORT_INT" + iniset $NEUTRON_CONF oslo_middleware enable_proxy_headers_parsing True + fi + + # Metering + if is_service_enabled neutron-metering; then + cp $NEUTRON_DIR/etc/metering_agent.ini.sample $NEUTRON_METERING_AGENT_CONF + neutron_service_plugin_class_add metering + fi +} + +# configure_neutron_rootwrap() - configure Neutron's rootwrap +function configure_neutron_rootwrap { + # Deploy new rootwrap filters files (owned by root). + # Wipe any existing rootwrap.d files first + if [[ -d $NEUTRON_CONF_DIR/rootwrap.d ]]; then + sudo rm -rf $NEUTRON_CONF_DIR/rootwrap.d + fi + + # Deploy filters to /etc/neutron/rootwrap.d + sudo install -d -o root -g root -m 755 $NEUTRON_CONF_DIR/rootwrap.d + sudo install -o root -g root -m 644 $NEUTRON_DIR/etc/neutron/rootwrap.d/*.filters $NEUTRON_CONF_DIR/rootwrap.d + + # Set up ``rootwrap.conf``, pointing to ``$NEUTRON_CONF_DIR/rootwrap.d`` + sudo install -o root -g root -m 644 $NEUTRON_DIR/etc/rootwrap.conf $NEUTRON_CONF_DIR + sudo sed -e "s:^filters_path=.*$:filters_path=$NEUTRON_CONF_DIR/rootwrap.d:" -i $NEUTRON_CONF_DIR/rootwrap.conf + + # Set up the rootwrap sudoers for Neutron + tempfile=`mktemp` + echo "$STACK_USER ALL=(root) NOPASSWD: $NEUTRON_ROOTWRAP_CMD *" >$tempfile + echo "$STACK_USER ALL=(root) NOPASSWD: $NEUTRON_ROOTWRAP_DAEMON_CMD" >>$tempfile + chmod 0440 $tempfile + sudo chown root:root $tempfile + sudo mv $tempfile /etc/sudoers.d/neutron-rootwrap +} + +# Make Neutron-required changes to nova.conf +# Takes a single optional argument which is the config file to update, +# if not passed $NOVA_CONF is used. +function configure_neutron_nova_new { + local conf=${1:-$NOVA_CONF} + iniset $conf DEFAULT use_neutron True + iniset $conf neutron auth_type "password" + iniset $conf neutron auth_url "$KEYSTONE_SERVICE_URI" + iniset $conf neutron username neutron + iniset $conf neutron password "$SERVICE_PASSWORD" + iniset $conf neutron user_domain_name "Default" + iniset $conf neutron project_name "$SERVICE_TENANT_NAME" + iniset $conf neutron project_domain_name "Default" + iniset $conf neutron auth_strategy $NEUTRON_AUTH_STRATEGY + iniset $conf neutron region_name "$REGION_NAME" + + iniset $conf DEFAULT firewall_driver nova.virt.firewall.NoopFirewallDriver + + # optionally set options in nova_conf + neutron_plugin_create_nova_conf $conf + + if is_service_enabled neutron-metadata-agent; then + iniset $conf neutron service_metadata_proxy "True" + fi + +} + +# Tenant User Roles +# ------------------------------------------------------------------ +# service neutron admin # if enabled + +# create_neutron_accounts() - Create required service accounts +function create_neutron_accounts_new { + local neutron_url + + if [ "$NEUTRON_DEPLOY_MOD_WSGI" == "True" ]; then + neutron_url=$NEUTRON_SERVICE_PROTOCOL://$NEUTRON_SERVICE_HOST/networking/ + else + neutron_url=$NEUTRON_SERVICE_PROTOCOL://$NEUTRON_SERVICE_HOST:$NEUTRON_SERVICE_PORT/ + fi + + + if [[ "$ENABLED_SERVICES" =~ "neutron-api" ]]; then + + create_service_user "neutron" + + neutron_service=$(get_or_create_service "neutron" \ + "network" "Neutron Service") + get_or_create_endpoint $neutron_service \ + "$REGION_NAME" "$neutron_url" + fi +} + +# create_neutron_cache_dir() - Part of the init_neutron() process +function create_neutron_cache_dir { + # Create cache dir + sudo install -d -o $STACK_USER $NEUTRON_AUTH_CACHE_DIR + rm -f $NEUTRON_AUTH_CACHE_DIR/* +} + +# init_neutron() - Initialize databases, etc. +function init_neutron_new { + + recreate_database neutron + + time_start "dbsync" + # Run Neutron db migrations + $NEUTRON_BIN_DIR/neutron-db-manage upgrade heads + time_stop "dbsync" + + create_neutron_cache_dir +} + +# install_neutron() - Collect source and prepare +function install_neutron_new { + git_clone $NEUTRON_REPO $NEUTRON_DIR $NEUTRON_BRANCH + setup_develop $NEUTRON_DIR + + # Install neutron-lib from git so we make sure we're testing + # the latest code. + if use_library_from_git "neutron-lib"; then + git_clone_by_name "neutron-lib" + setup_dev_lib "neutron-lib" + fi + + # L3 service requires radvd + if is_service_enabled neutron-l3; then + install_package radvd + fi + + if is_service_enabled neutron-agent neutron-dhcp neutron-l3; then + #TODO(sc68cal) - kind of ugly + source $TOP_DIR/lib/neutron_plugins/${NEUTRON_AGENT}_agent + neutron_plugin_install_agent_packages + fi + +} + +# install_neutronclient() - Collect source and prepare +function install_neutronclient { + if use_library_from_git "python-neutronclient"; then + git_clone_by_name "python-neutronclient" + setup_dev_lib "python-neutronclient" + sudo install -D -m 0644 -o $STACK_USER {${GITDIR["python-neutronclient"]}/tools/,/etc/bash_completion.d/}neutron.bash_completion + fi +} + +# start_neutron_api() - Start the API process ahead of other things +function start_neutron_api { + local service_port=$NEUTRON_SERVICE_PORT + local service_protocol=$NEUTRON_SERVICE_PROTOCOL + local neutron_url + if is_service_enabled tls-proxy; then + service_port=$NEUTRON_SERVICE_PORT_INT + service_protocol="http" + fi + + local opts="" + opts+=" --config-file $NEUTRON_CONF" + opts+=" --config-file $NEUTRON_CORE_PLUGIN_CONF" + local cfg_file + for cfg_file in ${_NEUTRON_SERVER_EXTRA_CONF_FILES_ABS[@]}; do + opts+=" --config-file $cfg_file" + done + + if [ "$NEUTRON_DEPLOY_MOD_WSGI" == "True" ]; then + run_process neutron-api "$NEUTRON_BIN_DIR/uwsgi --procname-prefix neutron-api --ini $NEUTRON_UWSGI_CONF" + neutron_url=$service_protocol://$NEUTRON_SERVICE_HOST/networking/ + enable_service neutron-rpc-server + run_process neutron-rpc-server "$NEUTRON_BIN_DIR/neutron-rpc-server $opts" + else + # Start the Neutron service + # TODO(sc68cal) Stop hard coding this + run_process neutron-api "$NEUTRON_BIN_DIR/neutron-server $opts" + neutron_url=$service_protocol://$NEUTRON_SERVICE_HOST:$service_port + # Start proxy if enabled + if is_service_enabled tls-proxy; then + start_tls_proxy neutron '*' $NEUTRON_SERVICE_PORT $NEUTRON_SERVICE_HOST $NEUTRON_SERVICE_PORT_INT + fi + fi + + if ! wait_for_service $SERVICE_TIMEOUT $neutron_url; then + die $LINENO "neutron-api did not start" + fi +} + +# start_neutron() - Start running processes +function start_neutron_new { + # Start up the neutron agents if enabled + # TODO(sc68cal) Make this pluggable so different DevStack plugins for different Neutron plugins + # can resolve the $NEUTRON_AGENT_BINARY + if is_service_enabled neutron-agent; then + # TODO(ihrachys) stop loading ml2_conf.ini into agents, instead load agent specific files + run_process neutron-agent "$NEUTRON_BIN_DIR/$NEUTRON_AGENT_BINARY --config-file $NEUTRON_CONF --config-file $NEUTRON_CORE_PLUGIN_CONF" + fi + if is_service_enabled neutron-dhcp; then + neutron_plugin_configure_dhcp_agent $NEUTRON_DHCP_CONF + run_process neutron-dhcp "$NEUTRON_BIN_DIR/$NEUTRON_DHCP_BINARY --config-file $NEUTRON_CONF --config-file $NEUTRON_DHCP_CONF" + fi + if is_service_enabled neutron-l3; then + run_process neutron-l3 "$NEUTRON_BIN_DIR/$NEUTRON_L3_BINARY --config-file $NEUTRON_CONF --config-file $NEUTRON_L3_CONF" + fi + if is_service_enabled neutron-api && [[ "$NEUTRON_CREATE_INITIAL_NETWORKS" == "True" ]]; then + # XXX(sc68cal) - Here's where plugins can wire up their own networks instead + # of the code in lib/neutron_plugins/services/l3 + if type -p neutron_plugin_create_initial_networks > /dev/null; then + neutron_plugin_create_initial_networks + else + # XXX(sc68cal) Load up the built in Neutron networking code and build a topology + source $TOP_DIR/lib/neutron_plugins/services/l3 + # Create the networks using servic + create_neutron_initial_network + fi + fi + if is_service_enabled neutron-metadata-agent; then + run_process neutron-metadata-agent "$NEUTRON_BIN_DIR/$NEUTRON_META_BINARY --config-file $NEUTRON_CONF --config-file $NEUTRON_META_CONF" + fi + + if is_service_enabled neutron-metering; then + run_process neutron-metering "$NEUTRON_BIN_DIR/$NEUTRON_METERING_BINARY --config-file $NEUTRON_CONF --config-file $NEUTRON_METERING_AGENT_CONF" + fi +} + +# stop_neutron() - Stop running processes +function stop_neutron_new { + for serv in neutron-api neutron-agent neutron-l3; do + stop_process $serv + done + + if is_service_enabled neutron-rpc-server; then + stop_process neutron-rpc-server + fi + + if is_service_enabled neutron-dhcp; then + stop_process neutron-dhcp + pid=$(ps aux | awk '/[d]nsmasq.+interface=(tap|ns-)/ { print $2 }') + [ ! -z "$pid" ] && sudo kill -9 $pid + fi + + if is_service_enabled neutron-metadata-agent; then + sudo pkill -9 -f neutron-ns-metadata-proxy || : + stop_process neutron-metadata-agent + fi +} + +# neutron_service_plugin_class_add() - add service plugin class +function neutron_service_plugin_class_add_new { + local service_plugin_class=$1 + local plugins="" + + plugins=$(iniget $NEUTRON_CONF DEFAULT service_plugins) + if [ $plugins ]; then + plugins+="," + fi + plugins+="${service_plugin_class}" + iniset $NEUTRON_CONF DEFAULT service_plugins $plugins +} + +function _neutron_ml2_extension_driver_add { + local driver=$1 + local drivers="" + + drivers=$(iniget $NEUTRON_CORE_PLUGIN_CONF ml2 extension_drivers) + if [ $drivers ]; then + drivers+="," + fi + drivers+="${driver}" + iniset $NEUTRON_CORE_PLUGIN_CONF ml2 extension_drivers $drivers +} + +function neutron_server_config_add_new { + _NEUTRON_SERVER_EXTRA_CONF_FILES_ABS+=($1) +} + +# neutron_deploy_rootwrap_filters() - deploy rootwrap filters +function neutron_deploy_rootwrap_filters_new { + local srcdir=$1 + sudo install -d -o root -g root -m 755 $NEUTRON_CONF_DIR/rootwrap.d + sudo install -o root -g root -m 644 $srcdir/etc/neutron/rootwrap.d/*.filters $NEUTRON_CONF_DIR/rootwrap.d +} + +# Dispatch functions +# These are needed for compatibility between the old and new implementations +# where there are function name overlaps. These will be removed when +# neutron-legacy is removed. +# TODO(sc68cal) Remove when neutron-legacy is no more. +function cleanup_neutron { + if [ "$NEUTRON_DEPLOY_MOD_WSGI" == "True" ]; then + stop_process neutron-api + stop_process neutron-rpc-server + remove_uwsgi_config "$NEUTRON_UWSGI_CONF" "$NEUTRON_BIN_DIR/neutron-api" + sudo rm -f $(apache_site_config_for neutron-api) + fi + + if is_neutron_legacy_enabled; then + # Call back to old function + cleanup_mutnauq "$@" + else + cleanup_neutron_new "$@" + fi +} + +function configure_neutron { + if is_neutron_legacy_enabled; then + # Call back to old function + configure_mutnauq "$@" + else + configure_neutron_new "$@" + fi + + if [ "$NEUTRON_DEPLOY_MOD_WSGI" == "True" ]; then + write_uwsgi_config "$NEUTRON_UWSGI_CONF" "$NEUTRON_BIN_DIR/neutron-api" "/networking" + fi +} + +function configure_neutron_nova { + if is_neutron_legacy_enabled; then + # Call back to old function + create_nova_conf_neutron $NOVA_CONF + if [[ "${CELLSV2_SETUP}" == "superconductor" ]]; then + for i in $(seq 1 $NOVA_NUM_CELLS); do + local conf + conf=$(conductor_conf $i) + create_nova_conf_neutron $conf + done + fi + else + configure_neutron_nova_new $NOVA_CONF + if [[ "${CELLSV2_SETUP}" == "superconductor" ]]; then + for i in $(seq 1 $NOVA_NUM_CELLS); do + local conf + conf=$(conductor_conf $i) + configure_neutron_nova_new $conf + done + fi + fi +} + +function create_neutron_accounts { + if is_neutron_legacy_enabled; then + # Call back to old function + create_mutnauq_accounts "$@" + else + create_neutron_accounts_new "$@" + fi +} + +function init_neutron { + if is_neutron_legacy_enabled; then + # Call back to old function + init_mutnauq "$@" + else + init_neutron_new "$@" + fi +} + +function install_neutron { + if is_neutron_legacy_enabled; then + # Call back to old function + install_mutnauq "$@" + else + install_neutron_new "$@" + fi +} + +function neutron_service_plugin_class_add { + if is_neutron_legacy_enabled; then + # Call back to old function + _neutron_service_plugin_class_add "$@" + else + neutron_service_plugin_class_add_new "$@" + fi +} + +function neutron_ml2_extension_driver_add { + if is_neutron_legacy_enabled; then + # Call back to old function + _neutron_ml2_extension_driver_add_old "$@" + else + _neutron_ml2_extension_driver_add "$@" + fi +} + +function install_neutron_agent_packages { + if is_neutron_legacy_enabled; then + # Call back to old function + install_neutron_agent_packages_mutnauq "$@" + else + : + fi +} + +function neutron_server_config_add { + if is_neutron_legacy_enabled; then + # Call back to old function + mutnauq_server_config_add "$@" + else + neutron_server_config_add_new "$@" + fi +} + +function start_neutron { + if is_neutron_legacy_enabled; then + # Call back to old function + start_mutnauq_l2_agent "$@" + start_mutnauq_other_agents "$@" + else + start_neutron_new "$@" + fi +} + +function stop_neutron { + if is_neutron_legacy_enabled; then + # Call back to old function + stop_mutnauq "$@" + else + stop_neutron_new "$@" + fi +} + +function neutron_deploy_rootwrap_filters { + if is_neutron_legacy_enabled; then + # Call back to old function + _neutron_deploy_rootwrap_filters "$@" + else + neutron_deploy_rootwrap_filters_new "$@" + fi +} + +# Restore xtrace +$XTRACE diff --git a/lib/neutron-legacy b/lib/neutron-legacy index 18b0942ae1..2fdb6db6f6 100644 --- a/lib/neutron-legacy +++ b/lib/neutron-legacy @@ -20,15 +20,14 @@ # - init_neutron_third_party # - start_neutron_third_party # - create_nova_conf_neutron +# - configure_neutron_after_post_config # - start_neutron_service_and_check # - check_neutron_third_party_integration # - start_neutron_agents # - create_neutron_initial_network -# - setup_neutron_debug # # ``unstack.sh`` calls the entry points in this order: # -# - teardown_neutron_debug # - stop_neutron # - stop_neutron_third_party # - cleanup_neutron @@ -61,35 +60,12 @@ # Neutron Network Configuration # ----------------------------- -# Subnet IP version -IP_VERSION=${IP_VERSION:-"4+6"} -# Validate IP_VERSION -if [[ $IP_VERSION != "4" ]] && [[ $IP_VERSION != "6" ]] && [[ $IP_VERSION != "4+6" ]]; then - die $LINENO "IP_VERSION must be either 4, 6, or 4+6" -fi -# Gateway and subnet defaults, in case they are not customized in localrc -NETWORK_GATEWAY=${NETWORK_GATEWAY:-10.0.0.1} -PUBLIC_NETWORK_GATEWAY=${PUBLIC_NETWORK_GATEWAY:-172.24.4.1} -PRIVATE_SUBNET_NAME=${PRIVATE_SUBNET_NAME:-"private-subnet"} -PUBLIC_SUBNET_NAME=${PUBLIC_SUBNET_NAME:-"public-subnet"} +deprecated "Using lib/neutron-legacy is deprecated, and it will be removed in the future" -if is_ssl_enabled_service "neutron" || is_service_enabled tls-proxy; then +if is_service_enabled tls-proxy; then Q_PROTOCOL="https" fi -# Generate 40-bit IPv6 Global ID to comply with RFC 4193 -IPV6_GLOBAL_ID=`uuidgen | sed s/-//g | cut -c 23- | sed -e "s/\(..\)\(....\)\(....\)/\1:\2:\3/"` - -# IPv6 gateway and subnet defaults, in case they are not customized in localrc -IPV6_RA_MODE=${IPV6_RA_MODE:-slaac} -IPV6_ADDRESS_MODE=${IPV6_ADDRESS_MODE:-slaac} -IPV6_PUBLIC_SUBNET_NAME=${IPV6_PUBLIC_SUBNET_NAME:-ipv6-public-subnet} -IPV6_PRIVATE_SUBNET_NAME=${IPV6_PRIVATE_SUBNET_NAME:-ipv6-private-subnet} -FIXED_RANGE_V6=${FIXED_RANGE_V6:-fd$IPV6_GLOBAL_ID::/64} -IPV6_PRIVATE_NETWORK_GATEWAY=${IPV6_PRIVATE_NETWORK_GATEWAY:-fd$IPV6_GLOBAL_ID::1} -IPV6_PUBLIC_RANGE=${IPV6_PUBLIC_RANGE:-2001:db8::/64} -IPV6_PUBLIC_NETWORK_GATEWAY=${IPV6_PUBLIC_NETWORK_GATEWAY:-2001:db8::2} -IPV6_ROUTER_GW_IP=${IPV6_ROUTER_GW_IP:-2001:db8::1} # Set up default directories GITDIR["python-neutronclient"]=$DEST/python-neutronclient @@ -97,8 +73,6 @@ GITDIR["python-neutronclient"]=$DEST/python-neutronclient NEUTRON_DIR=$DEST/neutron NEUTRON_FWAAS_DIR=$DEST/neutron-fwaas -NEUTRON_LBAAS_DIR=$DEST/neutron-lbaas -NEUTRON_VPNAAS_DIR=$DEST/neutron-vpnaas NEUTRON_AUTH_CACHE_DIR=${NEUTRON_AUTH_CACHE_DIR:-/var/cache/neutron} # Support entry points installation of console scripts @@ -112,6 +86,15 @@ NEUTRON_CONF_DIR=/etc/neutron NEUTRON_CONF=$NEUTRON_CONF_DIR/neutron.conf export NEUTRON_TEST_CONFIG_FILE=${NEUTRON_TEST_CONFIG_FILE:-"$NEUTRON_CONF_DIR/debug.ini"} +# NEUTRON_DEPLOY_MOD_WSGI defines how neutron is deployed, allowed values: +# - False (default) : Run neutron under Eventlet +# - True : Run neutron under uwsgi +# TODO(annp): Switching to uwsgi in next cycle if things turn out to be stable +# enough +NEUTRON_DEPLOY_MOD_WSGI=${NEUTRON_DEPLOY_MOD_WSGI:-False} + +NEUTRON_UWSGI_CONF=$NEUTRON_CONF_DIR/neutron-api-uwsgi.ini + # Agent binaries. Note, binary paths for other agents are set in per-service # scripts in lib/neutron_plugins/services/ AGENT_DHCP_BINARY="$NEUTRON_BIN_DIR/neutron-dhcp-agent" @@ -122,8 +105,6 @@ AGENT_META_BINARY="$NEUTRON_BIN_DIR/neutron-metadata-agent" # loaded from per-plugin scripts in lib/neutron_plugins/ Q_DHCP_CONF_FILE=$NEUTRON_CONF_DIR/dhcp_agent.ini Q_L3_CONF_FILE=$NEUTRON_CONF_DIR/l3_agent.ini -Q_FWAAS_CONF_FILE=$NEUTRON_CONF_DIR/fwaas_driver.ini -Q_VPN_CONF_FILE=$NEUTRON_CONF_DIR/vpn_agent.ini Q_META_CONF_FILE=$NEUTRON_CONF_DIR/metadata_agent.ini # Default name for Neutron database @@ -138,81 +119,42 @@ Q_PORT_INT=${Q_PORT_INT:-19696} Q_HOST=${Q_HOST:-$SERVICE_HOST} # Default protocol Q_PROTOCOL=${Q_PROTOCOL:-$SERVICE_PROTOCOL} +# Default listen address +Q_LISTEN_ADDRESS=${Q_LISTEN_ADDRESS:-$(ipv6_unquote $SERVICE_LISTEN_ADDRESS)} # Default admin username Q_ADMIN_USERNAME=${Q_ADMIN_USERNAME:-neutron} # Default auth strategy Q_AUTH_STRATEGY=${Q_AUTH_STRATEGY:-keystone} -# Use namespace or not -Q_USE_NAMESPACE=${Q_USE_NAMESPACE:-True} # RHEL's support for namespaces requires using veths with ovs Q_OVS_USE_VETH=${Q_OVS_USE_VETH:-False} Q_USE_ROOTWRAP=${Q_USE_ROOTWRAP:-True} Q_USE_ROOTWRAP_DAEMON=$(trueorfalse True Q_USE_ROOTWRAP_DAEMON) # Meta data IP -Q_META_DATA_IP=${Q_META_DATA_IP:-$SERVICE_HOST} +Q_META_DATA_IP=${Q_META_DATA_IP:-$(ipv6_unquote $SERVICE_HOST)} # Allow Overlapping IP among subnets Q_ALLOW_OVERLAPPING_IP=${Q_ALLOW_OVERLAPPING_IP:-True} -# Use neutron-debug command -Q_USE_DEBUG_COMMAND=${Q_USE_DEBUG_COMMAND:-False} -# The name of the default q-l3 router -Q_ROUTER_NAME=${Q_ROUTER_NAME:-router1} -# nova vif driver that all plugins should use -NOVA_VIF_DRIVER=${NOVA_VIF_DRIVER:-"nova.virt.libvirt.vif.LibvirtGenericVIFDriver"} Q_NOTIFY_NOVA_PORT_STATUS_CHANGES=${Q_NOTIFY_NOVA_PORT_STATUS_CHANGES:-True} Q_NOTIFY_NOVA_PORT_DATA_CHANGES=${Q_NOTIFY_NOVA_PORT_DATA_CHANGES:-True} VIF_PLUGGING_IS_FATAL=${VIF_PLUGGING_IS_FATAL:-True} VIF_PLUGGING_TIMEOUT=${VIF_PLUGGING_TIMEOUT:-300} -# Specify if the initial private and external networks should be created -NEUTRON_CREATE_INITIAL_NETWORKS=${NEUTRON_CREATE_INITIAL_NETWORKS:-True} -## Provider Network Information -PROVIDER_SUBNET_NAME=${PROVIDER_SUBNET_NAME:-"provider_net"} +# The directory which contains files for Q_PLUGIN_EXTRA_CONF_FILES. +# /etc/neutron is assumed by many of devstack plugins. Do not change. +_Q_PLUGIN_EXTRA_CONF_PATH=/etc/neutron -# Use flat providernet for public network -# -# If Q_USE_PROVIDERNET_FOR_PUBLIC=True, use a flat provider network -# for external interface of neutron l3-agent. In that case, -# PUBLIC_PHYSICAL_NETWORK specifies provider:physical_network value -# used for the network. In case of ofagent, you should add the -# corresponding entry to your OFAGENT_PHYSICAL_INTERFACE_MAPPINGS. -# For openvswitch agent, you should add the corresponding entry to -# your OVS_BRIDGE_MAPPINGS. -# -# eg. (ofagent) -# Q_USE_PROVIDERNET_FOR_PUBLIC=True -# Q_USE_PUBLIC_VETH=True -# PUBLIC_PHYSICAL_NETWORK=public -# OFAGENT_PHYSICAL_INTERFACE_MAPPINGS=public:veth-pub-int +# List of config file names in addition to the main plugin config file +# To add additional plugin config files, use ``neutron_server_config_add`` +# utility function. For example: # -# eg. (openvswitch agent) -# Q_USE_PROVIDERNET_FOR_PUBLIC=True -# PUBLIC_PHYSICAL_NETWORK=public -# OVS_BRIDGE_MAPPINGS=public:br-ex -Q_USE_PROVIDERNET_FOR_PUBLIC=${Q_USE_PROVIDERNET_FOR_PUBLIC:-False} -PUBLIC_PHYSICAL_NETWORK=${PUBLIC_PHYSICAL_NETWORK:-public} - -# If Q_USE_PUBLIC_VETH=True, create and use a veth pair instead of -# PUBLIC_BRIDGE. This is intended to be used with -# Q_USE_PROVIDERNET_FOR_PUBLIC=True. -Q_USE_PUBLIC_VETH=${Q_USE_PUBLIC_VETH:-False} -Q_PUBLIC_VETH_EX=${Q_PUBLIC_VETH_EX:-veth-pub-ex} -Q_PUBLIC_VETH_INT=${Q_PUBLIC_VETH_INT:-veth-pub-int} - -# The next two variables are configured by plugin -# e.g. _configure_neutron_l3_agent or lib/neutron_plugins/* +# ``neutron_server_config_add file1`` # -# The plugin supports L3. -Q_L3_ENABLED=${Q_L3_ENABLED:-False} -# L3 routers exist per tenant -Q_L3_ROUTER_PER_TENANT=${Q_L3_ROUTER_PER_TENANT:-False} - -# List of config file names in addition to the main plugin config file -# See _configure_neutron_common() for details about setting it up -declare -a Q_PLUGIN_EXTRA_CONF_FILES +# These config files are relative to ``/etc/neutron``. The above +# example would specify ``--config-file /etc/neutron/file1`` for +# neutron server. +declare -a -g Q_PLUGIN_EXTRA_CONF_FILES -# List of (optional) config files for VPN device drivers to use with -# the neutron-q-vpn agent -declare -a Q_VPN_EXTRA_CONF_FILES +# same as Q_PLUGIN_EXTRA_CONF_FILES, but with absolute path. +declare -a -g _Q_PLUGIN_EXTRA_CONF_FILES_ABS Q_RR_CONF_FILE=$NEUTRON_CONF_DIR/rootwrap.conf @@ -235,7 +177,7 @@ fi # Q_DVR_MODE=${Q_DVR_MODE:-legacy} if [[ "$Q_DVR_MODE" != "legacy" ]]; then - Q_ML2_PLUGIN_MECHANISM_DRIVERS=openvswitch,linuxbridge,l2population + Q_ML2_PLUGIN_MECHANISM_DRIVERS=openvswitch,l2population fi # Provider Network Configurations @@ -252,9 +194,9 @@ fi # GRE tunnels are only supported by the openvswitch. ENABLE_TENANT_TUNNELS=${ENABLE_TENANT_TUNNELS:-True} -# If using GRE tunnels for tenant networks, specify the range of -# tunnel IDs from which tenant networks are allocated. Can be -# overriden in ``localrc`` in necesssary. +# If using GRE, VXLAN or GENEVE tunnels for tenant networks, +# specify the range of IDs from which tenant networks are +# allocated. Can be overridden in ``localrc`` if necessary. TENANT_TUNNEL_RANGES=${TENANT_TUNNEL_RANGES:-1:1000} # To use VLANs for tenant networks, set to True in localrc. VLANs @@ -277,7 +219,7 @@ TENANT_VLAN_RANGE=${TENANT_VLAN_RANGE:-} # agent, as described below. # # Example: ``PHYSICAL_NETWORK=default`` -PHYSICAL_NETWORK=${PHYSICAL_NETWORK:-} +PHYSICAL_NETWORK=${PHYSICAL_NETWORK:-public} # With the openvswitch agent, if using VLANs for tenant networks, # or if using flat or VLAN provider networks, set in ``localrc`` to @@ -287,15 +229,17 @@ PHYSICAL_NETWORK=${PHYSICAL_NETWORK:-} # port for external connectivity. # # Example: ``OVS_PHYSICAL_BRIDGE=br-eth1`` -OVS_PHYSICAL_BRIDGE=${OVS_PHYSICAL_BRIDGE:-} +OVS_PHYSICAL_BRIDGE=${OVS_PHYSICAL_BRIDGE:-br-ex} +default_route_dev=$(ip route | grep ^default | awk '{print $5}') +die_if_not_set $LINENO default_route_dev "Failure retrieving default route device" # With the linuxbridge agent, if using VLANs for tenant networks, # or if using flat or VLAN provider networks, set in ``localrc`` to # the name of the network interface to use for the physical # network. # # Example: ``LB_PHYSICAL_INTERFACE=eth1`` -LB_PHYSICAL_INTERFACE=${LB_PHYSICAL_INTERFACE:-} +LB_PHYSICAL_INTERFACE=${LB_PHYSICAL_INTERFACE:-$default_route_dev} # When Neutron tunnels are enabled it is needed to specify the # IP address of the end point in the local server. This IP is set @@ -322,13 +266,9 @@ ENABLE_METADATA_NETWORK=${ENABLE_METADATA_NETWORK:-False} # --------------------------------- # Please refer to ``lib/neutron_plugins/README.md`` for details. -source $TOP_DIR/lib/neutron_plugins/$Q_PLUGIN - -# Agent loadbalancer service plugin functions -# ------------------------------------------- - -# Hardcoding for 1 service plugin for now -source $TOP_DIR/lib/neutron_plugins/services/loadbalancer +if [ -f $TOP_DIR/lib/neutron_plugins/$Q_PLUGIN ]; then + source $TOP_DIR/lib/neutron_plugins/$Q_PLUGIN +fi # Agent metering service plugin functions # ------------------------------------------- @@ -336,15 +276,8 @@ source $TOP_DIR/lib/neutron_plugins/services/loadbalancer # Hardcoding for 1 service plugin for now source $TOP_DIR/lib/neutron_plugins/services/metering -# VPN service plugin functions -# ------------------------------------------- -# Hardcoding for 1 service plugin for now -source $TOP_DIR/lib/neutron_plugins/services/vpn - -# Firewall Service Plugin functions -# --------------------------------- -source $TOP_DIR/lib/neutron_plugins/services/firewall - +# L3 Service functions +source $TOP_DIR/lib/neutron_plugins/services/l3 # Use security group or not if has_neutron_plugin_security_group; then Q_USE_SECGROUP=${Q_USE_SECGROUP:-True} @@ -352,12 +285,8 @@ else Q_USE_SECGROUP=False fi -# Tell Tempest this project is present -TEMPEST_SERVICES+=,neutron - - # Save trace setting -XTRACE=$(set +o | grep xtrace) +_XTRACE_NEUTRON=$(set +o | grep xtrace) set +o xtrace @@ -365,32 +294,30 @@ set +o xtrace # --------- function _determine_config_server { - local cfg_file - local opts="--config-file $NEUTRON_CONF --config-file /$Q_PLUGIN_CONF_FILE" + if [[ "$Q_PLUGIN_EXTRA_CONF_PATH" != '' ]]; then + if [[ "$Q_PLUGIN_EXTRA_CONF_PATH" = "$_Q_PLUGIN_EXTRA_CONF_PATH" ]]; then + deprecated "Q_PLUGIN_EXTRA_CONF_PATH is deprecated" + else + die $LINENO "Q_PLUGIN_EXTRA_CONF_PATH is deprecated" + fi + fi + if [[ ${#Q_PLUGIN_EXTRA_CONF_FILES[@]} > 0 ]]; then + deprecated "Q_PLUGIN_EXTRA_CONF_FILES is deprecated. Use neutron_server_config_add instead." + fi for cfg_file in ${Q_PLUGIN_EXTRA_CONF_FILES[@]}; do - opts+=" --config-file /$cfg_file" + _Q_PLUGIN_EXTRA_CONF_FILES_ABS+=($_Q_PLUGIN_EXTRA_CONF_PATH/$cfg_file) done - echo "$opts" -} -function _determine_config_vpn { local cfg_file - local opts="--config-file $NEUTRON_CONF --config-file=$Q_L3_CONF_FILE --config-file=$Q_VPN_CONF_FILE" - if is_service_enabled q-fwaas; then - opts+=" --config-file $Q_FWAAS_CONF_FILE" - fi - for cfg_file in ${Q_VPN_EXTRA_CONF_FILES[@]}; do + local opts="--config-file $NEUTRON_CONF --config-file /$Q_PLUGIN_CONF_FILE" + for cfg_file in ${_Q_PLUGIN_EXTRA_CONF_FILES_ABS[@]}; do opts+=" --config-file $cfg_file" done echo "$opts" - } function _determine_config_l3 { - local opts="--config-file $NEUTRON_CONF --config-file=$Q_L3_CONF_FILE" - if is_service_enabled q-fwaas; then - opts+=" --config-file $Q_FWAAS_CONF_FILE" - fi + local opts="--config-file $NEUTRON_CONF --config-file $Q_L3_CONF_FILE" echo "$opts" } @@ -400,7 +327,6 @@ function determine_config_files { local opts="" case "$1" in "neutron-server") opts="$(_determine_config_server)" ;; - "neutron-vpn-agent") opts="$(_determine_config_vpn)" ;; "neutron-l3-agent") opts="$(_determine_config_l3)" ;; esac if [ -z "$opts" ] ; then @@ -409,32 +335,15 @@ function determine_config_files { echo "$opts" } -# Test if any Neutron services are enabled -# is_neutron_enabled -function is_neutron_enabled { - [[ ,${ENABLED_SERVICES} =~ ,"q-" ]] && return 0 - return 1 -} - -# configure_neutron() +# configure_mutnauq() # Set common config for all neutron server and agents. -function configure_neutron { +function configure_mutnauq { _configure_neutron_common iniset_rpc_backend neutron $NEUTRON_CONF - # goes before q-svc to init Q_SERVICE_PLUGIN_CLASSES - if is_service_enabled q-lbaas; then - _configure_neutron_lbaas - fi if is_service_enabled q-metering; then _configure_neutron_metering fi - if is_service_enabled q-vpn; then - _configure_neutron_vpn - fi - if is_service_enabled q-fwaas; then - _configure_neutron_fwaas - fi if is_service_enabled q-agt q-svc; then _configure_neutron_service fi @@ -458,209 +367,92 @@ function configure_neutron { _configure_neutron_ceilometer_notifications fi - _configure_neutron_debug_command + iniset $NEUTRON_CONF DEFAULT api_workers "$API_WORKERS" + # devstack is not a tool for running uber scale OpenStack + # clouds, therefore running without a dedicated RPC worker + # for state reports is more than adequate. + iniset $NEUTRON_CONF DEFAULT rpc_state_report_workers 0 } function create_nova_conf_neutron { - iniset $NOVA_CONF DEFAULT network_api_class "nova.network.neutronv2.api.API" - iniset $NOVA_CONF neutron admin_username "$Q_ADMIN_USERNAME" - iniset $NOVA_CONF neutron admin_password "$SERVICE_PASSWORD" - iniset $NOVA_CONF neutron admin_auth_url "$KEYSTONE_SERVICE_PROTOCOL://$KEYSTONE_SERVICE_HOST:$KEYSTONE_AUTH_PORT/v2.0" - iniset $NOVA_CONF neutron auth_strategy "$Q_AUTH_STRATEGY" - iniset $NOVA_CONF neutron admin_tenant_name "$SERVICE_TENANT_NAME" - iniset $NOVA_CONF neutron region_name "$REGION_NAME" - iniset $NOVA_CONF neutron url "${Q_PROTOCOL}://$Q_HOST:$Q_PORT" + local conf=${1:-$NOVA_CONF} + iniset $conf DEFAULT use_neutron True + iniset $conf neutron auth_type "password" + iniset $conf neutron auth_url "$KEYSTONE_AUTH_URI" + iniset $conf neutron username "$Q_ADMIN_USERNAME" + iniset $conf neutron password "$SERVICE_PASSWORD" + iniset $conf neutron user_domain_name "$SERVICE_DOMAIN_NAME" + iniset $conf neutron project_name "$SERVICE_PROJECT_NAME" + iniset $conf neutron project_domain_name "$SERVICE_DOMAIN_NAME" + iniset $conf neutron auth_strategy "$Q_AUTH_STRATEGY" + iniset $conf neutron region_name "$REGION_NAME" if [[ "$Q_USE_SECGROUP" == "True" ]]; then LIBVIRT_FIREWALL_DRIVER=nova.virt.firewall.NoopFirewallDriver - iniset $NOVA_CONF DEFAULT firewall_driver $LIBVIRT_FIREWALL_DRIVER - iniset $NOVA_CONF DEFAULT security_group_api neutron + iniset $conf DEFAULT firewall_driver $LIBVIRT_FIREWALL_DRIVER fi - # set NOVA_VIF_DRIVER and optionally set options in nova_conf - neutron_plugin_create_nova_conf + # optionally set options in nova_conf + neutron_plugin_create_nova_conf $conf - iniset $NOVA_CONF libvirt vif_driver "$NOVA_VIF_DRIVER" - iniset $NOVA_CONF DEFAULT linuxnet_interface_driver "$LINUXNET_VIF_DRIVER" if is_service_enabled q-meta; then - iniset $NOVA_CONF neutron service_metadata_proxy "True" + iniset $conf neutron service_metadata_proxy "True" fi - iniset $NOVA_CONF DEFAULT vif_plugging_is_fatal "$VIF_PLUGGING_IS_FATAL" - iniset $NOVA_CONF DEFAULT vif_plugging_timeout "$VIF_PLUGGING_TIMEOUT" -} - -# create_neutron_cache_dir() - Part of the _neutron_setup_keystone() process -function create_neutron_cache_dir { - # Create cache dir - sudo install -d -o $STACK_USER $NEUTRON_AUTH_CACHE_DIR - rm -f $NEUTRON_AUTH_CACHE_DIR/* + iniset $conf DEFAULT vif_plugging_is_fatal "$VIF_PLUGGING_IS_FATAL" + iniset $conf DEFAULT vif_plugging_timeout "$VIF_PLUGGING_TIMEOUT" } -# create_neutron_accounts() - Set up common required neutron accounts +# create_mutnauq_accounts() - Set up common required neutron accounts # Tenant User Roles # ------------------------------------------------------------------ # service neutron admin # if enabled # Migrated from keystone_data.sh -function create_neutron_accounts { - if [[ "$ENABLED_SERVICES" =~ "q-svc" ]]; then - - create_service_user "neutron" - - if [[ "$KEYSTONE_CATALOG_BACKEND" = 'sql' ]]; then - - local neutron_service=$(get_or_create_service "neutron" \ - "network" "Neutron Service") - get_or_create_endpoint $neutron_service \ - "$REGION_NAME" \ - "$Q_PROTOCOL://$SERVICE_HOST:$Q_PORT/" \ - "$Q_PROTOCOL://$SERVICE_HOST:$Q_PORT/" \ - "$Q_PROTOCOL://$SERVICE_HOST:$Q_PORT/" - fi - fi -} - -function create_neutron_initial_network { - TENANT_ID=$(openstack project list | grep " demo " | get_field 1) - die_if_not_set $LINENO TENANT_ID "Failure retrieving TENANT_ID for demo" - - # Allow drivers that need to create an initial network to do so here - if type -p neutron_plugin_create_initial_network_profile > /dev/null; then - neutron_plugin_create_initial_network_profile $PHYSICAL_NETWORK - fi - - if is_provider_network; then - die_if_not_set $LINENO PHYSICAL_NETWORK "You must specify the PHYSICAL_NETWORK" - die_if_not_set $LINENO PROVIDER_NETWORK_TYPE "You must specifiy the PROVIDER_NETWORK_TYPE" - NET_ID=$(neutron net-create $PHYSICAL_NETWORK --tenant_id $TENANT_ID --provider:network_type $PROVIDER_NETWORK_TYPE --provider:physical_network "$PHYSICAL_NETWORK" ${SEGMENTATION_ID:+--provider:segmentation_id $SEGMENTATION_ID} --shared | grep ' id ' | get_field 2) - die_if_not_set $LINENO NET_ID "Failure creating NET_ID for $PHYSICAL_NETWORK $TENANT_ID" - - if [[ "$IP_VERSION" =~ 4.* ]]; then - SUBNET_ID=$(neutron subnet-create --tenant_id $TENANT_ID --ip_version 4 ${ALLOCATION_POOL:+--allocation-pool $ALLOCATION_POOL} --name $PROVIDER_SUBNET_NAME --gateway $NETWORK_GATEWAY $NET_ID $FIXED_RANGE | grep ' id ' | get_field 2) - die_if_not_set $LINENO SUBNET_ID "Failure creating SUBNET_ID for $PROVIDER_SUBNET_NAME $TENANT_ID" - fi - - if [[ "$IP_VERSION" =~ .*6 ]]; then - SUBNET_V6_ID=$(neutron subnet-create --tenant_id $TENANT_ID --ip_version 6 --ipv6-address-mode slaac --gateway $V6_NETWORK_GATEWAY --name $PROVIDER_SUBNET_NAME_V6 $NET_ID $FIXED_RANGE_V6 | grep 'id' | get_field 2) - die_if_not_set $LINENO SUBNET_V6_ID "Failure creating SUBNET_V6_ID for $PROVIDER_SUBNET_NAME_V6 $TENANT_ID" - fi - - sudo ip link set $OVS_PHYSICAL_BRIDGE up - sudo ip link set br-int up - sudo ip link set $PUBLIC_INTERFACE up +function create_mutnauq_accounts { + local neutron_url + if [ "$NEUTRON_DEPLOY_MOD_WSGI" == "True" ]; then + neutron_url=$Q_PROTOCOL://$SERVICE_HOST/networking/ else - NET_ID=$(neutron net-create --tenant-id $TENANT_ID "$PRIVATE_NETWORK_NAME" | grep ' id ' | get_field 2) - die_if_not_set $LINENO NET_ID "Failure creating NET_ID for $PRIVATE_NETWORK_NAME $TENANT_ID" - - if [[ "$IP_VERSION" =~ 4.* ]]; then - # Create IPv4 private subnet - SUBNET_ID=$(_neutron_create_private_subnet_v4) - fi - - if [[ "$IP_VERSION" =~ .*6 ]]; then - # Create IPv6 private subnet - IPV6_SUBNET_ID=$(_neutron_create_private_subnet_v6) - fi + neutron_url=$Q_PROTOCOL://$SERVICE_HOST:$Q_PORT/ fi - if [[ "$Q_L3_ENABLED" == "True" ]]; then - # Create a router, and add the private subnet as one of its interfaces - if [[ "$Q_L3_ROUTER_PER_TENANT" == "True" ]]; then - # create a tenant-owned router. - ROUTER_ID=$(neutron router-create --tenant-id $TENANT_ID $Q_ROUTER_NAME | grep ' id ' | get_field 2) - die_if_not_set $LINENO ROUTER_ID "Failure creating ROUTER_ID for $TENANT_ID $Q_ROUTER_NAME" - else - # Plugin only supports creating a single router, which should be admin owned. - ROUTER_ID=$(neutron router-create $Q_ROUTER_NAME | grep ' id ' | get_field 2) - die_if_not_set $LINENO ROUTER_ID "Failure creating ROUTER_ID for $Q_ROUTER_NAME" - fi - - # Create an external network, and a subnet. Configure the external network as router gw - if [ "$Q_USE_PROVIDERNET_FOR_PUBLIC" = "True" ]; then - EXT_NET_ID=$(neutron net-create "$PUBLIC_NETWORK_NAME" -- --router:external=True --provider:network_type=flat --provider:physical_network=${PUBLIC_PHYSICAL_NETWORK} | grep ' id ' | get_field 2) - else - EXT_NET_ID=$(neutron net-create "$PUBLIC_NETWORK_NAME" -- --router:external=True | grep ' id ' | get_field 2) - fi - die_if_not_set $LINENO EXT_NET_ID "Failure creating EXT_NET_ID for $PUBLIC_NETWORK_NAME" + if [[ "$ENABLED_SERVICES" =~ "q-svc" ]]; then - if [[ "$IP_VERSION" =~ 4.* ]]; then - # Configure router for IPv4 public access - _neutron_configure_router_v4 - fi + create_service_user "neutron" - if [[ "$IP_VERSION" =~ .*6 ]]; then - # Configure router for IPv6 public access - _neutron_configure_router_v6 - fi + get_or_create_service "neutron" "network" "Neutron Service" + get_or_create_endpoint \ + "network" \ + "$REGION_NAME" "$neutron_url" fi } -# init_neutron() - Initialize databases, etc. -function init_neutron { +# init_mutnauq() - Initialize databases, etc. +function init_mutnauq { recreate_database $Q_DB_NAME + time_start "dbsync" # Run Neutron db migrations $NEUTRON_BIN_DIR/neutron-db-manage --config-file $NEUTRON_CONF --config-file /$Q_PLUGIN_CONF_FILE upgrade head - for svc in fwaas lbaas vpnaas; do - if [ "$svc" = "vpnaas" ]; then - q_svc="q-vpn" - else - q_svc="q-$svc" - fi - if is_service_enabled $q_svc; then - $NEUTRON_BIN_DIR/neutron-db-manage --service $svc --config-file $NEUTRON_CONF --config-file /$Q_PLUGIN_CONF_FILE upgrade head - fi - done + time_stop "dbsync" } -# install_neutron() - Collect source and prepare -function install_neutron { - git_clone $NEUTRON_REPO $NEUTRON_DIR $NEUTRON_BRANCH - setup_develop $NEUTRON_DIR - if is_service_enabled q-fwaas; then - git_clone $NEUTRON_FWAAS_REPO $NEUTRON_FWAAS_DIR $NEUTRON_FWAAS_BRANCH - setup_develop $NEUTRON_FWAAS_DIR - fi - if is_service_enabled q-lbaas; then - git_clone $NEUTRON_LBAAS_REPO $NEUTRON_LBAAS_DIR $NEUTRON_LBAAS_BRANCH - setup_develop $NEUTRON_LBAAS_DIR - fi - if is_service_enabled q-vpn; then - git_clone $NEUTRON_VPNAAS_REPO $NEUTRON_VPNAAS_DIR $NEUTRON_VPNAAS_BRANCH - setup_develop $NEUTRON_VPNAAS_DIR - fi - - if [ "$VIRT_DRIVER" == 'xenserver' ]; then - local dom0_ip - dom0_ip=$(echo "$XENAPI_CONNECTION_URL" | cut -d "/" -f 3-) - - local ssh_dom0 - ssh_dom0="sudo -u $DOMZERO_USER ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null root@$dom0_ip" - - # Find where the plugins should go in dom0 - local xen_functions - xen_functions=$(cat $TOP_DIR/tools/xen/functions) - local plugin_dir - plugin_dir=$($ssh_dom0 "$xen_functions; set -eux; xapi_plugin_location") - - # install neutron plugins to dom0 - tar -czf - -C $NEUTRON_DIR/neutron/plugins/openvswitch/agent/xenapi/etc/xapi.d/plugins/ ./ | - $ssh_dom0 "tar -xzf - -C $plugin_dir && chmod a+x $plugin_dir/*" +# install_mutnauq() - Collect source and prepare +function install_mutnauq { + # Install neutron-lib from git so we make sure we're testing + # the latest code. + if use_library_from_git "neutron-lib"; then + git_clone_by_name "neutron-lib" + setup_dev_lib "neutron-lib" fi -} -# install_neutronclient() - Collect source and prepare -function install_neutronclient { - if use_library_from_git "python-neutronclient"; then - git_clone_by_name "python-neutronclient" - setup_dev_lib "python-neutronclient" - sudo install -D -m 0644 -o $STACK_USER {${GITDIR["python-neutronclient"]}/tools/,/etc/bash_completion.d/}neutron.bash_completion - fi + git_clone $NEUTRON_REPO $NEUTRON_DIR $NEUTRON_BRANCH + setup_develop $NEUTRON_DIR } # install_neutron_agent_packages() - Collect source and prepare -function install_neutron_agent_packages { +function install_neutron_agent_packages_mutnauq { # radvd doesn't come with the OS. Install it if the l3 service is enabled. if is_service_enabled q-l3; then install_package radvd @@ -669,43 +461,55 @@ function install_neutron_agent_packages { if is_service_enabled q-agt q-dhcp q-l3; then neutron_plugin_install_agent_packages fi +} - if is_service_enabled q-lbaas; then - neutron_agent_lbaas_install_agent_packages +# Finish neutron configuration +function configure_neutron_after_post_config { + if [[ $Q_SERVICE_PLUGIN_CLASSES != '' ]]; then + iniset $NEUTRON_CONF DEFAULT service_plugins $Q_SERVICE_PLUGIN_CLASSES fi } -# Start running processes, including screen +# Start running processes function start_neutron_service_and_check { - local cfg_file_options="$(determine_config_files neutron-server)" local service_port=$Q_PORT local service_protocol=$Q_PROTOCOL + local cfg_file_options + local neutron_url + + cfg_file_options="$(determine_config_files neutron-server)" + if is_service_enabled tls-proxy; then service_port=$Q_PORT_INT service_protocol="http" fi # Start the Neutron service - run_process q-svc "python $NEUTRON_BIN_DIR/neutron-server $cfg_file_options" - echo "Waiting for Neutron to start..." - if is_ssl_enabled_service "neutron"; then - ssl_ca="--ca-certificate=${SSL_BUNDLE_FILE}" - fi - if ! timeout $SERVICE_TIMEOUT sh -c "while ! wget ${ssl_ca} --no-proxy -q -O- $service_protocol://$Q_HOST:$service_port; do sleep 1; done"; then - die $LINENO "Neutron did not start" - fi - # Start proxy if enabled - if is_service_enabled tls-proxy; then - start_tls_proxy '*' $Q_PORT $Q_HOST $Q_PORT_INT & + if [ "$NEUTRON_DEPLOY_MOD_WSGI" == "True" ]; then + enable_service neutron-api + run_process neutron-api "$NEUTRON_BIN_DIR/uwsgi --procname-prefix neutron-api --ini $NEUTRON_UWSGI_CONF" + neutron_url=$Q_PROTOCOL://$Q_HOST/networking/ + enable_service neutron-rpc-server + run_process neutron-rpc-server "$NEUTRON_BIN_DIR/neutron-rpc-server $cfg_file_options" + else + run_process q-svc "$NEUTRON_BIN_DIR/neutron-server $cfg_file_options" + neutron_url=$service_protocol://$Q_HOST:$service_port + # Start proxy if enabled + if is_service_enabled tls-proxy; then + start_tls_proxy neutron '*' $Q_PORT $Q_HOST $Q_PORT_INT + fi fi + echo "Waiting for Neutron to start..." + + local testcmd="wget ${ssl_ca} --no-proxy -q -O- $neutron_url" + test_with_retry "$testcmd" "Neutron did not start" $SERVICE_TIMEOUT } -# Start running processes, including screen -function start_neutron_agents { - # Start up the neutron agents if enabled - run_process q-agt "python $AGENT_BINARY --config-file $NEUTRON_CONF --config-file /$Q_PLUGIN_CONF_FILE" - run_process q-dhcp "python $AGENT_DHCP_BINARY --config-file $NEUTRON_CONF --config-file=$Q_DHCP_CONF_FILE" +# Control of the l2 agent is separated out to make it easier to test partial +# upgrades (everything upgraded except the L2 agent) +function start_mutnauq_l2_agent { + run_process q-agt "$AGENT_BINARY --config-file $NEUTRON_CONF --config-file /$Q_PLUGIN_CONF_FILE" - if is_provider_network; then + if is_provider_network && [[ $Q_AGENT == "openvswitch" ]]; then sudo ovs-vsctl --no-wait -- --may-exist add-port $OVS_PHYSICAL_BRIDGE $PUBLIC_INTERFACE sudo ip link set $OVS_PHYSICAL_BRIDGE up sudo ip link set br-int up @@ -715,70 +519,84 @@ function start_neutron_agents { sudo ip addr del $IP dev $PUBLIC_INTERFACE sudo ip addr add $IP dev $OVS_PHYSICAL_BRIDGE done - sudo route add -net $FIXED_RANGE gw $NETWORK_GATEWAY dev $OVS_PHYSICAL_BRIDGE + sudo ip route replace $FIXED_RANGE via $NETWORK_GATEWAY dev $OVS_PHYSICAL_BRIDGE fi fi +} - if is_service_enabled q-vpn; then - run_process q-vpn "$AGENT_VPN_BINARY $(determine_config_files neutron-vpn-agent)" +function start_mutnauq_other_agents { + run_process q-dhcp "$AGENT_DHCP_BINARY --config-file $NEUTRON_CONF --config-file $Q_DHCP_CONF_FILE" + + if is_service_enabled neutron-vpnaas; then + : # Started by plugin else - run_process q-l3 "python $AGENT_L3_BINARY $(determine_config_files neutron-l3-agent)" + run_process q-l3 "$AGENT_L3_BINARY $(determine_config_files neutron-l3-agent)" fi - run_process q-meta "python $AGENT_META_BINARY --config-file $NEUTRON_CONF --config-file=$Q_META_CONF_FILE" - - if [ "$VIRT_DRIVER" = 'xenserver' ]; then - # For XenServer, start an agent for the domU openvswitch - run_process q-domua "python $AGENT_BINARY --config-file $NEUTRON_CONF --config-file /$Q_PLUGIN_CONF_FILE.domU" - fi + run_process q-meta "$AGENT_META_BINARY --config-file $NEUTRON_CONF --config-file $Q_META_CONF_FILE" + run_process q-metering "$AGENT_METERING_BINARY --config-file $NEUTRON_CONF --config-file $METERING_AGENT_CONF_FILENAME" +} - if is_service_enabled q-lbaas; then - run_process q-lbaas "python $AGENT_LBAAS_BINARY --config-file $NEUTRON_CONF --config-file=$LBAAS_AGENT_CONF_FILENAME" - fi +# Start running processes, including screen +function start_neutron_agents { + # Start up the neutron agents if enabled + start_mutnauq_l2_agent + start_mutnauq_other_agents +} - if is_service_enabled q-metering; then - run_process q-metering "python $AGENT_METERING_BINARY --config-file $NEUTRON_CONF --config-file $METERING_AGENT_CONF_FILENAME" - fi +function stop_mutnauq_l2_agent { + stop_process q-agt } -# stop_neutron() - Stop running processes (non-screen) -function stop_neutron { +# stop_mutnauq_other() - Stop running processes +function stop_mutnauq_other { if is_service_enabled q-dhcp; then stop_process q-dhcp pid=$(ps aux | awk '/[d]nsmasq.+interface=(tap|ns-)/ { print $2 }') [ ! -z "$pid" ] && sudo kill -9 $pid fi - stop_process q-svc - stop_process q-l3 + if [ "$NEUTRON_DEPLOY_MOD_WSGI" == "True" ]; then + stop_process neutron-rpc-server + stop_process neutron-api + else + stop_process q-svc + fi + + if is_service_enabled q-l3; then + sudo pkill -f "radvd -C $DATA_DIR/neutron/ra" + stop_process q-l3 + fi if is_service_enabled q-meta; then sudo pkill -9 -f neutron-ns-metadata-proxy || : stop_process q-meta fi - stop_process q-agt - - if is_service_enabled q-lbaas; then - neutron_lbaas_stop - fi - if is_service_enabled q-fwaas; then - neutron_fwaas_stop - fi - if is_service_enabled q-vpn; then - neutron_vpn_stop - fi if is_service_enabled q-metering; then neutron_metering_stop fi + + if [[ "$Q_USE_ROOTWRAP_DAEMON" == "True" ]]; then + sudo pkill -9 -f $NEUTRON_ROOTWRAP-daemon || : + fi +} + +# stop_neutron() - Stop running processes (non-screen) +function stop_mutnauq { + stop_mutnauq_other + stop_mutnauq_l2_agent } # _move_neutron_addresses_route() - Move the primary IP to the OVS bridge -# on startup, or back to the public interface on cleanup +# on startup, or back to the public interface on cleanup. If no IP is +# configured on the interface, just add it as a port to the OVS bridge. function _move_neutron_addresses_route { local from_intf=$1 local to_intf=$2 local add_ovs_port=$3 + local del_ovs_port=$4 + local af=$5 if [[ -n "$from_intf" && -n "$to_intf" ]]; then # Remove the primary IP address from $from_intf and add it to $to_intf, @@ -786,42 +604,79 @@ function _move_neutron_addresses_route { # on configure we will also add $from_intf as a port on $to_intf, # assuming it is an OVS bridge. - local IP_BRD=$(ip -4 a s dev $from_intf | awk '/inet/ { print $2, $3, $4; exit }') - local DEFAULT_ROUTE_GW=$(ip r | awk "/default.+$from_intf/ { print \$3; exit }") + local IP_REPLACE="" + local IP_DEL="" + local IP_UP="" + local DEFAULT_ROUTE_GW + DEFAULT_ROUTE_GW=$(ip -f $af r | awk "/default.+$from_intf\s/ { print \$3; exit }") local ADD_OVS_PORT="" + local DEL_OVS_PORT="" + local ARP_CMD="" + + IP_BRD=$(ip -f $af a s dev $from_intf scope global primary | grep inet | awk '{ print $2, $3, $4; exit }') if [ "$DEFAULT_ROUTE_GW" != "" ]; then - ADD_DEFAULT_ROUTE="sudo ip r replace default via $DEFAULT_ROUTE_GW dev $to_intf" + ADD_DEFAULT_ROUTE="sudo ip -f $af r replace default via $DEFAULT_ROUTE_GW dev $to_intf" fi if [[ "$add_ovs_port" == "True" ]]; then ADD_OVS_PORT="sudo ovs-vsctl --may-exist add-port $to_intf $from_intf" fi - sudo ip addr del $IP_BRD dev $from_intf; sudo ip addr add $IP_BRD dev $to_intf; $ADD_OVS_PORT; $ADD_DEFAULT_ROUTE + if [[ "$del_ovs_port" == "True" ]]; then + DEL_OVS_PORT="sudo ovs-vsctl --if-exists del-port $from_intf $to_intf" + fi + + if [[ "$IP_BRD" != "" ]]; then + IP_DEL="sudo ip addr del $IP_BRD dev $from_intf" + IP_REPLACE="sudo ip addr replace $IP_BRD dev $to_intf" + IP_UP="sudo ip link set $to_intf up" + if [[ "$af" == "inet" ]]; then + IP=$(echo $IP_BRD | awk '{ print $1; exit }' | grep -o -E '(.*)/' | cut -d "/" -f1) + ARP_CMD="sudo arping -A -c 3 -w 4.5 -I $to_intf $IP " + fi + fi + + # The add/del OVS port calls have to happen either before or + # after the address is moved in order to not leave it orphaned. + $DEL_OVS_PORT; $IP_DEL; $IP_REPLACE; $IP_UP; $ADD_OVS_PORT; $ADD_DEFAULT_ROUTE; $ARP_CMD fi } -# cleanup_neutron() - Remove residual data files, anything left over from previous +# cleanup_mutnauq() - Remove residual data files, anything left over from previous # runs that a clean run would need to clean up -function cleanup_neutron { +function cleanup_mutnauq { - _move_neutron_addresses_route "$OVS_PHYSICAL_BRIDGE" "$PUBLIC_INTERFACE" False + if [[ -n "$OVS_PHYSICAL_BRIDGE" ]]; then + _move_neutron_addresses_route "$OVS_PHYSICAL_BRIDGE" "$PUBLIC_INTERFACE" False True "inet" + + if [[ $(ip -f inet6 a s dev "$OVS_PHYSICAL_BRIDGE" | grep -c 'global') != 0 ]]; then + # ip(8) wants the prefix length when deleting + local v6_gateway + v6_gateway=$(ip -6 a s dev $OVS_PHYSICAL_BRIDGE | grep $IPV6_PUBLIC_NETWORK_GATEWAY | awk '{ print $2 }') + sudo ip -6 addr del $v6_gateway dev $OVS_PHYSICAL_BRIDGE + _move_neutron_addresses_route "$OVS_PHYSICAL_BRIDGE" "$PUBLIC_INTERFACE" False False "inet6" + fi - if is_provider_network && is_ironic_hardware; then - for IP in $(ip addr show dev $OVS_PHYSICAL_BRIDGE | grep ' inet ' | awk '{print $2}'); do - sudo ip addr del $IP dev $OVS_PHYSICAL_BRIDGE - sudo ip addr add $IP dev $PUBLIC_INTERFACE - done - sudo route del -net $FIXED_RANGE gw $NETWORK_GATEWAY dev $OVS_PHYSICAL_BRIDGE + if is_provider_network && is_ironic_hardware; then + for IP in $(ip addr show dev $OVS_PHYSICAL_BRIDGE | grep ' inet ' | awk '{print $2}'); do + sudo ip addr del $IP dev $OVS_PHYSICAL_BRIDGE + sudo ip addr add $IP dev $PUBLIC_INTERFACE + done + sudo route del -net $FIXED_RANGE gw $NETWORK_GATEWAY dev $OVS_PHYSICAL_BRIDGE + fi fi if is_neutron_ovs_base_plugin; then neutron_ovs_base_cleanup fi + if [[ $Q_AGENT == "linuxbridge" ]]; then + neutron_lb_cleanup + fi + # delete all namespaces created by neutron - for ns in $(sudo ip netns list | grep -o -E '(qdhcp|qrouter|qlbaas|fip|snat)-[0-9a-f-]*'); do + for ns in $(sudo ip netns list | grep -o -E '(qdhcp|qrouter|fip|snat)-[0-9a-f-]*'); do sudo ip netns delete ${ns} done } @@ -838,14 +693,24 @@ function _create_neutron_conf_dir { function _configure_neutron_common { _create_neutron_conf_dir - cp $NEUTRON_DIR/etc/neutron.conf $NEUTRON_CONF + # Uses oslo config generator to generate core sample configuration files + (cd $NEUTRON_DIR && exec ./tools/generate_config_file_samples.sh) + + cp $NEUTRON_DIR/etc/neutron.conf.sample $NEUTRON_CONF + + Q_POLICY_FILE=$NEUTRON_CONF_DIR/policy.json + + # allow neutron user to administer neutron to match neutron account + # NOTE(amotoki): This is required for nova works correctly with neutron. + if [ -f $NEUTRON_DIR/etc/policy.json ]; then + cp $NEUTRON_DIR/etc/policy.json $Q_POLICY_FILE + sed -i 's/"context_is_admin": "role:admin"/"context_is_admin": "role:admin or user_name:neutron"/g' $Q_POLICY_FILE + else + echo '{"context_is_admin": "role:admin or user_name:neutron"}' > $Q_POLICY_FILE + fi # Set plugin-specific variables ``Q_DB_NAME``, ``Q_PLUGIN_CLASS``. # For main plugin config file, set ``Q_PLUGIN_CONF_PATH``, ``Q_PLUGIN_CONF_FILENAME``. - # For addition plugin config files, set ``Q_PLUGIN_EXTRA_CONF_PATH``, - # ``Q_PLUGIN_EXTRA_CONF_FILES``. For example: - # - # ``Q_PLUGIN_EXTRA_CONF_FILES=(file1, file2)`` neutron_plugin_configure_common if [[ "$Q_PLUGIN_CONF_PATH" == '' || "$Q_PLUGIN_CONF_FILENAME" == '' || "$Q_PLUGIN_CLASS" == '' ]]; then @@ -855,24 +720,22 @@ function _configure_neutron_common { # If needed, move config file from ``$NEUTRON_DIR/etc/neutron`` to ``NEUTRON_CONF_DIR`` mkdir -p /$Q_PLUGIN_CONF_PATH Q_PLUGIN_CONF_FILE=$Q_PLUGIN_CONF_PATH/$Q_PLUGIN_CONF_FILENAME - cp $NEUTRON_DIR/$Q_PLUGIN_CONF_FILE /$Q_PLUGIN_CONF_FILE + # NOTE(hichihara): Some neutron vendor plugins were already decomposed and + # there is no config file in Neutron tree. They should prepare the file in each plugin. + if [ -f "$NEUTRON_DIR/$Q_PLUGIN_CONF_FILE.sample" ]; then + cp "$NEUTRON_DIR/$Q_PLUGIN_CONF_FILE.sample" /$Q_PLUGIN_CONF_FILE + elif [ -f $NEUTRON_DIR/$Q_PLUGIN_CONF_FILE ]; then + cp $NEUTRON_DIR/$Q_PLUGIN_CONF_FILE /$Q_PLUGIN_CONF_FILE + fi iniset $NEUTRON_CONF database connection `database_connection_url $Q_DB_NAME` iniset $NEUTRON_CONF DEFAULT state_path $DATA_DIR/neutron iniset $NEUTRON_CONF DEFAULT use_syslog $SYSLOG - # If addition config files are set, make sure their path name is set as well - if [[ ${#Q_PLUGIN_EXTRA_CONF_FILES[@]} > 0 && $Q_PLUGIN_EXTRA_CONF_PATH == '' ]]; then - die $LINENO "Neutron additional plugin config not set.. exiting" - fi + iniset $NEUTRON_CONF DEFAULT bind_host $Q_LISTEN_ADDRESS + iniset $NEUTRON_CONF oslo_concurrency lock_path $DATA_DIR/neutron/lock - # If additional config files exist, copy them over to neutron configuration - # directory - if [[ $Q_PLUGIN_EXTRA_CONF_PATH != '' ]]; then - local f - for (( f=0; $f < ${#Q_PLUGIN_EXTRA_CONF_FILES[@]}; f+=1 )); do - Q_PLUGIN_EXTRA_CONF_FILES[$f]=$Q_PLUGIN_EXTRA_CONF_PATH/${Q_PLUGIN_EXTRA_CONF_FILES[$f]} - done - fi + # NOTE(freerunner): Need to adjust Region Name for nova in multiregion installation + iniset $NEUTRON_CONF nova region_name $REGION_NAME if [ "$VIRT_DRIVER" = 'fake' ]; then # Disable arbitrary limits @@ -884,63 +747,27 @@ function _configure_neutron_common { fi # Format logging - if [ "$LOG_COLOR" == "True" ] && [ "$SYSLOG" == "False" ]; then - setup_colorized_logging $NEUTRON_CONF DEFAULT project_id - else - # Show user_name and project_name by default like in nova - iniset $NEUTRON_CONF DEFAULT logging_context_format_string "%(asctime)s.%(msecs)03d %(levelname)s %(name)s [%(request_id)s %(user_name)s %(project_name)s] %(instance)s%(message)s" - fi + setup_logging $NEUTRON_CONF - if is_service_enabled tls-proxy; then + if is_service_enabled tls-proxy && [ "$NEUTRON_DEPLOY_MOD_WSGI" == "False" ]; then # Set the service port for a proxy to take the original iniset $NEUTRON_CONF DEFAULT bind_port "$Q_PORT_INT" - fi - - if is_ssl_enabled_service "nova"; then - iniset $NEUTRON_CONF nova cafile $SSL_BUNDLE_FILE - fi - - if is_ssl_enabled_service "neutron"; then - ensure_certificates NEUTRON - - iniset $NEUTRON_CONF DEFAULT use_ssl True - iniset $NEUTRON_CONF DEFAULT ssl_cert_file "$NEUTRON_SSL_CERT" - iniset $NEUTRON_CONF DEFAULT ssl_key_file "$NEUTRON_SSL_KEY" + iniset $NEUTRON_CONF oslo_middleware enable_proxy_headers_parsing True fi _neutron_setup_rootwrap } -function _configure_neutron_debug_command { - if [[ "$Q_USE_DEBUG_COMMAND" != "True" ]]; then - return - fi - - cp $NEUTRON_DIR/etc/l3_agent.ini $NEUTRON_TEST_CONFIG_FILE - - iniset $NEUTRON_TEST_CONFIG_FILE DEFAULT verbose False - iniset $NEUTRON_TEST_CONFIG_FILE DEFAULT debug False - iniset $NEUTRON_TEST_CONFIG_FILE DEFAULT use_namespaces $Q_USE_NAMESPACE - iniset $NEUTRON_TEST_CONFIG_FILE agent root_helper "$Q_RR_COMMAND" - if [[ "$Q_USE_ROOTWRAP_DAEMON" == "True" ]]; then - iniset $NEUTRON_TEST_CONFIG_FILE agent root_helper_daemon "$Q_RR_DAEMON_COMMAND" - fi - - _neutron_setup_interface_driver $NEUTRON_TEST_CONFIG_FILE - - neutron_plugin_configure_debug_command -} - function _configure_neutron_dhcp_agent { - cp $NEUTRON_DIR/etc/dhcp_agent.ini $Q_DHCP_CONF_FILE + cp $NEUTRON_DIR/etc/dhcp_agent.ini.sample $Q_DHCP_CONF_FILE - iniset $Q_DHCP_CONF_FILE DEFAULT verbose True iniset $Q_DHCP_CONF_FILE DEFAULT debug $ENABLE_DEBUG_LOG_LEVEL - iniset $Q_DHCP_CONF_FILE DEFAULT use_namespaces $Q_USE_NAMESPACE - iniset $Q_DHCP_CONF_FILE DEFAULT root_helper "$Q_RR_COMMAND" + # make it so we have working DNS from guests + iniset $Q_DHCP_CONF_FILE DEFAULT dnsmasq_local_resolv True + iniset $Q_DHCP_CONF_FILE AGENT root_helper "$Q_RR_COMMAND" if [[ "$Q_USE_ROOTWRAP_DAEMON" == "True" ]]; then - iniset $NEUTRON_TEST_CONFIG_FILE agent root_helper_daemon "$Q_RR_DAEMON_COMMAND" + iniset $Q_DHCP_CONF_FILE AGENT root_helper_daemon "$Q_RR_DAEMON_COMMAND" fi if ! is_service_enabled q-l3; then @@ -956,65 +783,24 @@ function _configure_neutron_dhcp_agent { _neutron_setup_interface_driver $Q_DHCP_CONF_FILE - neutron_plugin_configure_dhcp_agent + neutron_plugin_configure_dhcp_agent $Q_DHCP_CONF_FILE } -function _configure_neutron_l3_agent { - local cfg_file - Q_L3_ENABLED=True - # for l3-agent, only use per tenant router if we have namespaces - Q_L3_ROUTER_PER_TENANT=$Q_USE_NAMESPACE - - if is_service_enabled q-vpn; then - neutron_vpn_configure_agent - fi - - cp $NEUTRON_DIR/etc/l3_agent.ini $Q_L3_CONF_FILE - - iniset $Q_L3_CONF_FILE DEFAULT verbose True - iniset $Q_L3_CONF_FILE DEFAULT debug $ENABLE_DEBUG_LOG_LEVEL - iniset $Q_L3_CONF_FILE DEFAULT use_namespaces $Q_USE_NAMESPACE - iniset $Q_L3_CONF_FILE DEFAULT root_helper "$Q_RR_COMMAND" - if [[ "$Q_USE_ROOTWRAP_DAEMON" == "True" ]]; then - iniset $Q_L3_CONF_FILE agent root_helper_daemon "$Q_RR_DAEMON_COMMAND" - fi - - _neutron_setup_interface_driver $Q_L3_CONF_FILE - - neutron_plugin_configure_l3_agent - - if [[ $(ip -4 a s dev "$PUBLIC_INTERFACE" | grep -c 'inet') != 0 ]]; then - _move_neutron_addresses_route "$PUBLIC_INTERFACE" "$OVS_PHYSICAL_BRIDGE" True - fi -} function _configure_neutron_metadata_agent { - cp $NEUTRON_DIR/etc/metadata_agent.ini $Q_META_CONF_FILE + cp $NEUTRON_DIR/etc/metadata_agent.ini.sample $Q_META_CONF_FILE - iniset $Q_META_CONF_FILE DEFAULT verbose True iniset $Q_META_CONF_FILE DEFAULT debug $ENABLE_DEBUG_LOG_LEVEL - iniset $Q_META_CONF_FILE DEFAULT nova_metadata_ip $Q_META_DATA_IP - iniset $Q_META_CONF_FILE DEFAULT root_helper "$Q_RR_COMMAND" + iniset $Q_META_CONF_FILE DEFAULT nova_metadata_host $Q_META_DATA_IP + iniset $Q_META_CONF_FILE DEFAULT metadata_workers $API_WORKERS + iniset $Q_META_CONF_FILE AGENT root_helper "$Q_RR_COMMAND" if [[ "$Q_USE_ROOTWRAP_DAEMON" == "True" ]]; then - iniset $Q_META_CONF_FILE agent root_helper_daemon "$Q_RR_DAEMON_COMMAND" + iniset $Q_META_CONF_FILE AGENT root_helper_daemon "$Q_RR_DAEMON_COMMAND" fi - - # Configures keystone for metadata_agent - # The third argument "True" sets auth_url needed to communicate with keystone - _neutron_setup_keystone $Q_META_CONF_FILE DEFAULT True - } function _configure_neutron_ceilometer_notifications { - iniset $NEUTRON_CONF DEFAULT notification_driver messaging -} - -function _configure_neutron_lbaas { - if [ -f $NEUTRON_LBAAS_DIR/etc/neutron_lbaas.conf ]; then - cp $NEUTRON_LBAAS_DIR/etc/neutron_lbaas.conf $NEUTRON_CONF_DIR - fi - neutron_agent_lbaas_configure_common - neutron_agent_lbaas_configure_agent + iniset $NEUTRON_CONF oslo_messaging_notifications driver messagingv2 } function _configure_neutron_metering { @@ -1022,22 +808,6 @@ function _configure_neutron_metering { neutron_agent_metering_configure_agent } -function _configure_neutron_fwaas { - if [ -f $NEUTRON_FWAAS_DIR/etc/neutron_fwaas.conf ]; then - cp $NEUTRON_FWAAS_DIR/etc/neutron_fwaas.conf $NEUTRON_CONF_DIR - fi - neutron_fwaas_configure_common - neutron_fwaas_configure_driver -} - -function _configure_neutron_vpn { - if [ -f $NEUTRON_VPNAAS_DIR/etc/neutron_vpnaas.conf ]; then - cp $NEUTRON_VPNAAS_DIR/etc/neutron_vpnaas.conf $NEUTRON_CONF_DIR - fi - neutron_vpn_install_agent_packages - neutron_vpn_configure_common -} - function _configure_dvr { iniset $NEUTRON_CONF DEFAULT router_distributed True iniset $Q_L3_CONF_FILE DEFAULT agent_mode $Q_DVR_MODE @@ -1053,7 +823,6 @@ function _configure_neutron_plugin_agent { if [[ "$Q_USE_ROOTWRAP_DAEMON" == "True" ]]; then iniset /$Q_PLUGIN_CONF_FILE agent root_helper_daemon "$Q_RR_DAEMON_COMMAND" fi - iniset $NEUTRON_CONF DEFAULT verbose True iniset $NEUTRON_CONF DEFAULT debug $ENABLE_DEBUG_LOG_LEVEL # Configure agent for plugin @@ -1064,22 +833,11 @@ function _configure_neutron_plugin_agent { # It is called when q-svc is enabled. function _configure_neutron_service { Q_API_PASTE_FILE=$NEUTRON_CONF_DIR/api-paste.ini - Q_POLICY_FILE=$NEUTRON_CONF_DIR/policy.json - cp $NEUTRON_DIR/etc/api-paste.ini $Q_API_PASTE_FILE - cp $NEUTRON_DIR/etc/policy.json $Q_POLICY_FILE - - # allow neutron user to administer neutron to match neutron account - sed -i 's/"context_is_admin": "role:admin"/"context_is_admin": "role:admin or user_name:neutron"/g' $Q_POLICY_FILE # Update either configuration file with plugin iniset $NEUTRON_CONF DEFAULT core_plugin $Q_PLUGIN_CLASS - if [[ $Q_SERVICE_PLUGIN_CLASSES != '' ]]; then - iniset $NEUTRON_CONF DEFAULT service_plugins $Q_SERVICE_PLUGIN_CLASSES - fi - - iniset $NEUTRON_CONF DEFAULT verbose True iniset $NEUTRON_CONF DEFAULT debug $ENABLE_DEBUG_LOG_LEVEL iniset $NEUTRON_CONF oslo_policy policy_file $Q_POLICY_FILE iniset $NEUTRON_CONF DEFAULT allow_overlapping_ips $Q_ALLOW_OVERLAPPING_IP @@ -1087,18 +845,11 @@ function _configure_neutron_service { iniset $NEUTRON_CONF DEFAULT auth_strategy $Q_AUTH_STRATEGY _neutron_setup_keystone $NEUTRON_CONF keystone_authtoken - # Configuration for neutron notifations to nova. + # Configuration for neutron notifications to nova. iniset $NEUTRON_CONF DEFAULT notify_nova_on_port_status_changes $Q_NOTIFY_NOVA_PORT_STATUS_CHANGES iniset $NEUTRON_CONF DEFAULT notify_nova_on_port_data_changes $Q_NOTIFY_NOVA_PORT_DATA_CHANGES - iniset $NEUTRON_CONF nova auth_plugin password - iniset $NEUTRON_CONF nova auth_url $KEYSTONE_AUTH_URI - iniset $NEUTRON_CONF nova username nova - iniset $NEUTRON_CONF nova password $SERVICE_PASSWORD - iniset $NEUTRON_CONF nova user_domain_id default - iniset $NEUTRON_CONF nova project_name $SERVICE_TENANT_NAME - iniset $NEUTRON_CONF nova project_domain_id default - iniset $NEUTRON_CONF nova region_name $REGION_NAME + configure_auth_token_middleware $NEUTRON_CONF nova $NEUTRON_AUTH_CACHE_DIR nova # Configure plugin neutron_plugin_configure_service @@ -1117,8 +868,26 @@ function _neutron_service_plugin_class_add { fi } +# _neutron_ml2_extension_driver_add_old() - add ML2 extension driver +function _neutron_ml2_extension_driver_add_old { + local extension=$1 + if [[ $Q_ML2_PLUGIN_EXT_DRIVERS == '' ]]; then + Q_ML2_PLUGIN_EXT_DRIVERS=$extension + elif [[ ! ,${Q_ML2_PLUGIN_EXT_DRIVERS}, =~ ,${extension}, ]]; then + Q_ML2_PLUGIN_EXT_DRIVERS="$Q_ML2_PLUGIN_EXT_DRIVERS,$extension" + fi +} + +# mutnauq_server_config_add() - add server config file +function mutnauq_server_config_add { + _Q_PLUGIN_EXTRA_CONF_FILES_ABS+=($1) +} + # _neutron_deploy_rootwrap_filters() - deploy rootwrap filters to $Q_CONF_ROOTWRAP_D (owned by root). function _neutron_deploy_rootwrap_filters { + if [[ "$Q_USE_ROOTWRAP" == "False" ]]; then + return + fi local srcdir=$1 sudo install -d -o root -m 755 $Q_CONF_ROOTWRAP_D sudo install -o root -m 644 $srcdir/etc/neutron/rootwrap.d/* $Q_CONF_ROOTWRAP_D/ @@ -1166,17 +935,10 @@ function _neutron_setup_rootwrap { fi } -# Configures keystone integration for neutron service and agents +# Configures keystone integration for neutron service function _neutron_setup_keystone { local conf_file=$1 local section=$2 - local use_auth_url=$3 - - # Configures keystone for metadata_agent - # metadata_agent needs auth_url to communicate with keystone - if [[ "$use_auth_url" == "True" ]]; then - iniset $conf_file $section auth_url $KEYSTONE_SERVICE_URI/v2.0 - fi create_neutron_cache_dir configure_auth_token_middleware $conf_file $Q_ADMIN_USERNAME $NEUTRON_AUTH_CACHE_DIR $section @@ -1190,153 +952,6 @@ function _neutron_setup_interface_driver { neutron_plugin_setup_interface_driver $1 } - -# Create private IPv4 subnet -function _neutron_create_private_subnet_v4 { - local subnet_params="--tenant-id $TENANT_ID " - subnet_params+="--ip_version 4 " - subnet_params+="--gateway $NETWORK_GATEWAY " - subnet_params+="--name $PRIVATE_SUBNET_NAME " - subnet_params+="$NET_ID $FIXED_RANGE" - local subnet_id=$(neutron subnet-create $subnet_params | grep ' id ' | get_field 2) - die_if_not_set $LINENO subnet_id "Failure creating private IPv4 subnet for $TENANT_ID" - echo $subnet_id -} - -# Create private IPv6 subnet -function _neutron_create_private_subnet_v6 { - die_if_not_set $LINENO IPV6_RA_MODE "IPV6 RA Mode not set" - die_if_not_set $LINENO IPV6_ADDRESS_MODE "IPV6 Address Mode not set" - local ipv6_modes="--ipv6-ra-mode $IPV6_RA_MODE --ipv6-address-mode $IPV6_ADDRESS_MODE" - local subnet_params="--tenant-id $TENANT_ID " - subnet_params+="--ip_version 6 " - subnet_params+="--gateway $IPV6_PRIVATE_NETWORK_GATEWAY " - subnet_params+="--name $IPV6_PRIVATE_SUBNET_NAME " - subnet_params+="$NET_ID $FIXED_RANGE_V6 $ipv6_modes" - local ipv6_subnet_id=$(neutron subnet-create $subnet_params | grep ' id ' | get_field 2) - die_if_not_set $LINENO ipv6_subnet_id "Failure creating private IPv6 subnet for $TENANT_ID" - echo $ipv6_subnet_id -} - -# Create public IPv4 subnet -function _neutron_create_public_subnet_v4 { - local subnet_params+="--ip_version 4 " - subnet_params+="${Q_FLOATING_ALLOCATION_POOL:+--allocation-pool $Q_FLOATING_ALLOCATION_POOL} " - subnet_params+="--gateway $PUBLIC_NETWORK_GATEWAY " - subnet_params+="--name $PUBLIC_SUBNET_NAME " - subnet_params+="$EXT_NET_ID $FLOATING_RANGE " - subnet_params+="-- --enable_dhcp=False" - local id_and_ext_gw_ip=$(neutron subnet-create $subnet_params | grep -e 'gateway_ip' -e ' id ') - die_if_not_set $LINENO id_and_ext_gw_ip "Failure creating public IPv4 subnet" - echo $id_and_ext_gw_ip -} - -# Create public IPv6 subnet -function _neutron_create_public_subnet_v6 { - local subnet_params="--ip_version 6 " - subnet_params+="--gateway $IPV6_PUBLIC_NETWORK_GATEWAY " - subnet_params+="--name $IPV6_PUBLIC_SUBNET_NAME " - subnet_params+="$EXT_NET_ID $IPV6_PUBLIC_RANGE " - subnet_params+="-- --enable_dhcp=False" - local ipv6_id_and_ext_gw_ip=$(neutron subnet-create $subnet_params | grep -e 'gateway_ip' -e ' id ') - die_if_not_set $LINENO ipv6_id_and_ext_gw_ip "Failure creating an IPv6 public subnet" - echo $ipv6_id_and_ext_gw_ip -} - -# Configure neutron router for IPv4 public access -function _neutron_configure_router_v4 { - neutron router-interface-add $ROUTER_ID $SUBNET_ID - # Create a public subnet on the external network - local id_and_ext_gw_ip=$(_neutron_create_public_subnet_v4 $EXT_NET_ID) - local ext_gw_ip=$(echo $id_and_ext_gw_ip | get_field 2) - PUB_SUBNET_ID=$(echo $id_and_ext_gw_ip | get_field 5) - # Configure the external network as the default router gateway - neutron router-gateway-set $ROUTER_ID $EXT_NET_ID - - # This logic is specific to using the l3-agent for layer 3 - if is_service_enabled q-l3; then - # Configure and enable public bridge - if is_neutron_ovs_base_plugin && [[ "$Q_USE_NAMESPACE" = "True" ]]; then - local ext_gw_interface=$(_neutron_get_ext_gw_interface) - local cidr_len=${FLOATING_RANGE#*/} - if [[ $(ip addr show dev $ext_gw_interface | grep -c $ext_gw_ip) == 0 && ( $Q_USE_PROVIDERNET_FOR_PUBLIC == "False" || $Q_USE_PUBLIC_VETH == "True" ) ]]; then - sudo ip addr add $ext_gw_ip/$cidr_len dev $ext_gw_interface - sudo ip link set $ext_gw_interface up - fi - ROUTER_GW_IP=`neutron port-list -c fixed_ips -c device_owner | grep router_gateway | awk -F '"' -v subnet_id=$PUB_SUBNET_ID '$4 == subnet_id { print $8; }'` - die_if_not_set $LINENO ROUTER_GW_IP "Failure retrieving ROUTER_GW_IP" - sudo route add -net $FIXED_RANGE gw $ROUTER_GW_IP - fi - _neutron_set_router_id - fi -} - -# Configure neutron router for IPv6 public access -function _neutron_configure_router_v6 { - neutron router-interface-add $ROUTER_ID $IPV6_SUBNET_ID - # Create a public subnet on the external network - local ipv6_id_and_ext_gw_ip=$(_neutron_create_public_subnet_v6 $EXT_NET_ID) - local ipv6_ext_gw_ip=$(echo $ipv6_id_and_ext_gw_ip | get_field 2) - local ipv6_pub_subnet_id=$(echo $ipv6_id_and_ext_gw_ip | get_field 5) - - # If the external network has not already been set as the default router - # gateway when configuring an IPv4 public subnet, do so now - if [[ "$IP_VERSION" == "6" ]]; then - neutron router-gateway-set $ROUTER_ID $EXT_NET_ID - fi - - # This logic is specific to using the l3-agent for layer 3 - if is_service_enabled q-l3; then - # Ensure IPv6 forwarding is enabled on the host - sudo sysctl -w net.ipv6.conf.all.forwarding=1 - # Configure and enable public bridge - # Override global IPV6_ROUTER_GW_IP with the true value from neutron - IPV6_ROUTER_GW_IP=`neutron port-list -c fixed_ips | grep $ipv6_pub_subnet_id | awk -F '"' -v subnet_id=$ipv6_pub_subnet_id '$4 == subnet_id { print $8; }'` - die_if_not_set $LINENO IPV6_ROUTER_GW_IP "Failure retrieving IPV6_ROUTER_GW_IP" - - # The ovs_base_configure_l3_agent function flushes the public - # bridge's ip addresses, so turn IPv6 support in the host off - # and then on to recover the public bridge's link local address - sudo sysctl -w net.ipv6.conf.${PUBLIC_BRIDGE}.disable_ipv6=1 - sudo sysctl -w net.ipv6.conf.${PUBLIC_BRIDGE}.disable_ipv6=0 - if ! ip -6 addr show dev $PUBLIC_BRIDGE | grep 'scope global'; then - # Create an IPv6 ULA address for PUBLIC_BRIDGE if one is not present - IPV6_BRIDGE_ULA=`uuidgen | sed s/-//g | cut -c 23- | sed -e "s/\(..\)\(....\)\(....\)/\1:\2:\3/"` - sudo ip -6 addr add fd$IPV6_BRIDGE_ULA::1 dev $PUBLIC_BRIDGE - fi - - if is_neutron_ovs_base_plugin && [[ "$Q_USE_NAMESPACE" = "True" ]]; then - local ext_gw_interface=$(_neutron_get_ext_gw_interface) - local ipv6_cidr_len=${IPV6_PUBLIC_RANGE#*/} - - # Configure interface for public bridge - sudo ip -6 addr add $ipv6_ext_gw_ip/$ipv6_cidr_len dev $ext_gw_interface - sudo ip -6 route add $FIXED_RANGE_V6 via $IPV6_ROUTER_GW_IP dev $ext_gw_interface - fi - _neutron_set_router_id - fi -} - -# Explicitly set router id in l3 agent configuration -function _neutron_set_router_id { - if [[ "$Q_USE_NAMESPACE" == "False" ]]; then - iniset $Q_L3_CONF_FILE DEFAULT router_id $ROUTER_ID - fi -} - -# Get ext_gw_interface depending on value of Q_USE_PUBLIC_VETH -function _neutron_get_ext_gw_interface { - if [[ "$Q_USE_PUBLIC_VETH" == "True" ]]; then - echo $Q_PUBLIC_VETH_EX - else - # Disable in-band as we are going to use local port - # to communicate with VMs - sudo ovs-vsctl set Bridge $PUBLIC_BRIDGE \ - other_config:disable-in-band=true - echo $PUBLIC_BRIDGE - fi -} - # Functions for Neutron Exercises #-------------------------------- @@ -1347,22 +962,8 @@ function delete_probe { neutron-debug --os-tenant-name admin --os-username admin probe-delete $probe_id } -function setup_neutron_debug { - if [[ "$Q_USE_DEBUG_COMMAND" == "True" ]]; then - public_net_id=`_get_net_id $PUBLIC_NETWORK_NAME` - neutron-debug --os-tenant-name admin --os-username admin --os-password $ADMIN_PASSWORD probe-create --device-owner compute $public_net_id - private_net_id=`_get_net_id $PRIVATE_NETWORK_NAME` - neutron-debug --os-tenant-name admin --os-username admin --os-password $ADMIN_PASSWORD probe-create --device-owner compute $private_net_id - fi -} - -function teardown_neutron_debug { - delete_probe $PUBLIC_NETWORK_NAME - delete_probe $PRIVATE_NETWORK_NAME -} - function _get_net_id { - neutron --os-tenant-name admin --os-username admin --os-password $ADMIN_PASSWORD net-list | grep $1 | awk '{print $2}' + openstack --os-cloud devstack-admin --os-region-name="$REGION_NAME" --os-project-name admin --os-username admin --os-password $ADMIN_PASSWORD network list | grep $1 | awk '{print $2}' } function _get_probe_cmd_prefix { @@ -1381,70 +982,12 @@ function _ssh_check_neutron { local timeout_sec=$5 local probe_cmd = "" probe_cmd=`_get_probe_cmd_prefix $from_net` - if ! timeout $timeout_sec sh -c "while ! $probe_cmd ssh -o StrictHostKeyChecking=no -i $key_file ${user}@$ip echo success; do sleep 1; done"; then - die $LINENO "server didn't become ssh-able!" - fi + local testcmd="$probe_cmd ssh -o StrictHostKeyChecking=no -i $key_file ${user}@$ip echo success" + test_with_retry "$testcmd" "server $ip didn't become ssh-able" $timeout_sec } -# Neutron 3rd party programs -#--------------------------- - -# please refer to ``lib/neutron_thirdparty/README.md`` for details -NEUTRON_THIRD_PARTIES="" -for f in $TOP_DIR/lib/neutron_thirdparty/*; do - third_party=$(basename $f) - if is_service_enabled $third_party; then - source $TOP_DIR/lib/neutron_thirdparty/$third_party - NEUTRON_THIRD_PARTIES="$NEUTRON_THIRD_PARTIES,$third_party" - fi -done - -function _neutron_third_party_do { - for third_party in ${NEUTRON_THIRD_PARTIES//,/ }; do - ${1}_${third_party} - done -} - -# configure_neutron_third_party() - Set config files, create data dirs, etc -function configure_neutron_third_party { - _neutron_third_party_do configure -} - -# init_neutron_third_party() - Initialize databases, etc. -function init_neutron_third_party { - _neutron_third_party_do init -} - -# install_neutron_third_party() - Collect source and prepare -function install_neutron_third_party { - _neutron_third_party_do install -} - -# start_neutron_third_party() - Start running processes, including screen -function start_neutron_third_party { - _neutron_third_party_do start -} - -# stop_neutron_third_party - Stop running processes (non-screen) -function stop_neutron_third_party { - _neutron_third_party_do stop -} - -# check_neutron_third_party_integration() - Check that third party integration is sane -function check_neutron_third_party_integration { - _neutron_third_party_do check -} - -function is_provider_network { - if [ "$Q_USE_PROVIDER_NETWORKING" == "True" ] && [ "$Q_L3_ENABLED" == "False" ]; then - return 0 - fi - return 1 -} - - # Restore xtrace -$XTRACE +$_XTRACE_NEUTRON # Tell emacs to use shell-script-mode ## Local variables: diff --git a/lib/neutron_plugins/README.md b/lib/neutron_plugins/README.md index 4b220d3377..ed40886fda 100644 --- a/lib/neutron_plugins/README.md +++ b/lib/neutron_plugins/README.md @@ -16,9 +16,7 @@ functions ``lib/neutron-legacy`` calls the following functions when the ``$Q_PLUGIN`` is enabled * ``neutron_plugin_create_nova_conf`` : - set ``NOVA_VIF_DRIVER`` and optionally set options in nova_conf - e.g. - NOVA_VIF_DRIVER=${NOVA_VIF_DRIVER:-"nova.virt.libvirt.vif.LibvirtGenericVIFDriver"} + optionally set options in nova_conf * ``neutron_plugin_install_agent_packages`` : install packages that is specific to plugin agent e.g. @@ -26,7 +24,6 @@ functions * ``neutron_plugin_configure_common`` : set plugin-specific variables, ``Q_PLUGIN_CONF_PATH``, ``Q_PLUGIN_CONF_FILENAME``, ``Q_PLUGIN_CLASS`` -* ``neutron_plugin_configure_debug_command`` * ``neutron_plugin_configure_dhcp_agent`` * ``neutron_plugin_configure_l3_agent`` * ``neutron_plugin_configure_plugin_agent`` diff --git a/lib/neutron_plugins/bigswitch_floodlight b/lib/neutron_plugins/bigswitch_floodlight index 4166131534..d3f5bd5752 100644 --- a/lib/neutron_plugins/bigswitch_floodlight +++ b/lib/neutron_plugins/bigswitch_floodlight @@ -1,10 +1,10 @@ #!/bin/bash # -# Neuton Big Switch/FloodLight plugin +# Neutron Big Switch/FloodLight plugin # ------------------------------------ # Save trace setting -BS_XTRACE=$(set +o | grep xtrace) +_XTRACE_NEUTRON_BIGSWITCH=$(set +o | grep xtrace) set +o xtrace source $TOP_DIR/lib/neutron_plugins/ovs_base @@ -26,10 +26,6 @@ function neutron_plugin_configure_common { BS_FL_CONTROLLER_TIMEOUT=${BS_FL_CONTROLLER_TIMEOUT:-10} } -function neutron_plugin_configure_debug_command { - _neutron_ovs_base_configure_debug_command -} - function neutron_plugin_configure_dhcp_agent { : } @@ -58,9 +54,9 @@ function neutron_plugin_configure_service { function neutron_plugin_setup_interface_driver { local conf_file=$1 if [ "$BS_FL_VIF_DRIVER" = "ivs" ]; then - iniset $conf_file DEFAULT interface_driver neutron.agent.linux.interface.IVSInterfaceDriver + iniset $conf_file DEFAULT interface_driver ivs else - iniset $conf_file DEFAULT interface_driver neutron.agent.linux.interface.OVSInterfaceDriver + iniset $conf_file DEFAULT interface_driver openvswitch fi } @@ -75,4 +71,4 @@ function neutron_plugin_check_adv_test_requirements { } # Restore xtrace -$BS_XTRACE +$_XTRACE_NEUTRON_BIGSWITCH diff --git a/lib/neutron_plugins/brocade b/lib/neutron_plugins/brocade index b8166d9af9..310b72e5ad 100644 --- a/lib/neutron_plugins/brocade +++ b/lib/neutron_plugins/brocade @@ -4,7 +4,7 @@ # ---------------------- # Save trace setting -BRCD_XTRACE=$(set +o | grep xtrace) +_XTRACE_NEUTRON_BROCADE=$(set +o | grep xtrace) set +o xtrace function is_neutron_ovs_base_plugin { @@ -12,7 +12,7 @@ function is_neutron_ovs_base_plugin { } function neutron_plugin_create_nova_conf { - NOVA_VIF_DRIVER=${NOVA_VIF_DRIVER:-"nova.virt.libvirt.vif.LibvirtGenericVIFDriver"} + : } function neutron_plugin_install_agent_packages { @@ -49,16 +49,11 @@ function neutron_plugin_configure_service { } -function neutron_plugin_configure_debug_command { - iniset $NEUTRON_TEST_CONFIG_FILE DEFAULT external_network_bridge -} - function neutron_plugin_configure_dhcp_agent { iniset $Q_DHCP_CONF_FILE DEFAULT dhcp_agent_manager neutron.agent.dhcp_agent.DhcpAgentWithStateReport } function neutron_plugin_configure_l3_agent { - iniset $Q_L3_CONF_FILE DEFAULT external_network_bridge iniset $Q_L3_CONF_FILE DEFAULT l3_agent_manager neutron.agent.l3_agent.L3NATAgentWithStateReport } @@ -68,7 +63,7 @@ function neutron_plugin_configure_plugin_agent { function neutron_plugin_setup_interface_driver { local conf_file=$1 - iniset $conf_file DEFAULT interface_driver neutron.agent.linux.interface.BridgeInterfaceDriver + iniset $conf_file DEFAULT interface_driver linuxbridge } function has_neutron_plugin_security_group { @@ -81,4 +76,4 @@ function neutron_plugin_check_adv_test_requirements { } # Restore xtrace -$BRCD_XTRACE +$_XTRACE_NEUTRON_BROCADE diff --git a/lib/neutron_plugins/cisco b/lib/neutron_plugins/cisco index 90dcd574c0..b397169b59 100644 --- a/lib/neutron_plugins/cisco +++ b/lib/neutron_plugins/cisco @@ -4,7 +4,7 @@ # --------------------------- # Save trace setting -CISCO_XTRACE=$(set +o | grep xtrace) +_XTRACE_NEUTRON_CISCO=$(set +o | grep xtrace) set +o xtrace # Scecify the VSM parameters @@ -45,7 +45,6 @@ source $TOP_DIR/lib/neutron_plugins/openvswitch _prefix_function neutron_plugin_create_nova_conf ovs _prefix_function neutron_plugin_install_agent_packages ovs _prefix_function neutron_plugin_configure_common ovs -_prefix_function neutron_plugin_configure_debug_command ovs _prefix_function neutron_plugin_configure_dhcp_agent ovs _prefix_function neutron_plugin_configure_l3_agent ovs _prefix_function neutron_plugin_configure_plugin_agent ovs @@ -83,10 +82,6 @@ function neutron_plugin_configure_common { Q_PLUGIN_CLASS="neutron.plugins.cisco.network_plugin.PluginV2" } -function neutron_plugin_configure_debug_command { - : -} - function neutron_plugin_configure_dhcp_agent { iniset $Q_DHCP_CONF_FILE DEFAULT dhcp_agent_manager neutron.agent.dhcp_agent.DhcpAgentWithStateReport } @@ -150,8 +145,8 @@ function neutron_plugin_create_initial_network_profile { function neutron_plugin_setup_interface_driver { local conf_file=$1 - iniset $conf_file DEFAULT interface_driver neutron.agent.linux.interface.OVSInterfaceDriver + iniset $conf_file DEFAULT interface_driver openvswitch } # Restore xtrace -$CISCO_XTRACE +$_XTRACE_NEUTRON_CISCO diff --git a/lib/neutron_plugins/embrane b/lib/neutron_plugins/embrane index 6b4819ef70..385dab8354 100644 --- a/lib/neutron_plugins/embrane +++ b/lib/neutron_plugins/embrane @@ -4,13 +4,14 @@ # --------------------------- # Save trace setting -EMBR_XTRACE=$(set +o | grep xtrace) +_XTRACE_NEUTRON_EMBR=$(set +o | grep xtrace) set +o xtrace source $TOP_DIR/lib/neutron_plugins/openvswitch function save_function { - local ORIG_FUNC=$(declare -f $1) + local ORIG_FUNC + ORIG_FUNC=$(declare -f $1) local NEW_FUNC="$2${ORIG_FUNC#$1}" eval "$NEW_FUNC" } @@ -38,4 +39,5 @@ function neutron_plugin_configure_service { } # Restore xtrace -$EMBR_XTRACE +$_XTRACE_NEUTRON_EMBR + diff --git a/lib/neutron_plugins/ibm b/lib/neutron_plugins/ibm deleted file mode 100644 index 3660a9f2b9..0000000000 --- a/lib/neutron_plugins/ibm +++ /dev/null @@ -1,134 +0,0 @@ -#!/bin/bash -# -# Neutron IBM SDN-VE plugin -# --------------------------- - -# Save trace setting -IBM_XTRACE=$(set +o | grep xtrace) -set +o xtrace - -source $TOP_DIR/lib/neutron_plugins/ovs_base - -function neutron_plugin_install_agent_packages { - _neutron_ovs_base_install_agent_packages -} - -function _neutron_interface_setup { - # Setup one interface on the integration bridge if needed - # The plugin agent to be used if more than one interface is used - local bridge=$1 - local interface=$2 - sudo ovs-vsctl --no-wait -- --may-exist add-port $bridge $interface -} - -function neutron_setup_integration_bridge { - # Setup integration bridge if needed - if [[ "$SDNVE_INTEGRATION_BRIDGE" != "" ]]; then - neutron_ovs_base_cleanup - _neutron_ovs_base_setup_bridge $SDNVE_INTEGRATION_BRIDGE - if [[ "$SDNVE_INTERFACE_MAPPINGS" != "" ]]; then - interfaces=(${SDNVE_INTERFACE_MAPPINGS//[,:]/ }) - _neutron_interface_setup $SDNVE_INTEGRATION_BRIDGE ${interfaces[1]} - fi - fi - - # Set controller to SDNVE controller (1st of list) if exists - if [[ "$SDNVE_CONTROLLER_IPS" != "" ]]; then - # Get the first controller - controllers=(${SDNVE_CONTROLLER_IPS//[\[,\]]/ }) - SDNVE_IP=${controllers[0]} - sudo ovs-vsctl set-controller $SDNVE_INTEGRATION_BRIDGE tcp:$SDNVE_IP - fi -} - -function neutron_plugin_create_nova_conf { - NOVA_VIF_DRIVER=${NOVA_VIF_DRIVER:-"nova.virt.libvirt.vif.LibvirtGenericVIFDriver"} - # if n-cpu is enabled, then setup integration bridge - if is_service_enabled n-cpu; then - neutron_setup_integration_bridge - fi -} - -function is_neutron_ovs_base_plugin { - if [[ "$SDNVE_INTEGRATION_BRIDGE" != "" ]]; then - # Yes, we use OVS. - return 0 - else - # No, we do not use OVS. - return 1 - fi -} - -function neutron_plugin_configure_common { - Q_PLUGIN_CONF_PATH=etc/neutron/plugins/ibm - Q_PLUGIN_CONF_FILENAME=sdnve_neutron_plugin.ini - Q_PLUGIN_CLASS="neutron.plugins.ibm.sdnve_neutron_plugin.SdnvePluginV2" -} - -function neutron_plugin_configure_service { - # Define extra "SDNVE" configuration options when q-svc is configured - - iniset /$Q_PLUGIN_CONF_FILE securitygroup firewall_driver neutron.agent.firewall.NoopFirewallDriver - - if [[ "$SDNVE_CONTROLLER_IPS" != "" ]]; then - iniset /$Q_PLUGIN_CONF_FILE sdnve controller_ips $SDNVE_CONTROLLER_IPS - fi - - if [[ "$SDNVE_INTEGRATION_BRIDGE" != "" ]]; then - iniset /$Q_PLUGIN_CONF_FILE sdnve integration_bridge $SDNVE_INTEGRATION_BRIDGE - fi - - if [[ "$SDNVE_RESET_BRIDGE" != "" ]]; then - iniset /$Q_PLUGIN_CONF_FILE sdnve reset_bridge $SDNVE_RESET_BRIDGE - fi - - if [[ "$SDNVE_OUT_OF_BAND" != "" ]]; then - iniset /$Q_PLUGIN_CONF_FILE sdnve out_of_band $SDNVE_OUT_OF_BAND - fi - - if [[ "$SDNVE_INTERFACE_MAPPINGS" != "" ]]; then - iniset /$Q_PLUGIN_CONF_FILE sdnve interface_mappings $SDNVE_INTERFACE_MAPPINGS - fi - - if [[ "$SDNVE_FAKE_CONTROLLER" != "" ]]; then - iniset /$Q_PLUGIN_CONF_FILE sdnve use_fake_controller $SDNVE_FAKE_CONTROLLER - fi - - - iniset $NEUTRON_CONF DEFAULT notification_driver neutron.openstack.common.notifier.no_op_notifier - -} - -function neutron_plugin_configure_plugin_agent { - AGENT_BINARY="$NEUTRON_BIN_DIR/neutron-ibm-agent" -} - -function neutron_plugin_configure_debug_command { - : -} - -function neutron_plugin_setup_interface_driver { - return 0 -} - -function has_neutron_plugin_security_group { - # Does not support Security Groups - return 1 -} - -function neutron_ovs_base_cleanup { - if [[ "$SDNVE_RESET_BRIDGE" != False ]]; then - # remove all OVS ports that look like Neutron created ports - for port in $(sudo ovs-vsctl list port | grep -o -e tap[0-9a-f\-]* -e q[rg]-[0-9a-f\-]*); do - sudo ovs-vsctl del-port ${port} - done - - # remove integration bridge created by Neutron - for bridge in $(sudo ovs-vsctl list-br | grep -o -e ${SDNVE_INTEGRATION_BRIDGE}); do - sudo ovs-vsctl del-br ${bridge} - done - fi -} - -# Restore xtrace -$IBM_XTRACE diff --git a/lib/neutron_plugins/linuxbridge_agent b/lib/neutron_plugins/linuxbridge_agent index c9ea1cac28..f2302e37bf 100644 --- a/lib/neutron_plugins/linuxbridge_agent +++ b/lib/neutron_plugins/linuxbridge_agent @@ -4,9 +4,28 @@ # ----------------------------- # Save trace setting -PLUGIN_XTRACE=$(set +o | grep xtrace) +_XTRACE_NEUTRON_LB=$(set +o | grep xtrace) set +o xtrace +function neutron_lb_cleanup { + sudo ip link set $PUBLIC_BRIDGE down + sudo brctl delbr $PUBLIC_BRIDGE + + if [[ "$Q_ML2_TENANT_NETWORK_TYPE" = "vxlan" ]]; then + for port in $(sudo brctl show | grep -o -e [a-zA-Z\-]*tap[0-9a-f\-]* -e vxlan-[0-9a-f\-]*); do + sudo ip link delete $port + done + elif [[ "$Q_ML2_TENANT_NETWORK_TYPE" = "vlan" ]]; then + for port in $(sudo brctl show | grep -o -e [a-zA-Z\-]*tap[0-9a-f\-]* -e ${LB_PHYSICAL_INTERFACE}\.[0-9a-f\-]*); do + sudo ip link delete $port + done + fi + for bridge in $(sudo brctl show |grep -o -e brq[0-9a-f\-]*); do + sudo ip link set $bridge down + sudo brctl delbr $bridge + done +} + function is_neutron_ovs_base_plugin { # linuxbridge doesn't use OVS return 1 @@ -20,17 +39,15 @@ function neutron_plugin_install_agent_packages { install_package bridge-utils } -function neutron_plugin_configure_debug_command { - iniset $NEUTRON_TEST_CONFIG_FILE DEFAULT external_network_bridge -} - function neutron_plugin_configure_dhcp_agent { - iniset $Q_DHCP_CONF_FILE DEFAULT dhcp_agent_manager neutron.agent.dhcp_agent.DhcpAgentWithStateReport + local conf_file=$1 + : } function neutron_plugin_configure_l3_agent { - iniset $Q_L3_CONF_FILE DEFAULT external_network_bridge - iniset $Q_L3_CONF_FILE DEFAULT l3_agent_manager neutron.agent.l3_agent.L3NATAgentWithStateReport + local conf_file=$1 + sudo brctl addbr $PUBLIC_BRIDGE + set_mtu $PUBLIC_BRIDGE $PUBLIC_BRIDGE_MTU } function neutron_plugin_configure_plugin_agent { @@ -40,21 +57,41 @@ function neutron_plugin_configure_plugin_agent { if [[ "$LB_INTERFACE_MAPPINGS" == "" ]] && [[ "$PHYSICAL_NETWORK" != "" ]] && [[ "$LB_PHYSICAL_INTERFACE" != "" ]]; then LB_INTERFACE_MAPPINGS=$PHYSICAL_NETWORK:$LB_PHYSICAL_INTERFACE fi + if [[ "$PUBLIC_BRIDGE" != "" ]] && [[ "$PUBLIC_PHYSICAL_NETWORK" != "" ]]; then + if is_service_enabled q-l3 || is_service_enabled neutron-l3; then + iniset /$Q_PLUGIN_CONF_FILE linux_bridge bridge_mappings "$PUBLIC_PHYSICAL_NETWORK:$PUBLIC_BRIDGE" + fi + fi if [[ "$LB_INTERFACE_MAPPINGS" != "" ]]; then iniset /$Q_PLUGIN_CONF_FILE linux_bridge physical_interface_mappings $LB_INTERFACE_MAPPINGS fi if [[ "$Q_USE_SECGROUP" == "True" ]]; then iniset /$Q_PLUGIN_CONF_FILE securitygroup firewall_driver neutron.agent.linux.iptables_firewall.IptablesFirewallDriver + if ! running_in_container; then + enable_kernel_bridge_firewall + fi else iniset /$Q_PLUGIN_CONF_FILE securitygroup firewall_driver neutron.agent.firewall.NoopFirewallDriver fi AGENT_BINARY="$NEUTRON_BIN_DIR/neutron-linuxbridge-agent" iniset /$Q_PLUGIN_CONF_FILE agent tunnel_types $Q_TUNNEL_TYPES + + # Configure vxlan tunneling + if [[ "$ENABLE_TENANT_TUNNELS" == "True" ]]; then + if [[ "$Q_ML2_TENANT_NETWORK_TYPE" == "vxlan" ]]; then + iniset /$Q_PLUGIN_CONF_FILE vxlan enable_vxlan "True" + iniset /$Q_PLUGIN_CONF_FILE vxlan local_ip $TUNNEL_ENDPOINT_IP + else + iniset /$Q_PLUGIN_CONF_FILE vxlan enable_vxlan "False" + fi + else + iniset /$Q_PLUGIN_CONF_FILE vxlan enable_vxlan "False" + fi } function neutron_plugin_setup_interface_driver { local conf_file=$1 - iniset $conf_file DEFAULT interface_driver neutron.agent.linux.interface.BridgeInterfaceDriver + iniset $conf_file DEFAULT interface_driver linuxbridge } function neutron_plugin_check_adv_test_requirements { @@ -62,4 +99,4 @@ function neutron_plugin_check_adv_test_requirements { } # Restore xtrace -$PLUGIN_XTRACE +$_XTRACE_NEUTRON_LB diff --git a/lib/neutron_plugins/midonet b/lib/neutron_plugins/midonet deleted file mode 100644 index 9e72aa0ce9..0000000000 --- a/lib/neutron_plugins/midonet +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/bash - -# REVISIT(devvesa): This file is intentionally left empty -# in order to keep Q_PLUGIN=midonet work. diff --git a/lib/neutron_plugins/ml2 b/lib/neutron_plugins/ml2 index 88537774b7..c5a4c02cc5 100644 --- a/lib/neutron_plugins/ml2 +++ b/lib/neutron_plugins/ml2 @@ -4,7 +4,7 @@ # ------------------------------ # Save trace setting -ML2_XTRACE=$(set +o | grep xtrace) +_XTRACE_NEUTRON_ML2=$(set +o | grep xtrace) set +o xtrace # Enable this to simply and quickly enable tunneling with ML2. @@ -19,21 +19,32 @@ fi # Default openvswitch L2 agent Q_AGENT=${Q_AGENT:-openvswitch} -source $TOP_DIR/lib/neutron_plugins/${Q_AGENT}_agent +if [ -f $TOP_DIR/lib/neutron_plugins/${Q_AGENT}_agent ]; then + source $TOP_DIR/lib/neutron_plugins/${Q_AGENT}_agent +fi # List of MechanismDrivers to load Q_ML2_PLUGIN_MECHANISM_DRIVERS=${Q_ML2_PLUGIN_MECHANISM_DRIVERS:-openvswitch,linuxbridge} -# List of Type Drivers to load -Q_ML2_PLUGIN_TYPE_DRIVERS=${Q_ML2_PLUGIN_TYPE_DRIVERS:-local,flat,vlan,gre,vxlan} # Default GRE TypeDriver options Q_ML2_PLUGIN_GRE_TYPE_OPTIONS=${Q_ML2_PLUGIN_GRE_TYPE_OPTIONS:-tunnel_id_ranges=$TENANT_TUNNEL_RANGES} # Default VXLAN TypeDriver options -Q_ML2_PLUGIN_VXLAN_TYPE_OPTIONS=${Q_ML2_PLUGIN_VXLAN_TYPE_OPTIONS:-vni_ranges=1001:2000} +Q_ML2_PLUGIN_VXLAN_TYPE_OPTIONS=${Q_ML2_PLUGIN_VXLAN_TYPE_OPTIONS:-vni_ranges=$TENANT_TUNNEL_RANGES} # Default VLAN TypeDriver options Q_ML2_PLUGIN_VLAN_TYPE_OPTIONS=${Q_ML2_PLUGIN_VLAN_TYPE_OPTIONS:-} +# Default GENEVE TypeDriver options +Q_ML2_PLUGIN_GENEVE_TYPE_OPTIONS=${Q_ML2_PLUGIN_GENEVE_TYPE_OPTIONS:-vni_ranges=$TENANT_TUNNEL_RANGES} +# List of extension drivers to load, use '-' instead of ':-' to allow people to +# explicitly override this to blank +if [[ "$NEUTRON_PORT_SECURITY" = "True" ]]; then + Q_ML2_PLUGIN_EXT_DRIVERS=${Q_ML2_PLUGIN_EXT_DRIVERS-port_security} +else + Q_ML2_PLUGIN_EXT_DRIVERS=${Q_ML2_PLUGIN_EXT_DRIVERS:-} +fi # L3 Plugin to load for ML2 -ML2_L3_PLUGIN=${ML2_L3_PLUGIN:-neutron.services.l3_router.l3_router_plugin.L3RouterPlugin} +# For some flat network environment, they not want to extend L3 plugin. +# Make sure it is able to set empty to ML2_L3_PLUGIN. +ML2_L3_PLUGIN=${ML2_L3_PLUGIN-neutron.services.l3_router.l3_router_plugin.L3RouterPlugin} function populate_ml2_config { CONF=$1 @@ -52,7 +63,7 @@ function populate_ml2_config { function neutron_plugin_configure_common { Q_PLUGIN_CONF_PATH=etc/neutron/plugins/ml2 Q_PLUGIN_CONF_FILENAME=ml2_conf.ini - Q_PLUGIN_CLASS="neutron.plugins.ml2.plugin.Ml2Plugin" + Q_PLUGIN_CLASS="ml2" # The ML2 plugin delegates L3 routing/NAT functionality to # the L3 service plugin which must therefore be specified. _neutron_service_plugin_class_add $ML2_L3_PLUGIN @@ -88,8 +99,16 @@ function neutron_plugin_configure_service { # Allow for setup the flat type network - if [[ -z "$Q_ML2_PLUGIN_FLAT_TYPE_OPTIONS" && -n "$PHYSICAL_NETWORK" ]]; then - Q_ML2_PLUGIN_FLAT_TYPE_OPTIONS="flat_networks=$PHYSICAL_NETWORK" + if [[ -z "$Q_ML2_PLUGIN_FLAT_TYPE_OPTIONS" ]]; then + if [[ -n "$PHYSICAL_NETWORK" || -n "$PUBLIC_PHYSICAL_NETWORK" ]]; then + Q_ML2_PLUGIN_FLAT_TYPE_OPTIONS="flat_networks=" + if [[ -n "$PHYSICAL_NETWORK" ]]; then + Q_ML2_PLUGIN_FLAT_TYPE_OPTIONS+="${PHYSICAL_NETWORK}," + fi + if [[ -n "$PUBLIC_PHYSICAL_NETWORK" ]] && [[ "${PHYSICAL_NETWORK}" != "$PUBLIC_PHYSICAL_NETWORK" ]]; then + Q_ML2_PLUGIN_FLAT_TYPE_OPTIONS+="${PUBLIC_PHYSICAL_NETWORK}," + fi + fi fi # REVISIT(rkukura): Setting firewall_driver here for # neutron.agent.securitygroups_rpc.is_firewall_enabled() which is @@ -104,14 +123,13 @@ function neutron_plugin_configure_service { iniset /$Q_PLUGIN_CONF_FILE securitygroup firewall_driver neutron.agent.firewall.NoopFirewallDriver fi - if [[ "$ENABLE_TENANT_TUNNELS" == "True" ]]; then - # Set local_ip if TENANT_TUNNELS are enabled. - iniset /$Q_PLUGIN_CONF_FILE ovs local_ip $TUNNEL_ENDPOINT_IP - fi - populate_ml2_config /$Q_PLUGIN_CONF_FILE ml2 mechanism_drivers=$Q_ML2_PLUGIN_MECHANISM_DRIVERS - populate_ml2_config /$Q_PLUGIN_CONF_FILE ml2 type_drivers=$Q_ML2_PLUGIN_TYPE_DRIVERS + if [[ -n "$Q_ML2_PLUGIN_TYPE_DRIVERS" ]]; then + populate_ml2_config /$Q_PLUGIN_CONF_FILE ml2 type_drivers=$Q_ML2_PLUGIN_TYPE_DRIVERS + fi + + populate_ml2_config /$Q_PLUGIN_CONF_FILE ml2 extension_drivers=$Q_ML2_PLUGIN_EXT_DRIVERS populate_ml2_config /$Q_PLUGIN_CONF_FILE ml2 $Q_SRV_EXTRA_OPTS @@ -123,6 +141,8 @@ function neutron_plugin_configure_service { populate_ml2_config /$Q_PLUGIN_CONF_FILE ml2_type_vlan $Q_ML2_PLUGIN_VLAN_TYPE_OPTIONS + populate_ml2_config /$Q_PLUGIN_CONF_FILE ml2_type_geneve $Q_ML2_PLUGIN_GENEVE_TYPE_OPTIONS + if [[ "$Q_DVR_MODE" != "legacy" ]]; then populate_ml2_config /$Q_PLUGIN_CONF_FILE agent l2_population=True populate_ml2_config /$Q_PLUGIN_CONF_FILE agent tunnel_types=vxlan @@ -135,4 +155,4 @@ function has_neutron_plugin_security_group { } # Restore xtrace -$ML2_XTRACE +$_XTRACE_NEUTRON_ML2 diff --git a/lib/neutron_plugins/nec b/lib/neutron_plugins/nec deleted file mode 100644 index 9ea7338696..0000000000 --- a/lib/neutron_plugins/nec +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/bash - -# This file is needed so Q_PLUGIN=nec will work. - -# FIXME(amotoki): This function should not be here, but unfortunately -# devstack calls it before the external plugins are fetched -function has_neutron_plugin_security_group { - # 0 means True here - return 0 -} diff --git a/lib/neutron_plugins/nuage b/lib/neutron_plugins/nuage index 7bce233853..f39c7c4f5b 100644 --- a/lib/neutron_plugins/nuage +++ b/lib/neutron_plugins/nuage @@ -4,15 +4,15 @@ # ---------------------- # Save trace setting -NU_XTRACE=$(set +o | grep xtrace) +_XTRACE_NEUTRON_NU=$(set +o | grep xtrace) set +o xtrace function neutron_plugin_create_nova_conf { + local conf="$1" NOVA_OVS_BRIDGE=${NOVA_OVS_BRIDGE:-"br-int"} - iniset $NOVA_CONF neutron ovs_bridge $NOVA_OVS_BRIDGE - NOVA_VIF_DRIVER=${NOVA_VIF_DRIVER:-"nova.virt.libvirt.vif.LibvirtGenericVIFDriver"} + iniset $conf neutron ovs_bridge $NOVA_OVS_BRIDGE LIBVIRT_FIREWALL_DRIVER=nova.virt.firewall.NoopFirewallDriver - iniset $NOVA_CONF DEFAULT firewall_driver $LIBVIRT_FIREWALL_DRIVER + iniset $conf DEFAULT firewall_driver $LIBVIRT_FIREWALL_DRIVER } function neutron_plugin_install_agent_packages { @@ -34,10 +34,6 @@ function neutron_plugin_configure_common { NUAGE_CNA_DEF_NETPART_NAME=${NUAGE_CNA_DEF_NETPART_NAME:-''} } -function neutron_plugin_configure_debug_command { - : -} - function neutron_plugin_configure_dhcp_agent { : } @@ -67,4 +63,4 @@ function has_neutron_plugin_security_group { } # Restore xtrace -$NU_XTRACE +$_XTRACE_NEUTRON_NU diff --git a/lib/neutron_plugins/ofagent_agent b/lib/neutron_plugins/ofagent_agent deleted file mode 100644 index 0bc9bffb55..0000000000 --- a/lib/neutron_plugins/ofagent_agent +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/bash - -# REVISIT(yamamoto): This file is intentionally left empty -# in order to keep Q_AGENT=ofagent_agent work. diff --git a/lib/neutron_plugins/oneconvergence b/lib/neutron_plugins/oneconvergence deleted file mode 100644 index 48a368a967..0000000000 --- a/lib/neutron_plugins/oneconvergence +++ /dev/null @@ -1,78 +0,0 @@ -#!/bin/bash -# -# Neutron One Convergence plugin -# ------------------------------ - -# Save trace setting -OC_XTRACE=$(set +o | grep xtrace) -set +o xtrace - -source $TOP_DIR/lib/neutron_plugins/ovs_base - -Q_L3_ENABLED=true -Q_L3_ROUTER_PER_TENANT=true -Q_USE_NAMESPACE=true - -function neutron_plugin_install_agent_packages { - _neutron_ovs_base_install_agent_packages -} -# Configure common parameters -function neutron_plugin_configure_common { - - Q_PLUGIN_CONF_PATH=etc/neutron/plugins/oneconvergence - Q_PLUGIN_CONF_FILENAME=nvsdplugin.ini - Q_PLUGIN_CLASS="neutron.plugins.oneconvergence.plugin.OneConvergencePluginV2" -} - -# Configure plugin specific information -function neutron_plugin_configure_service { - iniset /$Q_PLUGIN_CONF_FILE nvsd nvsd_ip $NVSD_IP - iniset /$Q_PLUGIN_CONF_FILE nvsd nvsd_port $NVSD_PORT - iniset /$Q_PLUGIN_CONF_FILE nvsd nvsd_user $NVSD_USER - iniset /$Q_PLUGIN_CONF_FILE nvsd nvsd_passwd $NVSD_PASSWD -} - -function neutron_plugin_configure_debug_command { - _neutron_ovs_base_configure_debug_command -} - -function neutron_plugin_setup_interface_driver { - local conf_file=$1 - iniset $conf_file DEFAULT interface_driver neutron.agent.linux.interface.OVSInterfaceDriver -} - -function has_neutron_plugin_security_group { - # 1 means False here - return 0 -} - -function setup_integration_bridge { - _neutron_ovs_base_setup_bridge $OVS_BRIDGE -} - -function neutron_plugin_configure_dhcp_agent { - setup_integration_bridge - iniset $Q_DHCP_CONF_FILE DEFAULT dhcp_agent_manager neutron.agent.dhcp_agent.DhcpAgentWithStateReport -} - -function neutron_plugin_configure_l3_agent { - _neutron_ovs_base_configure_l3_agent - iniset $Q_L3_CONF_FILE DEFAULT l3_agent_manager neutron.agent.l3_agent.L3NATAgentWithStateReport -} - -function neutron_plugin_configure_plugin_agent { - - AGENT_BINARY="$NEUTRON_BIN_DIR/neutron-nvsd-agent" - - _neutron_ovs_base_configure_firewall_driver -} - -function neutron_plugin_create_nova_conf { - NOVA_VIF_DRIVER=${NOVA_VIF_DRIVER:-"nova.virt.libvirt.vif.LibvirtGenericVIFDriver"} - if ( is_service_enabled n-cpu && ! ( is_service_enabled q-dhcp )) ; then - setup_integration_bridge - fi -} - -# Restore xtrace -$OC_XTRACE diff --git a/lib/neutron_plugins/openvswitch b/lib/neutron_plugins/openvswitch index 891ab4982b..130eaacab3 100644 --- a/lib/neutron_plugins/openvswitch +++ b/lib/neutron_plugins/openvswitch @@ -7,7 +7,7 @@ # which has been removed in Juno. # Save trace setting -OVS_XTRACE=$(set +o | grep xtrace) +_XTRACE_NEUTRON_OVS=$(set +o | grep xtrace) set +o xtrace source $TOP_DIR/lib/neutron_plugins/openvswitch_agent @@ -56,4 +56,5 @@ function has_neutron_plugin_security_group { } # Restore xtrace -$OVS_XTRACE +$_XTRACE_NEUTRON_OVS + diff --git a/lib/neutron_plugins/openvswitch_agent b/lib/neutron_plugins/openvswitch_agent index 1d24f3b837..b65a2587c2 100644 --- a/lib/neutron_plugins/openvswitch_agent +++ b/lib/neutron_plugins/openvswitch_agent @@ -4,36 +4,27 @@ # ----------------------------- # Save trace setting -OVSA_XTRACE=$(set +o | grep xtrace) +_XTRACE_NEUTRON_OVSL2=$(set +o | grep xtrace) set +o xtrace source $TOP_DIR/lib/neutron_plugins/ovs_base function neutron_plugin_create_nova_conf { _neutron_ovs_base_configure_nova_vif_driver - if [ "$VIRT_DRIVER" == 'xenserver' ]; then - iniset $NOVA_CONF xenserver vif_driver nova.virt.xenapi.vif.XenAPIOpenVswitchDriver - iniset $NOVA_CONF xenserver ovs_integration_bridge $XEN_INTEGRATION_BRIDGE - # Disable nova's firewall so that it does not conflict with neutron - iniset $NOVA_CONF DEFAULT firewall_driver nova.virt.firewall.NoopFirewallDriver - fi } function neutron_plugin_install_agent_packages { _neutron_ovs_base_install_agent_packages } -function neutron_plugin_configure_debug_command { - _neutron_ovs_base_configure_debug_command -} - function neutron_plugin_configure_dhcp_agent { - iniset $Q_DHCP_CONF_FILE DEFAULT dhcp_agent_manager neutron.agent.dhcp_agent.DhcpAgentWithStateReport + local conf_file=$1 + : } function neutron_plugin_configure_l3_agent { + local conf_file=$1 _neutron_ovs_base_configure_l3_agent - iniset $Q_L3_CONF_FILE DEFAULT l3_agent_manager neutron.agent.l3_agent.L3NATAgentWithStateReport } function neutron_plugin_configure_plugin_agent { @@ -43,13 +34,8 @@ function neutron_plugin_configure_plugin_agent { # Setup agent for tunneling if [[ "$OVS_ENABLE_TUNNELING" == "True" ]]; then - # Verify tunnels are supported - # REVISIT - also check kernel module support for GRE and patch ports - OVS_VERSION=`ovs-vsctl --version | head -n 1 | grep -E -o "[0-9]+\.[0-9]+"` - if [ `vercmp_numbers "$OVS_VERSION" "1.4"` -lt "0" ] && ! is_service_enabled q-svc ; then - die $LINENO "You are running OVS version $OVS_VERSION. OVS 1.4+ is required for tunneling between multiple hosts." - fi iniset /$Q_PLUGIN_CONF_FILE ovs local_ip $TUNNEL_ENDPOINT_IP + iniset /$Q_PLUGIN_CONF_FILE ovs tunnel_bridge $OVS_TUNNEL_BRIDGE fi # Setup physical network bridge mappings. Override @@ -59,56 +45,20 @@ function neutron_plugin_configure_plugin_agent { OVS_BRIDGE_MAPPINGS=$PHYSICAL_NETWORK:$OVS_PHYSICAL_BRIDGE # Configure bridge manually with physical interface as port for multi-node - sudo ovs-vsctl --no-wait -- --may-exist add-br $OVS_PHYSICAL_BRIDGE + _neutron_ovs_base_add_bridge $OVS_PHYSICAL_BRIDGE fi if [[ "$OVS_BRIDGE_MAPPINGS" != "" ]]; then iniset /$Q_PLUGIN_CONF_FILE ovs bridge_mappings $OVS_BRIDGE_MAPPINGS fi AGENT_BINARY="$NEUTRON_BIN_DIR/neutron-openvswitch-agent" - if [ "$VIRT_DRIVER" == 'xenserver' ]; then - # Make a copy of our config for domU - sudo cp /$Q_PLUGIN_CONF_FILE "/$Q_PLUGIN_CONF_FILE.domU" - - # Deal with Dom0's L2 Agent: - Q_RR_DOM0_COMMAND="$NEUTRON_BIN_DIR/neutron-rootwrap-xen-dom0 $Q_RR_CONF_FILE" - - # For now, duplicate the xen configuration already found in nova.conf - iniset $Q_RR_CONF_FILE xenapi xenapi_connection_url "$XENAPI_CONNECTION_URL" - iniset $Q_RR_CONF_FILE xenapi xenapi_connection_username "$XENAPI_USER" - iniset $Q_RR_CONF_FILE xenapi xenapi_connection_password "$XENAPI_PASSWORD" - - # Under XS/XCP, the ovs agent needs to target the dom0 - # integration bridge. This is enabled by using a root wrapper - # that executes commands on dom0 via a XenAPI plugin. - iniset /$Q_PLUGIN_CONF_FILE agent root_helper "$Q_RR_DOM0_COMMAND" - - # Set "physical" mapping - iniset /$Q_PLUGIN_CONF_FILE ovs bridge_mappings "physnet1:$FLAT_NETWORK_BRIDGE" - - # XEN_INTEGRATION_BRIDGE is the integration bridge in dom0 - iniset /$Q_PLUGIN_CONF_FILE ovs integration_bridge $XEN_INTEGRATION_BRIDGE - - # Set up domU's L2 agent: - - # Create a bridge "br-$GUEST_INTERFACE_DEFAULT" - sudo ovs-vsctl --no-wait -- --may-exist add-br "br-$GUEST_INTERFACE_DEFAULT" - # Add $GUEST_INTERFACE_DEFAULT to that bridge - sudo ovs-vsctl add-port "br-$GUEST_INTERFACE_DEFAULT" $GUEST_INTERFACE_DEFAULT - - # Set bridge mappings to "physnet1:br-$GUEST_INTERFACE_DEFAULT" - iniset "/$Q_PLUGIN_CONF_FILE.domU" ovs bridge_mappings "physnet1:br-$GUEST_INTERFACE_DEFAULT" - # Set integration bridge to domU's - iniset "/$Q_PLUGIN_CONF_FILE.domU" ovs integration_bridge $OVS_BRIDGE - # Set root wrap - iniset "/$Q_PLUGIN_CONF_FILE.domU" agent root_helper "$Q_RR_COMMAND" - fi iniset /$Q_PLUGIN_CONF_FILE agent tunnel_types $Q_TUNNEL_TYPES + iniset /$Q_PLUGIN_CONF_FILE ovs datapath_type $OVS_DATAPATH_TYPE } function neutron_plugin_setup_interface_driver { local conf_file=$1 - iniset $conf_file DEFAULT interface_driver neutron.agent.linux.interface.OVSInterfaceDriver + iniset $conf_file DEFAULT interface_driver openvswitch } function neutron_plugin_check_adv_test_requirements { @@ -116,4 +66,4 @@ function neutron_plugin_check_adv_test_requirements { } # Restore xtrace -$OVSA_XTRACE +$_XTRACE_NEUTRON_OVSL2 diff --git a/lib/neutron_plugins/ovs_base b/lib/neutron_plugins/ovs_base index 51999c60e4..523024e2fe 100644 --- a/lib/neutron_plugins/ovs_base +++ b/lib/neutron_plugins/ovs_base @@ -4,25 +4,34 @@ # ------------------------------------- # Save trace setting -OVSB_XTRACE=$(set +o | grep xtrace) +_XTRACE_NEUTRON_OVS_BASE=$(set +o | grep xtrace) set +o xtrace OVS_BRIDGE=${OVS_BRIDGE:-br-int} -PUBLIC_BRIDGE=${PUBLIC_BRIDGE:-br-ex} -OVS_DATAPATH_TYPE=${OVS_DATAPATH_TYPE:-""} +# OVS recognize default 'system' datapath or 'netdev' for userspace datapath +OVS_DATAPATH_TYPE=${OVS_DATAPATH_TYPE:-system} +OVS_TUNNEL_BRIDGE=${OVS_TUNNEL_BRIDGE:-br-tun} function is_neutron_ovs_base_plugin { # Yes, we use OVS. return 0 } -function _neutron_ovs_base_setup_bridge { +function _neutron_ovs_base_add_bridge { local bridge=$1 - neutron-ovs-cleanup - sudo ovs-vsctl --no-wait -- --may-exist add-br $bridge - if [[ $OVS_DATAPATH_TYPE != "" ]]; then - sudo ovs-vsctl set Bridge $bridge datapath_type=${OVS_DATAPATH_TYPE} + local addbr_cmd="sudo ovs-vsctl -- --may-exist add-br $bridge" + + if [ "$OVS_DATAPATH_TYPE" != "system" ] ; then + addbr_cmd="$addbr_cmd -- set Bridge $bridge datapath_type=${OVS_DATAPATH_TYPE}" fi + + $addbr_cmd +} + +function _neutron_ovs_base_setup_bridge { + local bridge=$1 + neutron-ovs-cleanup --config-file $NEUTRON_CONF + _neutron_ovs_base_add_bridge $bridge sudo ovs-vsctl --no-wait br-set-external-id $bridge bridge-id $bridge } @@ -33,17 +42,19 @@ function neutron_ovs_base_cleanup { done # remove all OVS bridges created by Neutron - for bridge in $(sudo ovs-vsctl list-br | grep -o -e ${OVS_BRIDGE} -e ${PUBLIC_BRIDGE}); do + for bridge in $(sudo ovs-vsctl list-br | grep -o -e ${OVS_BRIDGE} -e ${PUBLIC_BRIDGE} -e ${OVS_TUNNEL_BRIDGE}); do sudo ovs-vsctl del-br ${bridge} done } function _neutron_ovs_base_install_ubuntu_dkms { # install Dynamic Kernel Module Support packages if needed - local kernel_version=$(uname -r) - local kernel_major_minor=`echo $kernel_version | cut -d. -f1-2` + local kernel_version + kernel_version=$(uname -r) + local kernel_major_minor + kernel_major_minor=`echo $kernel_version | cut -d. -f1-2` # From kernel 3.13 on, openvswitch-datapath-dkms is not needed - if [ `vercmp_numbers "$kernel_major_minor" "3.13"` -lt "0" ]; then + if vercmp "$kernel_major_minor" "<" "3.13" ; then install_package "dkms openvswitch-datapath-dkms linux-headers-$kernel_version" fi } @@ -56,35 +67,40 @@ function _neutron_ovs_base_install_agent_packages { restart_service openvswitch-switch elif is_fedora; then restart_service openvswitch + sudo systemctl enable openvswitch elif is_suse; then - restart_service openvswitch-switch - fi -} - -function _neutron_ovs_base_configure_debug_command { - if [ "$Q_USE_PROVIDERNET_FOR_PUBLIC" = "True" ]; then - iniset $NEUTRON_TEST_CONFIG_FILE DEFAULT external_network_bridge "" - else - iniset $NEUTRON_TEST_CONFIG_FILE DEFAULT external_network_bridge $PUBLIC_BRIDGE + if [[ $DISTRO == "sle12" ]] && [[ $os_RELEASE -lt 12.2 ]]; then + restart_service openvswitch-switch + else + # workaround for https://bugzilla.suse.com/show_bug.cgi?id=1085971 + if [[ $DISTRO =~ "tumbleweed" ]]; then + sudo sed -i -e "s,^OVS_USER_ID=.*,OVS_USER_ID='root:root'," /etc/sysconfig/openvswitch + fi + restart_service openvswitch || { + journalctl -xe || : + systemctl status openvswitch + } + fi fi } function _neutron_ovs_base_configure_firewall_driver { if [[ "$Q_USE_SECGROUP" == "True" ]]; then - iniset /$Q_PLUGIN_CONF_FILE securitygroup firewall_driver neutron.agent.linux.iptables_firewall.OVSHybridIptablesFirewallDriver + iniset /$Q_PLUGIN_CONF_FILE securitygroup firewall_driver openvswitch + if ! running_in_container; then + enable_kernel_bridge_firewall + fi else - iniset /$Q_PLUGIN_CONF_FILE securitygroup firewall_driver neutron.agent.firewall.NoopFirewallDriver + iniset /$Q_PLUGIN_CONF_FILE securitygroup firewall_driver noop fi } function _neutron_ovs_base_configure_l3_agent { - if [ "$Q_USE_PROVIDERNET_FOR_PUBLIC" = "True" ]; then - iniset $Q_L3_CONF_FILE DEFAULT external_network_bridge "" - else + if [ "$Q_USE_PROVIDERNET_FOR_PUBLIC" != "True" ]; then iniset $Q_L3_CONF_FILE DEFAULT external_network_bridge $PUBLIC_BRIDGE fi - neutron-ovs-cleanup + neutron-ovs-cleanup --config-file $NEUTRON_CONF if [[ "$Q_USE_PUBLIC_VETH" = "True" ]]; then ip link show $Q_PUBLIC_VETH_INT > /dev/null 2>&1 || sudo ip link add $Q_PUBLIC_VETH_INT type veth \ @@ -93,14 +109,19 @@ function _neutron_ovs_base_configure_l3_agent { sudo ip link set $Q_PUBLIC_VETH_EX up sudo ip addr flush dev $Q_PUBLIC_VETH_EX else - sudo ovs-vsctl -- --may-exist add-br $PUBLIC_BRIDGE + _neutron_ovs_base_add_public_bridge sudo ovs-vsctl br-set-external-id $PUBLIC_BRIDGE bridge-id $PUBLIC_BRIDGE fi } +function _neutron_ovs_base_add_public_bridge { + _neutron_ovs_base_add_bridge $PUBLIC_BRIDGE + set_mtu $PUBLIC_BRIDGE $PUBLIC_BRIDGE_MTU +} + function _neutron_ovs_base_configure_nova_vif_driver { : } # Restore xtrace -$OVSB_XTRACE +$_XTRACE_NEUTRON_OVS_BASE diff --git a/lib/neutron_plugins/plumgrid b/lib/neutron_plugins/plumgrid deleted file mode 100644 index 0d711fe8b2..0000000000 --- a/lib/neutron_plugins/plumgrid +++ /dev/null @@ -1,58 +0,0 @@ -#!/bin/bash -# -# PLUMgrid Neutron Plugin -# Edgar Magana emagana@plumgrid.com -# ------------------------------------ - -# Save trace settings -PG_XTRACE=$(set +o | grep xtrace) -set +o xtrace - -function neutron_plugin_create_nova_conf { - : -} - -function neutron_plugin_setup_interface_driver { - : -} - -function neutron_plugin_configure_common { - Q_PLUGIN_CONF_PATH=etc/neutron/plugins/plumgrid - Q_PLUGIN_CONF_FILENAME=plumgrid.ini - Q_PLUGIN_CLASS="neutron.plugins.plumgrid.plumgrid_plugin.plumgrid_plugin.NeutronPluginPLUMgridV2" - PLUMGRID_DIRECTOR_IP=${PLUMGRID_DIRECTOR_IP:-localhost} - PLUMGRID_DIRECTOR_PORT=${PLUMGRID_DIRECTOR_PORT:-7766} - PLUMGRID_ADMIN=${PLUMGRID_ADMIN:-username} - PLUMGRID_PASSWORD=${PLUMGRID_PASSWORD:-password} - PLUMGRID_TIMEOUT=${PLUMGRID_TIMEOUT:-70} - PLUMGRID_DRIVER=${PLUMGRID_DRIVER:-neutron.plugins.plumgrid.drivers.fake_plumlib.Plumlib} -} - -function neutron_plugin_configure_service { - iniset /$Q_PLUGIN_CONF_FILE plumgriddirector director_server $PLUMGRID_DIRECTOR_IP - iniset /$Q_PLUGIN_CONF_FILE plumgriddirector director_server_port $PLUMGRID_DIRECTOR_PORT - iniset /$Q_PLUGIN_CONF_FILE plumgriddirector username $PLUMGRID_ADMIN - iniset /$Q_PLUGIN_CONF_FILE plumgriddirector password $PLUMGRID_PASSWORD - iniset /$Q_PLUGIN_CONF_FILE plumgriddirector servertimeout $PLUMGRID_TIMEOUT - iniset /$Q_PLUGIN_CONF_FILE plumgriddirector driver $PLUMGRID_DRIVER -} - -function neutron_plugin_configure_debug_command { - : -} - -function is_neutron_ovs_base_plugin { - # False - return 1 -} - -function has_neutron_plugin_security_group { - # return 0 means enabled - return 0 -} - -function neutron_plugin_check_adv_test_requirements { - is_service_enabled q-agt && is_service_enabled q-dhcp && return 0 -} -# Restore xtrace -$PG_XTRACE diff --git a/lib/neutron_plugins/services/firewall b/lib/neutron_plugins/services/firewall deleted file mode 100644 index 61a148e596..0000000000 --- a/lib/neutron_plugins/services/firewall +++ /dev/null @@ -1,27 +0,0 @@ -# Neutron firewall plugin -# --------------------------- - -# Save trace setting -FW_XTRACE=$(set +o | grep xtrace) -set +o xtrace - -FWAAS_PLUGIN=neutron_fwaas.services.firewall.fwaas_plugin.FirewallPlugin - -function neutron_fwaas_configure_common { - _neutron_service_plugin_class_add $FWAAS_PLUGIN -} - -function neutron_fwaas_configure_driver { - FWAAS_DRIVER_CONF_FILENAME=/etc/neutron/fwaas_driver.ini - cp $NEUTRON_FWAAS_DIR/etc/fwaas_driver.ini $FWAAS_DRIVER_CONF_FILENAME - - iniset_multiline $FWAAS_DRIVER_CONF_FILENAME fwaas enabled True - iniset_multiline $FWAAS_DRIVER_CONF_FILENAME fwaas driver "neutron_fwaas.services.firewall.drivers.linux.iptables_fwaas.IptablesFwaasDriver" -} - -function neutron_fwaas_stop { - : -} - -# Restore xtrace -$FW_XTRACE diff --git a/lib/neutron_plugins/services/l3 b/lib/neutron_plugins/services/l3 new file mode 100644 index 0000000000..ec289f6656 --- /dev/null +++ b/lib/neutron_plugins/services/l3 @@ -0,0 +1,439 @@ +#!/bin/bash +# Subnet IP version +IP_VERSION=${IP_VERSION:-"4+6"} +# Validate IP_VERSION +if [[ $IP_VERSION != "4" ]] && [[ $IP_VERSION != "6" ]] && [[ $IP_VERSION != "4+6" ]]; then + die $LINENO "IP_VERSION must be either 4, 6, or 4+6" +fi +# Specify if the initial private and external networks should be created +NEUTRON_CREATE_INITIAL_NETWORKS=${NEUTRON_CREATE_INITIAL_NETWORKS:-True} + +## Provider Network Information +PROVIDER_SUBNET_NAME=${PROVIDER_SUBNET_NAME:-"provider_net"} +IPV6_PROVIDER_SUBNET_NAME=${IPV6_PROVIDER_SUBNET_NAME:-"provider_net_v6"} +IPV6_PROVIDER_FIXED_RANGE=${IPV6_PROVIDER_FIXED_RANGE:-} +IPV6_PROVIDER_NETWORK_GATEWAY=${IPV6_PROVIDER_NETWORK_GATEWAY:-} + +PUBLIC_BRIDGE=${PUBLIC_BRIDGE:-br-ex} +PUBLIC_BRIDGE_MTU=${PUBLIC_BRIDGE_MTU:-1500} + +# If Q_ASSIGN_GATEWAY_TO_PUBLIC_BRIDGE=True, assign the gateway IP of the public +# subnet to the public bridge interface even if Q_USE_PROVIDERNET_FOR_PUBLIC is +# used. +Q_ASSIGN_GATEWAY_TO_PUBLIC_BRIDGE=${Q_ASSIGN_GATEWAY_TO_PUBLIC_BRIDGE:-True} + +# The name of the default router +Q_ROUTER_NAME=${Q_ROUTER_NAME:-router1} + +# If Q_USE_PUBLIC_VETH=True, create and use a veth pair instead of +# PUBLIC_BRIDGE. This is intended to be used with +# Q_USE_PROVIDERNET_FOR_PUBLIC=True. +Q_USE_PUBLIC_VETH=${Q_USE_PUBLIC_VETH:-False} +Q_PUBLIC_VETH_EX=${Q_PUBLIC_VETH_EX:-veth-pub-ex} +Q_PUBLIC_VETH_INT=${Q_PUBLIC_VETH_INT:-veth-pub-int} + +# The next variable is configured by plugin +# e.g. _configure_neutron_l3_agent or lib/neutron_plugins/* +# +# L3 routers exist per tenant +Q_L3_ROUTER_PER_TENANT=${Q_L3_ROUTER_PER_TENANT:-True} + + +# Use providernet for public network +# +# If Q_USE_PROVIDERNET_FOR_PUBLIC=True, use a provider network +# for external interface of neutron l3-agent. In that case, +# PUBLIC_PHYSICAL_NETWORK specifies provider:physical_network value +# used for the network. In case of ofagent, you should add the +# corresponding entry to your OFAGENT_PHYSICAL_INTERFACE_MAPPINGS. +# For openvswitch agent, you should add the corresponding entry to +# your OVS_BRIDGE_MAPPINGS. +# +# eg. (ofagent) +# Q_USE_PROVIDERNET_FOR_PUBLIC=True +# Q_USE_PUBLIC_VETH=True +# PUBLIC_PHYSICAL_NETWORK=public +# OFAGENT_PHYSICAL_INTERFACE_MAPPINGS=public:veth-pub-int +# +# eg. (openvswitch agent) +# Q_USE_PROVIDERNET_FOR_PUBLIC=True +# PUBLIC_PHYSICAL_NETWORK=public +# OVS_BRIDGE_MAPPINGS=public:br-ex +# +# The provider-network-type defaults to flat, however, the values +# PUBLIC_PROVIDERNET_TYPE and PUBLIC_PROVIDERNET_SEGMENTATION_ID could +# be set to specify the parameters for an alternate network type. +Q_USE_PROVIDERNET_FOR_PUBLIC=${Q_USE_PROVIDERNET_FOR_PUBLIC:-True} +PUBLIC_PHYSICAL_NETWORK=${PUBLIC_PHYSICAL_NETWORK:-public} + +# Generate 40-bit IPv6 Global ID to comply with RFC 4193 +IPV6_GLOBAL_ID=`uuidgen | sed s/-//g | cut -c 23- | sed -e "s/\(..\)\(....\)\(....\)/\1:\2:\3/"` + +# IPv6 gateway and subnet defaults, in case they are not customized in localrc +IPV6_RA_MODE=${IPV6_RA_MODE:-slaac} +IPV6_ADDRESS_MODE=${IPV6_ADDRESS_MODE:-slaac} +IPV6_PUBLIC_SUBNET_NAME=${IPV6_PUBLIC_SUBNET_NAME:-ipv6-public-subnet} +IPV6_PRIVATE_SUBNET_NAME=${IPV6_PRIVATE_SUBNET_NAME:-ipv6-private-subnet} +IPV6_ADDRS_SAFE_TO_USE=${IPV6_ADDRS_SAFE_TO_USE:-fd$IPV6_GLOBAL_ID::/56} +# if we got larger than a /64 safe to use, we only use the first /64 to +# avoid side effects outlined in rfc7421 +FIXED_RANGE_V6=${FIXED_RANGE_V6:-$(echo $IPV6_ADDRS_SAFE_TO_USE | awk -F '/' '{ print $1"/"($2>63 ? $2 : 64) }')} +IPV6_PRIVATE_NETWORK_GATEWAY=${IPV6_PRIVATE_NETWORK_GATEWAY:-} +IPV6_PUBLIC_RANGE=${IPV6_PUBLIC_RANGE:-2001:db8::/64} +IPV6_PUBLIC_NETWORK_GATEWAY=${IPV6_PUBLIC_NETWORK_GATEWAY:-2001:db8::2} +IPV6_ROUTER_GW_IP=${IPV6_ROUTER_GW_IP:-2001:db8::1} + +# Gateway and subnet defaults, in case they are not customized in localrc +NETWORK_GATEWAY=${NETWORK_GATEWAY:-} +PUBLIC_NETWORK_GATEWAY=${PUBLIC_NETWORK_GATEWAY:-} +PRIVATE_SUBNET_NAME=${PRIVATE_SUBNET_NAME:-"private-subnet"} +PUBLIC_SUBNET_NAME=${PUBLIC_SUBNET_NAME:-"public-subnet"} + +# Subnetpool defaults +USE_SUBNETPOOL=${USE_SUBNETPOOL:-True} +SUBNETPOOL_NAME_V4=${SUBNETPOOL_NAME:-"shared-default-subnetpool-v4"} +SUBNETPOOL_NAME_V6=${SUBNETPOOL_NAME:-"shared-default-subnetpool-v6"} + +SUBNETPOOL_PREFIX_V4=${SUBNETPOOL_PREFIX_V4:-$IPV4_ADDRS_SAFE_TO_USE} +SUBNETPOOL_PREFIX_V6=${SUBNETPOOL_PREFIX_V6:-$IPV6_ADDRS_SAFE_TO_USE} + +SUBNETPOOL_SIZE_V4=${SUBNETPOOL_SIZE_V4:-26} +SUBNETPOOL_SIZE_V6=${SUBNETPOOL_SIZE_V6:-64} + +default_v4_route_devs=$(ip -4 route | grep ^default | awk '{print $5}') +die_if_not_set $LINENO default_v4_route_devs "Failure retrieving default IPv4 route devices" + +default_v6_route_devs=$(ip -6 route list match default table all | grep via | awk '{print $5}') + +function _determine_config_l3 { + local opts="--config-file $NEUTRON_CONF --config-file $Q_L3_CONF_FILE" + echo "$opts" +} + +function _configure_neutron_l3_agent { + + cp $NEUTRON_DIR/etc/l3_agent.ini.sample $Q_L3_CONF_FILE + + iniset $Q_L3_CONF_FILE DEFAULT debug $ENABLE_DEBUG_LOG_LEVEL + iniset $Q_L3_CONF_FILE AGENT root_helper "$Q_RR_COMMAND" + if [[ "$Q_USE_ROOTWRAP_DAEMON" == "True" ]]; then + iniset $Q_L3_CONF_FILE AGENT root_helper_daemon "$Q_RR_DAEMON_COMMAND" + fi + + _neutron_setup_interface_driver $Q_L3_CONF_FILE + + neutron_plugin_configure_l3_agent $Q_L3_CONF_FILE + + # If we've given a PUBLIC_INTERFACE to take over, then we assume + # that we can own the whole thing, and privot it into the OVS + # bridge. If we are not, we're probably on a single interface + # machine, and we just setup NAT so that fixed guests can get out. + if [[ -n "$PUBLIC_INTERFACE" ]]; then + _move_neutron_addresses_route "$PUBLIC_INTERFACE" "$OVS_PHYSICAL_BRIDGE" True False "inet" + + if [[ $(ip -f inet6 a s dev "$PUBLIC_INTERFACE" | grep -c 'global') != 0 ]]; then + _move_neutron_addresses_route "$PUBLIC_INTERFACE" "$OVS_PHYSICAL_BRIDGE" False False "inet6" + fi + else + for d in $default_v4_route_devs; do + sudo iptables -t nat -A POSTROUTING -o $d -s $FLOATING_RANGE -j MASQUERADE + done + fi +} + +# Explicitly set router id in l3 agent configuration +function _neutron_set_router_id { + if [[ "$Q_L3_ROUTER_PER_TENANT" == "False" ]]; then + iniset $Q_L3_CONF_FILE DEFAULT router_id $ROUTER_ID + fi +} + +# Get ext_gw_interface depending on value of Q_USE_PUBLIC_VETH +function _neutron_get_ext_gw_interface { + if [[ "$Q_USE_PUBLIC_VETH" == "True" ]]; then + echo $Q_PUBLIC_VETH_EX + else + # Disable in-band as we are going to use local port + # to communicate with VMs + sudo ovs-vsctl set Bridge $PUBLIC_BRIDGE \ + other_config:disable-in-band=true + echo $PUBLIC_BRIDGE + fi +} + +function create_neutron_initial_network { + local project_id + project_id=$(openstack project list | grep " demo " | get_field 1) + die_if_not_set $LINENO project_id "Failure retrieving project_id for demo" + + # Allow drivers that need to create an initial network to do so here + if type -p neutron_plugin_create_initial_network_profile > /dev/null; then + neutron_plugin_create_initial_network_profile $PHYSICAL_NETWORK + fi + + if is_networking_extension_supported "auto-allocated-topology"; then + if [[ "$USE_SUBNETPOOL" == "True" ]]; then + if [[ "$IP_VERSION" =~ 4.* ]]; then + SUBNETPOOL_V4_ID=$(openstack --os-cloud devstack-admin --os-region "$REGION_NAME" subnet pool create $SUBNETPOOL_NAME_V4 --default-prefix-length $SUBNETPOOL_SIZE_V4 --pool-prefix $SUBNETPOOL_PREFIX_V4 --share --default -f value -c id) + fi + if [[ "$IP_VERSION" =~ .*6 ]]; then + SUBNETPOOL_V6_ID=$(openstack --os-cloud devstack-admin --os-region "$REGION_NAME" subnet pool create $SUBNETPOOL_NAME_V6 --default-prefix-length $SUBNETPOOL_SIZE_V6 --pool-prefix $SUBNETPOOL_PREFIX_V6 --share --default -f value -c id) + fi + fi + fi + + if is_provider_network; then + die_if_not_set $LINENO PHYSICAL_NETWORK "You must specify the PHYSICAL_NETWORK" + die_if_not_set $LINENO PROVIDER_NETWORK_TYPE "You must specify the PROVIDER_NETWORK_TYPE" + NET_ID=$(openstack --os-cloud devstack-admin --os-region "$REGION_NAME" network create $PHYSICAL_NETWORK --project $project_id --provider-network-type $PROVIDER_NETWORK_TYPE --provider-physical-network "$PHYSICAL_NETWORK" ${SEGMENTATION_ID:+--provider-segment $SEGMENTATION_ID} --share | grep ' id ' | get_field 2) + die_if_not_set $LINENO NET_ID "Failure creating NET_ID for $PHYSICAL_NETWORK $project_id" + + if [[ "$IP_VERSION" =~ 4.* ]]; then + if [ -z $SUBNETPOOL_V4_ID ]; then + fixed_range_v4=$FIXED_RANGE + fi + SUBNET_ID=$(openstack --os-cloud devstack-admin --os-region "$REGION_NAME" subnet create --project $project_id --ip-version 4 ${ALLOCATION_POOL:+--allocation-pool $ALLOCATION_POOL} $PROVIDER_SUBNET_NAME --gateway $NETWORK_GATEWAY ${SUBNETPOOL_V4_ID:+--subnet-pool $SUBNETPOOL_V4_ID} --network $NET_ID ${fixed_range_v4:+--subnet-range $fixed_range_v4} | grep ' id ' | get_field 2) + die_if_not_set $LINENO SUBNET_ID "Failure creating SUBNET_ID for $PROVIDER_SUBNET_NAME $project_id" + fi + + if [[ "$IP_VERSION" =~ .*6 ]]; then + die_if_not_set $LINENO IPV6_PROVIDER_FIXED_RANGE "IPV6_PROVIDER_FIXED_RANGE has not been set, but Q_USE_PROVIDER_NETWORKING is true and IP_VERSION includes 6" + die_if_not_set $LINENO IPV6_PROVIDER_NETWORK_GATEWAY "IPV6_PROVIDER_NETWORK_GATEWAY has not been set, but Q_USE_PROVIDER_NETWORKING is true and IP_VERSION includes 6" + if [ -z $SUBNETPOOL_V6_ID ]; then + fixed_range_v6=$IPV6_PROVIDER_FIXED_RANGE + fi + IPV6_SUBNET_ID=$(openstack --os-cloud devstack-admin --os-region "$REGION_NAME" subnet create --project $project_id --ip-version 6 --gateway $IPV6_PROVIDER_NETWORK_GATEWAY $IPV6_PROVIDER_SUBNET_NAME ${SUBNETPOOL_V6_ID:+--subnet-pool $SUBNETPOOL_V6_ID} --network $NET_ID ${fixed_range_v6:+--subnet-range $fixed_range_v6} | grep ' id ' | get_field 2) + die_if_not_set $LINENO IPV6_SUBNET_ID "Failure creating IPV6_SUBNET_ID for $IPV6_PROVIDER_SUBNET_NAME $project_id" + fi + + if [[ $Q_AGENT == "openvswitch" ]]; then + sudo ip link set $OVS_PHYSICAL_BRIDGE up + sudo ip link set br-int up + sudo ip link set $PUBLIC_INTERFACE up + fi + else + NET_ID=$(openstack --os-cloud devstack-admin --os-region "$REGION_NAME" network create --project $project_id "$PRIVATE_NETWORK_NAME" | grep ' id ' | get_field 2) + die_if_not_set $LINENO NET_ID "Failure creating NET_ID for $PRIVATE_NETWORK_NAME $project_id" + + if [[ "$IP_VERSION" =~ 4.* ]]; then + # Create IPv4 private subnet + SUBNET_ID=$(_neutron_create_private_subnet_v4 $project_id) + fi + + if [[ "$IP_VERSION" =~ .*6 ]]; then + # Create IPv6 private subnet + IPV6_SUBNET_ID=$(_neutron_create_private_subnet_v6 $project_id) + fi + fi + + if is_networking_extension_supported "router" && is_networking_extension_supported "external-net"; then + # Create a router, and add the private subnet as one of its interfaces + if [[ "$Q_L3_ROUTER_PER_TENANT" == "True" ]]; then + # create a tenant-owned router. + ROUTER_ID=$(openstack --os-cloud devstack-admin --os-region "$REGION_NAME" router create --project $project_id $Q_ROUTER_NAME | grep ' id ' | get_field 2) + die_if_not_set $LINENO ROUTER_ID "Failure creating ROUTER_ID for $project_id $Q_ROUTER_NAME" + else + # Plugin only supports creating a single router, which should be admin owned. + ROUTER_ID=$(openstack --os-cloud devstack-admin --os-region "$REGION_NAME" router create $Q_ROUTER_NAME | grep ' id ' | get_field 2) + die_if_not_set $LINENO ROUTER_ID "Failure creating ROUTER_ID for $Q_ROUTER_NAME" + fi + + EXTERNAL_NETWORK_FLAGS="--external" + if is_networking_extension_supported "auto-allocated-topology"; then + EXTERNAL_NETWORK_FLAGS="$EXTERNAL_NETWORK_FLAGS --default" + fi + # Create an external network, and a subnet. Configure the external network as router gw + if [ "$Q_USE_PROVIDERNET_FOR_PUBLIC" = "True" ]; then + EXT_NET_ID=$(openstack --os-cloud devstack-admin --os-region "$REGION_NAME" network create "$PUBLIC_NETWORK_NAME" $EXTERNAL_NETWORK_FLAGS --provider-network-type ${PUBLIC_PROVIDERNET_TYPE:-flat} ${PUBLIC_PROVIDERNET_SEGMENTATION_ID:+--provider-segment $PUBLIC_PROVIDERNET_SEGMENTATION_ID} --provider-physical-network ${PUBLIC_PHYSICAL_NETWORK} | grep ' id ' | get_field 2) + else + EXT_NET_ID=$(openstack --os-cloud devstack-admin --os-region "$REGION_NAME" network create "$PUBLIC_NETWORK_NAME" $EXTERNAL_NETWORK_FLAGS | grep ' id ' | get_field 2) + fi + die_if_not_set $LINENO EXT_NET_ID "Failure creating EXT_NET_ID for $PUBLIC_NETWORK_NAME" + + if [[ "$IP_VERSION" =~ 4.* ]]; then + # Configure router for IPv4 public access + _neutron_configure_router_v4 + fi + + if [[ "$IP_VERSION" =~ .*6 ]]; then + # Configure router for IPv6 public access + _neutron_configure_router_v6 + fi + fi +} + +# Create private IPv4 subnet +function _neutron_create_private_subnet_v4 { + local project_id=$1 + if [ -z $SUBNETPOOL_V4_ID ]; then + fixed_range_v4=$FIXED_RANGE + fi + local subnet_params="--project $project_id " + subnet_params+="--ip-version 4 " + if [[ -n "$NETWORK_GATEWAY" ]]; then + subnet_params+="--gateway $NETWORK_GATEWAY " + fi + subnet_params+="${SUBNETPOOL_V4_ID:+--subnet-pool $SUBNETPOOL_V4_ID} " + subnet_params+="${fixed_range_v4:+--subnet-range $fixed_range_v4} " + subnet_params+="--network $NET_ID $PRIVATE_SUBNET_NAME" + local subnet_id + subnet_id=$(openstack --os-cloud devstack-admin --os-region "$REGION_NAME" subnet create $subnet_params | grep ' id ' | get_field 2) + die_if_not_set $LINENO subnet_id "Failure creating private IPv4 subnet for $project_id" + echo $subnet_id +} + +# Create private IPv6 subnet +function _neutron_create_private_subnet_v6 { + local project_id=$1 + die_if_not_set $LINENO IPV6_RA_MODE "IPV6 RA Mode not set" + die_if_not_set $LINENO IPV6_ADDRESS_MODE "IPV6 Address Mode not set" + local ipv6_modes="--ipv6-ra-mode $IPV6_RA_MODE --ipv6-address-mode $IPV6_ADDRESS_MODE" + if [ -z $SUBNETPOOL_V6_ID ]; then + fixed_range_v6=$FIXED_RANGE_V6 + fi + local subnet_params="--project $project_id " + subnet_params+="--ip-version 6 " + if [[ -n "$IPV6_PRIVATE_NETWORK_GATEWAY" ]]; then + subnet_params+="--gateway $IPV6_PRIVATE_NETWORK_GATEWAY " + fi + subnet_params+="${SUBNETPOOL_V6_ID:+--subnet-pool $SUBNETPOOL_V6_ID} " + subnet_params+="${fixed_range_v6:+--subnet-range $fixed_range_v6} " + subnet_params+="$ipv6_modes --network $NET_ID $IPV6_PRIVATE_SUBNET_NAME " + local ipv6_subnet_id + ipv6_subnet_id=$(openstack --os-cloud devstack-admin --os-region "$REGION_NAME" subnet create $subnet_params | grep ' id ' | get_field 2) + die_if_not_set $LINENO ipv6_subnet_id "Failure creating private IPv6 subnet for $project_id" + echo $ipv6_subnet_id +} + +# Create public IPv4 subnet +function _neutron_create_public_subnet_v4 { + local subnet_params="--ip-version 4 " + subnet_params+="${Q_FLOATING_ALLOCATION_POOL:+--allocation-pool $Q_FLOATING_ALLOCATION_POOL} " + if [[ -n "$PUBLIC_NETWORK_GATEWAY" ]]; then + subnet_params+="--gateway $PUBLIC_NETWORK_GATEWAY " + fi + subnet_params+="--network $EXT_NET_ID --subnet-range $FLOATING_RANGE --no-dhcp " + subnet_params+="$PUBLIC_SUBNET_NAME" + local id_and_ext_gw_ip + id_and_ext_gw_ip=$(openstack --os-cloud devstack-admin --os-region "$REGION_NAME" subnet create $subnet_params | grep -e 'gateway_ip' -e ' id ') + die_if_not_set $LINENO id_and_ext_gw_ip "Failure creating public IPv4 subnet" + echo $id_and_ext_gw_ip +} + +# Create public IPv6 subnet +function _neutron_create_public_subnet_v6 { + local subnet_params="--ip-version 6 " + subnet_params+="--gateway $IPV6_PUBLIC_NETWORK_GATEWAY " + subnet_params+="--network $EXT_NET_ID --subnet-range $IPV6_PUBLIC_RANGE --no-dhcp " + subnet_params+="$IPV6_PUBLIC_SUBNET_NAME" + local ipv6_id_and_ext_gw_ip + ipv6_id_and_ext_gw_ip=$(openstack --os-cloud devstack-admin --os-region "$REGION_NAME" subnet create $subnet_params | grep -e 'gateway_ip' -e ' id ') + die_if_not_set $LINENO ipv6_id_and_ext_gw_ip "Failure creating an IPv6 public subnet" + echo $ipv6_id_and_ext_gw_ip +} + +# Configure neutron router for IPv4 public access +function _neutron_configure_router_v4 { + openstack --os-cloud devstack-admin --os-region "$REGION_NAME" router add subnet $ROUTER_ID $SUBNET_ID + # Create a public subnet on the external network + local id_and_ext_gw_ip + id_and_ext_gw_ip=$(_neutron_create_public_subnet_v4 $EXT_NET_ID) + local ext_gw_ip + ext_gw_ip=$(echo $id_and_ext_gw_ip | get_field 2) + PUB_SUBNET_ID=$(echo $id_and_ext_gw_ip | get_field 5) + # Configure the external network as the default router gateway + openstack --os-cloud devstack-admin --os-region "$REGION_NAME" router set --external-gateway $EXT_NET_ID $ROUTER_ID + + # This logic is specific to using the l3-agent for layer 3 + if is_service_enabled q-l3 || is_service_enabled neutron-l3; then + # Configure and enable public bridge + local ext_gw_interface="none" + if is_neutron_ovs_base_plugin; then + ext_gw_interface=$(_neutron_get_ext_gw_interface) + elif [[ "$Q_AGENT" = "linuxbridge" ]]; then + # Get the device the neutron router and network for $FIXED_RANGE + # will be using. + if [ "$Q_USE_PROVIDERNET_FOR_PUBLIC" = "True" ]; then + # in provider nets a bridge mapping uses the public bridge directly + ext_gw_interface=$PUBLIC_BRIDGE + else + # e.x. brq3592e767-da for NET_ID 3592e767-da66-4bcb-9bec-cdb03cd96102 + ext_gw_interface=brq${EXT_NET_ID:0:11} + fi + fi + if [[ "$ext_gw_interface" != "none" ]]; then + local cidr_len=${FLOATING_RANGE#*/} + local testcmd="ip -o link | grep -q $ext_gw_interface" + test_with_retry "$testcmd" "$ext_gw_interface creation failed" + if [[ $(ip addr show dev $ext_gw_interface | grep -c $ext_gw_ip) == 0 && ( $Q_USE_PROVIDERNET_FOR_PUBLIC == "False" || $Q_USE_PUBLIC_VETH == "True" || $Q_ASSIGN_GATEWAY_TO_PUBLIC_BRIDGE == "True" ) ]]; then + sudo ip addr add $ext_gw_ip/$cidr_len dev $ext_gw_interface + sudo ip link set $ext_gw_interface up + fi + ROUTER_GW_IP=$(openstack --os-cloud devstack-admin --os-region "$REGION_NAME" port list -c 'Fixed IP Addresses' --device-owner network:router_gateway | awk -F'ip_address' '{ print $2 }' | cut -f2 -d\' | tr '\n' ' ') + die_if_not_set $LINENO ROUTER_GW_IP "Failure retrieving ROUTER_GW_IP" + fi + _neutron_set_router_id + fi +} + +# Configure neutron router for IPv6 public access +function _neutron_configure_router_v6 { + openstack --os-cloud devstack-admin --os-region "$REGION_NAME" router add subnet $ROUTER_ID $IPV6_SUBNET_ID + # Create a public subnet on the external network + local ipv6_id_and_ext_gw_ip + ipv6_id_and_ext_gw_ip=$(_neutron_create_public_subnet_v6 $EXT_NET_ID) + local ipv6_ext_gw_ip + ipv6_ext_gw_ip=$(echo $ipv6_id_and_ext_gw_ip | get_field 2) + local ipv6_pub_subnet_id + ipv6_pub_subnet_id=$(echo $ipv6_id_and_ext_gw_ip | get_field 5) + + # If the external network has not already been set as the default router + # gateway when configuring an IPv4 public subnet, do so now + if [[ "$IP_VERSION" == "6" ]]; then + openstack --os-cloud devstack-admin --os-region "$REGION_NAME" router set --external-gateway $EXT_NET_ID $ROUTER_ID + fi + + # This logic is specific to using the l3-agent for layer 3 + if is_service_enabled q-l3 || is_service_enabled neutron-l3; then + # Ensure IPv6 forwarding is enabled on the host + sudo sysctl -w net.ipv6.conf.all.forwarding=1 + # if the Linux host considers itself to be a router then it will + # ignore all router advertisements + # Ensure IPv6 RAs are accepted on interfaces with a default route. + # This is needed for neutron-based devstack clouds to work in + # IPv6-only clouds in the gate. Please do not remove this without + # talking to folks in Infra. + for d in $default_v6_route_devs; do + # Slashes must be used in this sysctl command because route devices + # can have dots in their names. If dots were used, dots in the + # device name would be reinterpreted as a slash, causing an error. + sudo sysctl -w net/ipv6/conf/$d/accept_ra=2 + done + # Configure and enable public bridge + # Override global IPV6_ROUTER_GW_IP with the true value from neutron + IPV6_ROUTER_GW_IP=$(openstack --os-cloud devstack-admin --os-region "$REGION_NAME" port list -c 'Fixed IP Addresses' | grep $ipv6_pub_subnet_id | awk -F'ip_address' '{ print $2 }' | cut -f2 -d\' | tr '\n' ' ') + die_if_not_set $LINENO IPV6_ROUTER_GW_IP "Failure retrieving IPV6_ROUTER_GW_IP" + + if is_neutron_ovs_base_plugin; then + local ext_gw_interface + ext_gw_interface=$(_neutron_get_ext_gw_interface) + local ipv6_cidr_len=${IPV6_PUBLIC_RANGE#*/} + + # Configure interface for public bridge + sudo ip -6 addr replace $ipv6_ext_gw_ip/$ipv6_cidr_len dev $ext_gw_interface + local replace_range=${SUBNETPOOL_PREFIX_V6} + if [[ -z "${SUBNETPOOL_V6_ID}" ]]; then + replace_range=${FIXED_RANGE_V6} + fi + sudo ip -6 route replace $replace_range via $IPV6_ROUTER_GW_IP dev $ext_gw_interface + fi + _neutron_set_router_id + fi +} + +function is_networking_extension_supported { + local extension=$1 + # TODO(sc68cal) cache this instead of calling every time + EXT_LIST=$(openstack --os-cloud devstack-admin --os-region "$REGION_NAME" extension list --network -c Alias -f value) + [[ $EXT_LIST =~ $extension ]] && return 0 +} diff --git a/lib/neutron_plugins/services/loadbalancer b/lib/neutron_plugins/services/loadbalancer deleted file mode 100644 index f465cc94b4..0000000000 --- a/lib/neutron_plugins/services/loadbalancer +++ /dev/null @@ -1,49 +0,0 @@ -# Neutron loadbalancer plugin -# --------------------------- - -# Save trace setting -LB_XTRACE=$(set +o | grep xtrace) -set +o xtrace - - -AGENT_LBAAS_BINARY="$NEUTRON_BIN_DIR/neutron-lbaas-agent" -LBAAS_PLUGIN=neutron_lbaas.services.loadbalancer.plugin.LoadBalancerPlugin - -function neutron_agent_lbaas_install_agent_packages { - if is_ubuntu || is_fedora || is_suse; then - install_package haproxy - fi -} - -function neutron_agent_lbaas_configure_common { - _neutron_service_plugin_class_add $LBAAS_PLUGIN - _neutron_deploy_rootwrap_filters $NEUTRON_LBAAS_DIR -} - -function neutron_agent_lbaas_configure_agent { - LBAAS_AGENT_CONF_PATH=/etc/neutron/services/loadbalancer/haproxy - mkdir -p $LBAAS_AGENT_CONF_PATH - - LBAAS_AGENT_CONF_FILENAME="$LBAAS_AGENT_CONF_PATH/lbaas_agent.ini" - - cp $NEUTRON_LBAAS_DIR/etc/lbaas_agent.ini $LBAAS_AGENT_CONF_FILENAME - - # ovs_use_veth needs to be set before the plugin configuration - # occurs to allow plugins to override the setting. - iniset $LBAAS_AGENT_CONF_FILENAME DEFAULT ovs_use_veth $Q_OVS_USE_VETH - - neutron_plugin_setup_interface_driver $LBAAS_AGENT_CONF_FILENAME - - if is_fedora; then - iniset $LBAAS_AGENT_CONF_FILENAME DEFAULT user_group "nobody" - iniset $LBAAS_AGENT_CONF_FILENAME haproxy user_group "nobody" - fi -} - -function neutron_lbaas_stop { - pids=$(ps aux | awk '/haproxy/ { print $2 }') - [ ! -z "$pids" ] && sudo kill $pids -} - -# Restore xtrace -$LB_XTRACE diff --git a/lib/neutron_plugins/services/metering b/lib/neutron_plugins/services/metering index 37ba019b98..5b32468d21 100644 --- a/lib/neutron_plugins/services/metering +++ b/lib/neutron_plugins/services/metering @@ -1,8 +1,10 @@ +#!/bin/bash + # Neutron metering plugin # --------------------------- # Save trace setting -METER_XTRACE=$(set +o | grep xtrace) +_XTRACE_NETURON_METER=$(set +o | grep xtrace) set +o xtrace @@ -19,7 +21,7 @@ function neutron_agent_metering_configure_agent { METERING_AGENT_CONF_FILENAME="$METERING_AGENT_CONF_PATH/metering_agent.ini" - cp $NEUTRON_DIR/etc/metering_agent.ini $METERING_AGENT_CONF_FILENAME + cp $NEUTRON_DIR/etc/metering_agent.ini.sample $METERING_AGENT_CONF_FILENAME } function neutron_metering_stop { @@ -27,4 +29,5 @@ function neutron_metering_stop { } # Restore xtrace -$METER_XTRACE +$_XTRACE_NETURON_METER + diff --git a/lib/neutron_plugins/services/vpn b/lib/neutron_plugins/services/vpn deleted file mode 100644 index 4d6a2bf9a0..0000000000 --- a/lib/neutron_plugins/services/vpn +++ /dev/null @@ -1,54 +0,0 @@ -# Neutron VPN plugin -# --------------------------- - -# Save trace setting -VPN_XTRACE=$(set +o | grep xtrace) -set +o xtrace - - -AGENT_VPN_BINARY="$NEUTRON_BIN_DIR/neutron-vpn-agent" -VPN_PLUGIN=${VPN_PLUGIN:-"neutron_vpnaas.services.vpn.plugin.VPNDriverPlugin"} -IPSEC_PACKAGE=${IPSEC_PACKAGE:-"openswan"} - -function neutron_vpn_install_agent_packages { - install_package $IPSEC_PACKAGE - if is_ubuntu && [[ "$IPSEC_PACKAGE" == "strongswan" ]]; then - sudo ln -sf /etc/apparmor.d/usr.lib.ipsec.charon /etc/apparmor.d/disable/ - sudo ln -sf /etc/apparmor.d/usr.lib.ipsec.stroke /etc/apparmor.d/disable/ - # NOTE: Due to https://bugs.launchpad.net/ubuntu/+source/apparmor/+bug/1387220 - # one must use 'sudo start apparmor ACTION=reload' for Ubuntu 14.10 - restart_service apparmor - fi -} - -function neutron_vpn_configure_common { - _neutron_service_plugin_class_add $VPN_PLUGIN - _neutron_deploy_rootwrap_filters $NEUTRON_VPNAAS_DIR -} - -function neutron_vpn_configure_agent { - cp $NEUTRON_VPNAAS_DIR/etc/vpn_agent.ini $Q_VPN_CONF_FILE - if [[ "$IPSEC_PACKAGE" == "strongswan" ]]; then - iniset_multiline $Q_VPN_CONF_FILE vpnagent vpn_device_driver neutron_vpnaas.services.vpn.device_drivers.strongswan_ipsec.StrongSwanDriver - if is_fedora; then - iniset $Q_VPN_CONF_FILE strongswan default_config_area /usr/share/strongswan/templates/config/strongswan.d - fi - else - iniset_multiline $Q_VPN_CONF_FILE vpnagent vpn_device_driver neutron_vpnaas.services.vpn.device_drivers.ipsec.OpenSwanDriver - fi -} - -function neutron_vpn_stop { - local ipsec_data_dir=$DATA_DIR/neutron/ipsec - local pids - if [ -d $ipsec_data_dir ]; then - pids=$(find $ipsec_data_dir -name 'pluto.pid' -exec cat {} \;) - fi - if [ -n "$pids" ]; then - sudo kill $pids - fi - stop_process q-vpn -} - -# Restore xtrace -$VPN_XTRACE diff --git a/lib/neutron_plugins/vmware_nsx b/lib/neutron_plugins/vmware_nsx deleted file mode 100644 index b6c1c9c13f..0000000000 --- a/lib/neutron_plugins/vmware_nsx +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/bash - -# This file is needed so Q_PLUGIN=vmware_nsx will work. - -# FIXME(salv-orlando): This function should not be here, but unfortunately -# devstack calls it before the external plugins are fetched -function has_neutron_plugin_security_group { - # 0 means True here - return 0 -} diff --git a/lib/neutron_plugins/vmware_nsx_v b/lib/neutron_plugins/vmware_nsx_v deleted file mode 100644 index 3d33c652d1..0000000000 --- a/lib/neutron_plugins/vmware_nsx_v +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/bash -# -# This file is needed so Q_PLUGIN=vmware_nsx_v will work. - -# FIXME(salv-orlando): This function should not be here, but unfortunately -# devstack calls it before the external plugins are fetched -function has_neutron_plugin_security_group { - # 0 means True here - return 0 -} diff --git a/lib/neutron_thirdparty/README.md b/lib/neutron_thirdparty/README.md deleted file mode 100644 index 905ae776a8..0000000000 --- a/lib/neutron_thirdparty/README.md +++ /dev/null @@ -1,41 +0,0 @@ -Neutron third party specific files -================================== -Some Neutron plugins require third party programs to function. -The files under the directory, ``lib/neutron_thirdparty/``, will be used -when their service are enabled. -Third party program specific configuration variables should be in this file. - -* filename: ```` - * The corresponding file name should be same to service name, ````. - -functions ---------- -``lib/neutron-legacy`` calls the following functions when the ```` is enabled - -functions to be implemented -* ``configure_``: - set config files, create data dirs, etc - e.g. - sudo python setup.py deploy - iniset $XXXX_CONF... - -* ``init_``: - initialize databases, etc - -* ``install_``: - collect source and prepare - e.g. - git clone xxx - -* ``start_``: - start running processes, including screen if USE_SCREEN=True - e.g. - run_process XXXX "$XXXX_DIR/bin/XXXX-bin" - -* ``stop_``: - stop running processes (non-screen) - e.g. - stop_process XXXX - -* ``check_``: - verify that the integration between neutron server and third-party components is sane diff --git a/lib/neutron_thirdparty/bigswitch_floodlight b/lib/neutron_thirdparty/bigswitch_floodlight deleted file mode 100644 index e3f4689fd7..0000000000 --- a/lib/neutron_thirdparty/bigswitch_floodlight +++ /dev/null @@ -1,54 +0,0 @@ -#!/bin/bash -# -# Big Switch/FloodLight OpenFlow Controller -# ------------------------------------------ - -# Save trace setting -BS3_XTRACE=$(set +o | grep xtrace) -set +o xtrace - -BS_FL_CONTROLLERS_PORT=${BS_FL_CONTROLLERS_PORT:-localhost:80} -BS_FL_OF_PORT=${BS_FL_OF_PORT:-6633} - -function configure_bigswitch_floodlight { - : -} - -function init_bigswitch_floodlight { - install_neutron_agent_packages - - echo -n "Installing OVS managed by the openflow controllers:" - echo ${BS_FL_CONTROLLERS_PORT} - - # Create local OVS bridge and configure it - sudo ovs-vsctl --no-wait -- --if-exists del-br ${OVS_BRIDGE} - sudo ovs-vsctl --no-wait add-br ${OVS_BRIDGE} - sudo ovs-vsctl --no-wait br-set-external-id ${OVS_BRIDGE} bridge-id ${OVS_BRIDGE} - - ctrls= - for ctrl in `echo ${BS_FL_CONTROLLERS_PORT} | tr ',' ' '`; do - ctrl=${ctrl%:*} - ctrls="${ctrls} tcp:${ctrl}:${BS_FL_OF_PORT}" - done - echo "Adding Network conttrollers: " ${ctrls} - sudo ovs-vsctl --no-wait set-controller ${OVS_BRIDGE} ${ctrls} -} - -function install_bigswitch_floodlight { - : -} - -function start_bigswitch_floodlight { - : -} - -function stop_bigswitch_floodlight { - : -} - -function check_bigswitch_floodlight { - : -} - -# Restore xtrace -$BS3_XTRACE diff --git a/lib/neutron_thirdparty/vmware_nsx b/lib/neutron_thirdparty/vmware_nsx deleted file mode 100644 index 03853a9bf4..0000000000 --- a/lib/neutron_thirdparty/vmware_nsx +++ /dev/null @@ -1,2 +0,0 @@ -# REVISIT(roeyc): this file left empty so that 'enable_service vmware_nsx' -# continues to work. diff --git a/lib/nova b/lib/nova index 7d2145b170..d1d0b3c16b 100644 --- a/lib/nova +++ b/lib/nova @@ -7,6 +7,7 @@ # # - ``functions`` file # - ``DEST``, ``DATA_DIR``, ``STACK_USER`` must be defined +# - ``FILES`` # - ``SERVICE_{TENANT_NAME|PASSWORD}`` must be defined # - ``LIBVIRT_TYPE`` must be defined # - ``INSTANCE_NAME_PREFIX``, ``VOLUME_NAME_PREFIX`` must be defined @@ -16,7 +17,6 @@ # # - install_nova # - configure_nova -# - _config_nova_apache_wsgi # - create_nova_conf # - init_nova # - start_nova @@ -24,15 +24,15 @@ # - cleanup_nova # Save trace setting -XTRACE=$(set +o | grep xtrace) +_XTRACE_LIB_NOVA=$(set +o | grep xtrace) set +o xtrace - # Defaults # -------- # Set up default directories GITDIR["python-novaclient"]=$DEST/python-novaclient +GITDIR["os-vif"]=$DEST/os-vif NOVA_DIR=$DEST/nova # Nova virtual environment @@ -51,49 +51,61 @@ NOVA_AUTH_CACHE_DIR=${NOVA_AUTH_CACHE_DIR:-/var/cache/nova} NOVA_CONF_DIR=/etc/nova NOVA_CONF=$NOVA_CONF_DIR/nova.conf NOVA_CELLS_CONF=$NOVA_CONF_DIR/nova-cells.conf +NOVA_COND_CONF=$NOVA_CONF_DIR/nova.conf +NOVA_CPU_CONF=$NOVA_CONF_DIR/nova-cpu.conf NOVA_FAKE_CONF=$NOVA_CONF_DIR/nova-fake.conf NOVA_CELLS_DB=${NOVA_CELLS_DB:-nova_cell} +NOVA_API_DB=${NOVA_API_DB:-nova_api} +NOVA_UWSGI=$NOVA_BIN_DIR/nova-api-wsgi +NOVA_METADATA_UWSGI=$NOVA_BIN_DIR/nova-metadata-wsgi +NOVA_UWSGI_CONF=$NOVA_CONF_DIR/nova-api-uwsgi.ini +NOVA_METADATA_UWSGI_CONF=$NOVA_CONF_DIR/nova-metadata-uwsgi.ini + +# The total number of cells we expect. Must be greater than one and doesn't +# count cell0. +NOVA_NUM_CELLS=${NOVA_NUM_CELLS:-1} +# Our cell index, so we know what rabbit vhost to connect to. +# This should be in the range of 1-$NOVA_NUM_CELLS +NOVA_CPU_CELL=${NOVA_CPU_CELL:-1} NOVA_API_PASTE_INI=${NOVA_API_PASTE_INI:-$NOVA_CONF_DIR/api-paste.ini} -# NOVA_API_VERSION valid options -# - default - setup API end points as nova does out of the box -# - v21default - make v21 the default on /v2 -# -# NOTE(sdague): this is for transitional testing of the Nova v21 API. -# Expect to remove in L or M. -NOVA_API_VERSION=${NOVA_API_VERSION-default} - -if is_suse; then - NOVA_WSGI_DIR=${NOVA_WSGI_DIR:-/srv/www/htdocs/nova} -else - NOVA_WSGI_DIR=${NOVA_WSGI_DIR:-/var/www/nova} -fi -# Toggle for deploying Nova-API under HTTPD + mod_wsgi -NOVA_USE_MOD_WSGI=${NOVA_USE_MOD_WSGI:-False} +# Toggle for deploying Nova-API under a wsgi server. We default to +# true to use UWSGI, but allow False so that fall back to the +# eventlet server can happen for grenade runs. +# NOTE(cdent): We can adjust to remove the eventlet-base api service +# after pike, at which time we can stop using NOVA_USE_MOD_WSGI to +# mean "use uwsgi" because we'll be always using uwsgi. +NOVA_USE_MOD_WSGI=${NOVA_USE_MOD_WSGI:-True} -if is_ssl_enabled_service "nova" || is_service_enabled tls-proxy; then +if is_service_enabled tls-proxy; then NOVA_SERVICE_PROTOCOL="https" - EC2_SERVICE_PROTOCOL="https" -else - EC2_SERVICE_PROTOCOL="http" fi +# Whether to use TLS for comms between the VNC/SPICE/serial proxy +# services and the compute node +NOVA_CONSOLE_PROXY_COMPUTE_TLS=${NOVA_CONSOLE_PROXY_COMPUTE_TLS:-False} + # Public facing bits NOVA_SERVICE_HOST=${NOVA_SERVICE_HOST:-$SERVICE_HOST} NOVA_SERVICE_PORT=${NOVA_SERVICE_PORT:-8774} NOVA_SERVICE_PORT_INT=${NOVA_SERVICE_PORT_INT:-18774} NOVA_SERVICE_PROTOCOL=${NOVA_SERVICE_PROTOCOL:-$SERVICE_PROTOCOL} -EC2_SERVICE_PORT=${EC2_SERVICE_PORT:-8773} -EC2_SERVICE_PORT_INT=${EC2_SERVICE_PORT_INT:-18773} +NOVA_SERVICE_LOCAL_HOST=${NOVA_SERVICE_LOCAL_HOST:-$SERVICE_LOCAL_HOST} +NOVA_SERVICE_LISTEN_ADDRESS=${NOVA_SERVICE_LISTEN_ADDRESS:-$(ipv6_unquote $SERVICE_LISTEN_ADDRESS)} +METADATA_SERVICE_PORT=${METADATA_SERVICE_PORT:-8775} # Option to enable/disable config drive # NOTE: Set ``FORCE_CONFIG_DRIVE="False"`` to turn OFF config drive -FORCE_CONFIG_DRIVE=${FORCE_CONFIG_DRIVE:-"True"} +FORCE_CONFIG_DRIVE=${FORCE_CONFIG_DRIVE:-"False"} # Nova supports pluggable schedulers. The default ``FilterScheduler`` # should work in most cases. -SCHEDULER=${SCHEDULER:-nova.scheduler.filter_scheduler.FilterScheduler} +SCHEDULER=${SCHEDULER:-filter_scheduler} + +# The following FILTERS contains SameHostFilter and DifferentHostFilter with +# the default filters. +FILTERS="RetryFilter,AvailabilityZoneFilter,ComputeFilter,ComputeCapabilitiesFilter,ImagePropertiesFilter,ServerGroupAntiAffinityFilter,ServerGroupAffinityFilter,SameHostFilter,DifferentHostFilter" QEMU_CONF=/etc/libvirt/qemu.conf @@ -130,10 +142,9 @@ fi # -------------------------- NETWORK_MANAGER=${NETWORK_MANAGER:-${NET_MAN:-FlatDHCPManager}} -PUBLIC_INTERFACE=${PUBLIC_INTERFACE:-$PUBLIC_INTERFACE_DEFAULT} + VLAN_INTERFACE=${VLAN_INTERFACE:-$GUEST_INTERFACE_DEFAULT} FLAT_NETWORK_BRIDGE=${FLAT_NETWORK_BRIDGE:-$FLAT_NETWORK_BRIDGE_DEFAULT} -EC2_DMZ_HOST=${EC2_DMZ_HOST:-$SERVICE_HOST} # If you are using the FlatDHCP network mode on multiple hosts, set the # ``FLAT_INTERFACE`` variable but make sure that the interface doesn't already @@ -164,9 +175,13 @@ NOVA_ALLOW_MOVE_TO_SAME_HOST=$(trueorfalse True NOVA_ALLOW_MOVE_TO_SAME_HOST) TEST_FLOATING_POOL=${TEST_FLOATING_POOL:-test} TEST_FLOATING_RANGE=${TEST_FLOATING_RANGE:-192.168.253.0/29} -# Tell Tempest this project is present -TEMPEST_SERVICES+=,nova +# Other Nova configurations +# ---------------------------- +# ``NOVA_USE_SERVICE_TOKEN`` is a mode where service token is passed along with +# user token while communicating to external RESP API's like Neutron, Cinder +# and Glance. +NOVA_USE_SERVICE_TOKEN=$(trueorfalse False NOVA_USE_SERVICE_TOKEN) # Functions # --------- @@ -174,6 +189,7 @@ TEMPEST_SERVICES+=,nova # Test if any Nova services are enabled # is_nova_enabled function is_nova_enabled { + [[ ,${DISABLED_SERVICES} =~ ,"nova" ]] && return 1 [[ ,${ENABLED_SERVICES} =~ ,"n-" ]] && return 0 return 1 } @@ -185,6 +201,13 @@ function is_n-cell_enabled { return 1 } +# is_nova_console_proxy_compute_tls_enabled() - Test if the Nova Console Proxy +# service has TLS enabled +function is_nova_console_proxy_compute_tls_enabled { + [[ ${NOVA_CONSOLE_PROXY_COMPUTE_TLS} = "True" ]] && return 0 + return 1 +} + # Helper to clean iptables rules function clean_iptables { # Delete rules @@ -205,14 +228,19 @@ function cleanup_nova { clean_iptables # Destroy old instances - local instances=`sudo virsh list --all | grep $INSTANCE_NAME_PREFIX | sed "s/.*\($INSTANCE_NAME_PREFIX[0-9a-fA-F]*\).*/\1/g"` + local instances + instances=`sudo virsh list --all | grep $INSTANCE_NAME_PREFIX | sed "s/.*\($INSTANCE_NAME_PREFIX[0-9a-fA-F]*\).*/\1/g"` if [ ! "$instances" = "" ]; then echo $instances | xargs -n1 sudo virsh destroy || true - echo $instances | xargs -n1 sudo virsh undefine --managed-save || true + if ! xargs -n1 sudo virsh undefine --managed-save --nvram <<< $instances; then + # Can't delete with nvram flags, then just try without this flag + xargs -n1 sudo virsh undefine --managed-save <<< $instances + fi fi # Logout and delete iscsi sessions - local tgts=$(sudo iscsiadm --mode node | grep $VOLUME_NAME_PREFIX | cut -d ' ' -f2) + local tgts + tgts=$(sudo iscsiadm --mode node | grep $VOLUME_NAME_PREFIX | cut -d ' ' -f2) local target for target in $tgts; do sudo iscsiadm --mode node -T $target --logout || true @@ -231,64 +259,11 @@ function cleanup_nova { #if is_service_enabled n-cpu && [[ -r $NOVA_PLUGINS/hypervisor-$VIRT_DRIVER ]]; then # cleanup_nova_hypervisor #fi -} -# _cleanup_nova_apache_wsgi() - Remove wsgi files, disable and remove apache vhost file -function _cleanup_nova_apache_wsgi { - sudo rm -f $NOVA_WSGI_DIR/* - sudo rm -f $(apache_site_config_for nova-api) - sudo rm -f $(apache_site_config_for nova-ec2-api) -} - -# _config_nova_apache_wsgi() - Set WSGI config files of Keystone -function _config_nova_apache_wsgi { - sudo mkdir -p $NOVA_WSGI_DIR - - local nova_apache_conf=$(apache_site_config_for nova-api) - local nova_ec2_apache_conf=$(apache_site_config_for nova-ec2-api) - local nova_ssl="" - local nova_certfile="" - local nova_keyfile="" - local nova_api_port=$NOVA_SERVICE_PORT - local nova_ec2_api_port=$EC2_SERVICE_PORT - local venv_path="" - - if is_ssl_enabled_service nova-api; then - nova_ssl="SSLEngine On" - nova_certfile="SSLCertificateFile $NOVA_SSL_CERT" - nova_keyfile="SSLCertificateKeyFile $NOVA_SSL_KEY" - fi - if [[ ${USE_VENV} = True ]]; then - venv_path="python-path=${PROJECT_VENV["nova"]}/lib/$(python_version)/site-packages" - fi - - # copy proxy vhost and wsgi helper files - sudo cp $NOVA_DIR/nova/wsgi/nova-api.py $NOVA_WSGI_DIR/nova-api - sudo cp $NOVA_DIR/nova/wsgi/nova-ec2-api.py $NOVA_WSGI_DIR/nova-ec2-api - - sudo cp $FILES/apache-nova-api.template $nova_apache_conf - sudo sed -e " - s|%PUBLICPORT%|$nova_api_port|g; - s|%APACHE_NAME%|$APACHE_NAME|g; - s|%PUBLICWSGI%|$NOVA_WSGI_DIR/nova-api|g; - s|%SSLENGINE%|$nova_ssl|g; - s|%SSLCERTFILE%|$nova_certfile|g; - s|%SSLKEYFILE%|$nova_keyfile|g; - s|%USER%|$STACK_USER|g; - s|%VIRTUALENV%|$venv_path|g - " -i $nova_apache_conf - - sudo cp $FILES/apache-nova-ec2-api.template $nova_ec2_apache_conf - sudo sed -e " - s|%PUBLICPORT%|$nova_ec2_api_port|g; - s|%APACHE_NAME%|$APACHE_NAME|g; - s|%PUBLICWSGI%|$NOVA_WSGI_DIR/nova-ec2-api|g; - s|%SSLENGINE%|$nova_ssl|g; - s|%SSLCERTFILE%|$nova_certfile|g; - s|%SSLKEYFILE%|$nova_keyfile|g; - s|%USER%|$STACK_USER|g; - s|%VIRTUALENV%|$venv_path|g - " -i $nova_ec2_apache_conf + stop_process "n-api" + stop_process "n-api-meta" + remove_uwsgi_config "$NOVA_UWSGI_CONF" "$NOVA_UWSGI" + remove_uwsgi_config "$NOVA_METADATA_UWSGI_CONF" "$NOVA_METADATA_UWSGI" } # configure_nova() - Set config files, create data dirs, etc @@ -296,18 +271,11 @@ function configure_nova { # Put config files in ``/etc/nova`` for everyone to find sudo install -d -o $STACK_USER $NOVA_CONF_DIR - install_default_policy nova - - configure_rootwrap nova $NOVA_BIN_DIR/nova-rootwrap $NOVA_DIR/etc/nova + configure_rootwrap nova if [[ "$ENABLED_SERVICES" =~ "n-api" ]]; then # Get the sample configuration file in place cp $NOVA_DIR/etc/nova/api-paste.ini $NOVA_CONF_DIR - - # For testing v21 is equivalent to v2 - if [[ "$NOVA_API_VERSION" == "v21default" ]]; then - sed -i s/": openstack_compute_api_v2$"/": openstack_compute_api_v21"/ "$NOVA_API_PASTE_INI" - fi fi if is_service_enabled n-cpu; then @@ -323,7 +291,7 @@ function configure_nova { if [ ! -e /dev/kvm ]; then echo "WARNING: Switching to QEMU" LIBVIRT_TYPE=qemu - if which selinuxenabled 2>&1 > /dev/null && selinuxenabled; then + if which selinuxenabled >/dev/null 2>&1 && selinuxenabled; then # https://bugzilla.redhat.com/show_bug.cgi?id=753589 sudo setsebool virt_use_execmem on fi @@ -335,15 +303,10 @@ function configure_nova { # to simulate multiple systems. if [[ "$LIBVIRT_TYPE" == "lxc" ]]; then if is_ubuntu; then - if [[ ! "$DISTRO" > natty ]]; then - local cgline="none /cgroup cgroup cpuacct,memory,devices,cpu,freezer,blkio 0 0" - sudo mkdir -p /cgroup - if ! grep -q cgroup /etc/fstab; then - echo "$cgline" | sudo tee -a /etc/fstab - fi - if ! mount -n | grep -q cgroup; then - sudo mount /cgroup - fi + # enable nbd for lxc unless you're using an lvm backend + # otherwise you can't boot instances + if [[ "$NOVA_BACKEND" != "LVM" ]]; then + sudo modprobe nbd fi fi fi @@ -383,8 +346,8 @@ function configure_nova { # # Project User Roles # ------------------------------------------------------------------ -# SERVICE_TENANT_NAME nova admin -# SERVICE_TENANT_NAME nova ResellerAdmin (if Swift is enabled) +# SERVICE_PROJECT_NAME nova admin +# SERVICE_PROJECT_NAME nova ResellerAdmin (if Swift is enabled) function create_nova_accounts { # Nova @@ -394,24 +357,24 @@ function create_nova_accounts { # this service user when notifying nova of changes and that requires the admin role. create_service_user "nova" "admin" - if [[ "$KEYSTONE_CATALOG_BACKEND" = 'sql' ]]; then - - local nova_service=$(get_or_create_service "nova" \ - "compute" "Nova Compute Service") - get_or_create_endpoint $nova_service \ - "$REGION_NAME" \ - "$NOVA_SERVICE_PROTOCOL://$NOVA_SERVICE_HOST:$NOVA_SERVICE_PORT/v2/\$(tenant_id)s" \ - "$NOVA_SERVICE_PROTOCOL://$NOVA_SERVICE_HOST:$NOVA_SERVICE_PORT/v2/\$(tenant_id)s" \ - "$NOVA_SERVICE_PROTOCOL://$NOVA_SERVICE_HOST:$NOVA_SERVICE_PORT/v2/\$(tenant_id)s" - - local nova_v21_service=$(get_or_create_service "novav21" \ - "computev21" "Nova Compute Service V2.1") - get_or_create_endpoint $nova_v21_service \ - "$REGION_NAME" \ - "$NOVA_SERVICE_PROTOCOL://$NOVA_SERVICE_HOST:$NOVA_SERVICE_PORT/v2.1/\$(tenant_id)s" \ - "$NOVA_SERVICE_PROTOCOL://$NOVA_SERVICE_HOST:$NOVA_SERVICE_PORT/v2.1/\$(tenant_id)s" \ - "$NOVA_SERVICE_PROTOCOL://$NOVA_SERVICE_HOST:$NOVA_SERVICE_PORT/v2.1/\$(tenant_id)s" + local nova_api_url + if [[ "$NOVA_USE_MOD_WSGI" == "False" ]]; then + nova_api_url="$NOVA_SERVICE_PROTOCOL://$NOVA_SERVICE_HOST:$NOVA_SERVICE_PORT" + else + nova_api_url="$NOVA_SERVICE_PROTOCOL://$NOVA_SERVICE_HOST/compute" fi + + get_or_create_service "nova_legacy" "compute_legacy" "Nova Compute Service (Legacy 2.0)" + get_or_create_endpoint \ + "compute_legacy" \ + "$REGION_NAME" \ + "$nova_api_url/v2/\$(project_id)s" + + get_or_create_service "nova" "compute" "Nova Compute Service" + get_or_create_endpoint \ + "compute" \ + "$REGION_NAME" \ + "$nova_api_url/v2.1" fi if is_service_enabled n-api; then @@ -419,33 +382,19 @@ function create_nova_accounts { if is_service_enabled swift; then # Nova needs ResellerAdmin role to download images when accessing # swift through the s3 api. - get_or_add_user_project_role ResellerAdmin nova $SERVICE_TENANT_NAME - fi - - # EC2 - if [[ "$KEYSTONE_CATALOG_BACKEND" = "sql" ]]; then - - local ec2_service=$(get_or_create_service "ec2" \ - "ec2" "EC2 Compatibility Layer") - get_or_create_endpoint $ec2_service \ - "$REGION_NAME" \ - "$EC2_SERVICE_PROTOCOL://$SERVICE_HOST:8773/" \ - "$EC2_SERVICE_PROTOCOL://$SERVICE_HOST:8773/" \ - "$EC2_SERVICE_PROTOCOL://$SERVICE_HOST:8773/" + get_or_add_user_project_role ResellerAdmin nova $SERVICE_PROJECT_NAME $SERVICE_DOMAIN_NAME $SERVICE_DOMAIN_NAME fi fi # S3 - if is_service_enabled n-obj swift3; then - if [[ "$KEYSTONE_CATALOG_BACKEND" = 'sql' ]]; then - - local s3_service=$(get_or_create_service "s3" "s3" "S3") - get_or_create_endpoint $s3_service \ - "$REGION_NAME" \ - "http://$SERVICE_HOST:$S3_SERVICE_PORT" \ - "http://$SERVICE_HOST:$S3_SERVICE_PORT" \ - "http://$SERVICE_HOST:$S3_SERVICE_PORT" - fi + if is_service_enabled swift3; then + get_or_create_service "s3" "s3" "S3" + get_or_create_endpoint \ + "s3" \ + "$REGION_NAME" \ + "http://$SERVICE_HOST:$S3_SERVICE_PORT" \ + "http://$SERVICE_HOST:$S3_SERVICE_PORT" \ + "http://$SERVICE_HOST:$S3_SERVICE_PORT" fi } @@ -456,23 +405,29 @@ function create_nova_conf { # (Re)create ``nova.conf`` rm -f $NOVA_CONF - iniset $NOVA_CONF DEFAULT verbose "True" iniset $NOVA_CONF DEFAULT debug "$ENABLE_DEBUG_LOG_LEVEL" if [ "$NOVA_ALLOW_MOVE_TO_SAME_HOST" == "True" ]; then iniset $NOVA_CONF DEFAULT allow_resize_to_same_host "True" fi - iniset $NOVA_CONF DEFAULT api_paste_config "$NOVA_API_PASTE_INI" + iniset $NOVA_CONF wsgi api_paste_config "$NOVA_API_PASTE_INI" iniset $NOVA_CONF DEFAULT rootwrap_config "$NOVA_CONF_DIR/rootwrap.conf" - iniset $NOVA_CONF DEFAULT scheduler_driver "$SCHEDULER" - iniset $NOVA_CONF DEFAULT dhcpbridge_flagfile "$NOVA_CONF" - iniset $NOVA_CONF DEFAULT force_dhcp_release "True" + iniset $NOVA_CONF scheduler driver "$SCHEDULER" + iniset $NOVA_CONF filter_scheduler enabled_filters "$FILTERS" + if [[ $SCHEDULER == "filter_scheduler" ]]; then + iniset $NOVA_CONF scheduler workers "$API_WORKERS" + fi iniset $NOVA_CONF DEFAULT default_floating_pool "$PUBLIC_NETWORK_NAME" - iniset $NOVA_CONF DEFAULT s3_host "$SERVICE_HOST" - iniset $NOVA_CONF DEFAULT s3_port "$S3_SERVICE_PORT" - iniset $NOVA_CONF DEFAULT my_ip "$HOST_IP" - iniset $NOVA_CONF database connection `database_connection_url nova` + if [[ $SERVICE_IP_VERSION == 6 ]]; then + iniset $NOVA_CONF DEFAULT my_ip "$HOST_IPV6" + iniset $NOVA_CONF DEFAULT use_ipv6 "True" + else + iniset $NOVA_CONF DEFAULT my_ip "$HOST_IP" + fi iniset $NOVA_CONF DEFAULT instance_name_template "${INSTANCE_NAME_PREFIX}%08x" - iniset $NOVA_CONF osapi_v3 enabled "True" + iniset $NOVA_CONF DEFAULT osapi_compute_listen "$NOVA_SERVICE_LISTEN_ADDRESS" + iniset $NOVA_CONF DEFAULT metadata_listen "$NOVA_SERVICE_LISTEN_ADDRESS" + + iniset $NOVA_CONF key_manager backend nova.keymgr.conf_key_mgr.ConfKeyManager if is_fedora || is_suse; then # nova defaults to /usr/local/bin, but fedora and suse pip like to @@ -480,22 +435,43 @@ function create_nova_conf { iniset $NOVA_CONF DEFAULT bindir "/usr/bin" fi + # only setup database connections if there are services that + # require them running on the host. The ensures that n-cpu doesn't + # leak a need to use the db in a multinode scenario. + if is_service_enabled n-api n-cond n-sched; then + # If we're in multi-tier cells mode, we want our control services pointing + # at cell0 instead of cell1 to ensure isolation. If not, we point everything + # at the main database like normal. + if [[ "$CELLSV2_SETUP" == "singleconductor" ]]; then + local db="nova_cell1" + else + local db="nova_cell0" + # When in superconductor mode, nova-compute can't send instance + # info updates to the scheduler, so just disable it. + iniset $NOVA_CONF filter_scheduler track_instance_changes False + fi + + iniset $NOVA_CONF database connection `database_connection_url $db` + iniset $NOVA_CONF api_database connection `database_connection_url nova_api` + fi + if is_service_enabled n-api; then if is_service_enabled n-api-meta; then # If running n-api-meta as a separate service NOVA_ENABLED_APIS=$(echo $NOVA_ENABLED_APIS | sed "s/,metadata//") fi iniset $NOVA_CONF DEFAULT enabled_apis "$NOVA_ENABLED_APIS" - if is_service_enabled tls-proxy; then + if is_service_enabled tls-proxy && [ "$NOVA_USE_MOD_WSGI" == "False" ]; then # Set the service port for a proxy to take the original iniset $NOVA_CONF DEFAULT osapi_compute_listen_port "$NOVA_SERVICE_PORT_INT" + iniset $NOVA_CONF DEFAULT osapi_compute_link_prefix $NOVA_SERVICE_PROTOCOL://$NOVA_SERVICE_HOST:$NOVA_SERVICE_PORT fi configure_auth_token_middleware $NOVA_CONF nova $NOVA_AUTH_CACHE_DIR fi if is_service_enabled cinder; then - if is_ssl_enabled_service "cinder" || is_service_enabled tls-proxy; then + if is_service_enabled tls-proxy; then CINDER_SERVICE_HOST=${CINDER_SERVICE_HOST:-$SERVICE_HOST} CINDER_SERVICE_PORT=${CINDER_SERVICE_PORT:-8776} iniset $NOVA_CONF cinder cafile $SSL_BUNDLE_FILE @@ -519,103 +495,198 @@ function create_nova_conf { if [ "$FORCE_CONFIG_DRIVE" != "False" ]; then iniset $NOVA_CONF DEFAULT force_config_drive "$FORCE_CONFIG_DRIVE" fi - # Format logging - if [ "$LOG_COLOR" == "True" ] && [ "$SYSLOG" == "False" ] && [ "$NOVA_USE_MOD_WSGI" == "False" ] ; then - setup_colorized_logging $NOVA_CONF DEFAULT - else - # Show user_name and project_name instead of user_id and project_id - iniset $NOVA_CONF DEFAULT logging_context_format_string "%(asctime)s.%(msecs)03d %(levelname)s %(name)s [%(request_id)s %(user_name)s %(project_name)s] %(instance)s%(message)s" - fi - if [ "$NOVA_USE_MOD_WSGI" == "True" ]; then - _config_nova_apache_wsgi + + # nova defaults to genisoimage but only mkisofs is available for 15.0+ + if is_suse; then + iniset $NOVA_CONF DEFAULT mkisofs_cmd /usr/bin/mkisofs fi + # Format logging + setup_logging $NOVA_CONF + + iniset $NOVA_CONF upgrade_levels compute "auto" + + write_uwsgi_config "$NOVA_UWSGI_CONF" "$NOVA_UWSGI" "/compute" + write_uwsgi_config "$NOVA_METADATA_UWSGI_CONF" "$NOVA_METADATA_UWSGI" "" "$SERVICE_LISTEN_ADDRESS:${METADATA_SERVICE_PORT}" + if is_service_enabled ceilometer; then iniset $NOVA_CONF DEFAULT instance_usage_audit "True" iniset $NOVA_CONF DEFAULT instance_usage_audit_period "hour" iniset $NOVA_CONF DEFAULT notify_on_state_change "vm_and_task_state" - iniset $NOVA_CONF DEFAULT notification_driver "messaging" fi + # Set the oslo messaging driver to the typical default. This does not + # enable notifications, but it will allow them to function when enabled. + iniset $NOVA_CONF oslo_messaging_notifications driver "messagingv2" + iniset $NOVA_CONF oslo_messaging_notifications transport_url $(get_notification_url) + iniset_rpc_backend nova $NOVA_CONF + + iniset $NOVA_CONF DEFAULT osapi_compute_workers "$API_WORKERS" + iniset $NOVA_CONF DEFAULT metadata_workers "$API_WORKERS" + # don't let the conductor get out of control now that we're using a pure python db driver + iniset $NOVA_CONF conductor workers "$API_WORKERS" + + iniset $NOVA_CONF cinder os_region_name "$REGION_NAME" + + if is_service_enabled tls-proxy; then + iniset $NOVA_CONF DEFAULT glance_protocol https + iniset $NOVA_CONF oslo_middleware enable_proxy_headers_parsing True + fi + + iniset $NOVA_CONF DEFAULT graceful_shutdown_timeout "$SERVICE_GRACEFUL_SHUTDOWN_TIMEOUT" + + # Setup logging for nova-dhcpbridge command line + sudo cp "$NOVA_CONF" "$NOVA_CONF_DIR/nova-dhcpbridge.conf" + + if is_service_enabled n-net; then + local service="n-dhcp" + local logfile="${service}.log.${CURRENT_LOG_TIME}" + local real_logfile="${LOGDIR}/${logfile}" + if [[ -n ${LOGDIR} ]]; then + bash -c "cd '$LOGDIR' && ln -sf '$logfile' ${service}.log" + iniset "$NOVA_CONF_DIR/nova-dhcpbridge.conf" DEFAULT log_file "$real_logfile" + fi + + iniset $NOVA_CONF DEFAULT dhcpbridge_flagfile "$NOVA_CONF_DIR/nova-dhcpbridge.conf" + fi + + if [ "$NOVA_USE_SERVICE_TOKEN" == "True" ]; then + init_nova_service_user_conf + fi + + if is_service_enabled n-cond; then + for i in $(seq 1 $NOVA_NUM_CELLS); do + local conf + local vhost + conf=$(conductor_conf $i) + vhost="nova_cell${i}" + # clean old conductor conf + rm -f $conf + iniset $conf database connection `database_connection_url nova_cell${i}` + iniset $conf conductor workers "$API_WORKERS" + iniset $conf DEFAULT debug "$ENABLE_DEBUG_LOG_LEVEL" + # if we have a singleconductor, we don't have per host message queues. + if [[ "${CELLSV2_SETUP}" == "singleconductor" ]]; then + iniset_rpc_backend nova $conf DEFAULT + else + rpc_backend_add_vhost $vhost + iniset_rpc_backend nova $conf DEFAULT $vhost + # When running in superconductor mode, the cell conductor + # must be configured to talk to the placement service for + # reschedules to work. + if is_service_enabled placement placement-client; then + configure_placement_nova_compute $conf + fi + fi + # Format logging + setup_logging $conf + done + fi + + # Console proxy configuration has to go after conductor configuration + # because the per cell config file nova_cellN.conf is cleared out as part + # of conductor configuration. + if [[ "${CELLSV2_SETUP}" == "singleconductor" ]]; then + configure_console_proxies + else + for i in $(seq 1 $NOVA_NUM_CELLS); do + local conf + conf=$(conductor_conf $i) + configure_console_proxies $conf + done + fi +} + +function configure_console_compute { # All nova-compute workers need to know the vnc configuration options # These settings don't hurt anything if n-xvnc and n-novnc are disabled if is_service_enabled n-cpu; then NOVNCPROXY_URL=${NOVNCPROXY_URL:-"http://$SERVICE_HOST:6080/vnc_auto.html"} - iniset $NOVA_CONF DEFAULT novncproxy_base_url "$NOVNCPROXY_URL" + iniset $NOVA_CPU_CONF vnc novncproxy_base_url "$NOVNCPROXY_URL" XVPVNCPROXY_URL=${XVPVNCPROXY_URL:-"http://$SERVICE_HOST:6081/console"} - iniset $NOVA_CONF DEFAULT xvpvncproxy_base_url "$XVPVNCPROXY_URL" + iniset $NOVA_CPU_CONF vnc xvpvncproxy_base_url "$XVPVNCPROXY_URL" SPICEHTML5PROXY_URL=${SPICEHTML5PROXY_URL:-"http://$SERVICE_HOST:6082/spice_auto.html"} - iniset $NOVA_CONF spice html5proxy_base_url "$SPICEHTML5PROXY_URL" + iniset $NOVA_CPU_CONF spice html5proxy_base_url "$SPICEHTML5PROXY_URL" fi if is_service_enabled n-novnc || is_service_enabled n-xvnc || [ "$NOVA_VNC_ENABLED" != False ]; then # Address on which instance vncservers will listen on compute hosts. # For multi-host, this should be the management ip of the compute host. - VNCSERVER_LISTEN=${VNCSERVER_LISTEN=127.0.0.1} - VNCSERVER_PROXYCLIENT_ADDRESS=${VNCSERVER_PROXYCLIENT_ADDRESS=127.0.0.1} - iniset $NOVA_CONF DEFAULT vnc_enabled true - iniset $NOVA_CONF DEFAULT vncserver_listen "$VNCSERVER_LISTEN" - iniset $NOVA_CONF DEFAULT vncserver_proxyclient_address "$VNCSERVER_PROXYCLIENT_ADDRESS" + VNCSERVER_LISTEN=${VNCSERVER_LISTEN=$NOVA_SERVICE_LOCAL_HOST} + VNCSERVER_PROXYCLIENT_ADDRESS=${VNCSERVER_PROXYCLIENT_ADDRESS=$NOVA_SERVICE_LOCAL_HOST} + iniset $NOVA_CPU_CONF vnc server_listen "$VNCSERVER_LISTEN" + iniset $NOVA_CPU_CONF vnc server_proxyclient_address "$VNCSERVER_PROXYCLIENT_ADDRESS" else - iniset $NOVA_CONF DEFAULT vnc_enabled false + iniset $NOVA_CPU_CONF vnc enabled false fi if is_service_enabled n-spice; then # Address on which instance spiceservers will listen on compute hosts. # For multi-host, this should be the management ip of the compute host. - SPICESERVER_PROXYCLIENT_ADDRESS=${SPICESERVER_PROXYCLIENT_ADDRESS=127.0.0.1} - SPICESERVER_LISTEN=${SPICESERVER_LISTEN=127.0.0.1} - iniset $NOVA_CONF spice enabled true - iniset $NOVA_CONF spice server_listen "$SPICESERVER_LISTEN" - iniset $NOVA_CONF spice server_proxyclient_address "$SPICESERVER_PROXYCLIENT_ADDRESS" - else - iniset $NOVA_CONF spice enabled false + SPICESERVER_PROXYCLIENT_ADDRESS=${SPICESERVER_PROXYCLIENT_ADDRESS=$NOVA_SERVICE_LOCAL_HOST} + SPICESERVER_LISTEN=${SPICESERVER_LISTEN=$NOVA_SERVICE_LOCAL_HOST} + iniset $NOVA_CPU_CONF spice enabled true + iniset $NOVA_CPU_CONF spice server_listen "$SPICESERVER_LISTEN" + iniset $NOVA_CPU_CONF spice server_proxyclient_address "$SPICESERVER_PROXYCLIENT_ADDRESS" fi - iniset $NOVA_CONF DEFAULT ec2_dmz_host "$EC2_DMZ_HOST" - iniset $NOVA_CONF DEFAULT keystone_ec2_url $KEYSTONE_SERVICE_PROTOCOL://$KEYSTONE_SERVICE_HOST:$KEYSTONE_SERVICE_PORT/v2.0/ec2tokens - iniset_rpc_backend nova $NOVA_CONF - iniset $NOVA_CONF glance api_servers "${GLANCE_SERVICE_PROTOCOL}://${GLANCE_HOSTPORT}" - - iniset $NOVA_CONF DEFAULT osapi_compute_workers "$API_WORKERS" - iniset $NOVA_CONF DEFAULT ec2_workers "$API_WORKERS" - iniset $NOVA_CONF DEFAULT metadata_workers "$API_WORKERS" - - iniset $NOVA_CONF cinder os_region_name "$REGION_NAME" - - if [[ "$NOVA_BACKEND" == "LVM" ]]; then - iniset $NOVA_CONF libvirt images_type "lvm" - iniset $NOVA_CONF libvirt images_volume_group $DEFAULT_VOLUME_GROUP_NAME - fi - - if is_ssl_enabled_service glance || is_service_enabled tls-proxy; then - iniset $NOVA_CONF DEFAULT glance_protocol https + if is_service_enabled n-sproxy; then + iniset $NOVA_CPU_CONF serial_console enabled True fi +} - # Register SSL certificates if provided - if is_ssl_enabled_service nova; then - ensure_certificates NOVA - - iniset $NOVA_CONF DEFAULT ssl_cert_file "$NOVA_SSL_CERT" - iniset $NOVA_CONF DEFAULT ssl_key_file "$NOVA_SSL_KEY" +function configure_console_proxies { + # Use the provided config file path or default to $NOVA_CONF. + local conf=${1:-$NOVA_CONF} - iniset $NOVA_CONF DEFAULT enabled_ssl_apis "$NOVA_ENABLED_APIS" + if is_service_enabled n-novnc || is_service_enabled n-xvnc || [ "$NOVA_VNC_ENABLED" != False ]; then + iniset $conf vnc novncproxy_host "$NOVA_SERVICE_LISTEN_ADDRESS" + iniset $conf vnc xvpvncproxy_host "$NOVA_SERVICE_LISTEN_ADDRESS" + + if is_nova_console_proxy_compute_tls_enabled ; then + iniset $conf vnc auth_schemes "vencrypt" + iniset $conf vnc vencrypt_client_key "/etc/pki/nova-novnc/client-key.pem" + iniset $conf vnc vencrypt_client_cert "/etc/pki/nova-novnc/client-cert.pem" + iniset $conf vnc vencrypt_ca_certs "/etc/pki/nova-novnc/ca-cert.pem" + + sudo mkdir -p /etc/pki/nova-novnc + deploy_int_CA /etc/pki/nova-novnc/ca-cert.pem + deploy_int_cert /etc/pki/nova-novnc/client-cert.pem /etc/pki/nova-novnc/client-key.pem + fi fi - if is_service_enabled tls-proxy; then - iniset $NOVA_CONF DEFAULT ec2_listen_port $EC2_SERVICE_PORT_INT + if is_service_enabled n-spice; then + iniset $conf spice html5proxy_host "$NOVA_SERVICE_LISTEN_ADDRESS" fi if is_service_enabled n-sproxy; then - iniset $NOVA_CONF serial_console enabled True + iniset $conf serial_console serialproxy_host "$NOVA_SERVICE_LISTEN_ADDRESS" fi } +function init_nova_service_user_conf { + iniset $NOVA_CONF service_user send_service_user_token True + iniset $NOVA_CONF service_user auth_type password + iniset $NOVA_CONF service_user auth_url "$KEYSTONE_SERVICE_URI" + iniset $NOVA_CONF service_user username nova + iniset $NOVA_CONF service_user password "$SERVICE_PASSWORD" + iniset $NOVA_CONF service_user user_domain_name "$SERVICE_DOMAIN_NAME" + iniset $NOVA_CONF service_user project_name "$SERVICE_PROJECT_NAME" + iniset $NOVA_CONF service_user project_domain_name "$SERVICE_DOMAIN_NAME" + iniset $NOVA_CONF service_user auth_strategy keystone +} + +function conductor_conf { + local cell="$1" + echo "${NOVA_CONF_DIR}/nova_cell${cell}.conf" +} + function init_nova_cells { if is_service_enabled n-cell; then cp $NOVA_CONF $NOVA_CELLS_CONF iniset $NOVA_CELLS_CONF database connection `database_connection_url $NOVA_CELLS_DB` - iniset $NOVA_CELLS_CONF DEFAULT rabbit_virtual_host child_cell + rpc_backend_add_vhost child_cell + iniset_rpc_backend nova $NOVA_CELLS_CONF DEFAULT child_cell iniset $NOVA_CELLS_CONF DEFAULT dhcpbridge_flagfile $NOVA_CELLS_CONF iniset $NOVA_CELLS_CONF cells enable True iniset $NOVA_CELLS_CONF cells cell_type compute @@ -631,9 +702,18 @@ function init_nova_cells { iniset $NOVA_CELLS_CONF DEFAULT enabled_apis metadata fi + # Cells v1 conductor should be the nova-cells.conf + NOVA_COND_CONF=$NOVA_CELLS_CONF + + time_start "dbsync" $NOVA_BIN_DIR/nova-manage --config-file $NOVA_CELLS_CONF db sync + time_stop "dbsync" $NOVA_BIN_DIR/nova-manage --config-file $NOVA_CELLS_CONF cell create --name=region --cell_type=parent --username=$RABBIT_USERID --hostname=$RABBIT_HOST --port=5672 --password=$RABBIT_PASSWORD --virtual_host=/ --woffset=0 --wscale=1 $NOVA_BIN_DIR/nova-manage cell create --name=child --cell_type=child --username=$RABBIT_USERID --hostname=$RABBIT_HOST --port=5672 --password=$RABBIT_PASSWORD --virtual_host=child_cell --woffset=0 --wscale=1 + + # Creates the single cells v2 cell for the child cell (v1) nova db. + $NOVA_BIN_DIR/nova-manage --config-file $NOVA_CELLS_CONF cell_v2 create_cell \ + --transport-url $(get_transport_url child_cell) --name 'cell1' fi } @@ -645,13 +725,15 @@ function create_nova_cache_dir { } function create_nova_conf_nova_network { + local public_interface=${PUBLIC_INTERFACE:-$PUBLIC_INTERFACE_DEFAULT} iniset $NOVA_CONF DEFAULT network_manager "nova.network.manager.$NETWORK_MANAGER" - iniset $NOVA_CONF DEFAULT public_interface "$PUBLIC_INTERFACE" + iniset $NOVA_CONF DEFAULT public_interface "$public_interface" iniset $NOVA_CONF DEFAULT vlan_interface "$VLAN_INTERFACE" iniset $NOVA_CONF DEFAULT flat_network_bridge "$FLAT_NETWORK_BRIDGE" if [ -n "$FLAT_INTERFACE" ]; then iniset $NOVA_CONF DEFAULT flat_interface "$FLAT_INTERFACE" fi + iniset $NOVA_CONF DEFAULT use_neutron False } # create_nova_keys_dir() - Part of the init_nova() process @@ -665,15 +747,38 @@ function init_nova { # All nova components talk to a central database. # Only do this step once on the API node for an entire cluster. if is_service_enabled $DATABASE_BACKENDS && is_service_enabled n-api; then - # (Re)create nova database - recreate_database nova + recreate_database $NOVA_API_DB + $NOVA_BIN_DIR/nova-manage --config-file $NOVA_CONF api_db sync + + recreate_database nova_cell0 - # Migrate nova database - $NOVA_BIN_DIR/nova-manage db sync + # map_cell0 will create the cell mapping record in the nova_api DB so + # this needs to come after the api_db sync happens. We also want to run + # this before the db sync below since that will migrate both the nova + # and nova_cell0 databases. + $NOVA_BIN_DIR/nova-manage cell_v2 map_cell0 --database_connection `database_connection_url nova_cell0` + + # (Re)create nova databases + for i in $(seq 1 $NOVA_NUM_CELLS); do + recreate_database nova_cell${i} + $NOVA_BIN_DIR/nova-manage --config-file $(conductor_conf $i) db sync --local_cell + done + + # Migrate nova and nova_cell0 databases. + $NOVA_BIN_DIR/nova-manage --config-file $NOVA_CONF db sync if is_service_enabled n-cell; then recreate_database $NOVA_CELLS_DB fi + + # Run online migrations on the new databases + # Needed for flavor conversion + $NOVA_BIN_DIR/nova-manage --config-file $NOVA_CONF db online_data_migrations + + # create the cell1 cell for the main nova db where the hosts live + for i in $(seq 1 $NOVA_NUM_CELLS); do + $NOVA_BIN_DIR/nova-manage --config-file $NOVA_CONF --config-file $(conductor_conf $i) cell_v2 create_cell --name "cell$i" + done fi create_nova_cache_dir @@ -695,6 +800,13 @@ function install_novaclient { # install_nova() - Collect source and prepare function install_nova { + + # Install os-vif + if use_library_from_git "os-vif"; then + git_clone_by_name "os-vif" + setup_dev_lib "os-vif" + fi + if is_service_enabled n-cpu && [[ -r $NOVA_PLUGINS/hypervisor-$VIRT_DRIVER ]]; then install_nova_hypervisor fi @@ -726,13 +838,6 @@ function install_nova { git_clone $NOVA_REPO $NOVA_DIR $NOVA_BRANCH setup_develop $NOVA_DIR sudo install -D -m 0644 -o $STACK_USER {$NOVA_DIR/tools/,/etc/bash_completion.d/}nova-manage.bash_completion - - if [ "$NOVA_USE_MOD_WSGI" == "True" ]; then - install_apache_wsgi - if is_ssl_enabled_service "nova-api"; then - enable_mod_ssl - fi - fi } # start_nova_api() - Start the API process ahead of other things @@ -740,6 +845,7 @@ function start_nova_api { # Get right service port for testing local service_port=$NOVA_SERVICE_PORT local service_protocol=$NOVA_SERVICE_PROTOCOL + local nova_url if is_service_enabled tls-proxy; then service_port=$NOVA_SERVICE_PORT_INT service_protocol="http" @@ -749,32 +855,36 @@ function start_nova_api { local old_path=$PATH export PATH=$NOVA_BIN_DIR:$PATH - # If the site is not enabled then we are in a grenade scenario - local enabled_site_file=$(apache_site_config_for nova-api) - if [ -f ${enabled_site_file} ] && [ "$NOVA_USE_MOD_WSGI" == "True" ]; then - enable_apache_site nova-api - enable_apache_site nova-ec2-api - restart_apache_server - tail_log nova /var/log/$APACHE_NAME/nova-api.log - tail_log nova /var/log/$APACHE_NAME/nova-ec2-api.log - else + if [ "$NOVA_USE_MOD_WSGI" == "False" ]; then run_process n-api "$NOVA_BIN_DIR/nova-api" + nova_url=$service_protocol://$SERVICE_HOST:$service_port + # Start proxy if tsl enabled + if is_service_enabled tls-proxy; then + start_tls_proxy nova '*' $NOVA_SERVICE_PORT $NOVA_SERVICE_HOST $NOVA_SERVICE_PORT_INT + fi + else + run_process "n-api" "$NOVA_BIN_DIR/uwsgi --procname-prefix nova-api --ini $NOVA_UWSGI_CONF" + nova_url=$service_protocol://$SERVICE_HOST/compute/v2.1/ fi echo "Waiting for nova-api to start..." - if ! wait_for_service $SERVICE_TIMEOUT $service_protocol://$SERVICE_HOST:$service_port; then + if ! wait_for_service $SERVICE_TIMEOUT $nova_url; then die $LINENO "nova-api did not start" fi - # Start proxies if enabled - if is_service_enabled tls-proxy; then - start_tls_proxy '*' $NOVA_SERVICE_PORT $NOVA_SERVICE_HOST $NOVA_SERVICE_PORT_INT & - start_tls_proxy '*' $EC2_SERVICE_PORT $NOVA_SERVICE_HOST $EC2_SERVICE_PORT_INT & - fi - export PATH=$old_path } +# Detect and setup conditions under which singleconductor setup is +# needed. Notably cellsv1. +function _set_singleconductor { + # NOTE(danms): Don't setup conductor fleet for cellsv1 + if is_service_enabled n-cell; then + CELLSV2_SETUP="singleconductor" + fi +} + + # start_nova_compute() - Start the compute process function start_nova_compute { # Hack to set the path for rootwrap @@ -787,11 +897,39 @@ function start_nova_compute { local compute_cell_conf=$NOVA_CONF fi + if [[ "${CELLSV2_SETUP}" == "singleconductor" ]]; then + # NOTE(danms): Grenade doesn't setup multi-cell rabbit, so + # skip these bits and use the normal config. + NOVA_CPU_CONF=$compute_cell_conf + echo "Skipping multi-cell conductor fleet setup" + else + # "${CELLSV2_SETUP}" is "superconductor" + cp $compute_cell_conf $NOVA_CPU_CONF + # FIXME(danms): Should this be configurable? + iniset $NOVA_CPU_CONF workarounds disable_group_policy_check_upcall True + # Since the nova-compute service cannot reach nova-scheduler over + # RPC, we also disable track_instance_changes. + iniset $NOVA_CPU_CONF filter_scheduler track_instance_changes False + iniset_rpc_backend nova $NOVA_CPU_CONF DEFAULT "nova_cell${NOVA_CPU_CELL}" + # Make sure we nuke any database config + inidelete $NOVA_CPU_CONF database connection + inidelete $NOVA_CPU_CONF api_database connection + fi + + # Console proxies were configured earlier in create_nova_conf. Now that the + # nova-cpu.conf has been created, configure the console settings required + # by the compute process. + configure_console_compute + if [[ "$VIRT_DRIVER" = 'libvirt' ]]; then # The group **$LIBVIRT_GROUP** is added to the current user in this script. # ``sg`` is used in run_process to execute nova-compute as a member of the # **$LIBVIRT_GROUP** group. - run_process n-cpu "$NOVA_BIN_DIR/nova-compute --config-file $compute_cell_conf" $LIBVIRT_GROUP + run_process n-cpu "$NOVA_BIN_DIR/nova-compute --config-file $NOVA_CPU_CONF" $LIBVIRT_GROUP + elif [[ "$VIRT_DRIVER" = 'lxd' ]]; then + run_process n-cpu "$NOVA_BIN_DIR/nova-compute --config-file $NOVA_CPU_CONF" $LXD_GROUP + elif [[ "$VIRT_DRIVER" = 'docker' || "$VIRT_DRIVER" = 'zun' ]]; then + run_process n-cpu "$NOVA_BIN_DIR/nova-compute --config-file $NOVA_CPU_CONF" $DOCKER_GROUP elif [[ "$VIRT_DRIVER" = 'fake' ]]; then local i for i in `seq 1 $NUMBER_FAKE_NOVA_COMPUTE`; do @@ -799,20 +937,20 @@ function start_nova_compute { # creating or modifying real configurations. Each fake # gets its own configuration and own log file. local fake_conf="${NOVA_FAKE_CONF}-${i}" - iniset $fake_conf DEFAULT nhost "${HOSTNAME}${i}" - run_process "n-cpu-${i}" "$NOVA_BIN_DIR/nova-compute --config-file $compute_cell_conf --config-file $fake_conf" + iniset $fake_conf DEFAULT host "${HOSTNAME}${i}" + run_process "n-cpu-${i}" "$NOVA_BIN_DIR/nova-compute --config-file $NOVA_CPU_CONF --config-file $fake_conf" done else if is_service_enabled n-cpu && [[ -r $NOVA_PLUGINS/hypervisor-$VIRT_DRIVER ]]; then start_nova_hypervisor fi - run_process n-cpu "$NOVA_BIN_DIR/nova-compute --config-file $compute_cell_conf" + run_process n-cpu "$NOVA_BIN_DIR/nova-compute --config-file $NOVA_CPU_CONF" fi export PATH=$old_path } -# start_nova() - Start running processes, including screen +# start_nova() - Start running processes function start_nova_rest { # Hack to set the path for rootwrap local old_path=$PATH @@ -826,32 +964,130 @@ function start_nova_rest { fi # ``run_process`` checks ``is_service_enabled``, it is not needed here - run_process n-cond "$NOVA_BIN_DIR/nova-conductor --config-file $compute_cell_conf" run_process n-cell-region "$NOVA_BIN_DIR/nova-cells --config-file $api_cell_conf" run_process n-cell-child "$NOVA_BIN_DIR/nova-cells --config-file $compute_cell_conf" - run_process n-crt "$NOVA_BIN_DIR/nova-cert --config-file $api_cell_conf" + if is_service_enabled n-net; then + if ! running_in_container; then + enable_kernel_bridge_firewall + fi + fi run_process n-net "$NOVA_BIN_DIR/nova-network --config-file $compute_cell_conf" + run_process n-sch "$NOVA_BIN_DIR/nova-scheduler --config-file $compute_cell_conf" - run_process n-api-meta "$NOVA_BIN_DIR/nova-api-metadata --config-file $compute_cell_conf" + if [ "$NOVA_USE_MOD_WSGI" == "False" ]; then + run_process n-api-meta "$NOVA_BIN_DIR/nova-api-metadata --config-file $compute_cell_conf" + else + run_process n-api-meta "$NOVA_BIN_DIR/uwsgi --procname-prefix nova-api-meta --ini $NOVA_METADATA_UWSGI_CONF" + fi - run_process n-novnc "$NOVA_BIN_DIR/nova-novncproxy --config-file $api_cell_conf --web $NOVNC_WEB_DIR" - run_process n-xvnc "$NOVA_BIN_DIR/nova-xvpvncproxy --config-file $api_cell_conf" - run_process n-spice "$NOVA_BIN_DIR/nova-spicehtml5proxy --config-file $api_cell_conf --web $SPICE_WEB_DIR" + # nova-consoleauth always runs globally run_process n-cauth "$NOVA_BIN_DIR/nova-consoleauth --config-file $api_cell_conf" - run_process n-sproxy "$NOVA_BIN_DIR/nova-serialproxy --config-file $api_cell_conf" - # Starting the nova-objectstore only if swift3 service is not enabled. - # Swift will act as s3 objectstore. - is_service_enabled swift3 || \ - run_process n-obj "$NOVA_BIN_DIR/nova-objectstore --config-file $api_cell_conf" + export PATH=$old_path +} + +function enable_nova_console_proxies { + for i in $(seq 1 $NOVA_NUM_CELLS); do + for srv in n-novnc n-xvnc n-spice n-sproxy; do + if is_service_enabled $srv; then + enable_service ${srv}-cell${i} + fi + done + done +} + +function start_nova_console_proxies { + # Hack to set the path for rootwrap + local old_path=$PATH + # This is needed to find the nova conf + export PATH=$NOVA_BIN_DIR:$PATH + + local api_cell_conf=$NOVA_CONF + # console proxies run globally for singleconductor, else they run per cell + if [[ "${CELLSV2_SETUP}" == "singleconductor" ]]; then + run_process n-novnc "$NOVA_BIN_DIR/nova-novncproxy --config-file $api_cell_conf --web $NOVNC_WEB_DIR" + run_process n-xvnc "$NOVA_BIN_DIR/nova-xvpvncproxy --config-file $api_cell_conf" + run_process n-spice "$NOVA_BIN_DIR/nova-spicehtml5proxy --config-file $api_cell_conf --web $SPICE_WEB_DIR" + run_process n-sproxy "$NOVA_BIN_DIR/nova-serialproxy --config-file $api_cell_conf" + else + enable_nova_console_proxies + for i in $(seq 1 $NOVA_NUM_CELLS); do + local conf + conf=$(conductor_conf $i) + run_process n-novnc-cell${i} "$NOVA_BIN_DIR/nova-novncproxy --config-file $conf --web $NOVNC_WEB_DIR" + run_process n-xvnc-cell${i} "$NOVA_BIN_DIR/nova-xvpvncproxy --config-file $conf" + run_process n-spice-cell${i} "$NOVA_BIN_DIR/nova-spicehtml5proxy --config-file $conf --web $SPICE_WEB_DIR" + run_process n-sproxy-cell${i} "$NOVA_BIN_DIR/nova-serialproxy --config-file $conf" + done + fi export PATH=$old_path } +function enable_nova_fleet { + if is_service_enabled n-cond; then + enable_service n-super-cond + for i in $(seq 1 $NOVA_NUM_CELLS); do + enable_service n-cond-cell${i} + done + fi +} + +function start_nova_conductor { + if [[ "${CELLSV2_SETUP}" == "singleconductor" ]]; then + echo "Starting nova-conductor in a cellsv1-compatible way" + run_process n-cond "$NOVA_BIN_DIR/nova-conductor --config-file $NOVA_COND_CONF" + return + fi + + enable_nova_fleet + if is_service_enabled n-super-cond; then + run_process n-super-cond "$NOVA_BIN_DIR/nova-conductor --config-file $NOVA_COND_CONF" + fi + for i in $(seq 1 $NOVA_NUM_CELLS); do + if is_service_enabled n-cond-cell${i}; then + local conf + conf=$(conductor_conf $i) + run_process n-cond-cell${i} "$NOVA_BIN_DIR/nova-conductor --config-file $conf" + fi + done +} + +function is_nova_ready { + # NOTE(sdague): with cells v2 all the compute services must be up + # and checked into the database before discover_hosts is run. This + # happens in all in one installs by accident, because > 30 seconds + # happen between here and the script ending. However, in multinode + # tests this can very often not be the case. So ensure that the + # compute is up before we move on. + if is_service_enabled n-cell; then + # cells v1 can't complete the check below because it munges + # hostnames with cell information (grumble grumble). + return + fi + # TODO(sdague): honestly, this probably should be a plug point for + # an external system. + if [[ "$VIRT_DRIVER" == 'xenserver' ]]; then + # xenserver encodes information in the hostname of the compute + # because of the dom0/domU split. Just ignore for now. + return + fi + wait_for_compute $NOVA_READY_TIMEOUT +} + function start_nova { + # this catches the cells v1 case early + _set_singleconductor start_nova_rest + start_nova_console_proxies + start_nova_conductor start_nova_compute + if is_service_enabled n-api; then + # dump the cell mapping to ensure life is good + echo "Dumping cells_v2 mapping" + $NOVA_BIN_DIR/nova-manage cell_v2 list_cells --verbose + fi } function stop_nova_compute { @@ -869,30 +1105,73 @@ function stop_nova_compute { } function stop_nova_rest { - if [ "$NOVA_USE_MOD_WSGI" == "True" ]; then - disable_apache_site nova-api - disable_apache_site nova-ec2-api - restart_apache_server + # Kill the non-compute nova processes + for serv in n-api n-api-meta n-net n-sch n-cauth n-cell n-cell; do + stop_process $serv + done +} + +function stop_nova_console_proxies { + if [[ "${CELLSV2_SETUP}" == "singleconductor" ]]; then + for srv in n-novnc n-xvnc n-spice n-sproxy; do + stop_process $srv + done else - stop_process n-api + enable_nova_console_proxies + for i in $(seq 1 $NOVA_NUM_CELLS); do + for srv in n-novnc n-xvnc n-spice n-sproxy; do + stop_process ${srv}-cell${i} + done + done fi - # Kill the nova screen windows - # Some services are listed here twice since more than one instance - # of a service may be running in certain configs. - for serv in n-api n-crt n-net n-sch n-novnc n-xvnc n-cauth n-spice n-cond n-cell n-cell n-api-meta n-obj n-sproxy; do - stop_process $serv +} + +function stop_nova_conductor { + if [[ "${CELLSV2_SETUP}" == "singleconductor" ]]; then + stop_process n-cond + return + fi + + enable_nova_fleet + for srv in n-super-cond $(seq -f n-cond-cell%0.f 1 $NOVA_NUM_CELLS); do + if is_service_enabled $srv; then + stop_process $srv + fi done } -# stop_nova() - Stop running processes (non-screen) +# stop_nova() - Stop running processes function stop_nova { stop_nova_rest + stop_nova_console_proxies + stop_nova_conductor stop_nova_compute } +# create_instance_types(): Create default flavors +function create_flavors { + if is_service_enabled n-api; then + if ! openstack --os-region-name="$REGION_NAME" flavor list | grep -q ds512M; then + # Note that danms hates these flavors and apologizes for sdague + openstack --os-region-name="$REGION_NAME" flavor create --id c1 --ram 256 --disk 0 --vcpus 1 cirros256 + openstack --os-region-name="$REGION_NAME" flavor create --id d1 --ram 512 --disk 5 --vcpus 1 ds512M + openstack --os-region-name="$REGION_NAME" flavor create --id d2 --ram 1024 --disk 10 --vcpus 1 ds1G + openstack --os-region-name="$REGION_NAME" flavor create --id d3 --ram 2048 --disk 10 --vcpus 2 ds2G + openstack --os-region-name="$REGION_NAME" flavor create --id d4 --ram 4096 --disk 20 --vcpus 4 ds4G + fi + + if ! openstack --os-region-name="$REGION_NAME" flavor list | grep -q m1.tiny; then + openstack --os-region-name="$REGION_NAME" flavor create --id 1 --ram 512 --disk 1 --vcpus 1 m1.tiny + openstack --os-region-name="$REGION_NAME" flavor create --id 2 --ram 2048 --disk 20 --vcpus 1 m1.small + openstack --os-region-name="$REGION_NAME" flavor create --id 3 --ram 4096 --disk 40 --vcpus 2 m1.medium + openstack --os-region-name="$REGION_NAME" flavor create --id 4 --ram 8192 --disk 80 --vcpus 4 m1.large + openstack --os-region-name="$REGION_NAME" flavor create --id 5 --ram 16384 --disk 160 --vcpus 8 m1.xlarge + fi + fi +} # Restore xtrace -$XTRACE +$_XTRACE_LIB_NOVA # Tell emacs to use shell-script-mode ## Local variables: diff --git a/lib/nova_plugins/functions-libvirt b/lib/nova_plugins/functions-libvirt old mode 100755 new mode 100644 index 04da5e2b60..fcb4777997 --- a/lib/nova_plugins/functions-libvirt +++ b/lib/nova_plugins/functions-libvirt @@ -8,7 +8,7 @@ # ``STACK_USER`` has to be defined # Save trace setting -LV_XTRACE=$(set +o | grep xtrace) +_XTRACE_NOVA_FN_LIBVIRT=$(set +o | grep xtrace) set +o xtrace # Defaults @@ -20,42 +20,79 @@ set +o xtrace # extremely verbose.) DEBUG_LIBVIRT=$(trueorfalse True DEBUG_LIBVIRT) +# Try to enable coredumps for libvirt +# Currently fairly specific to OpenStackCI hosts +DEBUG_LIBVIRT_COREDUMPS=$(trueorfalse False DEBUG_LIBVIRT_COREDUMPS) + +# Only Xenial is left with libvirt-bin. Everywhere else is libvirtd +if is_ubuntu && [ ${DISTRO} == "xenial" ]; then + LIBVIRT_DAEMON=libvirt-bin +else + LIBVIRT_DAEMON=libvirtd +fi + +# Enable coredumps for libvirt +# Bug: https://bugs.launchpad.net/nova/+bug/1643911 +function _enable_coredump { + local confdir=/etc/systemd/system/${LIBVIRT_DAEMON}.service.d + local conffile=${confdir}/coredump.conf + + # Create a coredump directory, and instruct the kernel to save to + # here + sudo mkdir -p /var/core + sudo chmod a+wrx /var/core + echo '/var/core/core.%e.%p.%h.%t' | \ + sudo tee /proc/sys/kernel/core_pattern + + # Drop a config file to up the core ulimit + sudo mkdir -p ${confdir} + sudo tee ${conffile} < elif is_fedora || is_suse; then - install_package kvm + + # Note that in CentOS/RHEL this needs to come from the RDO + # repositories (qemu-kvm-ev ... which provides this package) + # as the base system version is too old. We should have + # pre-installed these + install_package qemu-kvm + install_package libvirt libvirt-devel + pip_uninstall libvirt-python pip_install_gr libvirt-python - install_package python-libguestfs fi - # Restart firewalld after install of libvirt to avoid a problem - # with polkit, which libvirtd brings in. See - # https://bugzilla.redhat.com/show_bug.cgi?id=1099031 - - # Note there is a difference between F20 rackspace cloud images - # and HP images used in the gate; rackspace has firewalld but hp - # cloud doesn't. - if is_fedora && is_package_installed firewalld; then - sudo service firewalld restart || true + if [[ $DEBUG_LIBVIRT_COREDUMPS == True ]]; then + _enable_coredump fi } # Configures the installed libvirt system so that is accessible by # STACK_USER via qemu:///system with management capabilities. function configure_libvirt { - if is_service_enabled neutron && is_neutron_ovs_base_plugin && ! sudo grep -q '^cgroup_device_acl' $QEMU_CONF; then + if is_service_enabled neutron && ! sudo grep -q '^cgroup_device_acl' $QEMU_CONF; then # Add /dev/net/tun to cgroup_device_acls, needed for type=ethernet interfaces cat <= 1.2.3 - local log_filters="1:libvirt.c 1:qemu 1:conf 1:security 3:object 3:event 3:json 3:file 1:util 1:qemu_monitor" + local log_filters="1:libvirt.c 1:qemu 1:conf 1:security 3:object 3:event 3:json 3:file 1:util 1:cpu" else - local log_filters="1:libvirt 1:qemu 1:conf 1:security 3:object 3:event 3:json 3:file 1:util 1:qemu_monitor" + local log_filters="1:libvirt 1:qemu 1:conf 1:security 3:object 3:event 3:json 3:file 1:util 1:cpu" fi local log_outputs="1:file:/var/log/libvirt/libvirtd.log" - if ! grep -q "log_filters=\"$log_filters\"" /etc/libvirt/libvirtd.conf; then + if ! sudo grep -q "^log_filters=\"$log_filters\"" /etc/libvirt/libvirtd.conf; then echo "log_filters=\"$log_filters\"" | sudo tee -a /etc/libvirt/libvirtd.conf fi - if ! grep -q "log_outputs=\"$log_outputs\"" /etc/libvirt/libvirtd.conf; then + if ! sudo grep -q "^log_outputs=\"$log_outputs\"" /etc/libvirt/libvirtd.conf; then echo "log_outputs=\"$log_outputs\"" | sudo tee -a /etc/libvirt/libvirtd.conf fi fi - # Update the libvirt cpu map with a gate64 cpu model. This enables nova - # live migration for 64bit guest OSes on heterogenous cloud "hardware". - if [[ -f /usr/share/libvirt/cpu_map.xml ]] ; then - sudo $TOP_DIR/tools/cpu_map_update.py /usr/share/libvirt/cpu_map.xml + if is_nova_console_proxy_compute_tls_enabled ; then + if is_service_enabled n-novnc ; then + echo "vnc_tls = 1" | sudo tee -a $QEMU_CONF + echo "vnc_tls_x509_verify = 1" | sudo tee -a $QEMU_CONF + + sudo mkdir -p /etc/pki/libvirt-vnc + sudo chown libvirt-qemu:libvirt-qemu /etc/pki/libvirt-vnc + deploy_int_CA /etc/pki/libvirt-vnc/ca-cert.pem + deploy_int_cert /etc/pki/libvirt-vnc/server-cert.pem /etc/pki/libvirt-vnc/server-key.pem + fi fi - # libvirt detects various settings on startup, as we potentially changed - # the system configuration (modules, filesystems), we need to restart - # libvirt to detect those changes. Use a stop start as otherwise the new - # cpu_map is not loaded properly on some systems (Ubuntu). - stop_service $LIBVIRT_DAEMON - start_service $LIBVIRT_DAEMON + # Service needs to be started on redhat/fedora -- do a restart for + # sanity after fiddling the config. + restart_service $LIBVIRT_DAEMON + + # Restart virtlogd companion service to ensure it is running properly + # https://bugs.launchpad.net/ubuntu/+source/libvirt/+bug/1577455 + # https://bugzilla.redhat.com/show_bug.cgi?id=1290357 + # (not all platforms have it; libvirt 1.3+ only, thus the ignore) + restart_service virtlogd || true } # Restore xtrace -$LV_XTRACE +$_XTRACE_NOVA_FN_LIBVIRT # Local variables: # mode: shell-script diff --git a/lib/nova_plugins/hypervisor-fake b/lib/nova_plugins/hypervisor-fake index 3180d91f0a..87ee49fa4b 100644 --- a/lib/nova_plugins/hypervisor-fake +++ b/lib/nova_plugins/hypervisor-fake @@ -17,7 +17,7 @@ # cleanup_nova_hypervisor - remove transient data and cache # Save trace setting -MY_XTRACE=$(set +o | grep xtrace) +_XTRACE_VIRTFAKE=$(set +o | grep xtrace) set +o xtrace @@ -36,20 +36,9 @@ function cleanup_nova_hypervisor { # configure_nova_hypervisor - Set config files, create data dirs, etc function configure_nova_hypervisor { - iniset $NOVA_CONF DEFAULT compute_driver "nova.virt.fake.FakeDriver" + iniset $NOVA_CONF DEFAULT compute_driver "fake.FakeDriver" # Disable arbitrary limits - iniset $NOVA_CONF DEFAULT quota_instances -1 - iniset $NOVA_CONF DEFAULT quota_cores -1 - iniset $NOVA_CONF DEFAULT quota_ram -1 - iniset $NOVA_CONF DEFAULT quota_floating_ips -1 - iniset $NOVA_CONF DEFAULT quota_fixed_ips -1 - iniset $NOVA_CONF DEFAULT quota_metadata_items -1 - iniset $NOVA_CONF DEFAULT quota_injected_files -1 - iniset $NOVA_CONF DEFAULT quota_injected_file_path_bytes -1 - iniset $NOVA_CONF DEFAULT quota_security_groups -1 - iniset $NOVA_CONF DEFAULT quota_security_group_rules -1 - iniset $NOVA_CONF DEFAULT quota_key_pairs -1 - iniset $NOVA_CONF DEFAULT scheduler_default_filters "RetryFilter,AvailabilityZoneFilter,ComputeFilter,ComputeCapabilitiesFilter,ImagePropertiesFilter,CoreFilter,RamFilter,DiskFilter" + iniset $NOVA_CONF quota driver nova.quota.NoopQuotaDriver } # install_nova_hypervisor() - Install external components @@ -72,7 +61,7 @@ function stop_nova_hypervisor { # Restore xtrace -$MY_XTRACE +$_XTRACE_VIRTFAKE # Local variables: # mode: shell-script diff --git a/lib/nova_plugins/hypervisor-ironic b/lib/nova_plugins/hypervisor-ironic index b9e286d5b6..49110a8643 100644 --- a/lib/nova_plugins/hypervisor-ironic +++ b/lib/nova_plugins/hypervisor-ironic @@ -17,7 +17,7 @@ # cleanup_nova_hypervisor - remove transient data and cache # Save trace setting -MY_XTRACE=$(set +o | grep xtrace) +_XTRACE_HYP_IRONIC=$(set +o | grep xtrace) set +o xtrace source $TOP_DIR/lib/nova_plugins/functions-libvirt @@ -39,17 +39,20 @@ function configure_nova_hypervisor { configure_libvirt LIBVIRT_FIREWALL_DRIVER=${LIBVIRT_FIREWALL_DRIVER:-"nova.virt.firewall.NoopFirewallDriver"} - iniset $NOVA_CONF DEFAULT compute_driver nova.virt.ironic.IronicDriver + iniset $NOVA_CONF DEFAULT compute_driver ironic.IronicDriver iniset $NOVA_CONF DEFAULT firewall_driver $LIBVIRT_FIREWALL_DRIVER - iniset $NOVA_CONF DEFAULT scheduler_host_manager nova.scheduler.ironic_host_manager.IronicHostManager - iniset $NOVA_CONF DEFAULT ram_allocation_ratio 1.0 - iniset $NOVA_CONF DEFAULT reserved_host_memory_mb 0 + # ironic section - iniset $NOVA_CONF ironic admin_username admin - iniset $NOVA_CONF ironic admin_password $ADMIN_PASSWORD - iniset $NOVA_CONF ironic admin_url $KEYSTONE_AUTH_URI/v2.0 - iniset $NOVA_CONF ironic admin_tenant_name demo - iniset $NOVA_CONF ironic api_endpoint $IRONIC_SERVICE_PROTOCOL://$IRONIC_HOSTPORT/v1 + iniset $NOVA_CONF ironic auth_type password + iniset $NOVA_CONF ironic username admin + iniset $NOVA_CONF ironic password $ADMIN_PASSWORD + iniset $NOVA_CONF ironic auth_url $KEYSTONE_AUTH_URI + iniset $NOVA_CONF ironic project_domain_id default + iniset $NOVA_CONF ironic user_domain_id default + iniset $NOVA_CONF ironic project_name demo + + iniset $NOVA_CONF ironic api_max_retries 300 + iniset $NOVA_CONF ironic api_retry_interval 5 } # install_nova_hypervisor() - Install external components @@ -81,7 +84,7 @@ function stop_nova_hypervisor { # Restore xtrace -$MY_XTRACE +$_XTRACE_HYP_IRONIC # Local variables: # mode: shell-script diff --git a/lib/nova_plugins/hypervisor-libvirt b/lib/nova_plugins/hypervisor-libvirt index a6a87f9164..3d676b9b8d 100644 --- a/lib/nova_plugins/hypervisor-libvirt +++ b/lib/nova_plugins/hypervisor-libvirt @@ -17,7 +17,7 @@ # cleanup_nova_hypervisor - remove transient data and cache # Save trace setting -MY_XTRACE=$(set +o | grep xtrace) +_XTRACE_NOVA_LIBVIRT=$(set +o | grep xtrace) set +o xtrace source $TOP_DIR/lib/nova_plugins/functions-libvirt @@ -25,9 +25,6 @@ source $TOP_DIR/lib/nova_plugins/functions-libvirt # Defaults # -------- -# File injection is disabled by default in Nova. This will turn it back on. -ENABLE_FILE_INJECTION=${ENABLE_FILE_INJECTION:-False} - # Entry Points # ------------ @@ -43,7 +40,8 @@ function configure_nova_hypervisor { configure_libvirt iniset $NOVA_CONF libvirt virt_type "$LIBVIRT_TYPE" iniset $NOVA_CONF libvirt cpu_mode "none" - iniset $NOVA_CONF libvirt use_usb_tablet "False" + # Do not enable USB tablet input devices to avoid QEMU CPU overhead. + iniset $NOVA_CONF DEFAULT pointer_model "ps2mouse" iniset $NOVA_CONF libvirt live_migration_uri "qemu+ssh://$STACK_USER@%s/system" iniset $NOVA_CONF DEFAULT default_ephemeral_format "ext4" iniset $NOVA_CONF DEFAULT compute_driver "libvirt.LibvirtDriver" @@ -51,31 +49,37 @@ function configure_nova_hypervisor { iniset $NOVA_CONF DEFAULT firewall_driver "$LIBVIRT_FIREWALL_DRIVER" # Power architecture currently does not support graphical consoles. if is_arch "ppc64"; then - iniset $NOVA_CONF DEFAULT vnc_enabled "false" + iniset $NOVA_CONF vnc enabled "false" fi # arm64-specific configuration if is_arch "aarch64"; then # arm64 architecture currently does not support graphical consoles. - iniset $NOVA_CONF DEFAULT vnc_enabled "false" + iniset $NOVA_CONF vnc enabled "false" + iniset $NOVA_CONF libvirt cpu_mode "host-passthrough" fi - ENABLE_FILE_INJECTION=$(trueorfalse False ENABLE_FILE_INJECTION) - if [[ "$ENABLE_FILE_INJECTION" = "True" ]] ; then - # When libguestfs is available for file injection, enable using - # libguestfs to inspect the image and figure out the proper - # partition to inject into. - iniset $NOVA_CONF libvirt inject_partition '-1' - iniset $NOVA_CONF libvirt inject_key 'true' - else - # File injection is being disabled by default in the near future - - # disable it here for now to avoid surprises later. - iniset $NOVA_CONF libvirt inject_partition '-2' + if isset ENABLE_FILE_INJECTION; then + if [ "$ENABLE_FILE_INJECTION" == "True" ]; then + # -1 means use libguestfs to inspect the guest OS image for the + # root partition to use for file injection. + iniset $NOVA_CONF libvirt inject_partition '-1' + fi fi if [[ "$LIBVIRT_TYPE" = "parallels" ]]; then iniset $NOVA_CONF libvirt connection_uri "parallels+unix:///system" iniset $NOVA_CONF libvirt images_type "ploop" + iniset $NOVA_CONF DEFAULT force_raw_images "False" + iniset $NOVA_CONF vnc server_proxyclient_address $HOST_IP + iniset $NOVA_CONF vnc server_listen $HOST_IP + iniset $NOVA_CONF vnc keymap + elif [[ "$NOVA_BACKEND" == "LVM" ]]; then + iniset $NOVA_CONF libvirt images_type "lvm" + iniset $NOVA_CONF libvirt images_volume_group $DEFAULT_VOLUME_GROUP_NAME + if isset LVM_VOLUME_CLEAR; then + iniset $NOVA_CONF libvirt volume_clear "$LVM_VOLUME_CLEAR" + fi fi } @@ -97,6 +101,27 @@ function install_nova_hypervisor { yum_install libcgroup-tools fi fi + + if [[ "$ENABLE_FILE_INJECTION" == "True" ]] ; then + if is_ubuntu; then + install_package python-guestfs + # NOTE(andreaf) Ubuntu kernel can only be read by root, which breaks libguestfs: + # https://bugs.launchpad.net/ubuntu/+source/linux/+bug/759725) + INSTALLED_KERNELS="$(ls /boot/vmlinuz-*)" + for kernel in $INSTALLED_KERNELS; do + STAT_OVERRIDE="root root 644 ${kernel}" + # unstack won't remove the statoverride, so make this idempotent + if [[ ! $(dpkg-statoverride --list | grep "$STAT_OVERRIDE") ]]; then + sudo dpkg-statoverride --add --update $STAT_OVERRIDE + fi + done + elif is_suse; then + # Workaround for missing dependencies in python-libguestfs + install_package python-libguestfs guestfs-data augeas augeas-lenses + elif is_fedora; then + install_package python-libguestfs + fi + fi } # start_nova_hypervisor - Start any required external services @@ -113,7 +138,7 @@ function stop_nova_hypervisor { # Restore xtrace -$MY_XTRACE +$_XTRACE_NOVA_LIBVIRT # Local variables: # mode: shell-script diff --git a/lib/nova_plugins/hypervisor-openvz b/lib/nova_plugins/hypervisor-openvz index cce36b8d3f..58ab5c11ac 100644 --- a/lib/nova_plugins/hypervisor-openvz +++ b/lib/nova_plugins/hypervisor-openvz @@ -17,7 +17,7 @@ # cleanup_nova_hypervisor - remove transient data and cache # Save trace setting -MY_XTRACE=$(set +o | grep xtrace) +_XTRACE_OPENVZ=$(set +o | grep xtrace) set +o xtrace @@ -62,7 +62,7 @@ function stop_nova_hypervisor { # Restore xtrace -$MY_XTRACE +$_XTRACE_OPENVZ # Local variables: # mode: shell-script diff --git a/lib/nova_plugins/hypervisor-vsphere b/lib/nova_plugins/hypervisor-vsphere index c406e094f3..7c08bc945b 100644 --- a/lib/nova_plugins/hypervisor-vsphere +++ b/lib/nova_plugins/hypervisor-vsphere @@ -17,7 +17,7 @@ # cleanup_nova_hypervisor - remove transient data and cache # Save trace setting -MY_XTRACE=$(set +o | grep xtrace) +_XTRACE_NOVA_VSPHERE=$(set +o | grep xtrace) set +o xtrace @@ -42,9 +42,6 @@ function configure_nova_hypervisor { iniset $NOVA_CONF vmware host_username "$VMWAREAPI_USER" iniset $NOVA_CONF vmware host_password "$VMWAREAPI_PASSWORD" iniset_multiline $NOVA_CONF vmware cluster_name "$VMWAREAPI_CLUSTER" - if is_service_enabled neutron; then - iniset $NOVA_CONF vmware integration_bridge $OVS_BRIDGE - fi } # install_nova_hypervisor() - Install external components @@ -67,7 +64,7 @@ function stop_nova_hypervisor { # Restore xtrace -$MY_XTRACE +$_XTRACE_NOVA_VSPHERE # Local variables: # mode: shell-script diff --git a/lib/nova_plugins/hypervisor-xenserver b/lib/nova_plugins/hypervisor-xenserver index efce383222..6f79e4ff7c 100644 --- a/lib/nova_plugins/hypervisor-xenserver +++ b/lib/nova_plugins/hypervisor-xenserver @@ -17,20 +17,15 @@ # cleanup_nova_hypervisor - remove transient data and cache # Save trace setting -MY_XTRACE=$(set +o | grep xtrace) +_XTRACE_XENSERVER=$(set +o | grep xtrace) set +o xtrace # Defaults # -------- -PUBLIC_INTERFACE_DEFAULT=eth2 -GUEST_INTERFACE_DEFAULT=eth1 # Allow ``build_domU.sh`` to specify the flat network bridge via kernel args FLAT_NETWORK_BRIDGE_DEFAULT=$(sed -e 's/.* flat_network_bridge=\([[:alnum:]]*\).*$/\1/g' /proc/cmdline) -if is_service_enabled neutron; then - XEN_INTEGRATION_BRIDGE=$(sed -e 's/.* xen_integration_bridge=\([[:alnum:]]*\).*$/\1/g' /proc/cmdline) -fi VNCSERVER_PROXYCLIENT_ADDRESS=${VNCSERVER_PROXYCLIENT_ADDRESS=169.254.0.1} @@ -49,6 +44,21 @@ function configure_nova_hypervisor { if [ -z "$XENAPI_CONNECTION_URL" ]; then die $LINENO "XENAPI_CONNECTION_URL is not specified" fi + + # Check os-xenapi plugin is enabled + local plugins="${DEVSTACK_PLUGINS}" + local plugin + local found=0 + for plugin in ${plugins//,/ }; do + if [[ "$plugin" = "os-xenapi" ]]; then + found=1 + break + fi + done + if [[ $found -ne 1 ]]; then + die $LINENO "os-xenapi plugin is not specified. Please enable this plugin in local.conf" + fi + read_password XENAPI_PASSWORD "ENTER A PASSWORD TO USE FOR XEN." iniset $NOVA_CONF DEFAULT compute_driver "xenapi.XenAPIDriver" iniset $NOVA_CONF xenserver connection_url "$XENAPI_CONNECTION_URL" @@ -65,36 +75,22 @@ function configure_nova_hypervisor { local ssh_dom0 ssh_dom0="sudo -u $DOMZERO_USER ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null root@$dom0_ip" - # Find where the plugins should go in dom0 - xen_functions=`cat $TOP_DIR/tools/xen/functions` - PLUGIN_DIR=`$ssh_dom0 "$xen_functions; set -eux; xapi_plugin_location"` - - # install nova plugins to dom0 - tar -czf - -C $NOVA_DIR/plugins/xenserver/xenapi/etc/xapi.d/plugins/ ./ | - $ssh_dom0 "tar -xzf - -C $PLUGIN_DIR && chmod a+x $PLUGIN_DIR/*" - # install console logrotate script tar -czf - -C $NOVA_DIR/tools/xenserver/ rotate_xen_guest_logs.sh | $ssh_dom0 'tar -xzf - -C /root/ && chmod +x /root/rotate_xen_guest_logs.sh && mkdir -p /var/log/xen/guest' # Create a cron job that will rotate guest logs $ssh_dom0 crontab - << CRONTAB -* * * * * /root/rotate_xen_guest_logs.sh +* * * * * /root/rotate_xen_guest_logs.sh >/dev/null 2>&1 CRONTAB - # Create directories for kernels and images - { - echo "set -eux" - cat $TOP_DIR/tools/xen/functions - echo "create_directory_for_images" - echo "create_directory_for_kernels" - } | $ssh_dom0 - } # install_nova_hypervisor() - Install external components function install_nova_hypervisor { - pip_install_gr xenapi + # xenapi functionality is now included in os-xenapi library which houses the plugin + # so this function intentionally left blank + : } # start_nova_hypervisor - Start any required external services @@ -111,7 +107,7 @@ function stop_nova_hypervisor { # Restore xtrace -$MY_XTRACE +$_XTRACE_XENSERVER # Local variables: # mode: shell-script diff --git a/lib/oslo b/lib/oslo index d9688a01cd..3ae64c8210 100644 --- a/lib/oslo +++ b/lib/oslo @@ -6,86 +6,6 @@ # # We need this to handle the fact that projects would like to use # pre-released versions of oslo libraries. - -# Dependencies: # -# - ``functions`` file - -# ``stack.sh`` calls the entry points in this order: -# -# - install_oslo - -# Save trace setting -XTRACE=$(set +o | grep xtrace) -set +o xtrace - - -# Defaults -# -------- -GITDIR["cliff"]=$DEST/cliff -GITDIR["debtcollector"]=$DEST/debtcollector -GITDIR["oslo.concurrency"]=$DEST/oslo.concurrency -GITDIR["oslo.config"]=$DEST/oslo.config -GITDIR["oslo.context"]=$DEST/oslo.context -GITDIR["oslo.db"]=$DEST/oslo.db -GITDIR["oslo.i18n"]=$DEST/oslo.i18n -GITDIR["oslo.log"]=$DEST/oslo.log -GITDIR["oslo.messaging"]=$DEST/oslo.messaging -GITDIR["oslo.middleware"]=$DEST/oslo.middleware -GITDIR["oslo.policy"]=$DEST/oslo.policy -GITDIR["oslo.rootwrap"]=$DEST/oslo.rootwrap -GITDIR["oslo.serialization"]=$DEST/oslo.serialization -GITDIR["oslo.utils"]=$DEST/oslo.utils -GITDIR["oslo.versionedobjects"]=$DEST/oslo.versionedobjects -GITDIR["oslo.vmware"]=$DEST/oslo.vmware -GITDIR["pycadf"]=$DEST/pycadf -GITDIR["stevedore"]=$DEST/stevedore -GITDIR["taskflow"]=$DEST/taskflow -GITDIR["tooz"]=$DEST/tooz - -# Support entry points installation of console scripts -OSLO_BIN_DIR=$(get_python_exec_prefix) - - -# Functions -# --------- - -function _do_install_oslo_lib { - local name=$1 - if use_library_from_git "$name"; then - git_clone_by_name "$name" - setup_lib "$name" - fi -} - -# install_oslo() - Collect source and prepare -function install_oslo { - _do_install_oslo_lib "cliff" - _do_install_oslo_lib "debtcollector" - _do_install_oslo_lib "oslo.concurrency" - _do_install_oslo_lib "oslo.config" - _do_install_oslo_lib "oslo.context" - _do_install_oslo_lib "oslo.db" - _do_install_oslo_lib "oslo.i18n" - _do_install_oslo_lib "oslo.log" - _do_install_oslo_lib "oslo.messaging" - _do_install_oslo_lib "oslo.middleware" - _do_install_oslo_lib "oslo.policy" - _do_install_oslo_lib "oslo.rootwrap" - _do_install_oslo_lib "oslo.serialization" - _do_install_oslo_lib "oslo.utils" - _do_install_oslo_lib "oslo.versionedobjects" - _do_install_oslo_lib "oslo.vmware" - _do_install_oslo_lib "pycadf" - _do_install_oslo_lib "stevedore" - _do_install_oslo_lib "taskflow" - _do_install_oslo_lib "tooz" -} - -# Restore xtrace -$XTRACE - -# Tell emacs to use shell-script-mode -## Local variables: -## mode: shell-script -## End: +# Included for compatibility with grenade, remove in Queens +source $TOP_DIR/lib/libraries diff --git a/lib/placement b/lib/placement new file mode 100644 index 0000000000..da69e39264 --- /dev/null +++ b/lib/placement @@ -0,0 +1,203 @@ +#!/bin/bash +# +# lib/placement +# Functions to control the configuration and operation of the **Placement** service +# + +# Dependencies: +# +# - ``functions`` file +# - ``DEST``, ``DATA_DIR``, ``STACK_USER`` must be defined +# - ``FILES`` + +# ``stack.sh`` calls the entry points in this order: +# +# - install_placement +# - cleanup_placement +# - configure_placement +# - init_placement +# - start_placement +# - stop_placement + +# Save trace setting +_XTRACE_LIB_PLACEMENT=$(set +o | grep xtrace) +set +o xtrace + +# Defaults +# -------- + +PLACEMENT_DIR=$DEST/placement +PLACEMENT_CONF_DIR=/etc/placement +PLACEMENT_CONF=$PLACEMENT_CONF_DIR/placement.conf +PLACEMENT_AUTH_CACHE_DIR=${PLACEMENT_AUTH_CACHE_DIR:-/var/cache/placement} +PLACEMENT_AUTH_STRATEGY=${PLACEMENT_AUTH_STRATEGY:-keystone} +# Placement virtual environment +if [[ ${USE_VENV} = True ]]; then + PROJECT_VENV["placement"]=${PLACEMENT_DIR}.venv + PLACEMENT_BIN_DIR=${PROJECT_VENV["placement"]}/bin +else + PLACEMENT_BIN_DIR=$(get_python_exec_prefix) +fi +PLACEMENT_UWSGI=$PLACEMENT_BIN_DIR/placement-api +PLACEMENT_UWSGI_CONF=$PLACEMENT_CONF_DIR/placement-uwsgi.ini + +if is_service_enabled tls-proxy; then + PLACEMENT_SERVICE_PROTOCOL="https" +fi + +# Public facing bits +PLACEMENT_SERVICE_PROTOCOL=${PLACEMENT_SERVICE_PROTOCOL:-$SERVICE_PROTOCOL} +PLACEMENT_SERVICE_HOST=${PLACEMENT_SERVICE_HOST:-$SERVICE_HOST} + +# Functions +# --------- + +# Test if any placement services are enabled +# is_placement_enabled +function is_placement_enabled { + [[ ,${ENABLED_SERVICES} =~ ,"placement-api" ]] && return 0 + return 1 +} + +# cleanup_placement() - Remove residual data files, anything left over from previous +# runs that a clean run would need to clean up +function cleanup_placement { + sudo rm -f $(apache_site_config_for placement-api) + remove_uwsgi_config "$PLACEMENT_UWSGI_CONF" "$PLACEMENT_UWSGI" + sudo rm -f $PLACEMENT_AUTH_CACHE_DIR/* +} + +# _config_placement_apache_wsgi() - Set WSGI config files +function _config_placement_apache_wsgi { + local placement_api_apache_conf + local venv_path="" + local placement_bin_dir="" + placement_bin_dir=$(get_python_exec_prefix) + placement_api_apache_conf=$(apache_site_config_for placement-api) + + if [[ ${USE_VENV} = True ]]; then + venv_path="python-path=${PROJECT_VENV["placement"]}/lib/$(python_version)/site-packages" + placement_bin_dir=${PROJECT_VENV["placement"]}/bin + fi + + sudo cp $FILES/apache-placement-api.template $placement_api_apache_conf + sudo sed -e " + s|%APACHE_NAME%|$APACHE_NAME|g; + s|%PUBLICWSGI%|$placement_bin_dir/placement-api|g; + s|%SSLENGINE%|$placement_ssl|g; + s|%SSLCERTFILE%|$placement_certfile|g; + s|%SSLKEYFILE%|$placement_keyfile|g; + s|%USER%|$STACK_USER|g; + s|%VIRTUALENV%|$venv_path|g + s|%APIWORKERS%|$API_WORKERS|g + " -i $placement_api_apache_conf +} + +function configure_placement_nova_compute { + # Use the provided config file path or default to $NOVA_CONF. + local conf=${1:-$NOVA_CONF} + iniset $conf placement auth_type "password" + iniset $conf placement auth_url "$KEYSTONE_SERVICE_URI" + iniset $conf placement username placement + iniset $conf placement password "$SERVICE_PASSWORD" + iniset $conf placement user_domain_name "$SERVICE_DOMAIN_NAME" + iniset $conf placement project_name "$SERVICE_TENANT_NAME" + iniset $conf placement project_domain_name "$SERVICE_DOMAIN_NAME" + iniset $conf placement auth_strategy $PLACEMENT_AUTH_STRATEGY +} + +# create_placement_conf() - Write config +function create_placement_conf { + rm -f $PLACEMENT_CONF + iniset $PLACEMENT_CONF placement_database connection `database_connection_url placement` + iniset $PLACEMENT_CONF DEFAULT debug "$ENABLE_DEBUG_LOG_LEVEL" + iniset $PLACEMENT_CONF api auth_strategy $PLACEMENT_AUTH_STRATEGY + configure_auth_token_middleware $PLACEMENT_CONF placement $PLACEMENT_AUTH_CACHE_DIR + setup_logging $PLACEMENT_CONF +} + +# configure_placement() - Set config files, create data dirs, etc +function configure_placement { + sudo install -d -o $STACK_USER $PLACEMENT_CONF_DIR + create_placement_conf + + if [[ "$WSGI_MODE" == "uwsgi" ]]; then + write_uwsgi_config "$PLACEMENT_UWSGI_CONF" "$PLACEMENT_UWSGI" "/placement" + else + _config_placement_apache_wsgi + fi +} + +# create_placement_accounts() - Set up required placement accounts +# and service and endpoints. +function create_placement_accounts { + create_service_user "placement" "admin" + local placement_api_url="$PLACEMENT_SERVICE_PROTOCOL://$PLACEMENT_SERVICE_HOST/placement" + get_or_create_service "placement" "placement" "Placement Service" + get_or_create_endpoint \ + "placement" \ + "$REGION_NAME" \ + "$placement_api_url" +} + +# create_placement_cache_dir() - Create directories for keystone cache +function create_placement_cache_dir { + # Create cache dir + sudo install -d -o $STACK_USER $PLACEMENT_AUTH_CACHE_DIR + rm -f $PLACEMENT_AUTH_CACHE_DIR/* +} + +# init_placement() - Create service user and endpoints +function init_placement { + recreate_database placement + $PLACEMENT_BIN_DIR/placement-manage db sync + create_placement_accounts + create_placement_cache_dir +} + +# install_placement() - Collect source and prepare +function install_placement { + install_apache_wsgi + # Install the openstackclient placement client plugin for CLI + pip_install_gr osc-placement + git_clone $PLACEMENT_REPO $PLACEMENT_DIR $PLACEMENT_BRANCH + setup_develop $PLACEMENT_DIR +} + +# start_placement_api() - Start the API processes ahead of other things +function start_placement_api { + if [[ "$WSGI_MODE" == "uwsgi" ]]; then + run_process "placement-api" "$PLACEMENT_BIN_DIR/uwsgi --procname-prefix placement --ini $PLACEMENT_UWSGI_CONF" + else + enable_apache_site placement-api + restart_apache_server + tail_log placement-api /var/log/$APACHE_NAME/placement-api.log + fi + + echo "Waiting for placement-api to start..." + if ! wait_for_service $SERVICE_TIMEOUT $PLACEMENT_SERVICE_PROTOCOL://$PLACEMENT_SERVICE_HOST/placement; then + die $LINENO "placement-api did not start" + fi +} + +function start_placement { + start_placement_api +} + +# stop_placement() - Disable the api service and stop it. +function stop_placement { + if [[ "$WSGI_MODE" == "uwsgi" ]]; then + stop_process "placement-api" + else + disable_apache_site placement-api + restart_apache_server + fi +} + +# Restore xtrace +$_XTRACE_LIB_PLACEMENT + +# Tell emacs to use shell-script-mode +## Local variables: +## mode: shell-script +## End: diff --git a/lib/rpc_backend b/lib/rpc_backend index 297ebacc08..1c7c82fcd3 100644 --- a/lib/rpc_backend +++ b/lib/rpc_backend @@ -1,72 +1,37 @@ #!/bin/bash # # lib/rpc_backend -# Interface for interactig with different RPC backends +# Interface for installing RabbitMQ on the system # Dependencies: # # - ``functions`` file # - ``RABBIT_{HOST|PASSWORD|USERID}`` must be defined when RabbitMQ is used -# - ``RPC_MESSAGING_PROTOCOL`` option for configuring the messaging protocol # ``stack.sh`` calls the entry points in this order: # # - check_rpc_backend # - install_rpc_backend # - restart_rpc_backend -# - iniset_rpc_backend +# - iniset_rpc_backend (stable interface) +# +# Note: if implementing an out of tree plugin for an RPC backend, you +# should install all services through normal plugin methods, then +# redefine ``iniset_rpc_backend`` in your code. That's the one portion +# of this file which is a standard interface. # Save trace setting -XTRACE=$(set +o | grep xtrace) +_XTRACE_RPC_BACKEND=$(set +o | grep xtrace) set +o xtrace -RPC_MESSAGING_PROTOCOL=${RPC_MESSAGING_PROTOCOL:-0.9} - -# TODO(sdague): RPC backend selection is super wonky because we treat -# messaging server as a service, which it really isn't for multi host -QPID_HOST=${QPID_HOST:-} - +RABBIT_USERID=${RABBIT_USERID:-stackrabbit} +if is_service_enabled rabbit; then + RABBIT_HOST=${RABBIT_HOST:-$SERVICE_HOST} +fi # Functions # --------- -# Make sure we only have one rpc backend enabled. -# Also check the specified rpc backend is available on your platform. -function check_rpc_backend { - local c svc - - local rpc_needed=1 - # We rely on the fact that filenames in lib/* match the service names - # that can be passed as arguments to is_service_enabled. - # We check for a call to iniset_rpc_backend in these files, meaning - # the service needs a backend. - rpc_candidates=$(grep -rl iniset_rpc_backend $TOP_DIR/lib/ | awk -F/ '{print $NF}') - for c in ${rpc_candidates}; do - if is_service_enabled $c; then - rpc_needed=0 - break - fi - done - local rpc_backend_cnt=0 - for svc in qpid zeromq rabbit; do - is_service_enabled $svc && - (( rpc_backend_cnt++ )) || true - done - if [ "$rpc_backend_cnt" -gt 1 ]; then - echo "ERROR: only one rpc backend may be enabled," - echo " set only one of 'rabbit', 'qpid', 'zeromq'" - echo " via ENABLED_SERVICES." - elif [ "$rpc_backend_cnt" == 0 ] && [ "$rpc_needed" == 0 ]; then - echo "ERROR: at least one rpc backend must be enabled," - echo " set one of 'rabbit', 'qpid', 'zeromq'" - echo " via ENABLED_SERVICES." - fi - - if is_service_enabled qpid && ! qpid_is_supported; then - die $LINENO "Qpid support is not available for this version of your distribution." - fi -} - # clean up after rpc backend - eradicate all traces so changing backends # produces a clean switch function cleanup_rpc_backend { @@ -79,110 +44,30 @@ function cleanup_rpc_backend { # And the Erlang runtime too apt_get purge -y erlang* fi - elif is_service_enabled qpid; then - if is_fedora; then - uninstall_package qpid-cpp-server - elif is_ubuntu; then - uninstall_package qpidd - else - exit_distro_not_supported "qpid installation" - fi - elif is_service_enabled zeromq; then - if is_fedora; then - uninstall_package zeromq python-zmq - if [ "$ZEROMQ_MATCHMAKER" == "redis" ]; then - uninstall_package redis python-redis - fi - elif is_ubuntu; then - uninstall_package libzmq1 python-zmq - if [ "$ZEROMQ_MATCHMAKER" == "redis" ]; then - uninstall_package redis-server python-redis - fi - elif is_suse; then - uninstall_package libzmq1 python-pyzmq - if [ "$ZEROMQ_MATCHMAKER" == "redis" ]; then - uninstall_package redis python-redis - fi - else - exit_distro_not_supported "zeromq installation" - fi - fi - - # Remove the AMQP 1.0 messaging libraries - if [ "$RPC_MESSAGING_PROTOCOL" == "AMQP1" ]; then - if is_fedora; then - uninstall_package qpid-proton-c-devel - uninstall_package python-qpid-proton - fi - # TODO(kgiusti) ubuntu cleanup fi } # install rpc backend function install_rpc_backend { - # Regardless of the broker used, if AMQP 1.0 is configured load - # the necessary messaging client libraries for oslo.messaging - if [ "$RPC_MESSAGING_PROTOCOL" == "AMQP1" ]; then - if is_fedora; then - install_package qpid-proton-c-devel - install_package python-qpid-proton - elif is_ubuntu; then - # TODO(kgiusti) The QPID AMQP 1.0 protocol libraries - # are not yet in the ubuntu repos. Enable these installs - # once they are present: - #install_package libqpid-proton2-dev - #install_package python-qpid-proton - # Also add 'uninstall' directives in cleanup_rpc_backend()! - exit_distro_not_supported "QPID AMQP 1.0 Proton libraries" - else - exit_distro_not_supported "QPID AMQP 1.0 Proton libraries" - fi - # Install pyngus client API - # TODO(kgiusti) can remove once python qpid bindings are - # available on all supported platforms _and_ pyngus is added - # to the requirements.txt file in oslo.messaging - pip_install_gr pyngus - fi - if is_service_enabled rabbit; then # Install rabbitmq-server install_package rabbitmq-server - elif is_service_enabled qpid; then - if is_fedora; then - install_package qpid-cpp-server - elif is_ubuntu; then - install_package qpidd - else - exit_distro_not_supported "qpid installation" + if is_suse; then + install_package rabbitmq-server-plugins + # the default systemd socket activation only listens on the loopback interface + # which causes rabbitmq to try to start its own epmd + sudo mkdir -p /etc/systemd/system/epmd.socket.d + cat </dev/null +[Socket] +ListenStream= +ListenStream=[::]:4369 +EOF + sudo systemctl daemon-reload + sudo systemctl restart epmd.socket epmd.service fi - _configure_qpid - elif is_service_enabled zeromq; then - if is_fedora; then - install_package zeromq python-zmq - if [ "$ZEROMQ_MATCHMAKER" == "redis" ]; then - install_package redis python-redis - fi - elif is_ubuntu; then - install_package libzmq1 python-zmq - if [ "$ZEROMQ_MATCHMAKER" == "redis" ]; then - install_package redis-server python-redis - fi - elif is_suse; then - install_package libzmq1 python-pyzmq - if [ "$ZEROMQ_MATCHMAKER" == "redis" ]; then - install_package redis python-redis - fi - else - exit_distro_not_supported "zeromq installation" + if is_fedora || is_suse; then + sudo systemctl enable rabbitmq-server fi - # Necessary directory for socket location. - sudo mkdir -p /var/run/openstack - sudo chown $STACK_USER /var/run/openstack - fi - - # If using the QPID broker, install the QPID python client API - if is_service_enabled qpid || [ -n "$QPID_HOST" ]; then - install_package python-qpid fi } @@ -194,13 +79,22 @@ function restart_rpc_backend { # NOTE(bnemec): Retry initial rabbitmq configuration to deal with # the fact that sometimes it fails to start properly. # Reference: https://bugzilla.redhat.com/show_bug.cgi?id=1144100 + # NOTE(tonyb): Extend the original retry logic to only restart rabbitmq + # every second time around the loop. + # See: https://bugs.launchpad.net/devstack/+bug/1449056 for details on + # why this is needed. This can bee seen on vivid and Debian unstable + # (May 2015) + # TODO(tonyb): Remove this when Debian and Ubuntu have a fixed systemd + # service file. local i - for i in `seq 10`; do + for i in `seq 20`; do local rc=0 - [[ $i -eq "10" ]] && die $LINENO "Failed to set rabbitmq password" + [[ $i -eq "20" ]] && die $LINENO "Failed to set rabbitmq password" - restart_service rabbitmq-server + if [[ $(( i % 2 )) == "0" ]] ; then + restart_service rabbitmq-server + fi rabbit_setuser "$RABBIT_USERID" "$RABBIT_PASSWORD" || rc=$? if [ $rc -ne 0 ]; then @@ -216,60 +110,51 @@ function restart_rpc_backend { break done - if is_service_enabled n-cell; then - # Add partitioned access for the child cell - if [ -z `sudo rabbitmqctl list_vhosts | grep child_cell` ]; then - sudo rabbitmqctl add_vhost child_cell - sudo rabbitmqctl set_permissions -p child_cell $RABBIT_USERID ".*" ".*" ".*" - fi + # NOTE(frickler): Remove the default guest user + sudo rabbitmqctl delete_user guest || true + fi +} + +# adds a vhost to the rpc backend +function rpc_backend_add_vhost { + local vhost="$1" + if is_service_enabled rabbit; then + if [ -z `sudo rabbitmqctl list_vhosts | grep $vhost` ]; then + sudo rabbitmqctl add_vhost $vhost + sudo rabbitmqctl set_permissions -p $vhost $RABBIT_USERID ".*" ".*" ".*" fi - elif is_service_enabled qpid; then - echo_summary "Starting qpid" - restart_service qpidd + else + echo 'RPC backend does not support vhosts' + return 1 fi } -# builds transport url string +# Returns the address of the RPC backend in URL format. function get_transport_url { - if is_service_enabled qpid || [ -n "$QPID_HOST" ]; then - echo "qpid://$QPID_USERNAME:$QPID_PASSWORD@$QPID_HOST:5672/" - elif is_service_enabled rabbit || { [ -n "$RABBIT_HOST" ] && [ -n "$RABBIT_PASSWORD" ]; }; then - echo "rabbit://$RABBIT_USERID:$RABBIT_PASSWORD@$RABBIT_HOST:5672/" + local virtual_host=$1 + if is_service_enabled rabbit || { [ -n "$RABBIT_HOST" ] && [ -n "$RABBIT_PASSWORD" ]; }; then + echo "rabbit://$RABBIT_USERID:$RABBIT_PASSWORD@$RABBIT_HOST:5672/$virtual_host" + fi +} + +# Returns the address of the Notification backend in URL format. This +# should be used to set the transport_url option in the +# oslo_messaging_notifications group. +function get_notification_url { + local virtual_host=$1 + if is_service_enabled rabbit || { [ -n "$RABBIT_HOST" ] && [ -n "$RABBIT_PASSWORD" ]; }; then + echo "rabbit://$RABBIT_USERID:$RABBIT_PASSWORD@$RABBIT_HOST:5672/$virtual_host" fi } -# iniset cofiguration +# iniset configuration function iniset_rpc_backend { local package=$1 local file=$2 local section=${3:-DEFAULT} - if is_service_enabled zeromq; then - iniset $file $section rpc_backend "zmq" - iniset $file $section rpc_zmq_host `hostname` - if [ "$ZEROMQ_MATCHMAKER" == "redis" ]; then - iniset $file $section rpc_zmq_matchmaker "redis" - MATCHMAKER_REDIS_HOST=${MATCHMAKER_REDIS_HOST:-127.0.0.1} - iniset $file matchmaker_redis host $MATCHMAKER_REDIS_HOST - else - die $LINENO "Other matchmaker drivers not supported" - fi - elif is_service_enabled qpid || [ -n "$QPID_HOST" ]; then - # For Qpid use the 'amqp' oslo.messaging transport when AMQP 1.0 is used - if [ "$RPC_MESSAGING_PROTOCOL" == "AMQP1" ]; then - iniset $file $section rpc_backend "amqp" - else - iniset $file $section rpc_backend "qpid" - fi - iniset $file $section qpid_hostname ${QPID_HOST:-$SERVICE_HOST} - if [ -n "$QPID_USERNAME" ]; then - iniset $file $section qpid_username $QPID_USERNAME - iniset $file $section qpid_password $QPID_PASSWORD - fi - elif is_service_enabled rabbit || { [ -n "$RABBIT_HOST" ] && [ -n "$RABBIT_PASSWORD" ]; }; then - iniset $file $section rpc_backend "rabbit" - iniset $file oslo_messaging_rabbit rabbit_hosts $RABBIT_HOST - iniset $file oslo_messaging_rabbit rabbit_password $RABBIT_PASSWORD - iniset $file oslo_messaging_rabbit rabbit_userid $RABBIT_USERID + local virtual_host=$4 + if is_service_enabled rabbit || { [ -n "$RABBIT_HOST" ] && [ -n "$RABBIT_PASSWORD" ]; }; then + iniset $file $section transport_url $(get_transport_url "$virtual_host") if [ -n "$RABBIT_HEARTBEAT_TIMEOUT_THRESHOLD" ]; then iniset $file oslo_messaging_rabbit heartbeat_timeout_threshold $RABBIT_HEARTBEAT_TIMEOUT_THRESHOLD fi @@ -279,17 +164,6 @@ function iniset_rpc_backend { fi } -# Check if qpid can be used on the current distro. -# qpid_is_supported -function qpid_is_supported { - if [[ -z "$DISTRO" ]]; then - GetDistro - fi - - # Qpid is not in openSUSE - ( ! is_suse ) -} - function rabbit_setuser { local user="$1" pass="$2" found="" out="" out=$(sudo rabbitmqctl list_users) || @@ -305,87 +179,8 @@ function rabbit_setuser { sudo rabbitmqctl set_permissions "$user" ".*" ".*" ".*" } -# Set up the various configuration files used by the qpidd broker -function _configure_qpid { - - # the location of the configuration files have changed since qpidd 0.14 - local qpid_conf_file - if [ -e /etc/qpid/qpidd.conf ]; then - qpid_conf_file=/etc/qpid/qpidd.conf - elif [ -e /etc/qpidd.conf ]; then - qpid_conf_file=/etc/qpidd.conf - else - exit_distro_not_supported "qpidd.conf file not found!" - fi - - # force the ACL file to a known location - local qpid_acl_file=/etc/qpid/qpidd.acl - if [ ! -e $qpid_acl_file ]; then - sudo mkdir -p -m 755 `dirname $qpid_acl_file` - sudo touch $qpid_acl_file - sudo chmod o+r $qpid_acl_file - fi - sudo sed -i.bak '/^acl-file=/d' $qpid_conf_file - echo "acl-file=$qpid_acl_file" | sudo tee --append $qpid_conf_file - - sudo sed -i '/^auth=/d' $qpid_conf_file - if [ -z "$QPID_USERNAME" ]; then - # no QPID user configured, so disable authentication - # and access control - echo "auth=no" | sudo tee --append $qpid_conf_file - cat </dev/null 2>&1; then + # FIXME(dhellmann): Needs to be python3-aware at some point. if [[ ${USE_VENV} = True && -n ${PROJECT_VENV[$service]:-} ]]; then rm -rf ${PROJECT_VENV[$service]} source $TOP_DIR/tools/build_venv.sh ${PROJECT_VENV[$service]} ${ADDITIONAL_VENV_PACKAGES//,/ } @@ -32,5 +33,8 @@ function stack_install_service { if [[ ${USE_VENV} = True && -n ${PROJECT_VENV[$service]:-} ]]; then unset PIP_VIRTUAL_ENV fi + else + echo "No function declared with name 'install_${service}'." + exit 1 fi } diff --git a/lib/swift b/lib/swift index 820042d972..3b3e608e80 100644 --- a/lib/swift +++ b/lib/swift @@ -7,7 +7,7 @@ # # - ``functions`` file # - ``apache`` file -# - ``DEST``, ``SCREEN_NAME``, `SWIFT_HASH` must be defined +# - ``DEST``, `SWIFT_HASH` must be defined # - ``STACK_USER`` must be defined # - ``SWIFT_DATA_DIR`` or ``DATA_DIR`` must be defined # - ``lib/keystone`` file @@ -24,27 +24,38 @@ # - _cleanup_swift_apache_wsgi # Save trace setting -XTRACE=$(set +o | grep xtrace) +_XTRACE_LIB_SWIFT=$(set +o | grep xtrace) set +o xtrace # Defaults # -------- -if is_ssl_enabled_service "s-proxy" || is_service_enabled tls-proxy; then +if is_service_enabled tls-proxy; then SWIFT_SERVICE_PROTOCOL="https" fi # Set up default directories GITDIR["python-swiftclient"]=$DEST/python-swiftclient - SWIFT_DIR=$DEST/swift + +# Swift virtual environment +if [[ ${USE_VENV} = True ]]; then + PROJECT_VENV["swift"]=${SWIFT_DIR}.venv + SWIFT_BIN_DIR=${PROJECT_VENV["swift"]}/bin +else + SWIFT_BIN_DIR=$(get_python_exec_prefix) +fi + SWIFT_AUTH_CACHE_DIR=${SWIFT_AUTH_CACHE_DIR:-/var/cache/swift} SWIFT_APACHE_WSGI_DIR=${SWIFT_APACHE_WSGI_DIR:-/var/www/swift} SWIFT3_DIR=$DEST/swift3 SWIFT_SERVICE_PROTOCOL=${SWIFT_SERVICE_PROTOCOL:-$SERVICE_PROTOCOL} +SWIFT_DEFAULT_BIND_PORT=${SWIFT_DEFAULT_BIND_PORT:-8080} SWIFT_DEFAULT_BIND_PORT_INT=${SWIFT_DEFAULT_BIND_PORT_INT:-8081} +SWIFT_SERVICE_LOCAL_HOST=${SWIFT_SERVICE_LOCAL_HOST:-$SERVICE_LOCAL_HOST} +SWIFT_SERVICE_LISTEN_ADDRESS=${SWIFT_SERVICE_LISTEN_ADDRESS:-$(ipv6_unquote $SERVICE_LISTEN_ADDRESS)} # TODO: add logging to different location. @@ -60,7 +71,7 @@ SWIFT_CONF_DIR=${SWIFT_CONF_DIR:-/etc/swift} if is_service_enabled s-proxy && is_service_enabled swift3; then # If we are using ``swift3``, we can default the S3 port to swift instead # of nova-objectstore - S3_SERVICE_PORT=${S3_SERVICE_PORT:-8080} + S3_SERVICE_PORT=${S3_SERVICE_PORT:-$SWIFT_DEFAULT_BIND_PORT} fi if is_service_enabled g-api; then @@ -68,17 +79,20 @@ if is_service_enabled g-api; then # only 1G we can not upload volume to image. # Increase Swift disk size up to 2G SWIFT_LOOPBACK_DISK_SIZE_DEFAULT=2G + SWIFT_MAX_FILE_SIZE_DEFAULT=1073741824 # 1G else # DevStack will create a loop-back disk formatted as XFS to store the # swift data. Set ``SWIFT_LOOPBACK_DISK_SIZE`` to the disk size in # kilobytes. # Default is 1 gigabyte. SWIFT_LOOPBACK_DISK_SIZE_DEFAULT=1G + SWIFT_MAX_FILE_SIZE_DEFAULT=536870912 # 512M fi # if tempest enabled the default size is 6 Gigabyte. if is_service_enabled tempest; then SWIFT_LOOPBACK_DISK_SIZE_DEFAULT=${SWIFT_LOOPBACK_DISK_SIZE:-6G} + SWIFT_MAX_FILE_SIZE_DEFAULT=5368709122 # Swift default 5G fi SWIFT_LOOPBACK_DISK_SIZE=${SWIFT_LOOPBACK_DISK_SIZE:-$SWIFT_LOOPBACK_DISK_SIZE_DEFAULT} @@ -95,7 +109,7 @@ SWIFT_EXTRAS_MIDDLEWARE_LAST=${SWIFT_EXTRAS_MIDDLEWARE_LAST:-} # the beginning of the pipeline, before authentication middlewares. SWIFT_EXTRAS_MIDDLEWARE_NO_AUTH=${SWIFT_EXTRAS_MIDDLEWARE_NO_AUTH:-crossdomain} -# The ring uses a configurable number of bits from a path’s MD5 hash as +# The ring uses a configurable number of bits from a path's MD5 hash as # a partition index that designates a device. The number of bits kept # from the hash is known as the partition power, and 2 to the partition # power indicates the partition count. Partitioning the full MD5 hash @@ -113,6 +127,11 @@ SWIFT_PARTITION_POWER_SIZE=${SWIFT_PARTITION_POWER_SIZE:-9} SWIFT_REPLICAS=${SWIFT_REPLICAS:-1} SWIFT_REPLICAS_SEQ=$(seq ${SWIFT_REPLICAS}) +# Set ``SWIFT_START_ALL_SERVICES`` to control whether all Swift +# services (including the *-auditor, *-replicator, *-reconstructor, etc. +# daemons) should be started. +SWIFT_START_ALL_SERVICES=$(trueorfalse True SWIFT_START_ALL_SERVICES) + # Set ``SWIFT_LOG_TOKEN_LENGTH`` to configure how many characters of an auth # token should be placed in the logs. When keystone is used with PKI tokens, # the token values can be huge, seemingly larger the 2K, at the least. We @@ -120,17 +139,21 @@ SWIFT_REPLICAS_SEQ=$(seq ${SWIFT_REPLICAS}) # trace through the logs when looking for its use. SWIFT_LOG_TOKEN_LENGTH=${SWIFT_LOG_TOKEN_LENGTH:-12} -# Set ``SWIFT_MAX_HEADER_SIZE`` to configure the maximun length of headers in +# Set ``SWIFT_MAX_HEADER_SIZE`` to configure the maximum length of headers in # Swift API SWIFT_MAX_HEADER_SIZE=${SWIFT_MAX_HEADER_SIZE:-16384} +# Set ``SWIFT_MAX_FILE_SIZE`` to configure the maximum file size in Swift API +# Default 500MB because the loopback file used for swift could be 1 or 2 GB +SWIFT_MAX_FILE_SIZE=${SWIFT_MAX_FILE_SIZE:-$SWIFT_MAX_FILE_SIZE_DEFAULT} + # Set ``OBJECT_PORT_BASE``, ``CONTAINER_PORT_BASE``, ``ACCOUNT_PORT_BASE`` -# Port bases used in port number calclution for the service "nodes" -# The specified port number will be used, the additinal ports calculated by +# Port bases used in port number calculation for the service "nodes" +# The specified port number will be used, the additional ports calculated by # base_port + node_num * 10 -OBJECT_PORT_BASE=${OBJECT_PORT_BASE:-6013} -CONTAINER_PORT_BASE=${CONTAINER_PORT_BASE:-6011} -ACCOUNT_PORT_BASE=${ACCOUNT_PORT_BASE:-6012} +OBJECT_PORT_BASE=${OBJECT_PORT_BASE:-6613} +CONTAINER_PORT_BASE=${CONTAINER_PORT_BASE:-6611} +ACCOUNT_PORT_BASE=${ACCOUNT_PORT_BASE:-6612} # Enable tempurl feature SWIFT_ENABLE_TEMPURLS=${SWIFT_ENABLE_TEMPURLS:-False} @@ -139,8 +162,9 @@ SWIFT_TEMPURL_KEY=${SWIFT_TEMPURL_KEY:-} # Toggle for deploying Swift under HTTPD + mod_wsgi SWIFT_USE_MOD_WSGI=${SWIFT_USE_MOD_WSGI:-False} -# Tell Tempest this project is present -TEMPEST_SERVICES+=,swift +# A space-separated list of storage node IPs that +# should be used to create the Swift rings +SWIFT_STORAGE_IPS=${SWIFT_STORAGE_IPS:-} # Functions @@ -149,6 +173,7 @@ TEMPEST_SERVICES+=,swift # Test if any Swift services are enabled # is_swift_enabled function is_swift_enabled { + [[ ,${DISABLED_SERVICES} =~ ,"swift" ]] && return 1 [[ ,${ENABLED_SERVICES} =~ ,"s-" ]] && return 0 return 1 } @@ -185,7 +210,7 @@ function _cleanup_swift_apache_wsgi { # _config_swift_apache_wsgi() - Set WSGI config files of Swift function _config_swift_apache_wsgi { sudo mkdir -p ${SWIFT_APACHE_WSGI_DIR} - local proxy_port=${SWIFT_DEFAULT_BIND_PORT:-8080} + local proxy_port=${SWIFT_DEFAULT_BIND_PORT} # copy proxy vhost and wsgi file sudo cp ${SWIFT_DIR}/examples/apache2/proxy-server.template $(apache_site_config_for proxy-server) @@ -207,9 +232,12 @@ function _config_swift_apache_wsgi { # copy apache vhost file and set name and port local node_number for node_number in ${SWIFT_REPLICAS_SEQ}; do - local object_port=$(( OBJECT_PORT_BASE + 10 * (node_number - 1) )) - local container_port=$(( CONTAINER_PORT_BASE + 10 * (node_number - 1) )) - local account_port=$(( ACCOUNT_PORT_BASE + 10 * (node_number - 1) )) + local object_port + object_port=$(( OBJECT_PORT_BASE + 10 * (node_number - 1) )) + local container_port + container_port=$(( CONTAINER_PORT_BASE + 10 * (node_number - 1) )) + local account_port + account_port=$(( ACCOUNT_PORT_BASE + 10 * (node_number - 1) )) sudo cp ${SWIFT_DIR}/examples/apache2/object-server.template $(apache_site_config_for object-server-${node_number}) sudo sed -e " @@ -312,7 +340,7 @@ function configure_swift { local user_group # Make sure to kill all swift processes first - swift-init --run-dir=${SWIFT_DATA_DIR}/run all stop || true + $SWIFT_BIN_DIR/swift-init --run-dir=${SWIFT_DATA_DIR}/run all stop || true sudo install -d -o ${STACK_USER} ${SWIFT_CONF_DIR} sudo install -d -o ${STACK_USER} ${SWIFT_CONF_DIR}/{object,container,account}-server @@ -340,13 +368,14 @@ function configure_swift { SWIFT_CONFIG_PROXY_SERVER=${SWIFT_CONF_DIR}/proxy-server.conf cp ${SWIFT_DIR}/etc/proxy-server.conf-sample ${SWIFT_CONFIG_PROXY_SERVER} + cp ${SWIFT_DIR}/etc/internal-client.conf-sample ${SWIFT_CONF_DIR}/internal-client.conf # To run container sync feature introduced in Swift ver 1.12.0, # container sync "realm" is added in container-sync-realms.conf local csyncfile=${SWIFT_CONF_DIR}/container-sync-realms.conf cp ${SWIFT_DIR}/etc/container-sync-realms.conf-sample ${csyncfile} iniset ${csyncfile} realm1 key realm1key - iniset ${csyncfile} realm1 cluster_name1 "$SWIFT_SERVICE_PROTOCOL://$SERVICE_HOST:8080/v1/" + iniset ${csyncfile} realm1 cluster_name1 "$SWIFT_SERVICE_PROTOCOL://$SERVICE_HOST:$SWIFT_DEFAULT_BIND_PORT/v1/" iniuncomment ${SWIFT_CONFIG_PROXY_SERVER} DEFAULT user iniset ${SWIFT_CONFIG_PROXY_SERVER} DEFAULT user ${STACK_USER} @@ -360,18 +389,14 @@ function configure_swift { iniuncomment ${SWIFT_CONFIG_PROXY_SERVER} DEFAULT log_level iniset ${SWIFT_CONFIG_PROXY_SERVER} DEFAULT log_level DEBUG + iniuncomment ${SWIFT_CONFIG_PROXY_SERVER} DEFAULT bind_ip + iniset ${SWIFT_CONFIG_PROXY_SERVER} DEFAULT bind_ip ${SWIFT_SERVICE_LISTEN_ADDRESS} + iniuncomment ${SWIFT_CONFIG_PROXY_SERVER} DEFAULT bind_port if is_service_enabled tls-proxy; then iniset ${SWIFT_CONFIG_PROXY_SERVER} DEFAULT bind_port ${SWIFT_DEFAULT_BIND_PORT_INT} else - iniset ${SWIFT_CONFIG_PROXY_SERVER} DEFAULT bind_port ${SWIFT_DEFAULT_BIND_PORT:-8080} - fi - - if is_ssl_enabled_service s-proxy; then - ensure_certificates SWIFT - - iniset ${SWIFT_CONFIG_PROXY_SERVER} DEFAULT cert_file "$SWIFT_SSL_CERT" - iniset ${SWIFT_CONFIG_PROXY_SERVER} DEFAULT key_file "$SWIFT_SSL_KEY" + iniset ${SWIFT_CONFIG_PROXY_SERVER} DEFAULT bind_port ${SWIFT_DEFAULT_BIND_PORT} fi # DevStack is commonly run in a small slow environment, so bump the timeouts up. @@ -380,12 +405,15 @@ function configure_swift { iniset ${SWIFT_CONFIG_PROXY_SERVER} app:proxy-server node_timeout 120 iniset ${SWIFT_CONFIG_PROXY_SERVER} app:proxy-server conn_timeout 20 + # Versioned Writes + iniset ${SWIFT_CONFIG_PROXY_SERVER} filter:versioned_writes allow_versioned_writes true + # Configure Ceilometer if is_service_enabled ceilometer; then iniset ${SWIFT_CONFIG_PROXY_SERVER} filter:ceilometer "set log_level" "WARN" iniset ${SWIFT_CONFIG_PROXY_SERVER} filter:ceilometer paste.filter_factory "ceilometermiddleware.swift:filter_factory" iniset ${SWIFT_CONFIG_PROXY_SERVER} filter:ceilometer control_exchange "swift" - iniset ${SWIFT_CONFIG_PROXY_SERVER} filter:ceilometer url $(get_transport_url) + iniset ${SWIFT_CONFIG_PROXY_SERVER} filter:ceilometer url $(get_notification_url) iniset ${SWIFT_CONFIG_PROXY_SERVER} filter:ceilometer driver "messaging" iniset ${SWIFT_CONFIG_PROXY_SERVER} filter:ceilometer topic "notifications" SWIFT_EXTRAS_MIDDLEWARE_LAST="${SWIFT_EXTRAS_MIDDLEWARE_LAST} ceilometer" @@ -411,6 +439,7 @@ function configure_swift { sed -i "/^pipeline/ { s/proxy-server/${SWIFT_EXTRAS_MIDDLEWARE_LAST} proxy-server/ ; }" ${SWIFT_CONFIG_PROXY_SERVER} iniset ${SWIFT_CONFIG_PROXY_SERVER} app:proxy-server account_autocreate true + iniset ${SWIFT_CONFIG_PROXY_SERVER} app:proxy-server allow_account_management true # Configure Crossdomain iniset ${SWIFT_CONFIG_PROXY_SERVER} filter:crossdomain use "egg:swift#crossdomain" @@ -433,89 +462,111 @@ function configure_swift { # out. Make sure we uncomment Tempauth after we uncomment Keystoneauth # otherwise, this code also sets the reseller_prefix for Keystoneauth. iniuncomment ${SWIFT_CONFIG_PROXY_SERVER} filter:tempauth account_autocreate - iniuncomment ${SWIFT_CONFIG_PROXY_SERVER} filter:tempauth reseller_prefix iniset ${SWIFT_CONFIG_PROXY_SERVER} filter:tempauth reseller_prefix "TEMPAUTH" + # Allow both reseller prefixes to be used with domain_remap + iniset ${SWIFT_CONFIG_PROXY_SERVER} filter:domain_remap reseller_prefixes "AUTH, TEMPAUTH" + if is_service_enabled swift3; then cat <>${SWIFT_CONFIG_PROXY_SERVER} [filter:s3token] paste.filter_factory = keystonemiddleware.s3_token:filter_factory -auth_port = ${KEYSTONE_AUTH_PORT} -auth_host = ${KEYSTONE_AUTH_HOST} -auth_protocol = ${KEYSTONE_AUTH_PROTOCOL} +auth_uri = ${KEYSTONE_AUTH_URI} cafile = ${SSL_BUNDLE_FILE} admin_user = swift -admin_tenant_name = ${SERVICE_TENANT_NAME} +admin_tenant_name = ${SERVICE_PROJECT_NAME} admin_password = ${SERVICE_PASSWORD} [filter:swift3] use = egg:swift3#swift3 +location = ${REGION_NAME} EOF fi cp ${SWIFT_DIR}/etc/swift.conf-sample ${SWIFT_CONF_DIR}/swift.conf iniset ${SWIFT_CONF_DIR}/swift.conf swift-hash swift_hash_path_suffix ${SWIFT_HASH} iniset ${SWIFT_CONF_DIR}/swift.conf swift-constraints max_header_size ${SWIFT_MAX_HEADER_SIZE} + iniset ${SWIFT_CONF_DIR}/swift.conf swift-constraints max_file_size ${SWIFT_MAX_FILE_SIZE} local node_number for node_number in ${SWIFT_REPLICAS_SEQ}; do local swift_node_config=${SWIFT_CONF_DIR}/object-server/${node_number}.conf cp ${SWIFT_DIR}/etc/object-server.conf-sample ${swift_node_config} generate_swift_config_services ${swift_node_config} ${node_number} $(( OBJECT_PORT_BASE + 10 * (node_number - 1) )) object + iniuncomment ${swift_node_config} DEFAULT bind_ip + iniset ${swift_node_config} DEFAULT bind_ip ${SWIFT_SERVICE_LISTEN_ADDRESS} iniset ${swift_node_config} filter:recon recon_cache_path ${SWIFT_DATA_DIR}/cache swift_node_config=${SWIFT_CONF_DIR}/container-server/${node_number}.conf cp ${SWIFT_DIR}/etc/container-server.conf-sample ${swift_node_config} generate_swift_config_services ${swift_node_config} ${node_number} $(( CONTAINER_PORT_BASE + 10 * (node_number - 1) )) container - iniuncomment ${swift_node_config} app:container-server allow_versions - iniset ${swift_node_config} app:container-server allow_versions "true" + iniuncomment ${swift_node_config} DEFAULT bind_ip + iniset ${swift_node_config} DEFAULT bind_ip ${SWIFT_SERVICE_LISTEN_ADDRESS} swift_node_config=${SWIFT_CONF_DIR}/account-server/${node_number}.conf cp ${SWIFT_DIR}/etc/account-server.conf-sample ${swift_node_config} generate_swift_config_services ${swift_node_config} ${node_number} $(( ACCOUNT_PORT_BASE + 10 * (node_number - 1) )) account + iniuncomment ${swift_node_config} DEFAULT bind_ip + iniset ${swift_node_config} DEFAULT bind_ip ${SWIFT_SERVICE_LISTEN_ADDRESS} done - # Set new accounts in tempauth to match keystone tenant/user (to make testing easier) - iniset ${SWIFT_CONFIG_PROXY_SERVER} filter:tempauth user_swifttenanttest1_swiftusertest1 "testing .admin" - iniset ${SWIFT_CONFIG_PROXY_SERVER} filter:tempauth user_swifttenanttest2_swiftusertest2 "testing2 .admin" - iniset ${SWIFT_CONFIG_PROXY_SERVER} filter:tempauth user_swifttenanttest1_swiftusertest3 "testing3 .admin" + # Set new accounts in tempauth to match keystone project/user (to make testing easier) + iniset ${SWIFT_CONFIG_PROXY_SERVER} filter:tempauth user_swiftprojecttest1_swiftusertest1 "testing .admin" + iniset ${SWIFT_CONFIG_PROXY_SERVER} filter:tempauth user_swiftprojecttest2_swiftusertest2 "testing2 .admin" + iniset ${SWIFT_CONFIG_PROXY_SERVER} filter:tempauth user_swiftprojecttest1_swiftusertest3 "testing3 .admin" testfile=${SWIFT_CONF_DIR}/test.conf cp ${SWIFT_DIR}/test/sample.conf ${testfile} # Set accounts for functional tests - iniset ${testfile} func_test account swifttenanttest1 + iniset ${testfile} func_test account swiftprojecttest1 iniset ${testfile} func_test username swiftusertest1 iniset ${testfile} func_test username3 swiftusertest3 - iniset ${testfile} func_test account2 swifttenanttest2 + iniset ${testfile} func_test account2 swiftprojecttest2 iniset ${testfile} func_test username2 swiftusertest2 - iniset ${testfile} func_test account4 swifttenanttest4 + iniset ${testfile} func_test account4 swiftprojecttest4 iniset ${testfile} func_test username4 swiftusertest4 iniset ${testfile} func_test password4 testing4 iniset ${testfile} func_test domain4 swift_test if is_service_enabled keystone; then iniuncomment ${testfile} func_test auth_version - local auth_vers=$(iniget ${testfile} func_test auth_version) + local auth_vers + auth_vers=$(iniget ${testfile} func_test auth_version) iniset ${testfile} func_test auth_host ${KEYSTONE_SERVICE_HOST} - iniset ${testfile} func_test auth_port ${KEYSTONE_AUTH_PORT} - if [[ $auth_vers == "3" ]]; then - iniset ${testfile} func_test auth_prefix /v3/ + if [[ "$KEYSTONE_AUTH_PROTOCOL" == "https" ]]; then + iniset ${testfile} func_test auth_port 443 + else + iniset ${testfile} func_test auth_port 80 + fi + iniset ${testfile} func_test auth_uri ${KEYSTONE_AUTH_URI} + if [[ "$auth_vers" == "3" ]]; then + iniset ${testfile} func_test auth_prefix /identity/v3/ else - iniset ${testfile} func_test auth_prefix /v2.0/ + iniset ${testfile} func_test auth_prefix /identity/v2.0/ + fi + if is_service_enabled tls-proxy; then + iniset ${testfile} func_test cafile ${SSL_BUNDLE_FILE} + iniset ${testfile} func_test web_front_end apache2 fi fi - local user_group=$(id -g ${STACK_USER}) + local user_group + user_group=$(id -g ${STACK_USER}) sudo install -d -o ${STACK_USER} -g ${user_group} ${SWIFT_DATA_DIR} local swift_log_dir=${SWIFT_DATA_DIR}/logs sudo rm -rf ${swift_log_dir} - sudo install -d -o ${STACK_USER} -g adm ${swift_log_dir}/hourly + local swift_log_group=adm + if is_suse; then + swift_log_group=root + fi + sudo install -d -o ${STACK_USER} -g ${swift_log_group} ${swift_log_dir}/hourly if [[ $SYSLOG != "False" ]]; then sed "s,%SWIFT_LOGDIR%,${swift_log_dir}," $FILES/swift/rsyslog.conf | sudo \ tee /etc/rsyslog.d/10-swift.conf + echo "MaxMessageSize 6k" | sudo tee /etc/rsyslog.d/99-maxsize.conf # restart syslog to take the changes sudo killall -HUP rsyslogd fi @@ -532,7 +583,8 @@ function create_swift_disk { # First do a bit of setup by creating the directories and # changing the permissions so we can run it as our user. - local user_group=$(id -g ${STACK_USER}) + local user_group + user_group=$(id -g ${STACK_USER}) sudo install -d -o ${STACK_USER} -g ${user_group} ${SWIFT_DATA_DIR}/{drives,cache,run,logs} # Create a loopback disk and format it to XFS. @@ -563,15 +615,13 @@ function create_swift_disk { # create all of the directories needed to emulate a few different servers local node_number for node_number in ${SWIFT_REPLICAS_SEQ}; do - sudo ln -sf ${SWIFT_DATA_DIR}/drives/sdb1/$node_number ${SWIFT_DATA_DIR}/$node_number; - local drive=${SWIFT_DATA_DIR}/drives/sdb1/${node_number} - local node=${SWIFT_DATA_DIR}/${node_number}/node - local node_device=${node}/sdb1 - [[ -d $node ]] && continue - [[ -d $drive ]] && continue - sudo install -o ${STACK_USER} -g $user_group -d $drive - sudo install -o ${STACK_USER} -g $user_group -d $node_device - sudo chown -R ${STACK_USER}: ${node} + # node_devices must match *.conf devices option + local node_devices=${SWIFT_DATA_DIR}/${node_number} + local real_devices=${SWIFT_DATA_DIR}/drives/sdb1/$node_number + sudo ln -sf $real_devices $node_devices; + local device=${real_devices}/sdb1 + [[ -d $device ]] && continue + sudo install -o ${STACK_USER} -g $user_group -d $device done } @@ -580,13 +630,13 @@ function create_swift_disk { # since we want to make it compatible with tempauth which use # underscores for separators. -# Tenant User Roles Domain -# ------------------------------------------------------------------ -# service swift service default -# swifttenanttest1 swiftusertest1 admin default -# swifttenanttest1 swiftusertest3 anotherrole default -# swifttenanttest2 swiftusertest2 admin default -# swifttenanttest4 swiftusertest4 admin swift_test +# Project User Roles Domain +# ------------------------------------------------------------------- +# service swift service default +# swiftprojecttest1 swiftusertest1 admin default +# swiftprojecttest1 swiftusertest3 anotherrole default +# swiftprojecttest2 swiftusertest2 admin default +# swiftprojecttest4 swiftusertest4 admin swift_test function create_swift_accounts { # Defines specific passwords used by ``tools/create_userrc.sh`` @@ -597,58 +647,64 @@ function create_swift_accounts { export swiftusertest3_password=testing3 export swiftusertest4_password=testing4 - KEYSTONE_CATALOG_BACKEND=${KEYSTONE_CATALOG_BACKEND:-sql} - - local another_role=$(openstack role list | awk "/ anotherrole / { print \$2 }") + local another_role + another_role=$(get_or_create_role "anotherrole") # NOTE(jroll): Swift doesn't need the admin role here, however Ironic uses # temp urls, which break when uploaded by a non-admin role create_service_user "swift" "admin" - if [[ "$KEYSTONE_CATALOG_BACKEND" = 'sql' ]]; then - - local swift_service=$(get_or_create_service "swift" \ - "object-store" "Swift Service") - get_or_create_endpoint $swift_service \ - "$REGION_NAME" \ - "$SWIFT_SERVICE_PROTOCOL://$SERVICE_HOST:8080/v1/AUTH_\$(tenant_id)s" \ - "$SWIFT_SERVICE_PROTOCOL://$SERVICE_HOST:8080" \ - "$SWIFT_SERVICE_PROTOCOL://$SERVICE_HOST:8080/v1/AUTH_\$(tenant_id)s" - fi - - local swift_tenant_test1=$(get_or_create_project swifttenanttest1) - die_if_not_set $LINENO swift_tenant_test1 "Failure creating swift_tenant_test1" - SWIFT_USER_TEST1=$(get_or_create_user swiftusertest1 $swiftusertest1_password "test@example.com") + get_or_create_service "swift" "object-store" "Swift Service" + get_or_create_endpoint \ + "object-store" \ + "$REGION_NAME" \ + "$SWIFT_SERVICE_PROTOCOL://$SERVICE_HOST:$SWIFT_DEFAULT_BIND_PORT/v1/AUTH_\$(project_id)s" \ + "$SWIFT_SERVICE_PROTOCOL://$SERVICE_HOST:$SWIFT_DEFAULT_BIND_PORT" + + local swift_project_test1 + swift_project_test1=$(get_or_create_project swiftprojecttest1 default) + die_if_not_set $LINENO swift_project_test1 "Failure creating swift_project_test1" + SWIFT_USER_TEST1=$(get_or_create_user swiftusertest1 $swiftusertest1_password \ + "default" "test@example.com") die_if_not_set $LINENO SWIFT_USER_TEST1 "Failure creating SWIFT_USER_TEST1" - get_or_add_user_project_role admin $SWIFT_USER_TEST1 $swift_tenant_test1 + get_or_add_user_project_role admin $SWIFT_USER_TEST1 $swift_project_test1 - local swift_user_test3=$(get_or_create_user swiftusertest3 $swiftusertest3_password "test3@example.com") + local swift_user_test3 + swift_user_test3=$(get_or_create_user swiftusertest3 $swiftusertest3_password \ + "default" "test3@example.com") die_if_not_set $LINENO swift_user_test3 "Failure creating swift_user_test3" - get_or_add_user_project_role $another_role $swift_user_test3 $swift_tenant_test1 + get_or_add_user_project_role $another_role $swift_user_test3 $swift_project_test1 - local swift_tenant_test2=$(get_or_create_project swifttenanttest2) - die_if_not_set $LINENO swift_tenant_test2 "Failure creating swift_tenant_test2" + local swift_project_test2 + swift_project_test2=$(get_or_create_project swiftprojecttest2 default) + die_if_not_set $LINENO swift_project_test2 "Failure creating swift_project_test2" - local swift_user_test2=$(get_or_create_user swiftusertest2 $swiftusertest2_password "test2@example.com") + local swift_user_test2 + swift_user_test2=$(get_or_create_user swiftusertest2 $swiftusertest2_password \ + "default" "test2@example.com") die_if_not_set $LINENO swift_user_test2 "Failure creating swift_user_test2" - get_or_add_user_project_role admin $swift_user_test2 $swift_tenant_test2 + get_or_add_user_project_role admin $swift_user_test2 $swift_project_test2 - local swift_domain=$(get_or_create_domain swift_test 'Used for swift functional testing') + local swift_domain + swift_domain=$(get_or_create_domain swift_test 'Used for swift functional testing') die_if_not_set $LINENO swift_domain "Failure creating swift_test domain" - local swift_tenant_test4=$(get_or_create_project swifttenanttest4 $swift_domain) - die_if_not_set $LINENO swift_tenant_test4 "Failure creating swift_tenant_test4" + local swift_project_test4 + swift_project_test4=$(get_or_create_project swiftprojecttest4 $swift_domain) + die_if_not_set $LINENO swift_project_test4 "Failure creating swift_project_test4" - local swift_user_test4=$(get_or_create_user swiftusertest4 $swiftusertest4_password "test4@example.com" $swift_domain) + local swift_user_test4 + swift_user_test4=$(get_or_create_user swiftusertest4 $swiftusertest4_password \ + $swift_domain "test4@example.com") die_if_not_set $LINENO swift_user_test4 "Failure creating swift_user_test4" - get_or_add_user_project_role admin $swift_user_test4 $swift_tenant_test4 + get_or_add_user_project_role admin $swift_user_test4 $swift_project_test4 } # init_swift() - Initialize rings function init_swift { local node_number # Make sure to kill all swift processes first - swift-init --run-dir=${SWIFT_DATA_DIR}/run all stop || true + $SWIFT_BIN_DIR/swift-init --run-dir=${SWIFT_DATA_DIR}/run all stop || true # Forcibly re-create the backing filesystem create_swift_disk @@ -659,18 +715,39 @@ function init_swift { rm -f *.builder *.ring.gz backups/*.builder backups/*.ring.gz - swift-ring-builder object.builder create ${SWIFT_PARTITION_POWER_SIZE} ${SWIFT_REPLICAS} 1 - swift-ring-builder container.builder create ${SWIFT_PARTITION_POWER_SIZE} ${SWIFT_REPLICAS} 1 - swift-ring-builder account.builder create ${SWIFT_PARTITION_POWER_SIZE} ${SWIFT_REPLICAS} 1 + $SWIFT_BIN_DIR/swift-ring-builder object.builder create ${SWIFT_PARTITION_POWER_SIZE} ${SWIFT_REPLICAS} 1 + $SWIFT_BIN_DIR/swift-ring-builder container.builder create ${SWIFT_PARTITION_POWER_SIZE} ${SWIFT_REPLICAS} 1 + $SWIFT_BIN_DIR/swift-ring-builder account.builder create ${SWIFT_PARTITION_POWER_SIZE} ${SWIFT_REPLICAS} 1 + + # The ring will be created on each node, and because the order of + # nodes is identical we can use a seed for rebalancing, making it + # possible to get a ring on each node that uses the same partition + # assignment. + if [[ -n $SWIFT_STORAGE_IPS ]]; then + local node_number + node_number=1 + + for node in ${SWIFT_STORAGE_IPS}; do + $SWIFT_BIN_DIR/swift-ring-builder object.builder add z${node_number}-${node}:${OBJECT_PORT_BASE}/sdb1 1 + $SWIFT_BIN_DIR/swift-ring-builder container.builder add z${node_number}-${node}:${CONTAINER_PORT_BASE}/sdb1 1 + $SWIFT_BIN_DIR/swift-ring-builder account.builder add z${node_number}-${node}:${ACCOUNT_PORT_BASE}/sdb1 1 + let "node_number=node_number+1" + done + + else - for node_number in ${SWIFT_REPLICAS_SEQ}; do - swift-ring-builder object.builder add z${node_number}-127.0.0.1:$(( OBJECT_PORT_BASE + 10 * (node_number - 1) ))/sdb1 1 - swift-ring-builder container.builder add z${node_number}-127.0.0.1:$(( CONTAINER_PORT_BASE + 10 * (node_number - 1) ))/sdb1 1 - swift-ring-builder account.builder add z${node_number}-127.0.0.1:$(( ACCOUNT_PORT_BASE + 10 * (node_number - 1) ))/sdb1 1 - done - swift-ring-builder object.builder rebalance - swift-ring-builder container.builder rebalance - swift-ring-builder account.builder rebalance + for node_number in ${SWIFT_REPLICAS_SEQ}; do + $SWIFT_BIN_DIR/swift-ring-builder object.builder add z${node_number}-${SWIFT_SERVICE_LOCAL_HOST}:$(( OBJECT_PORT_BASE + 10 * (node_number - 1) ))/sdb1 1 + $SWIFT_BIN_DIR/swift-ring-builder container.builder add z${node_number}-${SWIFT_SERVICE_LOCAL_HOST}:$(( CONTAINER_PORT_BASE + 10 * (node_number - 1) ))/sdb1 1 + $SWIFT_BIN_DIR/swift-ring-builder account.builder add z${node_number}-${SWIFT_SERVICE_LOCAL_HOST}:$(( ACCOUNT_PORT_BASE + 10 * (node_number - 1) ))/sdb1 1 + done + fi + + # We use a seed for rebalancing. Doing this allows us to create + # identical rings on multiple nodes if SWIFT_STORAGE_IPS is the same + $SWIFT_BIN_DIR/swift-ring-builder object.builder rebalance 42 + $SWIFT_BIN_DIR/swift-ring-builder container.builder rebalance 42 + $SWIFT_BIN_DIR/swift-ring-builder account.builder rebalance 42 } && popd >/dev/null # Create cache dir @@ -693,7 +770,22 @@ function install_swiftclient { fi } -# start_swift() - Start running processes, including screen +# install_ceilometermiddleware() - Collect source and prepare +# note that this doesn't really have anything to do with ceilometer; +# though ceilometermiddleware has ceilometer in its name as an +# artifact of history, it is not a ceilometer specific tool. It +# simply generates pycadf-based notifications about requests and +# responses on the swift proxy +function install_ceilometermiddleware { + if use_library_from_git "ceilometermiddleware"; then + git_clone_by_name "ceilometermiddleware" + setup_dev_lib "ceilometermiddleware" + else + pip_install_gr ceilometermiddleware + fi +} + +# start_swift() - Start running processes function start_swift { # (re)start memcached to make sure we have a clean memcache. restart_service memcached @@ -708,41 +800,57 @@ function start_swift { fi if [ "$SWIFT_USE_MOD_WSGI" == "True" ]; then + # Apache should serve the "PACO" a.k.a "main" services restart_apache_server - swift-init --run-dir=${SWIFT_DATA_DIR}/run rest start - tail_log s-proxy /var/log/$APACHE_NAME/proxy-server - if [[ ${SWIFT_REPLICAS} == 1 ]]; then - for type in object container account; do - tail_log s-${type} /var/log/$APACHE_NAME/${type}-server-1 - done - fi + # The rest of the services should be started in backgroud + $SWIFT_BIN_DIR/swift-init --run-dir=${SWIFT_DATA_DIR}/run rest start return 0 fi - # By default with only one replica we are launching the proxy, - # container, account and object server in screen in foreground and - # other services in background. If we have ``SWIFT_REPLICAS`` set to something - # greater than one we first spawn all the Swift services then kill the proxy - # service so we can run it in foreground in screen. ``swift-init ... - # {stop|restart}`` exits with '1' if no servers are running, ignore it just - # in case - local todo type - swift-init --run-dir=${SWIFT_DATA_DIR}/run all restart || true + + # By default with only one replica we are launching the proxy, container + # account and object server in screen in foreground. Then, the rest of + # the services is optionally started. + # + # If we have ``SWIFT_REPLICAS`` set to something greater than one + # we first spawn *all* the Swift services then kill the proxy service + # so we can run it in foreground in screen. + # + # ``swift-init ... {stop|restart}`` exits with '1' if no servers are + # running, ignore it just in case if [[ ${SWIFT_REPLICAS} == 1 ]]; then - todo="object container account" + local foreground_services type + + foreground_services="object container account" + for type in ${foreground_services}; do + run_process s-${type} "$SWIFT_BIN_DIR/swift-${type}-server ${SWIFT_CONF_DIR}/${type}-server/1.conf -v" + done + + if [[ "$SWIFT_START_ALL_SERVICES" == "True" ]]; then + $SWIFT_BIN_DIR/swift-init --run-dir=${SWIFT_DATA_DIR}/run rest start + else + # The container-sync daemon is strictly needed to pass the container + # sync Tempest tests. + enable_service s-container-sync + run_process s-container-sync "$SWIFT_BIN_DIR/swift-container-sync ${SWIFT_CONF_DIR}/container-server/1.conf" + fi + else + $SWIFT_BIN_DIR/swift-init --run-dir=${SWIFT_DATA_DIR}/run all restart || true + $SWIFT_BIN_DIR/swift-init --run-dir=${SWIFT_DATA_DIR}/run proxy stop || true fi - for type in proxy ${todo}; do - swift-init --run-dir=${SWIFT_DATA_DIR}/run ${type} stop || true - done + if is_service_enabled tls-proxy; then - local proxy_port=${SWIFT_DEFAULT_BIND_PORT:-8080} - start_tls_proxy '*' $proxy_port $SERVICE_HOST $SWIFT_DEFAULT_BIND_PORT_INT & + local proxy_port=${SWIFT_DEFAULT_BIND_PORT} + start_tls_proxy swift '*' $proxy_port $SERVICE_HOST $SWIFT_DEFAULT_BIND_PORT_INT $SWIFT_MAX_HEADER_SIZE fi - run_process s-proxy "$SWIFT_DIR/bin/swift-proxy-server ${SWIFT_CONF_DIR}/proxy-server.conf -v" - if [[ ${SWIFT_REPLICAS} == 1 ]]; then - for type in object container account; do - run_process s-${type} "$SWIFT_DIR/bin/swift-${type}-server ${SWIFT_CONF_DIR}/${type}-server/1.conf -v" - done + run_process s-proxy "$SWIFT_BIN_DIR/swift-proxy-server ${SWIFT_CONF_DIR}/proxy-server.conf -v" + + # We also started the storage services, but proxy started last and + # will take the longest to start, so by the time it comes up, we're + # probably fine. + echo "Waiting for swift proxy to start..." + if ! wait_for_service $SERVICE_TIMEOUT $SWIFT_SERVICE_PROTOCOL://$SERVICE_HOST:$SWIFT_DEFAULT_BIND_PORT/info; then + die $LINENO "swift proxy did not start" fi if [[ "$SWIFT_ENABLE_TEMPURLS" == "True" ]]; then @@ -750,17 +858,17 @@ function start_swift { fi } -# stop_swift() - Stop running processes (non-screen) +# stop_swift() - Stop running processes function stop_swift { local type if [ "$SWIFT_USE_MOD_WSGI" == "True" ]; then - swift-init --run-dir=${SWIFT_DATA_DIR}/run rest stop && return 0 + $SWIFT_BIN_DIR/swift-init --run-dir=${SWIFT_DATA_DIR}/run rest stop && return 0 fi # screen normally killed by ``unstack.sh`` - if type -p swift-init >/dev/null; then - swift-init --run-dir=${SWIFT_DATA_DIR}/run all stop || true + if type -p $SWIFT_BIN_DIR/swift-init >/dev/null; then + $SWIFT_BIN_DIR/swift-init --run-dir=${SWIFT_DATA_DIR}/run all stop || true fi # Dump all of the servers # Maintain the iteration as stop_process() has some desirable side-effects @@ -768,18 +876,22 @@ function stop_swift { stop_process s-${type} done # Blast out any stragglers - pkill -f swift- + pkill -f swift- || true } function swift_configure_tempurls { + # note we are using swift credentials! OS_USERNAME=swift \ - OS_TENANT_NAME=$SERVICE_TENANT_NAME \ - OS_PASSWORD=$SERVICE_PASSWORD \ - swift post -m "Temp-URL-Key: $SWIFT_TEMPURL_KEY" + OS_PASSWORD=$SERVICE_PASSWORD \ + OS_USER_DOMAIN_NAME=$SERVICE_DOMAIN_NAME \ + OS_PROJECT_NAME=$SERVICE_PROJECT_NAME \ + OS_PROJECT_DOMAIN_NAME=$SERVICE_DOMAIN_NAME \ + openstack object store account \ + set --property "Temp-URL-Key=$SWIFT_TEMPURL_KEY" } # Restore xtrace -$XTRACE +$_XTRACE_LIB_SWIFT # Tell emacs to use shell-script-mode ## Local variables: diff --git a/lib/tempest b/lib/tempest index 9c227167d8..fba8826a2d 100644 --- a/lib/tempest +++ b/lib/tempest @@ -11,34 +11,32 @@ # - ``DEST``, ``FILES`` # - ``ADMIN_PASSWORD`` # - ``DEFAULT_IMAGE_NAME`` +# - ``DEFAULT_IMAGE_FILE_NAME`` # - ``S3_SERVICE_PORT`` # - ``SERVICE_HOST`` # - ``BASE_SQL_CONN`` ``lib/database`` declares # - ``PUBLIC_NETWORK_NAME`` -# - ``Q_USE_NAMESPACE`` -# - ``Q_ROUTER_NAME`` -# - ``Q_L3_ENABLED`` # - ``VIRT_DRIVER`` # - ``LIBVIRT_TYPE`` -# - ``KEYSTONE_SERVICE_PROTOCOL``, ``KEYSTONE_SERVICE_HOST`` from lib/keystone +# - ``KEYSTONE_SERVICE_URI``, ``KEYSTONE_SERVICE_URI_V3`` from lib/keystone # # Optional Dependencies: # -# - ``ALT_*`` (similar vars exists in keystone_data.sh) +# - ``ALT_*`` # - ``LIVE_MIGRATION_AVAILABLE`` # - ``USE_BLOCK_MIGRATION_FOR_LIVE_MIGRATION`` # - ``DEFAULT_INSTANCE_TYPE`` # - ``DEFAULT_INSTANCE_USER`` # - ``CINDER_ENABLED_BACKENDS`` +# - ``NOVA_ALLOW_DUPLICATE_NETWORKS`` # # ``stack.sh`` calls the entry points in this order: # # - install_tempest # - configure_tempest -# - init_tempest # Save trace setting -XTRACE=$(set +o | grep xtrace) +_XTRACE_TEMPEST=$(set +o | grep xtrace) set +o xtrace @@ -46,17 +44,11 @@ set +o xtrace # -------- # Set up default directories -GITDIR["tempest-lib"]=$DEST/tempest-lib - TEMPEST_DIR=$DEST/tempest TEMPEST_CONFIG_DIR=${TEMPEST_CONFIG_DIR:-$TEMPEST_DIR/etc} TEMPEST_CONFIG=$TEMPEST_CONFIG_DIR/tempest.conf TEMPEST_STATE_PATH=${TEMPEST_STATE_PATH:=$DATA_DIR/tempest} -NOVA_SOURCE_DIR=$DEST/nova - -BUILD_INTERVAL=1 - # This is the timeout that tempest will wait for a VM to change state, # spawn, delete, etc. # The default is set to 196 seconds. @@ -67,8 +59,9 @@ BUILD_TIMEOUT=${BUILD_TIMEOUT:-196} # have tempest installed in DevStack by default. INSTALL_TEMPEST=${INSTALL_TEMPEST:-"True"} -BOTO_MATERIALS_PATH="$FILES/images/s3-materials/cirros-${CIRROS_VERSION}" -BOTO_CONF=/etc/boto.cfg +# This variable is passed directly to pip install inside the common tox venv +# that is created +TEMPEST_PLUGINS=${TEMPEST_PLUGINS:-0} # Cinder/Volume variables TEMPEST_VOLUME_DRIVER=${TEMPEST_VOLUME_DRIVER:-default} @@ -81,6 +74,21 @@ TEMPEST_STORAGE_PROTOCOL=${TEMPEST_STORAGE_PROTOCOL:-$TEMPEST_DEFAULT_STORAGE_PR IPV6_ENABLED=$(trueorfalse True IPV6_ENABLED) IPV6_SUBNET_ATTRIBUTES_ENABLED=$(trueorfalse True IPV6_SUBNET_ATTRIBUTES_ENABLED) +# Do we want to make a configuration where Tempest has admin on +# the cloud. We don't always want to so that we can ensure Tempest +# would work on a public cloud. +TEMPEST_HAS_ADMIN=$(trueorfalse True TEMPEST_HAS_ADMIN) + +# Credential provider configuration option variables +TEMPEST_ALLOW_TENANT_ISOLATION=${TEMPEST_ALLOW_TENANT_ISOLATION:-$TEMPEST_HAS_ADMIN} +TEMPEST_USE_TEST_ACCOUNTS=$(trueorfalse False TEMPEST_USE_TEST_ACCOUNTS) + +# The number of workers tempest is expected to be run with. This is used for +# generating a accounts.yaml for running with test-accounts. This is also the +# same variable that devstack-gate uses to specify the number of workers that +# it will run tempest with +TEMPEST_CONCURRENCY=${TEMPEST_CONCURRENCY:-$(nproc)} + # Functions # --------- @@ -91,10 +99,7 @@ function remove_disabled_extensions { local extensions_list=$1 shift local disabled_exts=$* - for ext_to_remove in ${disabled_exts//,/ } ; do - extensions_list=${extensions_list/$ext_to_remove","} - done - echo $extensions_list + remove_disabled_services "$extensions_list" "$disabled_exts" } # configure_tempest() - Set config files, create data dirs, etc @@ -106,10 +111,6 @@ function configure_tempest { pip_install_gr testrepository fi - # Used during configuration so make sure we have the correct - # version installed - pip_install_gr python-openstackclient - local image_lines local images local num_images @@ -123,9 +124,7 @@ function configure_tempest { local flavor_lines local public_network_id local public_router_id - local tenant_networks_reachable - local boto_instance_type="m1.tiny" - local ssh_connect_method="fixed" + local ssh_connect_method="floating" # Save IFS ifs=$IFS @@ -147,9 +146,7 @@ function configure_tempest { image_uuid_alt="$IMAGE_UUID" fi images+=($IMAGE_UUID) - # TODO(stevemar): update this command to use openstackclient's `openstack image list` - # when it supports listing by status. - done < <(glance image-list --status=active | awk -F'|' '!/^(+--)|ID|aki|ari/ { print $3,$2 }') + done < <(openstack image list --property status=active | awk -F'|' '!/^(+--)|ID|aki|ari/ { print $3,$2 }') case "${#images[*]}" in 0) @@ -171,63 +168,45 @@ function configure_tempest { esac fi - # Create ``tempest.conf`` from ``tempest.conf.sample`` - # Copy every time because the image UUIDS are going to change + # (Re)create ``tempest.conf`` + # Create every time because the image UUIDS are going to change sudo install -d -o $STACK_USER $TEMPEST_CONFIG_DIR - install -m 644 $TEMPEST_DIR/etc/tempest.conf.sample $TEMPEST_CONFIG + rm -f $TEMPEST_CONFIG - password=${ADMIN_PASSWORD:-secrete} - - # Do we want to make a configuration where Tempest has admin on - # the cloud. We don't always want to so that we can ensure Tempest - # would work on a public cloud. - TEMPEST_HAS_ADMIN=$(trueorfalse True TEMPEST_HAS_ADMIN) + local password=${ADMIN_PASSWORD:-secret} # See ``lib/keystone`` where these users and tenants are set up - ADMIN_USERNAME=${ADMIN_USERNAME:-admin} - ADMIN_TENANT_NAME=${ADMIN_TENANT_NAME:-admin} - ADMIN_DOMAIN_NAME=${ADMIN_DOMAIN_NAME:-Default} - TEMPEST_USERNAME=${TEMPEST_USERNAME:-demo} - TEMPEST_TENANT_NAME=${TEMPEST_TENANT_NAME:-demo} - ALT_USERNAME=${ALT_USERNAME:-alt_demo} - ALT_TENANT_NAME=${ALT_TENANT_NAME:-alt_demo} - ADMIN_TENANT_ID=$(openstack project list | awk "/ admin / { print \$2 }") + local admin_username=${ADMIN_USERNAME:-admin} + local admin_project_name=${ADMIN_TENANT_NAME:-admin} + local admin_domain_name=${ADMIN_DOMAIN_NAME:-Default} + local alt_username=${ALT_USERNAME:-alt_demo} + local alt_project_name=${ALT_TENANT_NAME:-alt_demo} + local admin_project_id + admin_project_id=$(openstack project list | awk "/ admin / { print \$2 }") if is_service_enabled nova; then # If ``DEFAULT_INSTANCE_TYPE`` is not declared, use the new behavior # Tempest creates its own instance types + available_flavors=$(nova flavor-list) if [[ -z "$DEFAULT_INSTANCE_TYPE" ]]; then - available_flavors=$(nova flavor-list) if [[ ! ( $available_flavors =~ 'm1.nano' ) ]]; then - if is_arch "ppc64"; then - # Qemu needs at least 128MB of memory to boot on ppc64 - nova flavor-create m1.nano 42 128 0 1 - else - nova flavor-create m1.nano 42 64 0 1 - fi + openstack flavor create --id 42 --ram 64 --disk 0 --vcpus 1 m1.nano fi flavor_ref=42 - boto_instance_type=m1.nano if [[ ! ( $available_flavors =~ 'm1.micro' ) ]]; then - if is_arch "ppc64"; then - nova flavor-create m1.micro 84 256 0 1 - else - nova flavor-create m1.micro 84 128 0 1 - fi + openstack flavor create --id 84 --ram 128 --disk 0 --vcpus 1 m1.micro fi flavor_ref_alt=84 else # Check Nova for existing flavors, if ``DEFAULT_INSTANCE_TYPE`` is set use it. - boto_instance_type=$DEFAULT_INSTANCE_TYPE - flavor_lines=`nova flavor-list` IFS=$'\r\n' flavors="" - for line in $flavor_lines; do + for line in $available_flavors; do f=$(echo $line | awk "/ $DEFAULT_INSTANCE_TYPE / { print \$2 }") flavors="$flavors $f" done - for line in $flavor_lines; do + for line in $available_flavors; do flavors="$flavors `echo $line | grep -v "^\(|\s*ID\|+--\)" | cut -d' ' -f2`" done @@ -245,7 +224,7 @@ function configure_tempest { # Ensure ``flavor_ref`` and ``flavor_ref_alt`` have different values. # Some resize instance in tempest tests depends on this. for f in ${flavors[@]:1}; do - if [[ $f -ne $flavor_ref ]]; then + if [[ "$f" != "$flavor_ref" ]]; then flavor_ref_alt=$f break fi @@ -253,35 +232,16 @@ function configure_tempest { fi fi - if [ "$Q_USE_NAMESPACE" != "False" ]; then - tenant_networks_reachable=false - if ! is_service_enabled n-net; then - ssh_connect_method="floating" - fi - else - tenant_networks_reachable=true - fi + iniset $TEMPEST_CONFIG network project_network_cidr $FIXED_RANGE ssh_connect_method=${TEMPEST_SSH_CONNECT_METHOD:-$ssh_connect_method} - if [ "$Q_L3_ENABLED" = "True" ]; then - public_network_id=$(neutron net-list | grep $PUBLIC_NETWORK_NAME | \ - awk '{print $2}') - if [ "$Q_USE_NAMESPACE" == "False" ]; then - # If namespaces are disabled, DevStack will create a single - # public router that tempest should be configured to use. - public_router_id=$(neutron router-list | awk "/ $Q_ROUTER_NAME / \ - { print \$2 }") - fi - fi - - EC2_URL=$(openstack endpoint show -f value -c publicurl ec2 || true) - if [[ -z $EC2_URL ]]; then - EC2_URL="$EC2_SERVICE_PROTOCOL://$SERVICE_HOST:8773/" - fi - S3_URL=$(openstack endpoint show -f value -c publicurl s3 || true) - if [[ -z $S3_URL ]]; then - S3_URL="http://$SERVICE_HOST:${S3_SERVICE_PORT:-3333}" + # the public network (for floating ip access) is only available + # if the extension is enabled. + # If NEUTRON_CREATE_INITIAL_NETWORKS is not true, there is no network created + # and the public_network_id should not be set. + if [[ "$NEUTRON_CREATE_INITIAL_NETWORKS" == "True" ]] && is_networking_extension_supported 'external-net'; then + public_network_id=$(openstack network show -f value -c id $PUBLIC_NETWORK_NAME) fi iniset $TEMPEST_CONFIG DEFAULT use_syslog $SYSLOG @@ -296,177 +256,251 @@ function configure_tempest { # Timeouts iniset $TEMPEST_CONFIG compute build_timeout $BUILD_TIMEOUT iniset $TEMPEST_CONFIG volume build_timeout $BUILD_TIMEOUT - iniset $TEMPEST_CONFIG boto build_timeout $BUILD_TIMEOUT - iniset $TEMPEST_CONFIG boto http_socket_timeout 5 # Identity - iniset $TEMPEST_CONFIG identity uri "$KEYSTONE_SERVICE_PROTOCOL://$KEYSTONE_SERVICE_HOST:5000/v2.0/" + iniset $TEMPEST_CONFIG identity uri "$KEYSTONE_SERVICE_URI/v2.0/" iniset $TEMPEST_CONFIG identity uri_v3 "$KEYSTONE_SERVICE_URI_V3" - iniset $TEMPEST_CONFIG identity username $TEMPEST_USERNAME - iniset $TEMPEST_CONFIG identity password "$password" - iniset $TEMPEST_CONFIG identity tenant_name $TEMPEST_TENANT_NAME - iniset $TEMPEST_CONFIG identity alt_username $ALT_USERNAME - iniset $TEMPEST_CONFIG identity alt_password "$password" - iniset $TEMPEST_CONFIG identity alt_tenant_name $ALT_TENANT_NAME + iniset $TEMPEST_CONFIG identity user_lockout_failure_attempts $KEYSTONE_LOCKOUT_FAILURE_ATTEMPTS + iniset $TEMPEST_CONFIG identity user_lockout_duration $KEYSTONE_LOCKOUT_DURATION + iniset $TEMPEST_CONFIG identity user_unique_last_password_count $KEYSTONE_UNIQUE_LAST_PASSWORD_COUNT + # Use domain scoped tokens for admin v3 tests, v3 dynamic credentials of v3 account generation + iniset $TEMPEST_CONFIG identity admin_domain_scope True if [[ "$TEMPEST_HAS_ADMIN" == "True" ]]; then - iniset $TEMPEST_CONFIG identity admin_username $ADMIN_USERNAME - iniset $TEMPEST_CONFIG identity admin_password "$password" - iniset $TEMPEST_CONFIG identity admin_tenant_name $ADMIN_TENANT_NAME - iniset $TEMPEST_CONFIG identity admin_tenant_id $ADMIN_TENANT_ID - iniset $TEMPEST_CONFIG identity admin_domain_name $ADMIN_DOMAIN_NAME - fi - iniset $TEMPEST_CONFIG identity auth_version ${TEMPEST_AUTH_VERSION:-v2} - if is_ssl_enabled_service "key" || is_service_enabled tls-proxy; then + iniset $TEMPEST_CONFIG auth admin_username $admin_username + iniset $TEMPEST_CONFIG auth admin_password "$password" + iniset $TEMPEST_CONFIG auth admin_project_name $admin_project_name + iniset $TEMPEST_CONFIG auth admin_domain_name $admin_domain_name + fi + if [ "$ENABLE_IDENTITY_V2" == "True" ]; then + # Run Identity API v2 tests ONLY if needed + iniset $TEMPEST_CONFIG identity-feature-enabled api_v2 True + else + # Skip Identity API v2 tests by default + iniset $TEMPEST_CONFIG identity-feature-enabled api_v2 False + fi + iniset $TEMPEST_CONFIG identity auth_version ${TEMPEST_AUTH_VERSION:-v3} + if [[ "$TEMPEST_AUTH_VERSION" != "v2" ]]; then + # we're going to disable v2 admin unless we're using v2 by default. + iniset $TEMPEST_CONFIG identity-feature-enabled api_v2_admin False + fi + + if is_service_enabled tls-proxy; then iniset $TEMPEST_CONFIG identity ca_certificates_file $SSL_BUNDLE_FILE fi + # Identity Features + if [[ "$KEYSTONE_SECURITY_COMPLIANCE_ENABLED" = True ]]; then + iniset $TEMPEST_CONFIG identity-feature-enabled security_compliance True + fi + + # When LDAP is enabled domain specific drivers are also enabled and the users + # and groups identity tests must adapt to this scenario + if is_service_enabled ldap; then + iniset $TEMPEST_CONFIG identity-feature-enabled domain_specific_drivers True + fi + + # TODO(felipemonteiro): Remove this once Tempest no longer supports Pike + # as this is supported in Queens and beyond. + iniset $TEMPEST_CONFIG identity-feature-enabled project_tags True + + # In Queens and later, application credentials are enabled by default + # so remove this once Tempest no longer supports Pike. + iniset $TEMPEST_CONFIG identity-feature-enabled application_credentials True + # Image # We want to be able to override this variable in the gate to avoid # doing an external HTTP fetch for this test. if [[ ! -z "$TEMPEST_HTTP_IMAGE" ]]; then iniset $TEMPEST_CONFIG image http_image $TEMPEST_HTTP_IMAGE fi + if [ "$VIRT_DRIVER" = "xenserver" ]; then + iniset $TEMPEST_CONFIG image disk_formats "ami,ari,aki,vhd,raw,iso" + fi - # Auth - TEMPEST_ALLOW_TENANT_ISOLATION=${TEMPEST_ALLOW_TENANT_ISOLATION:-$TEMPEST_HAS_ADMIN} - iniset $TEMPEST_CONFIG auth allow_tenant_isolation ${TEMPEST_ALLOW_TENANT_ISOLATION:-True} - iniset $TEMPEST_CONFIG auth tempest_roles "Member" + # Image Features + if [ "$GLANCE_V1_ENABLED" != "True" ]; then + iniset $TEMPEST_CONFIG image-feature-enabled api_v1 False + fi # Compute - iniset $TEMPEST_CONFIG compute ssh_user ${DEFAULT_INSTANCE_USER:-cirros} # DEPRECATED - iniset $TEMPEST_CONFIG compute network_for_ssh $PRIVATE_NETWORK_NAME - iniset $TEMPEST_CONFIG compute ip_version_for_ssh 4 - iniset $TEMPEST_CONFIG compute ssh_timeout $BUILD_TIMEOUT iniset $TEMPEST_CONFIG compute image_ref $image_uuid - iniset $TEMPEST_CONFIG compute image_ssh_user ${DEFAULT_INSTANCE_USER:-cirros} iniset $TEMPEST_CONFIG compute image_ref_alt $image_uuid_alt - iniset $TEMPEST_CONFIG compute image_alt_ssh_user ${ALT_INSTANCE_USER:-cirros} iniset $TEMPEST_CONFIG compute flavor_ref $flavor_ref iniset $TEMPEST_CONFIG compute flavor_ref_alt $flavor_ref_alt - iniset $TEMPEST_CONFIG compute ssh_connect_method $ssh_connect_method - if ! is_service_enabled n-cell; then + iniset $TEMPEST_CONFIG validation connect_method $ssh_connect_method + if ! is_service_enabled n-cell && ! is_service_enabled neutron; then iniset $TEMPEST_CONFIG compute fixed_network_name $PRIVATE_NETWORK_NAME fi - # Compute Features - # Run ``verify_tempest_config -ur`` to retrieve enabled extensions on API endpoints - # NOTE(mtreinish): This must be done after auth settings are added to the tempest config - local tmp_cfg_file=$(mktemp) - cd $TEMPEST_DIR - tox -revenv -- verify-tempest-config -uro $tmp_cfg_file + # Set the service catalog entry for Tempest to run on. Typically + # used to try different compute API version targets. The tempest + # default if 'compute', which is typically valid, so only set this + # if you want to change it. + if [[ -n "$TEMPEST_COMPUTE_TYPE" ]]; then + iniset $TEMPEST_CONFIG compute catalog_type $TEMPEST_COMPUTE_TYPE + fi - local compute_api_extensions=${COMPUTE_API_EXTENSIONS:-"all"} - if [[ ! -z "$DISABLE_COMPUTE_API_EXTENSIONS" ]]; then - # Enabled extensions are either the ones explicitly specified or those available on the API endpoint - compute_api_extensions=${COMPUTE_API_EXTENSIONS:-$(iniget $tmp_cfg_file compute-feature-enabled api_extensions | tr -d " ")} - # Remove disabled extensions - compute_api_extensions=$(remove_disabled_extensions $compute_api_extensions $DISABLE_COMPUTE_API_EXTENSIONS) + # Compute Features + # Set the microversion range for compute tests. + # This is used to run the Nova microversions tests. + # Setting [None, latest] range of microversion which allow Tempest to run all microversions tests. + # NOTE- To avoid microversion tests failure on stable branch, we need to change "tempest_compute_max_microversion" + # for stable branch on each release which should be changed from "latest" to max supported version of that release. + local tempest_compute_min_microversion=${TEMPEST_COMPUTE_MIN_MICROVERSION:-None} + local tempest_compute_max_microversion=${TEMPEST_COMPUTE_MAX_MICROVERSION:-"latest"} + # Reset microversions to None where v2.0 is running which does not support microversion. + # Both "None" means no microversion testing. + if [[ "$TEMPEST_COMPUTE_TYPE" == "compute_legacy" ]]; then + tempest_compute_min_microversion=None + tempest_compute_max_microversion=None + fi + if [ "$tempest_compute_min_microversion" == "None" ]; then + inicomment $TEMPEST_CONFIG compute min_microversion + else + iniset $TEMPEST_CONFIG compute min_microversion $tempest_compute_min_microversion + fi + if [ "$tempest_compute_max_microversion" == "None" ]; then + inicomment $TEMPEST_CONFIG compute max_microversion + else + iniset $TEMPEST_CONFIG compute max_microversion $tempest_compute_max_microversion fi + iniset $TEMPEST_CONFIG compute-feature-enabled personality ${ENABLE_FILE_INJECTION:-False} iniset $TEMPEST_CONFIG compute-feature-enabled resize True iniset $TEMPEST_CONFIG compute-feature-enabled live_migration ${LIVE_MIGRATION_AVAILABLE:-False} iniset $TEMPEST_CONFIG compute-feature-enabled change_password False iniset $TEMPEST_CONFIG compute-feature-enabled block_migration_for_live_migration ${USE_BLOCK_MIGRATION_FOR_LIVE_MIGRATION:-False} - iniset $TEMPEST_CONFIG compute-feature-enabled api_extensions $compute_api_extensions - # TODO(mriedem): Remove the preserve_ports flag when Juno is end of life. - iniset $TEMPEST_CONFIG compute-feature-enabled preserve_ports True - # TODO(gilliard): Remove the live_migrate_paused_instances flag when Juno is end of life. - iniset $TEMPEST_CONFIG compute-feature-enabled live_migrate_paused_instances True - - # Network - iniset $TEMPEST_CONFIG network api_version 2.0 - iniset $TEMPEST_CONFIG network tenant_networks_reachable "$tenant_networks_reachable" + iniset $TEMPEST_CONFIG compute-feature-enabled live_migrate_back_and_forth ${LIVE_MIGRATE_BACK_AND_FORTH:-False} + iniset $TEMPEST_CONFIG compute-feature-enabled attach_encrypted_volume ${ATTACH_ENCRYPTED_VOLUME_AVAILABLE:-True} + if is_service_enabled n-cell; then + # Cells doesn't support shelving/unshelving + iniset $TEMPEST_CONFIG compute-feature-enabled shelve False + # Cells doesn't support hot-plugging virtual interfaces. + iniset $TEMPEST_CONFIG compute-feature-enabled interface_attach False + # Cells v1 doesn't support the rescue/unrescue tests in Tempest + iniset $TEMPEST_CONFIG compute-feature-enabled rescue False + + if [[ -z "$DEFAULT_INSTANCE_TYPE" ]]; then + # Cells supports resize but does not currently work with devstack + # because of the custom flavors created for Tempest runs which are + # not in the cells database. + # TODO(mriedem): work on adding a nova-manage command to sync + # flavors into the cells database. + iniset $TEMPEST_CONFIG compute-feature-enabled resize False + fi + fi + + if [[ $ENABLE_VOLUME_MULTIATTACH == "True" ]]; then + iniset $TEMPEST_CONFIG compute-feature-enabled volume_multiattach True + fi + + if is_service_enabled n-novnc; then + iniset $TEMPEST_CONFIG compute-feature-enabled vnc_console True + fi + + # Network + iniset $TEMPEST_CONFIG network project_networks_reachable false iniset $TEMPEST_CONFIG network public_network_id "$public_network_id" iniset $TEMPEST_CONFIG network public_router_id "$public_router_id" iniset $TEMPEST_CONFIG network default_network "$FIXED_RANGE" iniset $TEMPEST_CONFIG network-feature-enabled ipv6 "$IPV6_ENABLED" iniset $TEMPEST_CONFIG network-feature-enabled ipv6_subnet_attributes "$IPV6_SUBNET_ATTRIBUTES_ENABLED" - - local network_api_extensions=${NETWORK_API_EXTENSIONS:-"all"} - if [[ ! -z "$DISABLE_NETWORK_API_EXTENSIONS" ]]; then - # Enabled extensions are either the ones explicitly specified or those available on the API endpoint - network_api_extensions=${NETWORK_API_EXTENSIONS:-$(iniget $tmp_cfg_file network-feature-enabled api_extensions | tr -d " ")} - # Remove disabled extensions - network_api_extensions=$(remove_disabled_extensions $network_api_extensions $DISABLE_NETWORK_API_EXTENSIONS) - fi - iniset $TEMPEST_CONFIG network-feature-enabled api_extensions $network_api_extensions - - # boto - iniset $TEMPEST_CONFIG boto ec2_url "$EC2_URL" - iniset $TEMPEST_CONFIG boto s3_url "$S3_URL" - iniset $TEMPEST_CONFIG boto s3_materials_path "$BOTO_MATERIALS_PATH" - iniset $TEMPEST_CONFIG boto ari_manifest cirros-${CIRROS_VERSION}-${CIRROS_ARCH}-initrd.manifest.xml - iniset $TEMPEST_CONFIG boto ami_manifest cirros-${CIRROS_VERSION}-${CIRROS_ARCH}-blank.img.manifest.xml - iniset $TEMPEST_CONFIG boto aki_manifest cirros-${CIRROS_VERSION}-${CIRROS_ARCH}-vmlinuz.manifest.xml - iniset $TEMPEST_CONFIG boto instance_type "$boto_instance_type" - iniset $TEMPEST_CONFIG boto http_socket_timeout 30 - iniset $TEMPEST_CONFIG boto ssh_user ${DEFAULT_INSTANCE_USER:-cirros} - - # Orchestration Tests - if is_service_enabled heat; then - if [[ ! -z "$HEAT_CFN_IMAGE_URL" ]]; then - iniset $TEMPEST_CONFIG orchestration image_ref $(basename "${HEAT_CFN_IMAGE_URL%.*}") - fi - # build a specialized heat flavor - available_flavors=$(nova flavor-list) - if [[ ! ( $available_flavors =~ 'm1.heat' ) ]]; then - nova flavor-create m1.heat 451 512 0 1 - fi - iniset $TEMPEST_CONFIG orchestration instance_type "m1.heat" - iniset $TEMPEST_CONFIG orchestration build_timeout 900 - iniset $TEMPEST_CONFIG orchestration stack_owner_role "_member_" - fi + iniset $TEMPEST_CONFIG network-feature-enabled port_security $NEUTRON_PORT_SECURITY # Scenario - SCENARIO_IMAGE_DIR=${SCENARIO_IMAGE_DIR:-$FILES/images/cirros-${CIRROS_VERSION}-${CIRROS_ARCH}-uec} + if [ "$VIRT_DRIVER" = "xenserver" ]; then + SCENARIO_IMAGE_DIR=${SCENARIO_IMAGE_DIR:-$FILES} + SCENARIO_IMAGE_FILE="cirros-${CIRROS_VERSION}-${CIRROS_ARCH}-disk.vhd.tgz" + iniset $TEMPEST_CONFIG scenario img_disk_format vhd + iniset $TEMPEST_CONFIG scenario img_container_format ovf + else + SCENARIO_IMAGE_DIR=${SCENARIO_IMAGE_DIR:-$FILES} + SCENARIO_IMAGE_FILE=$DEFAULT_IMAGE_FILE_NAME + fi iniset $TEMPEST_CONFIG scenario img_dir $SCENARIO_IMAGE_DIR - iniset $TEMPEST_CONFIG scenario ami_img_file "cirros-${CIRROS_VERSION}-${CIRROS_ARCH}-blank.img" - iniset $TEMPEST_CONFIG scenario ari_img_file "cirros-${CIRROS_VERSION}-${CIRROS_ARCH}-initrd" - iniset $TEMPEST_CONFIG scenario aki_img_file "cirros-${CIRROS_VERSION}-${CIRROS_ARCH}-vmlinuz" - iniset $TEMPEST_CONFIG scenario img_file "cirros-${CIRROS_VERSION}-${CIRROS_ARCH}-disk.img" - - # Large Ops Number - iniset $TEMPEST_CONFIG scenario large_ops_number ${TEMPEST_LARGE_OPS_NUMBER:-0} + iniset $TEMPEST_CONFIG scenario img_file $SCENARIO_IMAGE_FILE - # Telemetry - # Ceilometer API optimization happened in Juno that allows to run more tests in tempest. - # Once Tempest retires support for icehouse this flag can be removed. - iniset $TEMPEST_CONFIG telemetry too_slow_to_test "False" - - # Object Store - local object_storage_api_extensions=${OBJECT_STORAGE_API_EXTENSIONS:-"all"} - if [[ ! -z "$DISABLE_OBJECT_STORAGE_API_EXTENSIONS" ]]; then - # Enabled extensions are either the ones explicitly specified or those available on the API endpoint - object_storage_api_extensions=${OBJECT_STORAGE_API_EXTENSIONS:-$(iniget $tmp_cfg_file object-storage-feature-enabled discoverable_apis | tr -d " ")} - # Remove disabled extensions - object_storage_api_extensions=$(remove_disabled_extensions $object_storage_api_extensions $DISABLE_STORAGE_API_EXTENSIONS) + # If using provider networking, use the physical network for validation rather than private + TEMPEST_SSH_NETWORK_NAME=$PRIVATE_NETWORK_NAME + if is_provider_network; then + TEMPEST_SSH_NETWORK_NAME=$PHYSICAL_NETWORK fi - iniset $TEMPEST_CONFIG object-storage-feature-enabled discoverable_apis $object_storage_api_extensions + # Validation + iniset $TEMPEST_CONFIG validation run_validation ${TEMPEST_RUN_VALIDATION:-True} + iniset $TEMPEST_CONFIG validation ip_version_for_ssh 4 + iniset $TEMPEST_CONFIG validation ssh_timeout $BUILD_TIMEOUT + iniset $TEMPEST_CONFIG validation image_ssh_user ${DEFAULT_INSTANCE_USER:-cirros} + iniset $TEMPEST_CONFIG validation network_for_ssh $TEMPEST_SSH_NETWORK_NAME # Volume - local volume_api_extensions=${VOLUME_API_EXTENSIONS:-"all"} - if [[ ! -z "$DISABLE_VOLUME_API_EXTENSIONS" ]]; then - # Enabled extensions are either the ones explicitly specified or those available on the API endpoint - volume_api_extensions=${VOLUME_API_EXTENSIONS:-$(iniget $tmp_cfg_file volume-feature-enabled api_extensions | tr -d " ")} - # Remove disabled extensions - volume_api_extensions=$(remove_disabled_extensions $volume_api_extensions $DISABLE_VOLUME_API_EXTENSIONS) + # Set the service catalog entry for Tempest to run on. Typically + # used to try different Volume API version targets. The tempest + # default it to 'volumev3'(v3 APIs endpoint) , so only set this + # if you want to change it. + if [[ -n "$TEMPEST_VOLUME_TYPE" ]]; then + iniset $TEMPEST_CONFIG volume catalog_type $TEMPEST_VOLUME_TYPE + fi + # Only turn on TEMPEST_VOLUME_MANAGE_SNAPSHOT by default for "lvm" backends + if [[ "$CINDER_ENABLED_BACKENDS" == *"lvm"* ]]; then + TEMPEST_VOLUME_MANAGE_SNAPSHOT=${TEMPEST_VOLUME_MANAGE_SNAPSHOT:-True} + fi + iniset $TEMPEST_CONFIG volume-feature-enabled manage_snapshot $(trueorfalse False TEMPEST_VOLUME_MANAGE_SNAPSHOT) + # Only turn on TEMPEST_VOLUME_MANAGE_VOLUME by default for "lvm" backends + if [[ "$CINDER_ENABLED_BACKENDS" == *"lvm"* ]]; then + TEMPEST_VOLUME_MANAGE_VOLUME=${TEMPEST_VOLUME_MANAGE_VOLUME:-True} + fi + iniset $TEMPEST_CONFIG volume-feature-enabled manage_volume $(trueorfalse False TEMPEST_VOLUME_MANAGE_VOLUME) + # Only turn on TEMPEST_EXTEND_ATTACHED_VOLUME by default for "lvm" backends + # in Cinder and the libvirt driver in Nova. + if [[ "$CINDER_ENABLED_BACKENDS" == *"lvm"* ]] && [ "$VIRT_DRIVER" = "libvirt" ]; then + TEMPEST_EXTEND_ATTACHED_VOLUME=${TEMPEST_EXTEND_ATTACHED_VOLUME:-True} + fi + iniset $TEMPEST_CONFIG volume-feature-enabled extend_attached_volume $(trueorfalse False TEMPEST_EXTEND_ATTACHED_VOLUME) + local tempest_volume_min_microversion=${TEMPEST_VOLUME_MIN_MICROVERSION:-None} + local tempest_volume_max_microversion=${TEMPEST_VOLUME_MAX_MICROVERSION:-"latest"} + # Reset microversions to None where v2 is running which does not support microversion. + # Both "None" means no microversion testing. + if [[ "$TEMPEST_VOLUME_TYPE" == "volumev2" ]]; then + tempest_volume_min_microversion=None + tempest_volume_max_microversion=None + fi + if [ "$tempest_volume_min_microversion" == "None" ]; then + inicomment $TEMPEST_CONFIG volume min_microversion + else + iniset $TEMPEST_CONFIG volume min_microversion $tempest_volume_min_microversion + fi + + if [ "$tempest_volume_max_microversion" == "None" ]; then + inicomment $TEMPEST_CONFIG volume max_microversion + else + iniset $TEMPEST_CONFIG volume max_microversion $tempest_volume_max_microversion fi - iniset $TEMPEST_CONFIG volume-feature-enabled api_extensions $volume_api_extensions if ! is_service_enabled c-bak; then iniset $TEMPEST_CONFIG volume-feature-enabled backup False fi # Using ``CINDER_ENABLED_BACKENDS`` + # Cinder uses a comma separated list with "type:backend_name": + # CINDER_ENABLED_BACKENDS = ceph:cephBE1,lvm:lvmBE2,foo:my_foo if [[ -n "$CINDER_ENABLED_BACKENDS" ]] && [[ $CINDER_ENABLED_BACKENDS =~ .*,.* ]]; then + # We have at least 2 backends iniset $TEMPEST_CONFIG volume-feature-enabled multi_backend "True" - local i=1 + local add_comma_seperator=0 + local backends_list='' local be + # Tempest uses a comma separated list of backend_names: + # backend_names = BACKEND_1,BACKEND_2 for be in ${CINDER_ENABLED_BACKENDS//,/ }; do - local be_name=${be##*:} - iniset $TEMPEST_CONFIG volume "backend${i}_name" "$be_name" - i=$(( i + 1 )) + if [ "$add_comma_seperator" -eq "1" ]; then + backends_list+=,${be##*:} + else + # first element in the list + backends_list+=${be##*:} + add_comma_seperator=1 + fi done + iniset $TEMPEST_CONFIG volume "backend_names" "$backends_list" fi if [ $TEMPEST_VOLUME_DRIVER != "default" -o \ @@ -478,17 +512,8 @@ function configure_tempest { iniset $TEMPEST_CONFIG volume storage_protocol "$TEMPEST_STORAGE_PROTOCOL" fi - # Dashboard - iniset $TEMPEST_CONFIG dashboard dashboard_url "http://$SERVICE_HOST/" - iniset $TEMPEST_CONFIG dashboard login_url "http://$SERVICE_HOST/auth/login/" - - # CLI - iniset $TEMPEST_CONFIG cli cli_dir $NOVA_BIN_DIR - # Baremetal if [ "$VIRT_DRIVER" = "ironic" ] ; then - iniset $TEMPEST_CONFIG baremetal driver_enabled True - iniset $TEMPEST_CONFIG baremetal unprovision_timeout 300 iniset $TEMPEST_CONFIG compute-feature-enabled change_password False iniset $TEMPEST_CONFIG compute-feature-enabled console_output False iniset $TEMPEST_CONFIG compute-feature-enabled interface_attach False @@ -501,15 +526,29 @@ function configure_tempest { iniset $TEMPEST_CONFIG compute-feature-enabled suspend False fi - # Libvirt-LXC - if [ "$VIRT_DRIVER" = "libvirt" ] && [ "$LIBVIRT_TYPE" = "lxc" ]; then - iniset $TEMPEST_CONFIG compute-feature-enabled rescue False - iniset $TEMPEST_CONFIG compute-feature-enabled resize False - iniset $TEMPEST_CONFIG compute-feature-enabled suspend False + # Libvirt + if [ "$VIRT_DRIVER" = "libvirt" ]; then + # Libvirt-LXC + if [ "$LIBVIRT_TYPE" = "lxc" ]; then + iniset $TEMPEST_CONFIG compute-feature-enabled rescue False + iniset $TEMPEST_CONFIG compute-feature-enabled resize False + iniset $TEMPEST_CONFIG compute-feature-enabled shelve False + iniset $TEMPEST_CONFIG compute-feature-enabled snapshot False + iniset $TEMPEST_CONFIG compute-feature-enabled suspend False + elif ! is_service_enabled n-cell; then + # cells v1 does not support swapping volumes + iniset $TEMPEST_CONFIG compute-feature-enabled swap_volume True + fi fi # ``service_available`` - for service in ${TEMPEST_SERVICES//,/ }; do + # + # this tempest service list needs to be all the services that + # tempest supports, otherwise we can have an erroneous set of + # defaults (something defaulting true in Tempest, but not listed here). + local service + local tempest_services="key,glance,nova,neutron,cinder,swift,heat,ceilometer,horizon,sahara,ironic,trove" + for service in ${tempest_services//,/ }; do if is_service_enabled $service ; then iniset $TEMPEST_CONFIG service_available $service "True" else @@ -517,87 +556,119 @@ function configure_tempest { fi done - if is_ssl_enabled_service "key" || is_service_enabled tls-proxy; then - # Use the ``BOTO_CONFIG`` environment variable to point to this file - iniset $BOTO_CONF Boto ca_certificates_file $SSL_BUNDLE_FILE - sudo chown $STACK_USER $BOTO_CONF + if [ "$VIRT_DRIVER" = "libvirt" ] && [ "$LIBVIRT_TYPE" = "lxc" ]; then + # libvirt-lxc does not support boot from volume or attaching volumes + # so basically anything with cinder is out of the question. + iniset $TEMPEST_CONFIG service_available cinder "False" fi - # Restore IFS - IFS=$ifs -} + # Run tempest configuration utilities. This must be done last during configuration to + # ensure as complete a config as possible already exists -# create_tempest_accounts() - Set up common required tempest accounts + # NOTE(mtreinish): Respect constraints on tempest verify-config venv + local tmp_cfg_file + tmp_cfg_file=$(mktemp) + cd $TEMPEST_DIR + if [[ "$OFFLINE" != "True" ]]; then + tox -revenv-tempest --notest + fi -# Project User Roles -# ------------------------------------------------------------------ -# alt_demo alt_demo Member + # The requirements might be on a different branch, while tempest needs master requirements. + (cd $REQUIREMENTS_DIR && git show origin/master:upper-constraints.txt) > u-c-m.txt + tox -evenv-tempest -- pip install -c u-c-m.txt -r requirements.txt -function create_tempest_accounts { - if is_service_enabled tempest; then - # Tempest has some tests that validate various authorization checks - # between two regular users in separate tenants - get_or_create_project alt_demo - get_or_create_user alt_demo "$ADMIN_PASSWORD" "alt_demo@example.com" - get_or_add_user_project_role Member alt_demo alt_demo + # Auth: + iniset $TEMPEST_CONFIG auth tempest_roles "member" + if [[ $TEMPEST_USE_TEST_ACCOUNTS == "True" ]]; then + if [[ $TEMPEST_HAS_ADMIN == "True" ]]; then + tox -evenv-tempest -- tempest-account-generator -c $TEMPEST_CONFIG --os-username $admin_username --os-password "$password" --os-tenant-name $admin_project_name -r $TEMPEST_CONCURRENCY --with-admin etc/accounts.yaml + else + tox -evenv-tempest -- tempest-account-generator -c $TEMPEST_CONFIG --os-username $admin_username --os-password "$password" --os-tenant-name $admin_project_name -r $TEMPEST_CONCURRENCY etc/accounts.yaml + fi + iniset $TEMPEST_CONFIG auth use_dynamic_credentials False + iniset $TEMPEST_CONFIG auth test_accounts_file "etc/accounts.yaml" + elif [[ $TEMPEST_HAS_ADMIN == "False" ]]; then + iniset $TEMPEST_CONFIG auth use_dynamic_credentials ${TEMPEST_ALLOW_TENANT_ISOLATION:-False} + + else + iniset $TEMPEST_CONFIG auth use_dynamic_credentials ${TEMPEST_ALLOW_TENANT_ISOLATION:-True} fi -} -# install_tempest_lib() - Collect source, prepare, and install ``tempest-lib`` -function install_tempest_lib { - if use_library_from_git "tempest-lib"; then - git_clone_by_name "tempest-lib" - setup_dev_lib "tempest-lib" - # NOTE(mtreinish) For testing ``tempest-lib`` from git with Tempest we need to - # put the git version of ``tempest-lib`` in the Tempest job's tox venv - export PIP_VIRTUAL_ENV=${PROJECT_VENV["tempest"]} - setup_dev_lib "tempest-lib" - unset PIP_VIRTUAL_ENV + # API Extensions + # Run ``verify_tempest_config -ur`` to retrieve enabled extensions on API endpoints + # NOTE(mtreinish): This must be done after auth settings are added to the tempest config + tox -evenv -- tempest verify-config -uro $tmp_cfg_file + + # Neutron API Extensions + + # disable metering if we didn't enable the service + if ! is_service_enabled q-metering; then + DISABLE_NETWORK_API_EXTENSIONS+=", metering" + fi + + # disable l3_agent_scheduler if we didn't enable L3 agent + if ! is_service_enabled q-l3; then + DISABLE_NETWORK_API_EXTENSIONS+=", l3_agent_scheduler" + fi + + local network_api_extensions=${NETWORK_API_EXTENSIONS:-"all"} + if [[ ! -z "$DISABLE_NETWORK_API_EXTENSIONS" ]]; then + # Enabled extensions are either the ones explicitly specified or those available on the API endpoint + network_api_extensions=${NETWORK_API_EXTENSIONS:-$(iniget $tmp_cfg_file network-feature-enabled api_extensions | tr -d " ")} + # Remove disabled extensions + network_api_extensions=$(remove_disabled_extensions $network_api_extensions $DISABLE_NETWORK_API_EXTENSIONS) + fi + iniset $TEMPEST_CONFIG network-feature-enabled api_extensions $network_api_extensions + # Swift API Extensions + local object_storage_api_extensions=${OBJECT_STORAGE_API_EXTENSIONS:-"all"} + if [[ ! -z "$DISABLE_OBJECT_STORAGE_API_EXTENSIONS" ]]; then + # Enabled extensions are either the ones explicitly specified or those available on the API endpoint + object_storage_api_extensions=${OBJECT_STORAGE_API_EXTENSIONS:-$(iniget $tmp_cfg_file object-storage-feature-enabled discoverable_apis | tr -d " ")} + # Remove disabled extensions + object_storage_api_extensions=$(remove_disabled_extensions $object_storage_api_extensions $DISABLE_STORAGE_API_EXTENSIONS) + fi + iniset $TEMPEST_CONFIG object-storage-feature-enabled discoverable_apis $object_storage_api_extensions + # Cinder API Extensions + local volume_api_extensions=${VOLUME_API_EXTENSIONS:-"all"} + if [[ ! -z "$DISABLE_VOLUME_API_EXTENSIONS" ]]; then + # Enabled extensions are either the ones explicitly specified or those available on the API endpoint + volume_api_extensions=${VOLUME_API_EXTENSIONS:-$(iniget $tmp_cfg_file volume-feature-enabled api_extensions | tr -d " ")} + # Remove disabled extensions + volume_api_extensions=$(remove_disabled_extensions $volume_api_extensions $DISABLE_VOLUME_API_EXTENSIONS) fi + iniset $TEMPEST_CONFIG volume-feature-enabled api_extensions $volume_api_extensions + + # Restore IFS + IFS=$ifs } # install_tempest() - Collect source and prepare function install_tempest { git_clone $TEMPEST_REPO $TEMPEST_DIR $TEMPEST_BRANCH - pip_install tox + pip_install 'tox!=2.8.0' pushd $TEMPEST_DIR - tox --notest -efull - PROJECT_VENV["tempest"]=${TEMPEST_DIR}/.tox/full - install_tempest_lib + tox -r --notest -efull + # NOTE(mtreinish) Respect constraints in the tempest full venv, things that + # are using a tox job other than full will not be respecting constraints but + # running pip install -U on tempest requirements + $TEMPEST_DIR/.tox/tempest/bin/pip install -c $REQUIREMENTS_DIR/upper-constraints.txt -r requirements.txt + PROJECT_VENV["tempest"]=${TEMPEST_DIR}/.tox/tempest popd } -# init_tempest() - Initialize EC2 images -function init_tempest { - local base_image_name=cirros-${CIRROS_VERSION}-${CIRROS_ARCH} - # /opt/stack/devstack/files/images/cirros-${CIRROS_VERSION}-${CIRROS_ARCH}-uec - local image_dir="$FILES/images/${base_image_name}-uec" - local kernel="$image_dir/${base_image_name}-vmlinuz" - local ramdisk="$image_dir/${base_image_name}-initrd" - local disk_image="$image_dir/${base_image_name}-blank.img" - if is_service_enabled nova; then - # If the CirrOS uec downloaded and the system is UEC capable - if [ -f "$kernel" -a -f "$ramdisk" -a -f "$disk_image" -a "$VIRT_DRIVER" != "openvz" \ - -a \( "$LIBVIRT_TYPE" != "lxc" -o "$VIRT_DRIVER" != "libvirt" \) ]; then - echo "Prepare aki/ari/ami Images" - mkdir -p $BOTO_MATERIALS_PATH - ( #new namespace - # euca2ools should be installed to call euca-* commands - is_package_installed euca2ools || install_package euca2ools - # tenant:demo ; user: demo - source $TOP_DIR/accrc/demo/demo - euca-bundle-image -r ${CIRROS_ARCH} -i "$kernel" --kernel true -d "$BOTO_MATERIALS_PATH" - euca-bundle-image -r ${CIRROS_ARCH} -i "$ramdisk" --ramdisk true -d "$BOTO_MATERIALS_PATH" - euca-bundle-image -r ${CIRROS_ARCH} -i "$disk_image" -d "$BOTO_MATERIALS_PATH" - ) 2>&1 $tuning_file" << EOF +# worker MPM +# StartServers: initial number of server processes to start +# MinSpareThreads: minimum number of worker threads which are kept spare +# MaxSpareThreads: maximum number of worker threads which are kept spare +# ThreadLimit: ThreadsPerChild can be changed to this maximum value during a +# graceful restart. ThreadLimit can only be changed by stopping +# and starting Apache. +# ThreadsPerChild: constant number of worker threads in each server process +# MaxClients: maximum number of simultaneous client connections +# MaxRequestsPerChild: maximum number of requests a server process serves +# +# We want to be memory thrifty so tune down apache to allow 256 total +# connections. This should still be plenty for a dev env yet lighter than +# apache defaults. + +# Note that the next three conf values must be changed together. +# MaxClients = ServerLimit * ThreadsPerChild +ServerLimit 8 +ThreadsPerChild 32 +MaxClients 256 +StartServers 2 +MinSpareThreads 32 +MaxSpareThreads 96 +ThreadLimit 64 +MaxRequestsPerChild 0 + + +# Note that the next three conf values must be changed together. +# MaxClients = ServerLimit * ThreadsPerChild +ServerLimit 8 +ThreadsPerChild 32 +MaxClients 256 +StartServers 2 +MinSpareThreads 32 +MaxSpareThreads 96 +ThreadLimit 64 +MaxRequestsPerChild 0 + +EOF + restart_apache_server + fi +} + # Starts the TLS proxy for the given IP/ports -# start_tls_proxy front-host front-port back-host back-port +# start_tls_proxy service-name front-host front-port back-host back-port function start_tls_proxy { - local f_host=$1 - local f_port=$2 - local b_host=$3 - local b_port=$4 - - stud $STUD_PROTO -f $f_host,$f_port -b $b_host,$b_port $DEVSTACK_CERT 2>/dev/null + local b_service="$1-tls-proxy" + local f_host=$2 + local f_port=$3 + local b_host=$4 + local b_port=$5 + # 8190 is the default apache size. + local f_header_size=${6:-8190} + + tune_apache_connections + + local config_file + config_file=$(apache_site_config_for $b_service) + local listen_string + # Default apache configs on ubuntu and centos listen on 80 and 443 + # newer apache seems fine with duplicate listen directive but older + # apache does not so special case 80 and 443. + if [[ "$f_port" == "80" ]] || [[ "$f_port" == "443" ]]; then + listen_string="" + elif [[ "$f_host" == '*' ]] ; then + listen_string="Listen $f_port" + else + listen_string="Listen $f_host:$f_port" + fi + sudo bash -c "cat >$config_file" << EOF +$listen_string + + + SSLEngine On + SSLCertificateFile $DEVSTACK_CERT + + # Disable KeepAlive to fix bug #1630664 a.k.a the + # ('Connection aborted.', BadStatusLine("''",)) error + KeepAlive Off + + # This increase in allowed request header sizes is required + # for swift functional testing to work with tls enabled. It is 2 bytes + # larger than the apache default of 8190. + LimitRequestFieldSize $f_header_size + RequestHeader set X-Forwarded-Proto "https" + + # Avoid races (at the cost of performance) to re-use a pooled connection + # where the connection is closed (bug 1807518). + SetEnv proxy-initial-not-pooled + + ProxyPass http://$b_host:$b_port/ retry=0 nocanon + ProxyPassReverse http://$b_host:$b_port/ + + ErrorLog $APACHE_LOG_DIR/tls-proxy_error.log + ErrorLogFormat "%{cu}t [%-m:%l] [pid %P:tid %T] %7F: %E: [client\ %a] [frontend\ %A] %M% ,\ referer\ %{Referer}i" + LogLevel info + CustomLog $APACHE_LOG_DIR/tls-proxy_access.log "%{%Y-%m-%d}t %{%T}t.%{msec_frac}t [%l] %a \"%r\" %>s %b" + +EOF + if is_suse ; then + sudo a2enflag SSL + fi + for mod in headers ssl proxy proxy_http; do + enable_apache_mod $mod + done + enable_apache_site $b_service + restart_apache_server } +# Follow TLS proxy +function follow_tls_proxy { + sudo touch /var/log/$APACHE_NAME/tls-proxy_error.log + tail_log tls-error /var/log/$APACHE_NAME/tls-proxy_error.log + sudo touch /var/log/$APACHE_NAME/tls-proxy_access.log + tail_log tls-proxy /var/log/$APACHE_NAME/tls-proxy_access.log +} # Cleanup Functions # ================= -# Stops all stud processes. This should be done only after all services +# Stops the apache service. This should be done only after all services # using tls configuration are down. function stop_tls_proxy { - killall stud + stop_apache_server + + # NOTE(jh): Removing all tls-proxy configs is a bit of a hack, but + # necessary so that we can restart after an unstack. A better + # solution would be to ensure that each service calling + # start_tls_proxy will call stop_tls_proxy with the same + # parameters on shutdown so we can use the disable_apache_site + # function and remove individual files there. + if is_ubuntu; then + sudo rm -f /etc/apache2/sites-enabled/*-tls-proxy.conf + else + for i in $APACHE_CONF_DIR/*-tls-proxy.conf; do + sudo mv $i $i.disabled + done + fi } -# Remove CA along with configuration, as well as the local server certificate +# Clean up the CA files +# cleanup_CA function cleanup_CA { - rm -rf "$DATA_DIR/CA" "$DEVSTACK_CERT" + if is_fedora; then + sudo rm -f /usr/share/pki/ca-trust-source/anchors/devstack-chain.pem + sudo update-ca-trust + elif is_ubuntu; then + sudo rm -f /usr/local/share/ca-certificates/devstack-int.crt + sudo rm -f /usr/local/share/ca-certificates/devstack-root.crt + sudo update-ca-certificates + fi + + rm -rf "$INT_CA_DIR" "$ROOT_CA_DIR" "$DEVSTACK_CERT" } # Tell emacs to use shell-script-mode diff --git a/lib/zaqar b/lib/zaqar deleted file mode 100644 index 8d51910896..0000000000 --- a/lib/zaqar +++ /dev/null @@ -1,231 +0,0 @@ -#!/bin/bash -# -# lib/zaqar -# Install and start **Zaqar** service - -# To enable a minimal set of Zaqar services, add the following to localrc: -# -# enable_service zaqar-server -# -# Dependencies: -# - functions -# - OS_AUTH_URL for auth in api -# - DEST set to the destination directory -# - SERVICE_PASSWORD, SERVICE_TENANT_NAME for auth in api -# - STACK_USER service user - -# stack.sh -# --------- -# install_zaqar -# configure_zaqar -# init_zaqar -# start_zaqar -# stop_zaqar -# cleanup_zaqar -# cleanup_zaqar_mongodb - -# Save trace setting -XTRACE=$(set +o | grep xtrace) -set +o xtrace - - -# Defaults -# -------- - -# Set up default directories -ZAQAR_DIR=$DEST/zaqar -ZAQARCLIENT_DIR=$DEST/python-zaqarclient -ZAQAR_CONF_DIR=/etc/zaqar -ZAQAR_CONF=$ZAQAR_CONF_DIR/zaqar.conf -ZAQAR_AUTH_CACHE_DIR=${ZAQAR_AUTH_CACHE_DIR:-/var/cache/zaqar} - -# Support potential entry-points console scripts -ZAQAR_BIN_DIR=$(get_python_exec_prefix) - -# Set up database backend -ZAQAR_BACKEND=${ZAQAR_BACKEND:-mongodb} - - -# Set Zaqar repository -ZAQAR_REPO=${ZAQAR_REPO:-${GIT_BASE}/openstack/zaqar.git} -ZAQAR_BRANCH=${ZAQAR_BRANCH:-master} - -# Set client library repository -ZAQARCLIENT_REPO=${ZAQARCLIENT_REPO:-${GIT_BASE}/openstack/python-zaqarclient.git} -ZAQARCLIENT_BRANCH=${ZAQARCLIENT_BRANCH:-master} - -# Set Zaqar Connection Info -ZAQAR_SERVICE_HOST=${ZAQAR_SERVICE_HOST:-$SERVICE_HOST} -ZAQAR_SERVICE_PORT=${ZAQAR_SERVICE_PORT:-8888} -ZAQAR_SERVICE_PROTOCOL=${ZAQAR_SERVICE_PROTOCOL:-$SERVICE_PROTOCOL} - -# Tell Tempest this project is present -TEMPEST_SERVICES+=,zaqar - - -# Functions -# --------- - -# Test if any Zaqar services are enabled -# is_zaqar_enabled -function is_zaqar_enabled { - [[ ,${ENABLED_SERVICES} =~ ,"zaqar-" ]] && return 0 - return 1 -} - -# cleanup_zaqar() - Cleans up general things from previous -# runs and storage specific left overs. -function cleanup_zaqar { - if [ "$ZAQAR_BACKEND" = 'mongodb' ] ; then - cleanup_zaqar_mongodb - fi -} - -# cleanup_zaqar_mongodb() - Remove residual data files, anything left over from previous -# runs that a clean run would need to clean up -function cleanup_zaqar_mongodb { - if ! timeout $SERVICE_TIMEOUT sh -c "while ! mongo zaqar --eval 'db.dropDatabase();'; do sleep 1; done"; then - die $LINENO "Mongo DB did not start" - else - full_version=$(mongo zaqar --eval 'db.dropDatabase();') - mongo_version=`echo $full_version | cut -d' ' -f4` - required_mongo_version='2.2' - if [[ $mongo_version < $required_mongo_version ]]; then - die $LINENO "Zaqar needs Mongo DB version >= 2.2 to run." - fi - fi -} - -# configure_zaqarclient() - Set config files, create data dirs, etc -function configure_zaqarclient { - setup_develop $ZAQARCLIENT_DIR -} - -# configure_zaqar() - Set config files, create data dirs, etc -function configure_zaqar { - setup_develop $ZAQAR_DIR - - sudo install -d -o $STACK_USER -m 755 $ZAQAR_CONF_DIR - - iniset $ZAQAR_CONF DEFAULT debug True - iniset $ZAQAR_CONF DEFAULT verbose True - iniset $ZAQAR_CONF DEFAULT admin_mode True - iniset $ZAQAR_CONF DEFAULT use_syslog $SYSLOG - iniset $ZAQAR_CONF 'drivers:transport:wsgi' bind $ZAQAR_SERVICE_HOST - - configure_auth_token_middleware $ZAQAR_CONF zaqar $ZAQAR_AUTH_CACHE_DIR - - if [ "$ZAQAR_BACKEND" = 'mysql' ] || [ "$ZAQAR_BACKEND" = 'postgresql' ] ; then - iniset $ZAQAR_CONF drivers storage sqlalchemy - iniset $ZAQAR_CONF 'drivers:storage:sqlalchemy' uri `database_connection_url zaqar` - elif [ "$ZAQAR_BACKEND" = 'mongodb' ] ; then - iniset $ZAQAR_CONF drivers storage mongodb - iniset $ZAQAR_CONF 'drivers:storage:mongodb' uri mongodb://localhost:27017/zaqar - configure_mongodb - elif [ "$ZAQAR_BACKEND" = 'redis' ] ; then - iniset $ZAQAR_CONF drivers storage redis - iniset $ZAQAR_CONF 'drivers:storage:redis' uri redis://localhost:6379 - configure_redis - fi - - if is_service_enabled qpid || [ -n "$RABBIT_HOST" ] && [ -n "$RABBIT_PASSWORD" ]; then - iniset $ZAQAR_CONF DEFAULT notification_driver messaging - iniset $ZAQAR_CONF DEFAULT control_exchange zaqar - fi - iniset_rpc_backend zaqar $ZAQAR_CONF - - cleanup_zaqar -} - -function configure_redis { - if is_ubuntu; then - install_package redis-server - pip_install_gr redis - elif is_fedora; then - install_package redis - pip_install_gr redis - else - exit_distro_not_supported "redis installation" - fi -} - -function configure_mongodb { - # Set nssize to 2GB. This increases the number of namespaces supported - # # per database. - if is_ubuntu; then - sudo sed -i -e " - s|[^ \t]*#[ \t]*\(nssize[ \t]*=.*\$\)|\1| - s|^\(nssize[ \t]*=[ \t]*\).*\$|\1 2047| - " /etc/mongodb.conf - restart_service mongodb - elif is_fedora; then - sudo sed -i '/--nssize/!s/OPTIONS=\"/OPTIONS=\"--nssize 2047 /' /etc/sysconfig/mongod - restart_service mongod - fi -} - -# init_zaqar() - Initialize etc. -function init_zaqar { - # Create cache dir - sudo install -d -o $STACK_USER $ZAQAR_AUTH_CACHE_DIR - rm -f $ZAQAR_AUTH_CACHE_DIR/* -} - -# install_zaqar() - Collect source and prepare -function install_zaqar { - git_clone $ZAQAR_REPO $ZAQAR_DIR $ZAQAR_BRANCH - setup_develop $ZAQAR_DIR -} - -# install_zaqarclient() - Collect source and prepare -function install_zaqarclient { - git_clone $ZAQARCLIENT_REPO $ZAQARCLIENT_DIR $ZAQARCLIENT_BRANCH - setup_develop $ZAQARCLIENT_DIR -} - -# start_zaqar() - Start running processes, including screen -function start_zaqar { - if [[ "$USE_SCREEN" = "False" ]]; then - run_process zaqar-server "zaqar-server --config-file $ZAQAR_CONF --daemon" - else - run_process zaqar-server "zaqar-server --config-file $ZAQAR_CONF" - fi - - echo "Waiting for Zaqar to start..." - if ! timeout $SERVICE_TIMEOUT sh -c "while ! wget --no-proxy -q -O- $ZAQAR_SERVICE_PROTOCOL://$ZAQAR_SERVICE_HOST:$ZAQAR_SERVICE_PORT/v1/health; do sleep 1; done"; then - die $LINENO "Zaqar did not start" - fi -} - -# stop_zaqar() - Stop running processes -function stop_zaqar { - local serv - # Kill the zaqar screen windows - for serv in zaqar-server; do - screen -S $SCREEN_NAME -p $serv -X kill - done -} - -function create_zaqar_accounts { - create_service_user "zaqar" - - if [[ "$KEYSTONE_CATALOG_BACKEND" = 'sql' ]]; then - - local zaqar_service=$(get_or_create_service "zaqar" \ - "messaging" "Zaqar Service") - get_or_create_endpoint $zaqar_service \ - "$REGION_NAME" \ - "$ZAQAR_SERVICE_PROTOCOL://$ZAQAR_SERVICE_HOST:$ZAQAR_SERVICE_PORT" \ - "$ZAQAR_SERVICE_PROTOCOL://$ZAQAR_SERVICE_HOST:$ZAQAR_SERVICE_PORT" \ - "$ZAQAR_SERVICE_PROTOCOL://$ZAQAR_SERVICE_HOST:$ZAQAR_SERVICE_PORT" - fi - -} - - -# Restore xtrace -$XTRACE - -# Local variables: -# mode: shell-script -# End: diff --git a/openrc b/openrc index aec8a2a642..99d3351d53 100644 --- a/openrc +++ b/openrc @@ -1,9 +1,9 @@ #!/usr/bin/env bash # -# source openrc [username] [tenantname] +# source openrc [username] [projectname] # -# Configure a set of credentials for $TENANT/$USERNAME: -# Set OS_TENANT_NAME to override the default tenant 'demo' +# Configure a set of credentials for $PROJECT/$USERNAME: +# Set OS_PROJECT_NAME to override the default project 'demo' # Set OS_USERNAME to override the default user name 'demo' # Set ADMIN_PASSWORD to set the password for 'admin' and 'demo' @@ -14,7 +14,7 @@ if [[ -n "$1" ]]; then OS_USERNAME=$1 fi if [[ -n "$2" ]]; then - OS_TENANT_NAME=$2 + OS_PROJECT_NAME=$2 fi # Find the other rc files @@ -29,65 +29,85 @@ source $RC_DIR/stackrc # Load the last env variables if available if [[ -r $RC_DIR/.stackenv ]]; then source $RC_DIR/.stackenv + export OS_CACERT fi # Get some necessary configuration source $RC_DIR/lib/tls -# The introduction of Keystone to the OpenStack ecosystem has standardized the -# term **tenant** as the entity that owns resources. In some places references -# still exist to the original Nova term **project** for this use. Also, -# **tenant_name** is preferred to **tenant_id**. -export OS_TENANT_NAME=${OS_TENANT_NAME:-demo} +# The OpenStack ecosystem has standardized the term **project** as the +# entity that owns resources. In some places **tenant** remains +# referenced, but in all cases this just means **project**. We will +# warn if we need to turn on legacy **tenant** support to have a +# working environment. +export OS_PROJECT_NAME=${OS_PROJECT_NAME:-demo} -# In addition to the owning entity (tenant), nova stores the entity performing +echo "WARNING: setting legacy OS_TENANT_NAME to support cli tools." +export OS_TENANT_NAME=$OS_PROJECT_NAME + +# In addition to the owning entity (project), nova stores the entity performing # the action as the **user**. export OS_USERNAME=${OS_USERNAME:-demo} # With Keystone you pass the keystone password instead of an api key. # Recent versions of novaclient use OS_PASSWORD instead of NOVA_API_KEYs # or NOVA_PASSWORD. -export OS_PASSWORD=${ADMIN_PASSWORD:-secrete} - -# Don't put the key into a keyring by default. Testing for development is much -# easier with this off. -export OS_NO_CACHE=${OS_NO_CACHE:-1} +export OS_PASSWORD=${ADMIN_PASSWORD:-secret} # Region export OS_REGION_NAME=${REGION_NAME:-RegionOne} -# Set api HOST_IP endpoint. SERVICE_HOST may also be used to specify the endpoint, -# which is convenient for some localrc configurations. -HOST_IP=${HOST_IP:-127.0.0.1} -SERVICE_HOST=${SERVICE_HOST:-$HOST_IP} -SERVICE_PROTOCOL=${SERVICE_PROTOCOL:-http} -KEYSTONE_AUTH_PROTOCOL=${KEYSTONE_AUTH_PROTOCOL:-$SERVICE_PROTOCOL} -KEYSTONE_AUTH_HOST=${KEYSTONE_AUTH_HOST:-$SERVICE_HOST} - -# Some exercises call glance directly. On a single-node installation, Glance -# should be listening on HOST_IP. If its running elsewhere, it can be set here -GLANCE_HOST=${GLANCE_HOST:-$HOST_IP} +# Set the host API endpoint. This will default to HOST_IP if SERVICE_IP_VERSION +# is 4, else HOST_IPV6 if it's 6. SERVICE_HOST may also be used to specify the +# endpoint, which is convenient for some localrc configurations. Additionally, +# some exercises call Glance directly. On a single-node installation, Glance +# should be listening on a local IP address, depending on the setting of +# SERVICE_IP_VERSION. If its running elsewhere, it can be set here. +if [[ $SERVICE_IP_VERSION == 6 ]]; then + HOST_IPV6=${HOST_IPV6:-::1} + SERVICE_HOST=${SERVICE_HOST:-[$HOST_IPV6]} + GLANCE_HOST=${GLANCE_HOST:-[$HOST_IPV6]} +else + HOST_IP=${HOST_IP:-127.0.0.1} + SERVICE_HOST=${SERVICE_HOST:-$HOST_IP} + GLANCE_HOST=${GLANCE_HOST:-$HOST_IP} +fi # Identity API version -export OS_IDENTITY_API_VERSION=${IDENTITY_API_VERSION:-2.0} +export OS_IDENTITY_API_VERSION=${IDENTITY_API_VERSION:-3} + +# Ask keystoneauth1 to use keystone +export OS_AUTH_TYPE=password # Authenticating against an OpenStack cloud using Keystone returns a **Token** # and **Service Catalog**. The catalog contains the endpoints for all services -# the user/tenant has access to - including nova, glance, keystone, swift, ... -# We currently recommend using the 2.0 *identity api*. +# the user/project has access to - including nova, glance, keystone, swift, ... +# We currently recommend using the version 3 *identity api*. # -export OS_AUTH_URL=$KEYSTONE_AUTH_PROTOCOL://$KEYSTONE_AUTH_HOST:5000/v${OS_IDENTITY_API_VERSION} -# Set the pointer to our CA certificate chain. Harmless if TLS is not used. -export OS_CACERT=${OS_CACERT:-$INT_CA_DIR/ca-chain.pem} +# If you don't have a working .stackenv, this is the backup position +KEYSTONE_BACKUP=$SERVICE_PROTOCOL://$SERVICE_HOST:5000 +KEYSTONE_AUTH_URI=${KEYSTONE_AUTH_URI:-$KEYSTONE_BACKUP} -# Currently novaclient needs you to specify the *compute api* version. This -# needs to match the config of your catalog returned by Keystone. -export NOVA_VERSION=${NOVA_VERSION:-1.1} -# In the future this will change names: -export COMPUTE_API_VERSION=${COMPUTE_API_VERSION:-$NOVA_VERSION} +export OS_AUTH_URL=${OS_AUTH_URL:-$KEYSTONE_AUTH_URI} + +# Currently, in order to use openstackclient with Identity API v3, +# we need to set the domain which the user and project belong to. +if [ "$OS_IDENTITY_API_VERSION" = "3" ]; then + export OS_USER_DOMAIN_ID=${OS_USER_DOMAIN_ID:-"default"} + export OS_PROJECT_DOMAIN_ID=${OS_PROJECT_DOMAIN_ID:-"default"} +fi + +# Set OS_CACERT to a default CA certificate chain if it exists. +if [[ ! -v OS_CACERT ]] ; then + DEFAULT_OS_CACERT=$INT_CA_DIR/ca-chain.pem + # If the file does not exist, this may confuse preflight sanity checks + if [ -e $DEFAULT_OS_CACERT ] ; then + export OS_CACERT=$DEFAULT_OS_CACERT + fi +fi # Currently cinderclient needs you to specify the *volume api* version. This # needs to match the config of your catalog returned by Keystone. -export CINDER_VERSION=${CINDER_VERSION:-2} +export CINDER_VERSION=${CINDER_VERSION:-3} export OS_VOLUME_API_VERSION=${OS_VOLUME_API_VERSION:-$CINDER_VERSION} diff --git a/pkg/elasticsearch.sh b/pkg/elasticsearch.sh index 79f67a0179..bd4415315f 100755 --- a/pkg/elasticsearch.sh +++ b/pkg/elasticsearch.sh @@ -6,13 +6,11 @@ # step can probably be factored out to something nicer TOP_DIR=$(cd $(dirname "$0")/.. && pwd) FILES=$TOP_DIR/files -source $TOP_DIR/functions -DEST=${DEST:-/opt/stack} -source $TOP_DIR/lib/infra +source $TOP_DIR/stackrc # Package source and version, all pkg files are expected to have # something like this, as well as a way to override them. -ELASTICSEARCH_VERSION=${ELASTICSEARCH_VERSION:-1.4.2} +ELASTICSEARCH_VERSION=${ELASTICSEARCH_VERSION:-1.7.5} ELASTICSEARCH_BASEURL=${ELASTICSEARCH_BASEURL:-https://download.elasticsearch.org/elasticsearch/elasticsearch} # Elastic search actual implementation @@ -39,7 +37,7 @@ function wget_elasticsearch { function download_elasticsearch { if is_ubuntu; then wget_elasticsearch elasticsearch-${ELASTICSEARCH_VERSION}.deb - elif is_fedora; then + elif is_fedora || is_suse; then wget_elasticsearch elasticsearch-${ELASTICSEARCH_VERSION}.noarch.rpm fi } @@ -51,7 +49,7 @@ function configure_elasticsearch { function _check_elasticsearch_ready { # poll elasticsearch to see if it's started - if ! wait_for_service 30 http://localhost:9200; then + if ! wait_for_service 120 http://localhost:9200; then die $LINENO "Maximum timeout reached. Could not connect to ElasticSearch" fi } @@ -63,6 +61,9 @@ function start_elasticsearch { elif is_fedora; then sudo /bin/systemctl start elasticsearch.service _check_elasticsearch_ready + elif is_suse; then + sudo /usr/bin/systemctl start elasticsearch.service + _check_elasticsearch_ready else echo "Unsupported architecture...can not start elasticsearch." fi @@ -73,6 +74,8 @@ function stop_elasticsearch { sudo /etc/init.d/elasticsearch stop elif is_fedora; then sudo /bin/systemctl stop elasticsearch.service + elif is_suse ; then + sudo /usr/bin/systemctl stop elasticsearch.service else echo "Unsupported architecture...can not stop elasticsearch." fi @@ -85,19 +88,20 @@ function install_elasticsearch { return fi if is_ubuntu; then - is_package_installed openjdk-7-jre-headless || install_package openjdk-7-jre-headless + is_package_installed default-jre-headless || install_package default-jre-headless sudo dpkg -i ${FILES}/elasticsearch-${ELASTICSEARCH_VERSION}.deb sudo update-rc.d elasticsearch defaults 95 10 elif is_fedora; then - if [[ "$os_RELEASE" -ge "21" ]]; then - is_package_installed java-1.8.0-openjdk-headless || install_package java-1.8.0-openjdk-headless - else - is_package_installed java-1.7.0-openjdk-headless || install_package java-1.7.0-openjdk-headless - fi + is_package_installed java-1.8.0-openjdk-headless || install_package java-1.8.0-openjdk-headless yum_install ${FILES}/elasticsearch-${ELASTICSEARCH_VERSION}.noarch.rpm sudo /bin/systemctl daemon-reload sudo /bin/systemctl enable elasticsearch.service + elif is_suse; then + is_package_installed java-1_8_0-openjdk-headless || install_package java-1_8_0-openjdk-headless + zypper_install --no-gpg-checks ${FILES}/elasticsearch-${ELASTICSEARCH_VERSION}.noarch.rpm + sudo /usr/bin/systemctl daemon-reload + sudo /usr/bin/systemctl enable elasticsearch.service else echo "Unsupported install of elasticsearch on this architecture." fi @@ -109,6 +113,8 @@ function uninstall_elasticsearch { sudo apt-get purge elasticsearch elif is_fedora; then sudo yum remove elasticsearch + elif is_suse; then + sudo zypper rm elasticsearch else echo "Unsupported install of elasticsearch on this architecture." fi diff --git a/playbooks/devstack.yaml b/playbooks/devstack.yaml new file mode 100644 index 0000000000..d0906380ab --- /dev/null +++ b/playbooks/devstack.yaml @@ -0,0 +1,7 @@ +- hosts: all + # This is the default strategy, however since orchestrate-devstack requires + # "linear", it is safer to enforce it in case this is running in an + # environment configured with a different default strategy. + strategy: linear + roles: + - orchestrate-devstack diff --git a/playbooks/post.yaml b/playbooks/post.yaml new file mode 100644 index 0000000000..9e66f20e9e --- /dev/null +++ b/playbooks/post.yaml @@ -0,0 +1,32 @@ +- hosts: all + become: True + vars: + devstack_log_dir: "{{ devstack_base_dir|default('/opt/stack') }}/logs/" + devstack_conf_dir: "{{ devstack_base_dir|default('/opt/stack') }}/devstack/" + devstack_full_log: "{{ devstack_early_log|default('/opt/stack/logs/devstack-early.txt') }}" + tasks: + # NOTE(andreaf) If the tempest service is enabled, a tempest.log is + # generated as part of lib/tempest, as a result of verify_tempest_config + - name: Check if a tempest log exits + stat: + path: "{{ devstack_conf_dir }}/tempest.log" + register: tempest_log + - name: Link post-devstack tempest.log + file: + src: "{{ devstack_conf_dir }}/tempest.log" + dest: "{{ stage_dir }}/verify_tempest_conf.log" + state: hard + when: tempest_log.stat.exists + roles: + - export-devstack-journal + - apache-logs-conf + - devstack-project-conf + # capture-system-logs should be the last role before stage-output + - capture-system-logs + - role: stage-output + # NOTE(andreaf) We need fetch-devstack-log-dir only as long as the base job + # starts pulling logs for us from {{ ansible_user_dir }}/logs. + # Meanwhile we already store things in ansible_user_dir and use + # fetch-devstack-log-dir setting devstack_base_dir + - role: fetch-devstack-log-dir + devstack_base_dir: "{{ ansible_user_dir }}" diff --git a/playbooks/pre.yaml b/playbooks/pre.yaml new file mode 100644 index 0000000000..4689a6354f --- /dev/null +++ b/playbooks/pre.yaml @@ -0,0 +1,30 @@ +- hosts: all + pre_tasks: + - name: Gather minimum local MTU + set_fact: + local_mtu: > + {% set mtus = [] -%} + {% for interface in ansible_interfaces -%} + {% set interface_variable = 'ansible_' + interface -%} + {% if interface_variable in hostvars[inventory_hostname] -%} + {% set _ = mtus.append(hostvars[inventory_hostname][interface_variable]['mtu']|int) -%} + {% endif -%} + {% endfor -%} + {{- mtus|min -}} + - name: Calculate external_bridge_mtu + # 50 bytes is overhead for vxlan (which is greater than GRE + # allowing us to use either overlay option with this MTU. + # TODO(andreaf) This should work, but it may have to be reconcilied with + # the MTU setting used by the multinode setup roles in multinode pre.yaml + set_fact: + external_bridge_mtu: "{{ local_mtu | int - 50 }}" + roles: + - test-matrix + - configure-swap + - setup-stack-user + - setup-tempest-user + - setup-devstack-source-dirs + - setup-devstack-log-dir + - setup-devstack-cache + - start-fresh-logging + - write-devstack-local-conf diff --git a/playbooks/tox/post.yaml b/playbooks/tox/post.yaml new file mode 100644 index 0000000000..7f0cb19824 --- /dev/null +++ b/playbooks/tox/post.yaml @@ -0,0 +1,4 @@ +- hosts: all + roles: + - fetch-tox-output + - fetch-subunit-output diff --git a/playbooks/tox/pre.yaml b/playbooks/tox/pre.yaml new file mode 100644 index 0000000000..d7e4670a80 --- /dev/null +++ b/playbooks/tox/pre.yaml @@ -0,0 +1,8 @@ +- hosts: all + roles: + # Run bindep and test-setup after devstack so that they won't interfere + - role: bindep + bindep_profile: test + bindep_dir: "{{ zuul_work_dir }}" + - test-setup + - ensure-tox diff --git a/playbooks/tox/run-both.yaml b/playbooks/tox/run-both.yaml new file mode 100644 index 0000000000..e85c2eee96 --- /dev/null +++ b/playbooks/tox/run-both.yaml @@ -0,0 +1,10 @@ +- hosts: all + roles: + - run-devstack + # Run bindep and test-setup after devstack so that they won't interfere + - role: bindep + bindep_profile: test + bindep_dir: "{{ zuul_work_dir }}" + - test-setup + - ensure-tox + - tox diff --git a/playbooks/tox/run.yaml b/playbooks/tox/run.yaml new file mode 100644 index 0000000000..22f82096c7 --- /dev/null +++ b/playbooks/tox/run.yaml @@ -0,0 +1,3 @@ +- hosts: all + roles: + - tox diff --git a/playbooks/unit-tests/pre.yaml b/playbooks/unit-tests/pre.yaml new file mode 100644 index 0000000000..cfa1676378 --- /dev/null +++ b/playbooks/unit-tests/pre.yaml @@ -0,0 +1,13 @@ +- hosts: all + + tasks: + + - name: Install prerequisites + shell: + chdir: '{{ zuul.project.src_dir }}' + executable: /bin/bash + cmd: | + set -e + set -x + echo "IPV4_ADDRS_SAFE_TO_USE=10.1.0.0/20" >> localrc + ./tools/install_prereqs.sh diff --git a/playbooks/unit-tests/run.yaml b/playbooks/unit-tests/run.yaml new file mode 100644 index 0000000000..181521f072 --- /dev/null +++ b/playbooks/unit-tests/run.yaml @@ -0,0 +1,12 @@ +- hosts: all + + tasks: + + - name: Run run_tests.sh + shell: + chdir: '{{ zuul.project.src_dir }}' + executable: /bin/bash + cmd: | + set -e + set -x + ./run_tests.sh diff --git a/rejoin-stack.sh b/rejoin-stack.sh deleted file mode 100755 index 30b7bab1cc..0000000000 --- a/rejoin-stack.sh +++ /dev/null @@ -1,24 +0,0 @@ -#! /usr/bin/env bash - -# This script rejoins an existing screen, or re-creates a -# screen session from a previous run of stack.sh. - -TOP_DIR=`dirname $0` - -# Import common functions in case the localrc (loaded via stackrc) -# uses them. -source $TOP_DIR/functions - -source $TOP_DIR/stackrc - -# if screenrc exists, run screen -if [[ -e $TOP_DIR/stack-screenrc ]]; then - if screen -ls | egrep -q "[0-9].stack"; then - echo "Attaching to already started screen session.." - exec screen -r stack - fi - exec screen -c $TOP_DIR/stack-screenrc -fi - -echo "Couldn't find $TOP_DIR/stack-screenrc file; have you run stack.sh yet?" -exit 1 diff --git a/roles/apache-logs-conf/README.rst b/roles/apache-logs-conf/README.rst new file mode 100644 index 0000000000..eccee403a5 --- /dev/null +++ b/roles/apache-logs-conf/README.rst @@ -0,0 +1,12 @@ +Prepare apache configs and logs for staging + +Make sure apache config files and log files are available in a linux flavor +independent location. Note that this relies on hard links, to the staging +directory must be in the same partition where the logs and configs are. + +**Role Variables** + +.. zuul:rolevar:: stage_dir + :default: {{ ansible_user_dir }} + + The base stage directory. diff --git a/roles/apache-logs-conf/defaults/main.yaml b/roles/apache-logs-conf/defaults/main.yaml new file mode 100644 index 0000000000..1fb04fedc8 --- /dev/null +++ b/roles/apache-logs-conf/defaults/main.yaml @@ -0,0 +1,2 @@ +devstack_base_dir: /opt/stack +stage_dir: "{{ ansible_user_dir }}" diff --git a/roles/apache-logs-conf/tasks/main.yaml b/roles/apache-logs-conf/tasks/main.yaml new file mode 100644 index 0000000000..bd64574c9b --- /dev/null +++ b/roles/apache-logs-conf/tasks/main.yaml @@ -0,0 +1,89 @@ +- name: Ensure {{ stage_dir }}/apache exists + file: + path: "{{ stage_dir }}/apache" + state: directory + +- name: Link apache logs on Debian/SuSE + block: + - name: Find logs + find: + path: "/var/log/apache2" + file_type: any + register: debian_suse_apache_logs + + - name: Dereference files + stat: + path: "{{ item.path }}" + with_items: "{{ debian_suse_apache_logs.files }}" + register: debian_suse_apache_deref_logs + + - name: Create hard links + file: + src: "{{ item.stat.lnk_source | default(item.stat.path) }}" + dest: "{{ stage_dir }}/apache/{{ item.stat.path | basename }}" + state: hard + with_items: "{{ debian_suse_apache_deref_logs.results }}" + when: + - item.stat.isreg or item.stat.islnk + when: ansible_os_family in ('Debian', 'Suse') + no_log: true + +- name: Link apache logs on RedHat + block: + - name: Find logs + find: + path: "/var/log/httpd" + file_type: any + register: redhat_apache_logs + + - name: Dereference files + stat: + path: "{{ item.path }}" + with_items: "{{ redhat_apache_logs.files }}" + register: redhat_apache_deref_logs + + - name: Create hard links + file: + src: "{{ item.stat.lnk_source | default(item.stat.path) }}" + dest: "{{ stage_dir }}/apache/{{ item.stat.path | basename }}" + state: hard + with_items: "{{ redhat_apache_deref_logs.results }}" + when: + - item.stat.isreg or item.stat.islnk + when: ansible_os_family == 'RedHat' + no_log: true + +- name: Ensure {{ stage_dir }}/apache_config apache_config exists + file: + path: "{{ stage_dir }}/apache_config" + state: directory + +- name: Define config paths + set_fact: + apache_config_paths: + 'Debian': '/etc/apache2/sites-enabled/' + 'Suse': '/etc/apache2/conf.d/' + 'RedHat': '/etc/httpd/conf.d/' + +- name: Discover configurations + find: + path: "{{ apache_config_paths[ansible_os_family] }}" + file_type: any + register: apache_configs + no_log: true + +- name: Dereference configurations + stat: + path: "{{ item.path }}" + with_items: "{{ apache_configs.files }}" + register: apache_configs_deref + no_log: true + +- name: Link configurations + file: + src: "{{ item.stat.lnk_source | default(item.stat.path) }}" + dest: "{{ stage_dir }}/apache_config/{{ item.stat.path | basename }}" + state: hard + with_items: "{{ apache_configs_deref.results }}" + when: item.stat.isreg or item.stat.islnk + no_log: true diff --git a/roles/capture-system-logs/README.rst b/roles/capture-system-logs/README.rst new file mode 100644 index 0000000000..c28412457a --- /dev/null +++ b/roles/capture-system-logs/README.rst @@ -0,0 +1,20 @@ +Stage a number of system type logs + +Stage a number of different logs / reports: +- snapshot of iptables +- disk space available +- pip[2|3] freeze +- installed packages (dpkg/rpm) +- ceph, openswitch, gluster +- coredumps +- dns resolver +- listen53 +- unbound.log +- deprecation messages + +**Role Variables** + +.. zuul:rolevar:: stage_dir + :default: {{ ansible_user_dir }} + + The base stage directory. diff --git a/roles/capture-system-logs/defaults/main.yaml b/roles/capture-system-logs/defaults/main.yaml new file mode 100644 index 0000000000..fea05c8146 --- /dev/null +++ b/roles/capture-system-logs/defaults/main.yaml @@ -0,0 +1 @@ +devstack_base_dir: /opt/stack diff --git a/roles/capture-system-logs/tasks/main.yaml b/roles/capture-system-logs/tasks/main.yaml new file mode 100644 index 0000000000..de4f8eda08 --- /dev/null +++ b/roles/capture-system-logs/tasks/main.yaml @@ -0,0 +1,39 @@ +# TODO(andreaf) Make this into proper Ansible +- name: Stage various logs and reports + shell: + executable: /bin/bash + cmd: | + sudo iptables-save > {{ stage_dir }}/iptables.txt + df -h > {{ stage_dir }}/df.txt + + for py_ver in 2 3; do + if [[ `which python${py_ver}` ]]; then + python${py_ver} -m pip freeze > {{ stage_dir }}/pip${py_ver}-freeze.txt + fi + done + + if [ `command -v dpkg` ]; then + dpkg -l> {{ stage_dir }}/dpkg-l.txt + fi + if [ `command -v rpm` ]; then + rpm -qa | sort > {{ stage_dir }}/rpm-qa.txt + fi + + # gzip and save any coredumps in /var/core + if [ -d /var/core ]; then + sudo gzip -r /var/core + sudo cp -r /var/core {{ stage_dir }}/ + fi + + sudo ss -lntup | grep ':53' > {{ stage_dir }}/listen53.txt + + # NOTE(andreaf) Service logs are already in logs/ thanks for the + # export-devstack-journal log. Apache logs are under apache/ thans to the + # apache-logs-conf role. + grep -i deprecat {{ stage_dir }}/logs/*.txt {{ stage_dir }}/apache/*.log | \ + sed -r 's/[0-9]{1,2}\:[0-9]{1,2}\:[0-9]{1,2}\.[0-9]{1,3}/ /g' | \ + sed -r 's/[0-9]{1,2}\:[0-9]{1,2}\:[0-9]{1,2}/ /g' | \ + sed -r 's/[0-9]{1,4}-[0-9]{1,2}-[0-9]{1,4}/ /g' | + sed -r 's/\[.*\]/ /g' | \ + sed -r 's/\s[0-9]+\s/ /g' | \ + awk '{if ($0 in seen) {seen[$0]++} else {out[++n]=$0;seen[$0]=1}} END { for (i=1; i<=n; i++) print seen[out[i]]" :: " out[i] }' > {{ stage_dir }}/deprecations.log diff --git a/roles/devstack-project-conf/README.rst b/roles/devstack-project-conf/README.rst new file mode 100644 index 0000000000..3f2d4c9697 --- /dev/null +++ b/roles/devstack-project-conf/README.rst @@ -0,0 +1,11 @@ +Prepare OpenStack project configurations for staging + +Prepare all relevant config files for staging. +This is helpful to avoid staging the entire /etc. + +**Role Variables** + +.. zuul:rolevar:: stage_dir + :default: {{ ansible_user_dir }} + + The base stage directory. diff --git a/roles/devstack-project-conf/defaults/main.yaml b/roles/devstack-project-conf/defaults/main.yaml new file mode 100644 index 0000000000..f8fb8deac9 --- /dev/null +++ b/roles/devstack-project-conf/defaults/main.yaml @@ -0,0 +1 @@ +stage_dir: "{{ ansible_user_dir }}" diff --git a/roles/devstack-project-conf/tasks/main.yaml b/roles/devstack-project-conf/tasks/main.yaml new file mode 100644 index 0000000000..917cdbc370 --- /dev/null +++ b/roles/devstack-project-conf/tasks/main.yaml @@ -0,0 +1,25 @@ +- name: Ensure {{ stage_dir }}/etc exists + file: + path: "{{ stage_dir }}/etc" + state: directory + +- name: Check which projects have a config folder + stat: + path: "/etc/{{ item.value.short_name }}" + with_dict: "{{ zuul.projects }}" + register: project_configs + no_log: true + +- name: Copy configuration files + command: cp -pRL {{ item.stat.path }} {{ stage_dir }}/etc/{{ item.item.value.short_name }} + when: item.stat.exists + with_items: "{{ project_configs.results }}" + +- name: Check if openstack has a config folder + stat: + path: "/etc/openstack" + register: openstack_configs + +- name: Copy configuration files + command: cp -pRL /etc/openstack {{ stage_dir }}/etc/ + when: openstack_configs.stat.exists diff --git a/roles/export-devstack-journal/README.rst b/roles/export-devstack-journal/README.rst new file mode 100644 index 0000000000..a34e0706a9 --- /dev/null +++ b/roles/export-devstack-journal/README.rst @@ -0,0 +1,21 @@ +Export journal files from devstack services + +Export the systemd journal for every devstack service in native +journal format as well as text. Also, export a syslog-style file with +kernal and sudo messages. + +Writes the output to the ``logs/`` subdirectory of +``stage_dir``. + +**Role Variables** + +.. zuul:rolevar:: devstack_base_dir + :default: /opt/stack + + The devstack base directory. This is used to obtain the + ``log-start-timestamp.txt``, used to filter the systemd journal. + +.. zuul:rolevar:: stage_dir + :default: {{ ansible_user_dir }} + + The base stage directory. diff --git a/roles/export-devstack-journal/defaults/main.yaml b/roles/export-devstack-journal/defaults/main.yaml new file mode 100644 index 0000000000..1fb04fedc8 --- /dev/null +++ b/roles/export-devstack-journal/defaults/main.yaml @@ -0,0 +1,2 @@ +devstack_base_dir: /opt/stack +stage_dir: "{{ ansible_user_dir }}" diff --git a/roles/export-devstack-journal/tasks/main.yaml b/roles/export-devstack-journal/tasks/main.yaml new file mode 100644 index 0000000000..6e760c1f6f --- /dev/null +++ b/roles/export-devstack-journal/tasks/main.yaml @@ -0,0 +1,37 @@ +# NOTE(andreaf) This bypasses the stage-output role +- name: Ensure {{ stage_dir }}/logs exists + become: true + file: + path: "{{ stage_dir }}/logs" + state: directory + owner: "{{ ansible_user }}" + +# TODO: convert this to ansible +- name: Export journal files + become: true + shell: + cmd: | + u="" + name="" + for u in `systemctl list-unit-files | grep devstack | awk '{print $1}'`; do + name=$(echo $u | sed 's/devstack@/screen-/' | sed 's/\.service//') + journalctl -o short-precise --unit $u | gzip - > {{ stage_dir }}/logs/$name.txt.gz + done + + # Export the journal in export format to make it downloadable + # for later searching. It can then be rewritten to a journal native + # format locally using systemd-journal-remote. This makes a class of + # debugging much easier. We don't do the native conversion here as + # some distros do not package that tooling. + journalctl -u 'devstack@*' -o export | \ + xz --threads=0 - > {{ stage_dir }}/logs/devstack.journal.xz + + # The journal contains everything running under systemd, we'll + # build an old school version of the syslog with just the + # kernel and sudo messages. + journalctl \ + -t kernel \ + -t sudo \ + --no-pager \ + --since="$(cat {{ devstack_base_dir }}/log-start-timestamp.txt)" \ + | gzip - > {{ stage_dir }}/logs/syslog.txt.gz diff --git a/roles/fetch-devstack-log-dir/README.rst b/roles/fetch-devstack-log-dir/README.rst new file mode 100644 index 0000000000..360a2e3dd0 --- /dev/null +++ b/roles/fetch-devstack-log-dir/README.rst @@ -0,0 +1,10 @@ +Fetch content from the devstack log directory + +Copy logs from every host back to the zuul executor. + +**Role Variables** + +.. zuul:rolevar:: devstack_base_dir + :default: /opt/stack + + The devstack base directory. diff --git a/roles/fetch-devstack-log-dir/defaults/main.yaml b/roles/fetch-devstack-log-dir/defaults/main.yaml new file mode 100644 index 0000000000..fea05c8146 --- /dev/null +++ b/roles/fetch-devstack-log-dir/defaults/main.yaml @@ -0,0 +1 @@ +devstack_base_dir: /opt/stack diff --git a/roles/fetch-devstack-log-dir/tasks/main.yaml b/roles/fetch-devstack-log-dir/tasks/main.yaml new file mode 100644 index 0000000000..5a198b21b4 --- /dev/null +++ b/roles/fetch-devstack-log-dir/tasks/main.yaml @@ -0,0 +1,5 @@ +- name: Collect devstack logs + synchronize: + dest: "{{ zuul.executor.log_root }}/{{ inventory_hostname }}" + mode: pull + src: "{{ devstack_base_dir }}/logs" diff --git a/roles/orchestrate-devstack/README.rst b/roles/orchestrate-devstack/README.rst new file mode 100644 index 0000000000..097dcea55e --- /dev/null +++ b/roles/orchestrate-devstack/README.rst @@ -0,0 +1,25 @@ +Orchestrate a devstack + +Runs devstack in a multinode scenario, with one controller node +and a group of subnodes. + +The reason for this role is so that jobs in other repository may +run devstack in their plays with no need for re-implementing the +orchestration logic. + +The "run-devstack" role is available to run devstack with no +orchestration. + +This role sets up the controller and CA first, it then pushes CA +data to sub-nodes and run devstack there. The only requirement for +this role is for the controller inventory_hostname to be "controller" +and for all sub-nodes to be defined in a group called "subnode". + +This role needs to be invoked from a playbook that uses a "linear" strategy. + +**Role Variables** + +.. zuul:rolevar:: devstack_base_dir + :default: /opt/stack + + The devstack base directory. diff --git a/roles/orchestrate-devstack/defaults/main.yaml b/roles/orchestrate-devstack/defaults/main.yaml new file mode 100644 index 0000000000..fea05c8146 --- /dev/null +++ b/roles/orchestrate-devstack/defaults/main.yaml @@ -0,0 +1 @@ +devstack_base_dir: /opt/stack diff --git a/roles/orchestrate-devstack/tasks/main.yaml b/roles/orchestrate-devstack/tasks/main.yaml new file mode 100644 index 0000000000..f747943f3c --- /dev/null +++ b/roles/orchestrate-devstack/tasks/main.yaml @@ -0,0 +1,44 @@ +- name: Run devstack on the controller + include_role: + name: run-devstack + when: inventory_hostname == 'controller' + +- name: Setup devstack on sub-nodes + block: + + - name: Distribute the build sshkey for the user "stack" + include_role: + name: copy-build-sshkey + vars: + copy_sshkey_target_user: 'stack' + + - name: Sync CA data to subnodes (when any) + # Only do this if the tls-proxy service is defined and enabled + include_role: + name: sync-devstack-data + when: devstack_services['tls-proxy']|default(false) + + - name: Run devstack on the sub-nodes + include_role: + name: run-devstack + when: inventory_hostname in groups['subnode'] + + - name: Discover hosts + # Discovers compute nodes (subnodes) and maps them to cells. Only run + # on the controller node. + # NOTE(mriedem): We want to remove this if/when nova supports + # auto-registration of computes with cells, but that's not happening in + # Ocata. + # NOTE(andreaf) This is taken (NOTE included) from the discover_hosts + # function in devstack gate. Since this is now in devstack, which is + # branched, we know that the discover_hosts tool exists. + become: true + become_user: stack + shell: ./tools/discover_hosts.sh + args: + chdir: "{{ devstack_base_dir }}/devstack" + when: inventory_hostname == 'controller' + + when: + - '"controller" in hostvars' + - '"subnode" in groups' diff --git a/roles/run-devstack/README.rst b/roles/run-devstack/README.rst new file mode 100644 index 0000000000..d77eb15e99 --- /dev/null +++ b/roles/run-devstack/README.rst @@ -0,0 +1,8 @@ +Run devstack + +**Role Variables** + +.. zuul:rolevar:: devstack_base_dir + :default: /opt/stack + + The devstack base directory. diff --git a/roles/run-devstack/defaults/main.yaml b/roles/run-devstack/defaults/main.yaml new file mode 100644 index 0000000000..fea05c8146 --- /dev/null +++ b/roles/run-devstack/defaults/main.yaml @@ -0,0 +1 @@ +devstack_base_dir: /opt/stack diff --git a/roles/run-devstack/tasks/main.yaml b/roles/run-devstack/tasks/main.yaml new file mode 100644 index 0000000000..f58b31d477 --- /dev/null +++ b/roles/run-devstack/tasks/main.yaml @@ -0,0 +1,11 @@ +- name: Run devstack + shell: + cmd: | + ./stack.sh 2>&1 + rc=$? + echo "*** FINISHED ***" + exit $rc + args: + chdir: "{{devstack_base_dir}}/devstack" + become: true + become_user: stack diff --git a/roles/setup-devstack-cache/README.rst b/roles/setup-devstack-cache/README.rst new file mode 100644 index 0000000000..b8938c3dea --- /dev/null +++ b/roles/setup-devstack-cache/README.rst @@ -0,0 +1,15 @@ +Set up the devstack cache directory + +If the node has a cache of devstack image files, copy it into place. + +**Role Variables** + +.. zuul:rolevar:: devstack_base_dir + :default: /opt/stack + + The devstack base directory. + +.. zuul:rolevar:: devstack_cache_dir + :default: /opt/cache + + The directory with the cached files. diff --git a/roles/setup-devstack-cache/defaults/main.yaml b/roles/setup-devstack-cache/defaults/main.yaml new file mode 100644 index 0000000000..c56720b4f5 --- /dev/null +++ b/roles/setup-devstack-cache/defaults/main.yaml @@ -0,0 +1,2 @@ +devstack_base_dir: /opt/stack +devstack_cache_dir: /opt/cache diff --git a/roles/setup-devstack-cache/tasks/main.yaml b/roles/setup-devstack-cache/tasks/main.yaml new file mode 100644 index 0000000000..84f33f0e16 --- /dev/null +++ b/roles/setup-devstack-cache/tasks/main.yaml @@ -0,0 +1,14 @@ +- name: Copy cached devstack files + # This uses hard links to avoid using extra space. + command: "find {{ devstack_cache_dir }}/files -mindepth 1 -maxdepth 1 -exec cp -l {} {{ devstack_base_dir }}/devstack/files/ ;" + become: true + +- name: Set ownership of cached files + file: + path: '{{ devstack_base_dir }}/devstack/files' + state: directory + recurse: true + owner: stack + group: stack + mode: a+r + become: yes diff --git a/roles/setup-devstack-log-dir/README.rst b/roles/setup-devstack-log-dir/README.rst new file mode 100644 index 0000000000..9d8dba3442 --- /dev/null +++ b/roles/setup-devstack-log-dir/README.rst @@ -0,0 +1,11 @@ +Set up the devstack log directory + +Create a log directory on the ephemeral disk partition to save space +on the root device. + +**Role Variables** + +.. zuul:rolevar:: devstack_base_dir + :default: /opt/stack + + The devstack base directory. diff --git a/roles/setup-devstack-log-dir/defaults/main.yaml b/roles/setup-devstack-log-dir/defaults/main.yaml new file mode 100644 index 0000000000..fea05c8146 --- /dev/null +++ b/roles/setup-devstack-log-dir/defaults/main.yaml @@ -0,0 +1 @@ +devstack_base_dir: /opt/stack diff --git a/roles/setup-devstack-log-dir/tasks/main.yaml b/roles/setup-devstack-log-dir/tasks/main.yaml new file mode 100644 index 0000000000..b9f38dfacb --- /dev/null +++ b/roles/setup-devstack-log-dir/tasks/main.yaml @@ -0,0 +1,5 @@ +- name: Create logs directory + file: + path: '{{ devstack_base_dir }}/logs' + state: directory + become: yes diff --git a/roles/setup-devstack-source-dirs/README.rst b/roles/setup-devstack-source-dirs/README.rst new file mode 100644 index 0000000000..49d22c3c64 --- /dev/null +++ b/roles/setup-devstack-source-dirs/README.rst @@ -0,0 +1,16 @@ +Set up the devstack source directories + +Ensure that the base directory exists, and then move the source repos +into it. + +**Role Variables** + +.. zuul:rolevar:: devstack_base_dir + :default: /opt/stack + + The devstack base directory. + + .. zuul:rolevar:: devstack_sources_branch + :default: None + + The target branch to be setup (where available). diff --git a/roles/setup-devstack-source-dirs/defaults/main.yaml b/roles/setup-devstack-source-dirs/defaults/main.yaml new file mode 100644 index 0000000000..fea05c8146 --- /dev/null +++ b/roles/setup-devstack-source-dirs/defaults/main.yaml @@ -0,0 +1 @@ +devstack_base_dir: /opt/stack diff --git a/roles/setup-devstack-source-dirs/tasks/main.yaml b/roles/setup-devstack-source-dirs/tasks/main.yaml new file mode 100644 index 0000000000..c196c37e09 --- /dev/null +++ b/roles/setup-devstack-source-dirs/tasks/main.yaml @@ -0,0 +1,51 @@ +- name: Find all source repos used by this job + find: + paths: + - src/git.openstack.org/openstack + - src/git.openstack.org/openstack-dev + - src/git.openstack.org/openstack-infra + file_type: directory + register: found_repos + +- name: Copy Zuul repos into devstack working directory + command: rsync -a {{ item.path }} {{ devstack_base_dir }} + with_items: '{{ found_repos.files }}' + become: yes + +- name: Setup refspec for repos into devstack working directory + shell: + # Copied almost "as-is" from devstack-gate setup-workspace function + # but removing the dependency on functions.sh + # TODO this should be rewritten as a python module. + cmd: | + cd {{ devstack_base_dir }}/{{ item.path | basename }} + base_branch={{ devstack_sources_branch }} + if git branch -a | grep "$base_branch" > /dev/null ; then + git checkout $base_branch + elif [[ "$base_branch" == stable/* ]]; then + # Look for an eol tag for the stable branch. + eol_tag=${base_branch#stable/}-eol + if git tag -l |grep $eol_tag >/dev/null; then + git checkout $eol_tag + git reset --hard $eol_tag + if ! git clean -x -f -d -q ; then + sleep 1 + git clean -x -f -d -q + fi + fi + else + git checkout master + fi + args: + executable: /bin/bash + with_items: '{{ found_repos.files }}' + when: devstack_sources_branch is defined + +- name: Set ownership of repos + file: + path: '{{ devstack_base_dir }}' + state: directory + recurse: true + owner: stack + group: stack + become: yes diff --git a/roles/setup-stack-user/README.rst b/roles/setup-stack-user/README.rst new file mode 100644 index 0000000000..80c4d39eff --- /dev/null +++ b/roles/setup-stack-user/README.rst @@ -0,0 +1,16 @@ +Set up the `stack` user + +Create the stack user, set up its home directory, and allow it to +sudo. + +**Role Variables** + +.. zuul:rolevar:: devstack_base_dir + :default: /opt/stack + + The devstack base directory. + +.. zuul:rolevar:: devstack_stack_home_dir + :default: {{ devstack_base_dir }} + + The home directory for the stack user. diff --git a/roles/setup-stack-user/defaults/main.yaml b/roles/setup-stack-user/defaults/main.yaml new file mode 100644 index 0000000000..6d0be666d4 --- /dev/null +++ b/roles/setup-stack-user/defaults/main.yaml @@ -0,0 +1,2 @@ +devstack_base_dir: /opt/stack +devstack_stack_home_dir: '{{ devstack_base_dir }}' diff --git a/roles/setup-stack-user/files/50_stack_sh b/roles/setup-stack-user/files/50_stack_sh new file mode 100644 index 0000000000..4c6b46bdb1 --- /dev/null +++ b/roles/setup-stack-user/files/50_stack_sh @@ -0,0 +1 @@ +stack ALL=(root) NOPASSWD:ALL diff --git a/roles/setup-stack-user/tasks/main.yaml b/roles/setup-stack-user/tasks/main.yaml new file mode 100644 index 0000000000..0fc7c2d78b --- /dev/null +++ b/roles/setup-stack-user/tasks/main.yaml @@ -0,0 +1,47 @@ +- name: Create stack group + group: + name: stack + become: yes + +# NOTE(andreaf) Create a user home_dir is not safe via +# the user module since it will fail if the containing +# folder does not exists. If the folder does exists and +# it's empty, the skeleton is setup and ownership set. +- name: Create the stack user home folder + file: + path: '{{ devstack_stack_home_dir }}' + state: directory + become: yes + +- name: Create stack user + user: + name: stack + shell: /bin/bash + home: '{{ devstack_stack_home_dir }}' + group: stack + become: yes + +- name: Set stack user home directory permissions and ownership + file: + path: '{{ devstack_stack_home_dir }}' + mode: 0755 + owner: stack + group: stack + become: yes + +- name: Copy 50_stack_sh file to /etc/sudoers.d + copy: + src: 50_stack_sh + dest: /etc/sudoers.d + mode: 0440 + owner: root + group: root + become: yes + +- name: Create .cache folder within BASE + file: + path: '{{ devstack_stack_home_dir }}/.cache' + state: directory + owner: stack + group: stack + become: yes diff --git a/roles/setup-tempest-user/README.rst b/roles/setup-tempest-user/README.rst new file mode 100644 index 0000000000..bb29c50a28 --- /dev/null +++ b/roles/setup-tempest-user/README.rst @@ -0,0 +1,10 @@ +Set up the `tempest` user + +Create the tempest user and allow it to sudo. + +**Role Variables** + +.. zuul:rolevar:: devstack_base_dir + :default: /opt/stack + + The devstack base directory. diff --git a/roles/setup-tempest-user/files/51_tempest_sh b/roles/setup-tempest-user/files/51_tempest_sh new file mode 100644 index 0000000000..f88ff9f4f2 --- /dev/null +++ b/roles/setup-tempest-user/files/51_tempest_sh @@ -0,0 +1,3 @@ +tempest ALL=(root) NOPASSWD:/sbin/ip +tempest ALL=(root) NOPASSWD:/sbin/iptables +tempest ALL=(root) NOPASSWD:/usr/bin/ovsdb-client diff --git a/roles/setup-tempest-user/tasks/main.yaml b/roles/setup-tempest-user/tasks/main.yaml new file mode 100644 index 0000000000..892eaf655a --- /dev/null +++ b/roles/setup-tempest-user/tasks/main.yaml @@ -0,0 +1,20 @@ +- name: Create tempest group + group: + name: tempest + become: yes + +- name: Create tempest user + user: + name: tempest + shell: /bin/bash + group: tempest + become: yes + +- name: Copy 51_tempest_sh to /etc/sudoers.d + copy: + src: 51_tempest_sh + dest: /etc/sudoers.d + owner: root + group: root + mode: 0440 + become: yes diff --git a/roles/start-fresh-logging/README.rst b/roles/start-fresh-logging/README.rst new file mode 100644 index 0000000000..11b029e182 --- /dev/null +++ b/roles/start-fresh-logging/README.rst @@ -0,0 +1,11 @@ +Restart logging on all hosts + +Restart syslog so that the system logs only include output from the +job. + +**Role Variables** + +.. zuul:rolevar:: devstack_base_dir + :default: /opt/stack + + The devstack base directory. diff --git a/roles/start-fresh-logging/defaults/main.yaml b/roles/start-fresh-logging/defaults/main.yaml new file mode 100644 index 0000000000..fea05c8146 --- /dev/null +++ b/roles/start-fresh-logging/defaults/main.yaml @@ -0,0 +1 @@ +devstack_base_dir: /opt/stack diff --git a/roles/start-fresh-logging/tasks/main.yaml b/roles/start-fresh-logging/tasks/main.yaml new file mode 100644 index 0000000000..6c7ba66de7 --- /dev/null +++ b/roles/start-fresh-logging/tasks/main.yaml @@ -0,0 +1,56 @@ +- name: Check for /bin/journalctl file + command: which journalctl + changed_when: False + failed_when: False + register: which_out + +- block: + - name: Get current date + command: date +"%Y-%m-%d %H:%M:%S" + register: date_out + + - name: Copy current date to log-start-timestamp.txt + copy: + dest: "{{ devstack_base_dir }}/log-start-timestamp.txt" + content: "{{ date_out.stdout }}" + when: which_out.rc == 0 + become: yes + +- block: + - name: Stop rsyslog + service: name=rsyslog state=stopped + + - name: Save syslog file prior to devstack run + command: mv /var/log/syslog /var/log/syslog-pre-devstack + + - name: Save kern.log file prior to devstack run + command: mv /var/log/kern.log /var/log/kern_log-pre-devstack + + - name: Recreate syslog file + file: name=/var/log/syslog state=touch + + - name: Recreate syslog file owner and group + command: chown /var/log/syslog --ref /var/log/syslog-pre-devstack + + - name: Recreate syslog file permissions + command: chmod /var/log/syslog --ref /var/log/syslog-pre-devstack + + - name: Add read permissions to all on syslog file + file: name=/var/log/syslog mode=a+r + + - name: Recreate kern.log file + file: name=/var/log/kern.log state=touch + + - name: Recreate kern.log file owner and group + command: chown /var/log/kern.log --ref /var/log/kern_log-pre-devstack + + - name: Recreate kern.log file permissions + command: chmod /var/log/kern.log --ref /var/log/kern_log-pre-devstack + + - name: Add read permissions to all on kern.log file + file: name=/var/log/kern.log mode=a+r + + - name: Start rsyslog + service: name=rsyslog state=started + when: which_out.rc == 1 + become: yes diff --git a/roles/sync-devstack-data/README.rst b/roles/sync-devstack-data/README.rst new file mode 100644 index 0000000000..500e8cccc4 --- /dev/null +++ b/roles/sync-devstack-data/README.rst @@ -0,0 +1,12 @@ +Sync devstack data for multinode configurations + +Sync any data files which include certificates to be used if TLS is enabled. +This role must be executed on the controller and it pushes data to all +subnodes. + +**Role Variables** + +.. zuul:rolevar:: devstack_base_dir + :default: /opt/stack + + The devstack base directory. diff --git a/roles/sync-devstack-data/defaults/main.yaml b/roles/sync-devstack-data/defaults/main.yaml new file mode 100644 index 0000000000..fea05c8146 --- /dev/null +++ b/roles/sync-devstack-data/defaults/main.yaml @@ -0,0 +1 @@ +devstack_base_dir: /opt/stack diff --git a/roles/sync-devstack-data/tasks/main.yaml b/roles/sync-devstack-data/tasks/main.yaml new file mode 100644 index 0000000000..46000159d4 --- /dev/null +++ b/roles/sync-devstack-data/tasks/main.yaml @@ -0,0 +1,48 @@ +- name: Ensure the data folder exists + become: true + file: + path: "{{ devstack_base_dir }}/data" + state: directory + owner: stack + group: stack + mode: 0755 + when: 'inventory_hostname in groups["subnode"]|default([])' + +- name: Ensure the CA folder exists + become: true + file: + path: "{{ devstack_base_dir }}/data/CA" + state: directory + owner: stack + group: stack + mode: 0755 + when: 'inventory_hostname in groups["subnode"]|default([])' + +- name: Pull the CA certificate and folder + become: true + synchronize: + src: "{{ item }}" + dest: "{{ zuul.executor.work_root }}/{{ item | basename }}" + mode: pull + with_items: + - "{{ devstack_base_dir }}/data/ca-bundle.pem" + - "{{ devstack_base_dir }}/data/CA" + when: inventory_hostname == 'controller' + +- name: Push the CA certificate + become: true + become_user: stack + synchronize: + src: "{{ zuul.executor.work_root }}/ca-bundle.pem" + dest: "{{ devstack_base_dir }}/data/ca-bundle.pem" + mode: push + when: 'inventory_hostname in groups["subnode"]|default([])' + +- name: Push the CA folder + become: true + become_user: stack + synchronize: + src: "{{ zuul.executor.work_root }}/CA/" + dest: "{{ devstack_base_dir }}/data/" + mode: push + when: 'inventory_hostname in groups["subnode"]|default([])' diff --git a/roles/write-devstack-local-conf/README.rst b/roles/write-devstack-local-conf/README.rst new file mode 100644 index 0000000000..e9739cdea8 --- /dev/null +++ b/roles/write-devstack-local-conf/README.rst @@ -0,0 +1,90 @@ +Write the local.conf file for use by devstack + +**Role Variables** + +.. zuul:rolevar:: devstack_base_dir + :default: /opt/stack + + The devstack base directory. + +.. zuul:rolevar:: devstack_local_conf_path + :default: {{ devstack_base_dir }}/devstack/local.conf + + The path of the local.conf file. + +.. zuul:rolevar:: devstack_localrc + :type: dict + + A dictionary of variables that should be written to the localrc + section of local.conf. The values (which are strings) may contain + bash shell variables, and will be ordered so that variables used by + later entries appear first. + + As a special case, the variable ``LIBS_FROM_GIT`` will be + constructed automatically from the projects which appear in the + ``required-projects`` list defined by the job plus the project of + the change under test. To instruct devstack to install a library + from source rather than pypi, simply add that library to the job's + ``required-projects`` list. To override the + automatically-generated value, set ``LIBS_FROM_GIT`` in + ``devstack_localrc`` to the desired value. + +.. zuul:rolevar:: devstack_local_conf + :type: dict + + A complex argument consisting of nested dictionaries which combine + to form the meta-sections of the local_conf file. The top level is + a dictionary of phases, followed by dictionaries of filenames, then + sections, which finally contain key-value pairs for the INI file + entries in those sections. + + The keys in this dictionary are the devstack phases. + + .. zuul:rolevar:: [phase] + :type: dict + + The keys in this dictionary are the filenames for this phase. + + .. zuul:rolevar:: [filename] + :type: dict + + The keys in this dictionary are the INI sections in this file. + + .. zuul:rolevar:: [section] + :type: dict + + This is a dictionary of key-value pairs which comprise + this section of the INI file. + +.. zuul:rolevar:: devstack_base_services + :type: list + :default: {{ base_services | default(omit) }} + + A list of base services which are enabled. Services can be added or removed + from this list via the ``devstack_services`` variable. This is ignored if + ``base`` is set to ``False`` in ``devstack_services``. + +.. zuul:rolevar:: devstack_services + :type: dict + + A dictionary mapping service names to boolean values. If the + boolean value is ``false``, a ``disable_service`` line will be + emitted for the service name. If it is ``true``, then + ``enable_service`` will be emitted. All other values are ignored. + + The special key ``base`` can be used to enable or disable the base set of + services enabled by default. If ``base`` is found, it will processed before + all other keys. If its value is ``False`` a ``disable_all_services`` will be + emitted; if its value is ``True`` services from ``devstack_base_services`` + will be emitted via ``ENABLED_SERVICES``. + +.. zuul:rolevar:: devstack_plugins + :type: dict + + A dictionary mapping a plugin name to a git repo location. If the + location is a non-empty string, then an ``enable_plugin`` line will + be emmitted for the plugin name. + + If a plugin declares a dependency on another plugin (via + ``plugin_requires`` in the plugin's settings file), this role will + automatically emit ``enable_plugin`` lines in the correct order. diff --git a/roles/write-devstack-local-conf/defaults/main.yaml b/roles/write-devstack-local-conf/defaults/main.yaml new file mode 100644 index 0000000000..7bc1dec9b8 --- /dev/null +++ b/roles/write-devstack-local-conf/defaults/main.yaml @@ -0,0 +1,3 @@ +devstack_base_dir: /opt/stack +devstack_local_conf_path: "{{ devstack_base_dir }}/devstack/local.conf" +devstack_base_services: "{{ enabled_services | default(omit) }}" diff --git a/roles/write-devstack-local-conf/library/devstack_local_conf.py b/roles/write-devstack-local-conf/library/devstack_local_conf.py new file mode 100644 index 0000000000..bba7e31f96 --- /dev/null +++ b/roles/write-devstack-local-conf/library/devstack_local_conf.py @@ -0,0 +1,324 @@ +# Copyright (C) 2017 Red Hat, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +# implied. +# +# See the License for the specific language governing permissions and +# limitations under the License. + +import os +import re + + +class DependencyGraph(object): + # This is based on the JobGraph from Zuul. + + def __init__(self): + self._names = set() + self._dependencies = {} # dependent_name -> set(parent_names) + + def add(self, name, dependencies): + # Append the dependency information + self._dependencies.setdefault(name, set()) + try: + for dependency in dependencies: + # Make sure a circular dependency is never created + ancestors = self._getParentNamesRecursively( + dependency, soft=True) + ancestors.add(dependency) + if name in ancestors: + raise Exception("Dependency cycle detected in {}". + format(name)) + self._dependencies[name].add(dependency) + except Exception: + del self._dependencies[name] + raise + + def getDependenciesRecursively(self, parent): + dependencies = [] + + current_dependencies = self._dependencies[parent] + for current in current_dependencies: + if current not in dependencies: + dependencies.append(current) + for dep in self.getDependenciesRecursively(current): + if dep not in dependencies: + dependencies.append(dep) + return dependencies + + def _getParentNamesRecursively(self, dependent, soft=False): + all_parent_items = set() + items_to_iterate = set([dependent]) + while len(items_to_iterate) > 0: + current_item = items_to_iterate.pop() + current_parent_items = self._dependencies.get(current_item) + if current_parent_items is None: + if soft: + current_parent_items = set() + else: + raise Exception("Dependent item {} not found: ".format( + dependent)) + new_parent_items = current_parent_items - all_parent_items + items_to_iterate |= new_parent_items + all_parent_items |= new_parent_items + return all_parent_items + + +class VarGraph(DependencyGraph): + def __init__(self, vars): + super(VarGraph, self).__init__() + self.vars = {} + self._varnames = set() + for k, v in vars.items(): + self._varnames.add(k) + for k, v in vars.items(): + self._addVar(k, str(v)) + + bash_var_re = re.compile(r'\$\{?(\w+)') + def getDependencies(self, value): + return self.bash_var_re.findall(value) + + def _addVar(self, key, value): + if key in self.vars: + raise Exception("Variable {} already added".format(key)) + self.vars[key] = value + # Append the dependency information + dependencies = set() + for dependency in self.getDependencies(value): + if dependency == key: + # A variable is allowed to reference itself; no + # dependency link needed in that case. + continue + if dependency not in self._varnames: + # It's not necessary to create a link for an + # external variable. + continue + dependencies.add(dependency) + try: + self.add(key, dependencies) + except Exception: + del self.vars[key] + raise + + def getVars(self): + ret = [] + keys = sorted(self.vars.keys()) + seen = set() + for key in keys: + dependencies = self.getDependenciesRecursively(key) + for var in dependencies + [key]: + if var not in seen: + ret.append((var, self.vars[var])) + seen.add(var) + return ret + + +class PluginGraph(DependencyGraph): + def __init__(self, base_dir, plugins): + super(PluginGraph, self).__init__() + # The dependency trees expressed by all the plugins we found + # (which may be more than those the job is using). + self._plugin_dependencies = {} + self.loadPluginNames(base_dir) + + self.plugins = {} + self._pluginnames = set() + for k, v in plugins.items(): + self._pluginnames.add(k) + for k, v in plugins.items(): + self._addPlugin(k, str(v)) + + def loadPluginNames(self, base_dir): + if base_dir is None: + return + git_roots = [] + for root, dirs, files in os.walk(base_dir): + if '.git' not in dirs: + continue + # Don't go deeper than git roots + dirs[:] = [] + git_roots.append(root) + for root in git_roots: + devstack = os.path.join(root, 'devstack') + if not (os.path.exists(devstack) and os.path.isdir(devstack)): + continue + settings = os.path.join(devstack, 'settings') + if not (os.path.exists(settings) and os.path.isfile(settings)): + continue + self.loadDevstackPluginInfo(settings) + + define_re = re.compile(r'^define_plugin\s+(\w+).*') + require_re = re.compile(r'^plugin_requires\s+(\w+)\s+(\w+).*') + def loadDevstackPluginInfo(self, fn): + name = None + reqs = set() + with open(fn) as f: + for line in f: + m = self.define_re.match(line) + if m: + name = m.group(1) + m = self.require_re.match(line) + if m: + if name == m.group(1): + reqs.add(m.group(2)) + if name and reqs: + self._plugin_dependencies[name] = reqs + + def getDependencies(self, value): + return self._plugin_dependencies.get(value, []) + + def _addPlugin(self, key, value): + if key in self.plugins: + raise Exception("Plugin {} already added".format(key)) + self.plugins[key] = value + # Append the dependency information + dependencies = set() + for dependency in self.getDependencies(key): + if dependency == key: + continue + dependencies.add(dependency) + try: + self.add(key, dependencies) + except Exception: + del self.plugins[key] + raise + + def getPlugins(self): + ret = [] + keys = sorted(self.plugins.keys()) + seen = set() + for key in keys: + dependencies = self.getDependenciesRecursively(key) + for plugin in dependencies + [key]: + if plugin not in seen: + ret.append((plugin, self.plugins[plugin])) + seen.add(plugin) + return ret + + +class LocalConf(object): + + def __init__(self, localrc, localconf, base_services, services, plugins, + base_dir, projects, project): + self.localrc = [] + self.meta_sections = {} + self.plugin_deps = {} + self.base_dir = base_dir + self.projects = projects + self.project = project + if plugins: + self.handle_plugins(plugins) + if services or base_services: + self.handle_services(base_services, services or {}) + self.handle_localrc(localrc) + if localconf: + self.handle_localconf(localconf) + + def handle_plugins(self, plugins): + pg = PluginGraph(self.base_dir, plugins) + for k, v in pg.getPlugins(): + if v: + self.localrc.append('enable_plugin {} {}'.format(k, v)) + + def handle_services(self, base_services, services): + enable_base_services = services.pop('base', True) + if enable_base_services and base_services: + self.localrc.append('ENABLED_SERVICES={}'.format( + ",".join(base_services))) + else: + self.localrc.append('disable_all_services') + for k, v in services.items(): + if v is False: + self.localrc.append('disable_service {}'.format(k)) + elif v is True: + self.localrc.append('enable_service {}'.format(k)) + + def handle_localrc(self, localrc): + lfg = False + if localrc: + vg = VarGraph(localrc) + for k, v in vg.getVars(): + self.localrc.append('{}={}'.format(k, v)) + if k == 'LIBS_FROM_GIT': + lfg = True + + if not lfg and (self.projects or self.project): + required_projects = [] + if self.projects: + for project_name, project_info in self.projects.items(): + if project_info.get('required'): + required_projects.append(project_info['short_name']) + if self.project: + if self.project['short_name'] not in required_projects: + required_projects.append(self.project['short_name']) + if required_projects: + self.localrc.append('LIBS_FROM_GIT={}'.format( + ','.join(required_projects))) + + def handle_localconf(self, localconf): + for phase, phase_data in localconf.items(): + for fn, fn_data in phase_data.items(): + ms_name = '[[{}|{}]]'.format(phase, fn) + ms_data = [] + for section, section_data in fn_data.items(): + ms_data.append('[{}]'.format(section)) + for k, v in section_data.items(): + ms_data.append('{} = {}'.format(k, v)) + ms_data.append('') + self.meta_sections[ms_name] = ms_data + + def write(self, path): + with open(path, 'w') as f: + f.write('[[local|localrc]]\n') + f.write('\n'.join(self.localrc)) + f.write('\n\n') + for section, lines in self.meta_sections.items(): + f.write('{}\n'.format(section)) + f.write('\n'.join(lines)) + + +def main(): + module = AnsibleModule( + argument_spec=dict( + plugins=dict(type='dict'), + base_services=dict(type='list'), + services=dict(type='dict'), + localrc=dict(type='dict'), + local_conf=dict(type='dict'), + base_dir=dict(type='path'), + path=dict(type='str'), + projects=dict(type='dict'), + project=dict(type='dict'), + ) + ) + + p = module.params + lc = LocalConf(p.get('localrc'), + p.get('local_conf'), + p.get('base_services'), + p.get('services'), + p.get('plugins'), + p.get('base_dir'), + p.get('projects'), + p.get('project')) + lc.write(p['path']) + + module.exit_json() + + +try: + from ansible.module_utils.basic import * # noqa + from ansible.module_utils.basic import AnsibleModule +except ImportError: + pass + +if __name__ == '__main__': + main() diff --git a/roles/write-devstack-local-conf/library/test.py b/roles/write-devstack-local-conf/library/test.py new file mode 100644 index 0000000000..791552d1ad --- /dev/null +++ b/roles/write-devstack-local-conf/library/test.py @@ -0,0 +1,235 @@ +# Copyright (C) 2017 Red Hat, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +# implied. +# +# See the License for the specific language governing permissions and +# limitations under the License. + +import os +import shutil +import tempfile +import unittest + +from devstack_local_conf import LocalConf +from collections import OrderedDict + +class TestDevstackLocalConf(unittest.TestCase): + def setUp(self): + self.tmpdir = tempfile.mkdtemp() + + def tearDown(self): + shutil.rmtree(self.tmpdir) + + def test_plugins(self): + "Test that plugins without dependencies work" + localrc = {'test_localrc': '1'} + local_conf = {'install': + {'nova.conf': + {'main': + {'test_conf': '2'}}}} + services = {'cinder': True} + # We use ordereddict here to make sure the plugins are in the + # *wrong* order for testing. + plugins = OrderedDict([ + ('bar', 'git://git.openstack.org/openstack/bar-plugin'), + ('foo', 'git://git.openstack.org/openstack/foo-plugin'), + ('baz', 'git://git.openstack.org/openstack/baz-plugin'), + ]) + p = dict(localrc=localrc, + local_conf=local_conf, + base_services=[], + services=services, + plugins=plugins, + base_dir='./test', + path=os.path.join(self.tmpdir, 'test.local.conf')) + lc = LocalConf(p.get('localrc'), + p.get('local_conf'), + p.get('base_services'), + p.get('services'), + p.get('plugins'), + p.get('base_dir'), + p.get('projects'), + p.get('project')) + lc.write(p['path']) + + plugins = [] + with open(p['path']) as f: + for line in f: + if line.startswith('enable_plugin'): + plugins.append(line.split()[1]) + self.assertEqual(['bar', 'baz', 'foo'], plugins) + + + def test_plugin_deps(self): + "Test that plugins with dependencies work" + os.makedirs(os.path.join(self.tmpdir, 'foo-plugin', 'devstack')) + os.makedirs(os.path.join(self.tmpdir, 'foo-plugin', '.git')) + os.makedirs(os.path.join(self.tmpdir, 'bar-plugin', 'devstack')) + os.makedirs(os.path.join(self.tmpdir, 'bar-plugin', '.git')) + with open(os.path.join( + self.tmpdir, + 'foo-plugin', 'devstack', 'settings'), 'w') as f: + f.write('define_plugin foo\n') + with open(os.path.join( + self.tmpdir, + 'bar-plugin', 'devstack', 'settings'), 'w') as f: + f.write('define_plugin bar\n') + f.write('plugin_requires bar foo\n') + + localrc = {'test_localrc': '1'} + local_conf = {'install': + {'nova.conf': + {'main': + {'test_conf': '2'}}}} + services = {'cinder': True} + # We use ordereddict here to make sure the plugins are in the + # *wrong* order for testing. + plugins = OrderedDict([ + ('bar', 'git://git.openstack.org/openstack/bar-plugin'), + ('foo', 'git://git.openstack.org/openstack/foo-plugin'), + ]) + p = dict(localrc=localrc, + local_conf=local_conf, + base_services=[], + services=services, + plugins=plugins, + base_dir=self.tmpdir, + path=os.path.join(self.tmpdir, 'test.local.conf')) + + def test_libs_from_git(self): + "Test that LIBS_FROM_GIT is auto-generated" + projects = { + 'git.openstack.org/openstack/nova': { + 'required': True, + 'short_name': 'nova', + }, + 'git.openstack.org/openstack/oslo.messaging': { + 'required': True, + 'short_name': 'oslo.messaging', + }, + 'git.openstack.org/openstack/devstack-plugin': { + 'required': False, + 'short_name': 'devstack-plugin', + }, + } + project = { + 'short_name': 'glance', + } + p = dict(base_services=[], + base_dir='./test', + path=os.path.join(self.tmpdir, 'test.local.conf'), + projects=projects, + project=project) + lc = LocalConf(p.get('localrc'), + p.get('local_conf'), + p.get('base_services'), + p.get('services'), + p.get('plugins'), + p.get('base_dir'), + p.get('projects'), + p.get('project')) + lc.write(p['path']) + + lfg = None + with open(p['path']) as f: + for line in f: + if line.startswith('LIBS_FROM_GIT'): + lfg = line.strip().split('=')[1] + self.assertEqual('nova,oslo.messaging,glance', lfg) + + def test_overridelibs_from_git(self): + "Test that LIBS_FROM_GIT can be overridden" + localrc = {'LIBS_FROM_GIT': 'oslo.db'} + projects = { + 'git.openstack.org/openstack/nova': { + 'required': True, + 'short_name': 'nova', + }, + 'git.openstack.org/openstack/oslo.messaging': { + 'required': True, + 'short_name': 'oslo.messaging', + }, + 'git.openstack.org/openstack/devstack-plugin': { + 'required': False, + 'short_name': 'devstack-plugin', + }, + } + p = dict(localrc=localrc, + base_services=[], + base_dir='./test', + path=os.path.join(self.tmpdir, 'test.local.conf'), + projects=projects) + lc = LocalConf(p.get('localrc'), + p.get('local_conf'), + p.get('base_services'), + p.get('services'), + p.get('plugins'), + p.get('base_dir'), + p.get('projects'), + p.get('project')) + lc.write(p['path']) + + lfg = None + with open(p['path']) as f: + for line in f: + if line.startswith('LIBS_FROM_GIT'): + lfg = line.strip().split('=')[1] + self.assertEqual('oslo.db', lfg) + + def test_plugin_circular_deps(self): + "Test that plugins with circular dependencies fail" + os.makedirs(os.path.join(self.tmpdir, 'foo-plugin', 'devstack')) + os.makedirs(os.path.join(self.tmpdir, 'foo-plugin', '.git')) + os.makedirs(os.path.join(self.tmpdir, 'bar-plugin', 'devstack')) + os.makedirs(os.path.join(self.tmpdir, 'bar-plugin', '.git')) + with open(os.path.join( + self.tmpdir, + 'foo-plugin', 'devstack', 'settings'), 'w') as f: + f.write('define_plugin foo\n') + f.write('plugin_requires foo bar\n') + with open(os.path.join( + self.tmpdir, + 'bar-plugin', 'devstack', 'settings'), 'w') as f: + f.write('define_plugin bar\n') + f.write('plugin_requires bar foo\n') + + localrc = {'test_localrc': '1'} + local_conf = {'install': + {'nova.conf': + {'main': + {'test_conf': '2'}}}} + services = {'cinder': True} + # We use ordereddict here to make sure the plugins are in the + # *wrong* order for testing. + plugins = OrderedDict([ + ('bar', 'git://git.openstack.org/openstack/bar-plugin'), + ('foo', 'git://git.openstack.org/openstack/foo-plugin'), + ]) + p = dict(localrc=localrc, + local_conf=local_conf, + base_services=[], + services=services, + plugins=plugins, + base_dir=self.tmpdir, + path=os.path.join(self.tmpdir, 'test.local.conf')) + with self.assertRaises(Exception): + lc = LocalConf(p.get('localrc'), + p.get('local_conf'), + p.get('base_services'), + p.get('services'), + p.get('plugins'), + p.get('base_dir')) + lc.write(p['path']) + + +if __name__ == '__main__': + unittest.main() diff --git a/roles/write-devstack-local-conf/tasks/main.yaml b/roles/write-devstack-local-conf/tasks/main.yaml new file mode 100644 index 0000000000..9a6b083a2f --- /dev/null +++ b/roles/write-devstack-local-conf/tasks/main.yaml @@ -0,0 +1,13 @@ +- name: Write a job-specific local_conf file + become: true + become_user: stack + devstack_local_conf: + path: "{{ devstack_local_conf_path }}" + plugins: "{{ devstack_plugins|default(omit) }}" + base_services: "{{ devstack_base_services|default(omit) }}" + services: "{{ devstack_services|default(omit) }}" + localrc: "{{ devstack_localrc|default(omit) }}" + local_conf: "{{ devstack_local_conf|default(omit) }}" + base_dir: "{{ devstack_base_dir|default(omit) }}" + projects: "{{ zuul.projects }}" + project: "{{ zuul.project }}" \ No newline at end of file diff --git a/samples/local.conf b/samples/local.conf index bd0cd9c0db..8b76137c38 100644 --- a/samples/local.conf +++ b/samples/local.conf @@ -10,7 +10,7 @@ # This is a collection of some of the settings we have found to be useful # in our DevStack development environments. Additional settings are described -# in http://devstack.org/local.conf.html +# in https://docs.openstack.org/devstack/latest/configuration.html#local-conf # These should be considered as samples and are unsupported DevStack code. # The ``localrc`` section replaces the old ``localrc`` configuration file. @@ -23,23 +23,22 @@ # While ``stack.sh`` is happy to run without ``localrc``, devlife is better when # there are a few minimal variables set: -# If the ``SERVICE_TOKEN`` and ``*_PASSWORD`` variables are not set -# here you will be prompted to enter values for them by ``stack.sh`` -# and they will be added to ``local.conf``. -SERVICE_TOKEN=azertytoken -ADMIN_PASSWORD=nomoresecrete -MYSQL_PASSWORD=stackdb +# If the ``*_PASSWORD`` variables are not set here you will be prompted to enter +# values for them by ``stack.sh``and they will be added to ``local.conf``. +ADMIN_PASSWORD=nomoresecret +DATABASE_PASSWORD=stackdb RABBIT_PASSWORD=stackqueue SERVICE_PASSWORD=$ADMIN_PASSWORD -# ``HOST_IP`` should be set manually for best results if the NIC configuration -# of the host is unusual, i.e. ``eth1`` has the default route but ``eth0`` is the -# public interface. It is auto-detected in ``stack.sh`` but often is indeterminate -# on later runs due to the IP moving from an Ethernet interface to a bridge on -# the host. Setting it here also makes it available for ``openrc`` to include -# when setting ``OS_AUTH_URL``. -# ``HOST_IP`` is not set by default. +# ``HOST_IP`` and ``HOST_IPV6`` should be set manually for best results if +# the NIC configuration of the host is unusual, i.e. ``eth1`` has the default +# route but ``eth0`` is the public interface. They are auto-detected in +# ``stack.sh`` but often is indeterminate on later runs due to the IP moving +# from an Ethernet interface to a bridge on the host. Setting it here also +# makes it available for ``openrc`` to include when setting ``OS_AUTH_URL``. +# Neither is set by default. #HOST_IP=w.x.y.z +#HOST_IPV6=2001:db8::7 # Logging @@ -62,7 +61,8 @@ LOGDAYS=2 # Using milestone-proposed branches # --------------------------------- -# Uncomment these to grab the milestone-proposed branches from the repos: +# Uncomment these to grab the milestone-proposed branches from the +# repos: #CINDER_BRANCH=milestone-proposed #GLANCE_BRANCH=milestone-proposed #HORIZON_BRANCH=milestone-proposed @@ -73,14 +73,20 @@ LOGDAYS=2 #NEUTRON_BRANCH=milestone-proposed #SWIFT_BRANCH=milestone-proposed +# Using git versions of clients +# ----------------------------- +# By default clients are installed from pip. See LIBS_FROM_GIT in +# stackrc for details on getting clients from specific branches or +# revisions. e.g. +# LIBS_FROM_GIT="python-ironicclient" +# IRONICCLIENT_BRANCH=refs/changes/44/2.../1 # Swift # ----- -# Swift is now used as the back-end for the S3-like object store. If Nova's -# objectstore (``n-obj`` in ``ENABLED_SERVICES``) is enabled, it will NOT -# run if Swift is enabled. Setting the hash value is required and you will -# be prompted for it if Swift is enabled so just set it to something already: +# Swift is now used as the back-end for the S3-like object store. Setting the +# hash value is required and you will be prompted for it if Swift is enabled +# so just set it to something already: SWIFT_HASH=66a3d6b56c1f479c8b4e70ab5c2000f5 # For development purposes the default of 3 replicas is usually not required. @@ -92,9 +98,3 @@ SWIFT_REPLICAS=1 # moved by setting ``SWIFT_DATA_DIR``. The directory will be created # if it does not exist. SWIFT_DATA_DIR=$DEST/data - -# Tempest -# ------- - -# Install the tempest test suite -enable_service tempest diff --git a/samples/local.sh b/samples/local.sh index 634f6ddb17..9cd0bdcc17 100755 --- a/samples/local.sh +++ b/samples/local.sh @@ -36,7 +36,7 @@ if is_service_enabled nova; then # Add first keypair found in localhost:$HOME/.ssh for i in $HOME/.ssh/id_rsa.pub $HOME/.ssh/id_dsa.pub; do if [[ -r $i ]]; then - nova keypair-add --pub_key=$i `hostname` + openstack keypair create --public-key $i `hostname` break fi done @@ -53,8 +53,8 @@ if is_service_enabled nova; then MI_NAME=m1.micro # Create micro flavor if not present - if [[ -z $(nova flavor-list | grep $MI_NAME) ]]; then - nova flavor-create $MI_NAME 6 128 0 1 + if [[ -z $(openstack flavor list | grep $MI_NAME) ]]; then + openstack flavor create $MI_NAME --id 6 --ram 128 --disk 0 --vcpus 1 fi @@ -62,7 +62,7 @@ if is_service_enabled nova; then # ---------- # Add tcp/22 and icmp to default security group - nova secgroup-add-rule default tcp 22 22 0.0.0.0/0 - nova secgroup-add-rule default icmp -1 -1 0.0.0.0/0 + openstack security group rule create --project $OS_PROJECT_NAME default --protocol tcp --ingress --dst-port 22 + openstack security group rule create --project $OS_PROJECT_NAME default --protocol icmp fi diff --git a/setup.cfg b/setup.cfg index 58871344aa..825d386026 100644 --- a/setup.cfg +++ b/setup.cfg @@ -2,10 +2,10 @@ name = DevStack summary = OpenStack DevStack description-file = - README.md + README.rst author = OpenStack -author-email = openstack-dev@lists.openstack.org -home-page = http://devstack.org +author-email = openstack-discuss@lists.openstack.org +home-page = https://docs.openstack.org/devstack/latest classifier = Intended Audience :: Developers License :: OSI Approved :: Apache Software License @@ -15,6 +15,7 @@ classifier = all_files = 1 build-dir = doc/build source-dir = doc/source +warning-is-error = 1 [pbr] warnerrors = True diff --git a/stack.sh b/stack.sh index f20af219a6..144c233f05 100755 --- a/stack.sh +++ b/stack.sh @@ -1,9 +1,8 @@ #!/usr/bin/env bash # ``stack.sh`` is an opinionated OpenStack developer installation. It -# installs and configures various combinations of **Ceilometer**, **Cinder**, -# **Glance**, **Heat**, **Horizon**, **Keystone**, **Nova**, **Neutron**, -# and **Swift** +# installs and configures various combinations of **Cinder**, **Glance**, +# **Horizon**, **Keystone**, **Nova**, **Neutron**, and **Swift** # This script's options can be changed by setting appropriate environment # variables. You can configure things like which git repositories to use, @@ -13,7 +12,7 @@ # a multi-node developer install. # To keep this script simple we assume you are running on a recent **Ubuntu** -# (14.04 Trusty or newer), **Fedora** (F20 or newer), or **CentOS/RHEL** +# (16.04 Xenial or newer), **Fedora** (F24 or newer), or **CentOS/RHEL** # (7 or newer) machine. (It may work on other platforms but support for those # platforms is left to those who added them to DevStack.) It should work in # a VM or physical server. Additionally, we maintain a list of ``deb`` and @@ -21,14 +20,44 @@ # Learn more and get the most recent version at http://devstack.org +# Print the commands being run so that we can see the command that triggers +# an error. It is also useful for following along as the install occurs. +set -o xtrace + # Make sure custom grep options don't get in the way unset GREP_OPTIONS -# Sanitize language settings to avoid commands bailing out -# with "unsupported locale setting" errors. +# NOTE(sdague): why do we explicitly set locale when running stack.sh? +# +# Devstack is written in bash, and many functions used throughout +# devstack process text coming off a command (like the ip command) +# and do transforms using grep, sed, cut, awk on the strings that are +# returned. Many of these programs are internationalized, which is +# great for end users, but means that the strings that devstack +# functions depend upon might not be there in other locales. We thus +# need to pin the world to an english basis during the runs. +# +# Previously we used the C locale for this, every system has it, and +# it gives us a stable sort order. It does however mean that we +# effectively drop unicode support.... boo! :( +# +# With python3 being more unicode aware by default, that's not the +# right option. While there is a C.utf8 locale, some distros are +# shipping it as C.UTF8 for extra confusingness. And it's support +# isn't super clear across distros. This is made more challenging when +# trying to support both out of the box distros, and the gate which +# uses diskimage builder to build disk images in a different way than +# the distros do. +# +# So... en_US.utf8 it is. That's existed for a very long time. It is a +# compromise position, but it is the least worse idea at the time of +# this comment. +# +# We also have to unset other variables that might impact LC_ALL +# taking effect. unset LANG unset LANGUAGE -LC_ALL=C +LC_ALL=en_US.utf8 export LC_ALL # Make sure umask is sane @@ -46,6 +75,8 @@ if [[ -n "$NOUNSET" ]]; then set -o nounset fi +# Set start of devstack timestamp +DEVSTACK_START_TIME=$(date +%s) # Configuration # ============= @@ -79,6 +110,7 @@ fi # Check if run in POSIX shell if [[ "${POSIXLY_CORRECT}" == "y" ]]; then + set +o xtrace echo "You are running POSIX compatibility mode, DevStack requires bash 4.2 or newer." exit 1 fi @@ -89,14 +121,39 @@ fi # action to create a suitable user account. if [[ $EUID -eq 0 ]]; then - echo "You are running this script as root." - echo "Cut it out." - echo "Really." - echo "If you need an account to run DevStack, do this (as root, heh) to create a non-root account:" - echo "$TOP_DIR/tools/create-stack-user.sh" + set +o xtrace + echo "DevStack should be run as a user with sudo permissions, " + echo "not root." + echo "A \"stack\" user configured correctly can be created with:" + echo " $TOP_DIR/tools/create-stack-user.sh" + exit 1 +fi + +# OpenStack is designed to run at a system level, with system level +# installation of python packages. It does not support running under a +# virtual env, and will fail in really odd ways if you do this. Make +# this explicit as it has come up on the mailing list. +if [[ -n "$VIRTUAL_ENV" ]]; then + set +o xtrace + echo "You appear to be running under a python virtualenv." + echo "DevStack does not support this, as we may break the" + echo "virtualenv you are currently in by modifying " + echo "external system-level components the virtualenv relies on." + echo "We recommend you use a separate virtual-machine if " + echo "you are worried about DevStack taking over your system." exit 1 fi +# Provide a safety switch for devstack. If you do a lot of devstack, +# on a lot of different environments, you sometimes run it on the +# wrong box. This makes there be a way to prevent that. +if [[ -e $HOME/.no-devstack ]]; then + set +o xtrace + echo "You've marked this host as a no-devstack host, to save yourself from" + echo "running devstack accidentally. If this is in error, please remove the" + echo "~/.no-devstack file" + exit 1 +fi # Prepare the environment # ----------------------- @@ -114,7 +171,7 @@ source $TOP_DIR/inc/meta-config source $TOP_DIR/lib/stack # Determine what system we are running on. This provides ``os_VENDOR``, -# ``os_RELEASE``, ``os_UPDATE``, ``os_PACKAGE``, ``os_CODENAME`` +# ``os_RELEASE``, ``os_PACKAGE``, ``os_CODENAME`` # and ``DISTRO`` GetDistro @@ -127,31 +184,19 @@ GetDistro # Phase: local rm -f $TOP_DIR/.localrc.auto -if [[ -r $TOP_DIR/local.conf ]]; then - LRC=$(get_meta_section_files $TOP_DIR/local.conf local) - for lfile in $LRC; do - if [[ "$lfile" == "localrc" ]]; then - if [[ -r $TOP_DIR/localrc ]]; then - warn $LINENO "localrc and local.conf:[[local]] both exist, using localrc" - else - echo "# Generated file, do not edit" >$TOP_DIR/.localrc.auto - get_meta_section $TOP_DIR/local.conf local $lfile >>$TOP_DIR/.localrc.auto - fi - fi - done -fi +extract_localrc_section $TOP_DIR/local.conf $TOP_DIR/localrc $TOP_DIR/.localrc.auto # ``stack.sh`` is customizable by setting environment variables. Override a -# default setting via export:: +# default setting via export: # # export DATABASE_PASSWORD=anothersecret # ./stack.sh # -# or by setting the variable on the command line:: +# or by setting the variable on the command line: # # DATABASE_PASSWORD=simple ./stack.sh # -# Persistent variables can be placed in a ``local.conf`` file:: +# Persistent variables can be placed in a ``local.conf`` file: # # [[local|localrc]] # DATABASE_PASSWORD=anothersecret @@ -171,25 +216,18 @@ if [[ ! -r $TOP_DIR/stackrc ]]; then fi source $TOP_DIR/stackrc +# write /etc/devstack-version +write_devstack_version + # Warn users who aren't on an explicitly supported distro, but allow them to # override check and attempt installation with ``FORCE=yes ./stack`` -if [[ ! ${DISTRO} =~ (precise|trusty|7.0|wheezy|sid|testing|jessie|f20|f21|rhel7) ]]; then +if [[ ! ${DISTRO} =~ (xenial|artful|bionic|stretch|jessie|f27|f28|opensuse-42.3|opensuse-15.0|opensuse-tumbleweed|rhel7) ]]; then echo "WARNING: this script has not been tested on $DISTRO" if [[ "$FORCE" != "yes" ]]; then die $LINENO "If you wish to run this script anyway run with FORCE=yes" fi fi -# Check to see if we are already running DevStack -# Note that this may fail if USE_SCREEN=False -if type -p screen > /dev/null && screen -ls | egrep -q "[0-9]\.$SCREEN_NAME"; then - echo "You are already running a stack.sh session." - echo "To rejoin this session type 'screen -x stack'." - echo "To destroy this session, type './unstack.sh'." - exit 1 -fi - - # Local Settings # -------------- @@ -212,6 +250,15 @@ is_package_installed sudo || install_package sudo sudo grep -q "^#includedir.*/etc/sudoers.d" /etc/sudoers || echo "#includedir /etc/sudoers.d" | sudo tee -a /etc/sudoers +# Conditionally setup detailed logging for sudo +if [[ -n "$LOG_SUDO" ]]; then + TEMPFILE=`mktemp` + echo "Defaults log_output" > $TEMPFILE + chmod 0440 $TEMPFILE + sudo chown root:root $TEMPFILE + sudo mv $TEMPFILE /etc/sudoers.d/00_logging +fi + # Set up DevStack sudoers TEMPFILE=`mktemp` echo "$STACK_USER ALL=(root) NOPASSWD:ALL" >$TEMPFILE @@ -235,9 +282,7 @@ fi # Some distros need to add repos beyond the defaults provided by the vendor # to pick up required packages. -if is_fedora && [[ $DISTRO == "rhel7" ]]; then - # RHEL requires EPEL for many Open Stack dependencies - +function _install_epel { # NOTE: We always remove and install latest -- some environments # use snapshot images, and if EPEL version updates they break # unless we update them to latest version. @@ -263,30 +308,44 @@ gpgcheck=0 EOF # Enable a bootstrap repo. It is removed after finishing # the epel-release installation. + is_package_installed yum-utils || install_package yum-utils sudo yum-config-manager --enable epel-bootstrap yum_install epel-release || \ die $LINENO "Error installing EPEL repo, cannot continue" - # EPEL rpm has installed it's version sudo rm -f /etc/yum.repos.d/epel-bootstrap.repo +} - # ... and also optional to be enabled - is_package_installed yum-utils || install_package yum-utils - sudo yum-config-manager --enable rhel-7-server-optional-rpms +function _install_rdo { + # There are multiple options for this, including using CloudSIG + # repositories (centos-release-*), trunk versions, etc. Since + # we're not interested in the actual openstack distributions + # (since we're using git to run!) but only peripherial packages + # like kvm or ovs, this has been reliable. + + # TODO(ianw): figure out how to best mirror -- probably use infra + # mirror RDO reverse proxy. We could either have test + # infrastructure set it up disabled like EPEL, or fiddle it here. + # Per the point above, it's a bunch of repos so starts getting a + # little messy... + if ! is_package_installed rdo-release ; then + yum_install https://rdoproject.org/repos/rdo-release.rpm + fi - RHEL_RDO_REPO_RPM=${RHEL7_RDO_REPO_RPM:-"https://repos.fedorapeople.org/repos/openstack/openstack-juno/rdo-release-juno-1.noarch.rpm"} - RHEL_RDO_REPO_ID=${RHEL7_RDO_REPO_ID:-"openstack-juno"} + # Also enable optional for RHEL7 proper. Note this is a silent + # no-op on other platforms. + sudo yum-config-manager --enable rhel-7-server-optional-rpms - if ! sudo yum repolist enabled $RHEL_RDO_REPO_ID | grep -q $RHEL_RDO_REPO_ID; then - echo "RDO repo not detected; installing" - yum_install $RHEL_RDO_REPO_RPM || \ - die $LINENO "Error installing RDO repo, cannot continue" + # Enable the Software Collections (SCL) repository for CentOS. + # This repository includes useful software (e.g. the Go Toolset) + # which is not present in the main repository. + if [[ "$os_VENDOR" =~ (CentOS) ]]; then + yum_install centos-release-scl fi if is_oraclelinux; then sudo yum-config-manager --enable ol7_optional_latest ol7_addons ol7_MySQL56 fi - -fi +} # Configure Target Directories @@ -301,28 +360,59 @@ sudo mkdir -p $DEST safe_chown -R $STACK_USER $DEST safe_chmod 0755 $DEST -# Basic test for ``$DEST`` path permissions (fatal on error unless skipped) -check_path_perm_sanity ${DEST} +# Destination path for devstack logs +if [[ -n ${LOGDIR:-} ]]; then + mkdir -p $LOGDIR +fi # Destination path for service data DATA_DIR=${DATA_DIR:-${DEST}/data} sudo mkdir -p $DATA_DIR safe_chown -R $STACK_USER $DATA_DIR +safe_chmod 0755 $DATA_DIR # Configure proper hostname # Certain services such as rabbitmq require that the local hostname resolves # correctly. Make sure it exists in /etc/hosts so that is always true. LOCAL_HOSTNAME=`hostname -s` -if [ -z "`grep ^127.0.0.1 /etc/hosts | grep $LOCAL_HOSTNAME`" ]; then +if ! fgrep -qwe "$LOCAL_HOSTNAME" /etc/hosts; then sudo sed -i "s/\(^127.0.0.1.*\)/\1 $LOCAL_HOSTNAME/" /etc/hosts fi +# If you have all the repos installed above already setup (e.g. a CI +# situation where they are on your image) you may choose to skip this +# to speed things up +SKIP_EPEL_INSTALL=$(trueorfalse False SKIP_EPEL_INSTALL) + +if [[ $DISTRO == "rhel7" ]]; then + # If we have /etc/ci/mirror_info.sh assume we're on a OpenStack CI + # node, where EPEL is installed (but disabled) and already + # pointing at our internal mirror + if [[ -f /etc/ci/mirror_info.sh ]]; then + SKIP_EPEL_INSTALL=True + sudo yum-config-manager --enable epel + fi + + if [[ ${SKIP_EPEL_INSTALL} != True ]]; then + _install_epel + fi + # Along with EPEL, CentOS (and a-likes) require some packages only + # available in RDO repositories (e.g. OVS, or later versions of + # kvm) to run. + _install_rdo +fi + +# Ensure python is installed +# -------------------------- +is_package_installed python || install_package python + # Configure Logging # ----------------- # Set up logging level VERBOSE=$(trueorfalse True VERBOSE) +VERBOSE_NO_TIMESTAMP=$(trueorfalse False VERBOSE) # Draw a spinner so the user knows something is happening function spinner { @@ -372,10 +462,6 @@ TIMESTAMP_FORMAT=${TIMESTAMP_FORMAT:-"%F-%H%M%S"} LOGDAYS=${LOGDAYS:-7} CURRENT_LOG_TIME=$(date "+$TIMESTAMP_FORMAT") -if [[ -n ${LOGDIR:-} ]]; then - mkdir -p $LOGDIR -fi - if [[ -n "$LOGFILE" ]]; then # Clean up old log files. Append '.*' to the user-specified # ``LOGFILE`` to match the date in the search template. @@ -392,8 +478,12 @@ if [[ -n "$LOGFILE" ]]; then # stdout later. exec 3>&1 if [[ "$VERBOSE" == "True" ]]; then + _of_args="-v" + if [[ "$VERBOSE_NO_TIMESTAMP" == "True" ]]; then + _of_args="$_of_args --no-timestamp" + fi # Set fd 1 and 2 to write the log file - exec 1> >( $TOP_DIR/tools/outfilter.py -v -o "${LOGFILE}" ) 2>&1 + exec 1> >( $TOP_DIR/tools/outfilter.py $_of_args -o "${LOGFILE}" ) 2>&1 # Set fd 6 to summary log file exec 6> >( $TOP_DIR/tools/outfilter.py -o "${SUMFILE}" ) else @@ -420,24 +510,8 @@ else exec 6> >( $TOP_DIR/tools/outfilter.py -v >&3 ) fi -# Set up logging of screen windows -# Set ``SCREEN_LOGDIR`` to turn on logging of screen windows to the -# directory specified in ``SCREEN_LOGDIR``, we will log to the the file -# ``screen-$SERVICE_NAME-$TIMESTAMP.log`` in that dir and have a link -# ``screen-$SERVICE_NAME.log`` to the latest log file. -# Logs are kept for as long specified in ``LOGDAYS``. -# This is deprecated....logs go in ``LOGDIR``, only symlinks will be here now. -if [[ -n "$SCREEN_LOGDIR" ]]; then - - # We make sure the directory is created. - if [[ -d "$SCREEN_LOGDIR" ]]; then - # We cleanup the old logs - find $SCREEN_LOGDIR -maxdepth 1 -name screen-\*.log -mtime +$LOGDAYS -exec rm {} \; - else - mkdir -p $SCREEN_LOGDIR - fi -fi - +# Basic test for ``$DEST`` path permissions (fatal on error unless skipped) +check_path_perm_sanity ${DEST} # Configure Error Traps # --------------------- @@ -454,16 +528,30 @@ function exit_trap { kill 2>&1 $jobs fi + #Remove timing data file + if [ -f "$OSCWRAP_TIMER_FILE" ] ; then + rm "$OSCWRAP_TIMER_FILE" + fi + # Kill the last spinner process kill_spinner if [[ $r -ne 0 ]]; then echo "Error on exit" + # If we error before we've installed os-testr, this will fail. + if type -p generate-subunit > /dev/null; then + generate-subunit $DEVSTACK_START_TIME $SECONDS 'fail' >> ${SUBUNIT_OUTPUT} + fi if [[ -z $LOGDIR ]]; then $TOP_DIR/tools/worlddump.py else $TOP_DIR/tools/worlddump.py -d $LOGDIR fi + else + # If we error before we've installed os-testr, this will fail. + if type -p generate-subunit > /dev/null; then + generate-subunit $DEVSTACK_START_TIME $SECONDS >> ${SUBUNIT_OUTPUT} + fi fi exit $r @@ -485,10 +573,6 @@ function err_trap { # Begin trapping error exit codes set -o errexit -# Print the commands being run so that we can see the command that triggers -# an error. It is also useful for following along as the install occurs. -set -o xtrace - # Print the kernel version uname -a @@ -500,24 +584,13 @@ rm -f $SSL_BUNDLE_FILE source $TOP_DIR/lib/database source $TOP_DIR/lib/rpc_backend -# Make sure we only have one rpc backend enabled, -# and the specified rpc backend is available on your platform. -check_rpc_backend - -# Service to enable with SSL if ``USE_SSL`` is True -SSL_ENABLED_SERVICES="key,nova,cinder,glance,s-proxy,neutron,sahara" - -if is_service_enabled tls-proxy && [ "$USE_SSL" == "True" ]; then - die $LINENO "tls-proxy and SSL are mutually exclusive" -fi - # Configure Projects # ================== # Clone all external plugins fetch_plugins -# Plugin Phase 0: override_defaults - allow pluggins to override +# Plugin Phase 0: override_defaults - allow plugins to override # defaults before other services are run run_phase override_defaults @@ -529,19 +602,19 @@ source $TOP_DIR/lib/tls # Source project function libraries source $TOP_DIR/lib/infra -source $TOP_DIR/lib/oslo +source $TOP_DIR/lib/libraries source $TOP_DIR/lib/lvm source $TOP_DIR/lib/horizon source $TOP_DIR/lib/keystone source $TOP_DIR/lib/glance source $TOP_DIR/lib/nova +source $TOP_DIR/lib/placement source $TOP_DIR/lib/cinder source $TOP_DIR/lib/swift -source $TOP_DIR/lib/ceilometer -source $TOP_DIR/lib/heat -source $TOP_DIR/lib/neutron-legacy +source $TOP_DIR/lib/neutron source $TOP_DIR/lib/ldap source $TOP_DIR/lib/dstat +source $TOP_DIR/lib/etcd3 # Extras Source # -------------- @@ -549,6 +622,7 @@ source $TOP_DIR/lib/dstat # Phase: source run_phase source + # Interactive Configuration # ------------------------- @@ -556,7 +630,8 @@ run_phase source # Generic helper to configure passwords function read_password { - XTRACE=$(set +o | grep xtrace) + local xtrace + xtrace=$(set +o | grep xtrace) set +o xtrace var=$1; msg=$2 pw=${!var} @@ -564,7 +639,7 @@ function read_password { if [[ -f $RC_DIR/localrc ]]; then localrc=$TOP_DIR/localrc else - localrc=$TOP_DIR/.localrc.auto + localrc=$TOP_DIR/.localrc.password fi # If the password is not defined yet, proceed to prompt user for a password. @@ -574,13 +649,15 @@ function read_password { touch $localrc fi - # Presumably if we got this far it can only be that our localrc is missing - # the required password. Prompt user for a password and write to localrc. + # Presumably if we got this far it can only be that our + # localrc is missing the required password. Prompt user for a + # password and write to localrc. + echo '' echo '################################################################################' echo $msg echo '################################################################################' - echo "This value will be written to your localrc file so you don't have to enter it " + echo "This value will be written to ${localrc} file so you don't have to enter it " echo "again. Use only alphanumeric characters." echo "If you leave this blank, a random default value will be used." pw=" " @@ -597,7 +674,9 @@ function read_password { eval "$var=$pw" echo "$var=$pw" >> $localrc fi - $XTRACE + + # restore previous xtrace value + $xtrace } @@ -621,9 +700,7 @@ initialize_database_backends && echo "Using $DATABASE_TYPE database backend" || # Rabbit connection info # In multi node DevStack, second node needs ``RABBIT_USERID``, but rabbit # isn't enabled. -RABBIT_USERID=${RABBIT_USERID:-stackrabbit} if is_service_enabled rabbit; then - RABBIT_HOST=${RABBIT_HOST:-$SERVICE_HOST} read_password RABBIT_PASSWORD "ENTER A PASSWORD TO USE FOR RABBIT." fi @@ -632,9 +709,6 @@ fi # -------- if is_service_enabled keystone; then - # The ``SERVICE_TOKEN`` is used to bootstrap the Keystone database. It is - # just a string and is not a 'real' Keystone token. - read_password SERVICE_TOKEN "ENTER A SERVICE_TOKEN TO USE FOR THE SERVICE ADMIN TOKEN." # Services authenticate to Identity with servicename/``SERVICE_PASSWORD`` read_password SERVICE_PASSWORD "ENTER A SERVICE_PASSWORD TO USE FOR THE SERVICE AUTHENTICATION." # Horizon currently truncates usernames and passwords at 20 characters @@ -669,12 +743,20 @@ if is_service_enabled s-proxy; then fi fi +# Save configuration values +save_stackenv $LINENO + # Install Packages # ================ # OpenStack uses a fair number of other projects. +# Bring down global requirements before any use of pip_install. This is +# necessary to ensure that the constraints file is in place before we +# attempt to apply any constraints to pip installs. +git_clone $REQUIREMENTS_REPO $REQUIREMENTS_DIR $REQUIREMENTS_BRANCH + # Install package requirements # Source it so the entire environment is available echo_summary "Installing package prerequisites" @@ -685,6 +767,9 @@ if [[ "$OFFLINE" != "True" ]]; then PYPI_ALTERNATIVE_URL=${PYPI_ALTERNATIVE_URL:-""} $TOP_DIR/tools/install_pip.sh fi +# Install subunit for the subunit output stream +pip_install -U os-testr + TRACK_DEPENDS=${TRACK_DEPENDS:-False} # Install Python packages into a virtualenv so that we can track them @@ -700,7 +785,15 @@ fi # Do the ugly hacks for broken packages and distros source $TOP_DIR/tools/fixup_stuff.sh +fixup_all +if [[ "$USE_SYSTEMD" == "True" ]]; then + pip_install_gr systemd-python + # the default rate limit of 1000 messages / 30 seconds is not + # sufficient given how verbose our logging is. + iniset -sudo /etc/systemd/journald.conf "Journal" "RateLimitBurst" "0" + sudo systemctl restart systemd-journald +fi # Virtual Environment # ------------------- @@ -708,21 +801,21 @@ source $TOP_DIR/tools/fixup_stuff.sh # Install required infra support libraries install_infra -# Pre-build some problematic wheels -if [[ -n ${WHEELHOUSE:-} && ! -d ${WHEELHOUSE:-} ]]; then - source $TOP_DIR/tools/build_wheels.sh -fi - - # Extras Pre-install # ------------------ # Phase: pre-install run_phase stack pre-install +# NOTE(danms): Set global limits before installing anything +set_systemd_override DefaultLimitNOFILE ${ULIMIT_NOFILE} + install_rpc_backend +restart_rpc_backend if is_service_enabled $DATABASE_BACKENDS; then install_database +fi +if [ -n "$DATABASE_TYPE" ]; then install_database_python fi @@ -730,15 +823,23 @@ if is_service_enabled neutron; then install_neutron_agent_packages fi +if is_service_enabled etcd3; then + install_etcd3 +fi + # Check Out and Install Source # ---------------------------- echo_summary "Installing OpenStack project source" -# Install Oslo libraries -install_oslo +# Install additional libraries +install_libs + +# Install uwsgi +install_apache_uwsgi # Install client libraries +install_keystoneauth install_keystoneclient install_glanceclient install_cinderclient @@ -749,8 +850,12 @@ fi if is_service_enabled neutron nova horizon; then install_neutronclient fi -if is_service_enabled heat horizon; then - install_heatclient + +# Setup TLS certs +if is_service_enabled tls-proxy; then + configure_CA + init_CA + init_cert fi # Install middleware @@ -763,7 +868,7 @@ if is_service_enabled keystone; then fi fi -if is_service_enabled s-proxy; then +if is_service_enabled swift; then if is_service_enabled ceilometer; then install_ceilometermiddleware fi @@ -794,47 +899,42 @@ fi if is_service_enabled neutron; then # Network service stack_install_service neutron - install_neutron_third_party fi if is_service_enabled nova; then # Compute service stack_install_service nova - cleanup_nova configure_nova fi -if is_service_enabled horizon; then - # django openstack_auth - install_django_openstack_auth - # dashboard - stack_install_service horizon - configure_horizon +if is_service_enabled placement; then + # placement api + stack_install_service placement + configure_placement fi -if is_service_enabled ceilometer; then - install_ceilometerclient - stack_install_service ceilometer - echo_summary "Configuring Ceilometer" - configure_ceilometer +# create a placement-client fake service to know we need to configure +# placement connectivity. We configure the placement service for nova +# if placement-api or placement-client is active, and n-cpu on the +# same box. +if is_service_enabled placement placement-client; then + if is_service_enabled n-cpu || is_service_enabled n-sch; then + configure_placement_nova_compute + fi fi -if is_service_enabled heat; then - stack_install_service heat - install_heat_other - cleanup_heat - configure_heat +if is_service_enabled horizon; then + # dashboard + stack_install_service horizon fi -if is_service_enabled tls-proxy || [ "$USE_SSL" == "True" ]; then - configure_CA - init_CA - init_cert - # Add name to ``/etc/hosts``. - # Don't be naive and add to existing line! +if is_service_enabled tls-proxy; then + fix_system_ca_bundle_path + if python3_enabled ; then + fix_system_ca_bundle_path python3 + fi fi - # Extras Install # -------------- @@ -849,6 +949,10 @@ else pip_install_gr python-openstackclient fi +# Installs alias for osc so that we can collect timing for all +# osc commands. Alias dies with stack.sh. +install_oscwrap + if [[ $TRACK_DEPENDS = True ]]; then $DEST/.venv/bin/pip freeze > $DEST/requires-post-pip if ! diff -Nru $DEST/requires-pre-pip $DEST/requires-post-pip > $DEST/requires.diff; then @@ -866,17 +970,15 @@ fi if [[ $SYSLOG != "False" ]]; then if [[ "$SYSLOG_HOST" = "$HOST_IP" ]]; then # Configure the master host to receive - cat </tmp/90-stack-m.conf + cat </dev/null \$ModLoad imrelp \$InputRELPServerRun $SYSLOG_PORT EOF - sudo mv /tmp/90-stack-m.conf /etc/rsyslog.d else # Set rsyslog to send to remote host - cat </tmp/90-stack-s.conf + cat </dev/null *.* :omrelp:$SYSLOG_HOST:$SYSLOG_PORT EOF - sudo mv /tmp/90-stack-s.conf /etc/rsyslog.d fi RSYSLOGCONF="/etc/rsyslog.conf" @@ -899,13 +1001,8 @@ EOF fi -# Finalize queue installation -# ---------------------------- -restart_rpc_backend - - -# Export Certicate Authority Bundle -# --------------------------------- +# Export Certificate Authority Bundle +# ----------------------------------- # If certificates were used and written to the SSL bundle file then these # should be exported so clients can validate their connections. @@ -922,34 +1019,25 @@ if is_service_enabled $DATABASE_BACKENDS; then configure_database fi +# Save configuration values +save_stackenv $LINENO -# Configure screen -# ---------------- +# Kernel Samepage Merging (KSM) +# ----------------------------- -USE_SCREEN=$(trueorfalse True USE_SCREEN) -if [[ "$USE_SCREEN" == "True" ]]; then - # Create a new named screen to run processes in - screen -d -m -S $SCREEN_NAME -t shell -s /bin/bash - sleep 1 +# Processes that mark their memory as mergeable can share identical memory +# pages if KSM is enabled. This is particularly useful for nova + libvirt +# backends but any other setup that marks its memory as mergeable can take +# advantage. The drawback is there is higher cpu load; however, we tend to +# be memory bound not cpu bound so enable KSM by default but allow people +# to opt out if the CPU time is more important to them. - # Set a reasonable status bar - SCREEN_HARDSTATUS=${SCREEN_HARDSTATUS:-} - if [ -z "$SCREEN_HARDSTATUS" ]; then - SCREEN_HARDSTATUS='%{= .} %-Lw%{= .}%> %n%f %t*%{= .}%+Lw%< %-=%{g}(%{d}%H/%l%{g})' +if [[ $ENABLE_KSM == "True" ]] ; then + if [[ -f /sys/kernel/mm/ksm/run ]] ; then + sudo sh -c "echo 1 > /sys/kernel/mm/ksm/run" fi - screen -r $SCREEN_NAME -X hardstatus alwayslastline "$SCREEN_HARDSTATUS" - screen -r $SCREEN_NAME -X setenv PROMPT_COMMAND /bin/true fi -# Clear ``screenrc`` file -SCREENRC=$TOP_DIR/$SCREEN_NAME-screenrc -if [[ -e $SCREENRC ]]; then - rm -f $SCREENRC -fi - -# Initialize the directory for service status check -init_service_check - # Start Services # ============== @@ -960,78 +1048,81 @@ init_service_check # A better kind of sysstat, with the top process per time slice start_dstat +# Etcd +# ----- + +# etcd is a distributed key value store that provides a reliable way to store data across a cluster of machines +if is_service_enabled etcd3; then + start_etcd3 +fi # Keystone # -------- +# Rather than just export these, we write them out to a +# intermediate userrc file that can also be used to debug if +# something goes wrong between here and running +# tools/create_userrc.sh (this script relies on services other +# than keystone being available, so we can't call it right now) +cat > $TOP_DIR/userrc_early <> $TOP_DIR/userrc_early + start_tls_proxy http-services '*' 443 $SERVICE_HOST 80 +fi + +source $TOP_DIR/userrc_early + if is_service_enabled keystone; then echo_summary "Starting Keystone" if [ "$KEYSTONE_AUTH_HOST" == "$SERVICE_HOST" ]; then init_keystone start_keystone + bootstrap_keystone fi - # Set up a temporary admin URI for Keystone - SERVICE_ENDPOINT=$KEYSTONE_AUTH_URI/v2.0 - - if is_service_enabled tls-proxy; then - export OS_CACERT=$INT_CA_DIR/ca-chain.pem - # Until the client support is fixed, just use the internal endpoint - SERVICE_ENDPOINT=http://$KEYSTONE_AUTH_HOST:$KEYSTONE_AUTH_PORT_INT/v2.0 - fi - - # Setup OpenStackClient token-endpoint auth - export OS_TOKEN=$SERVICE_TOKEN - export OS_URL=$SERVICE_ENDPOINT - create_keystone_accounts - create_nova_accounts - create_glance_accounts - create_cinder_accounts - create_neutron_accounts - - if is_service_enabled ceilometer; then - create_ceilometer_accounts + if is_service_enabled nova; then + create_nova_accounts + fi + if is_service_enabled glance; then + create_glance_accounts + fi + if is_service_enabled cinder; then + create_cinder_accounts + fi + if is_service_enabled neutron; then + create_neutron_accounts fi - if is_service_enabled swift; then create_swift_accounts fi - if is_service_enabled heat; then - create_heat_accounts - fi - - # Begone token auth - unset OS_TOKEN OS_URL - - # Set up password auth credentials now that Keystone is bootstrapped - export OS_AUTH_URL=$SERVICE_ENDPOINT - export OS_TENANT_NAME=admin - export OS_USERNAME=admin - export OS_PASSWORD=$ADMIN_PASSWORD - export OS_REGION_NAME=$REGION_NAME -fi - - -# ZeroMQ -# ------ -if is_service_enabled zeromq; then - echo_summary "Starting zeromq receiver" - run_process zeromq "$OSLO_BIN_DIR/oslo-messaging-zmq-receiver" fi +# Write a clouds.yaml file +write_clouds_yaml # Horizon # ------- -# Set up the django horizon application to serve via apache/wsgi - if is_service_enabled horizon; then - echo_summary "Configuring and starting Horizon" - init_horizon - start_horizon + echo_summary "Configuring Horizon" + configure_horizon fi @@ -1051,21 +1142,13 @@ if is_service_enabled neutron; then echo_summary "Configuring Neutron" configure_neutron + # Run init_neutron only on the node hosting the Neutron API server - if is_service_enabled $DATABASE_BACKENDS && is_service_enabled q-svc; then + if is_service_enabled $DATABASE_BACKENDS && is_service_enabled neutron; then init_neutron fi fi -# Some Neutron plugins require network controllers which are not -# a part of the OpenStack project. Configure and start them. -if is_service_enabled neutron; then - configure_neutron_third_party - init_neutron_third_party - start_neutron_third_party -fi - - # Nova # ---- @@ -1095,7 +1178,7 @@ fi # Storage Service # --------------- -if is_service_enabled s-proxy; then +if is_service_enabled swift; then echo_summary "Configuring Swift" init_swift fi @@ -1109,6 +1192,13 @@ if is_service_enabled cinder; then init_cinder fi +# Placement Service +# --------------- + +if is_service_enabled placement; then + echo_summary "Configuring placement" + init_placement +fi # Compute Service # --------------- @@ -1119,7 +1209,7 @@ if is_service_enabled nova; then # Additional Nova configuration that is dependent on other services if is_service_enabled neutron; then - create_nova_conf_neutron + configure_neutron_nova elif is_service_enabled n-net; then create_nova_conf_nova_network fi @@ -1149,7 +1239,7 @@ merge_config_group $TOP_DIR/local.conf post-config # Only run the services specified in ``ENABLED_SERVICES`` # Launch Swift Services -if is_service_enabled s-proxy; then +if is_service_enabled swift; then echo_summary "Starting Swift" start_swift fi @@ -1172,32 +1262,25 @@ fi # See https://help.ubuntu.com/community/CloudInit for more on ``cloud-init`` if is_service_enabled g-reg; then - TOKEN=$(openstack token issue -c id -f value) - die_if_not_set $LINENO TOKEN "Keystone fail to get token" echo_summary "Uploading images" - # Option to upload legacy ami-tty, which works with xenserver - if [[ -n "$UPLOAD_LEGACY_TTY" ]]; then - IMAGE_URLS="${IMAGE_URLS:+${IMAGE_URLS},}https://github.com/downloads/citrix-openstack/warehouse/tty.tgz" - fi - for image_url in ${IMAGE_URLS//,/ }; do - upload_image $image_url $TOKEN + upload_image $image_url done fi -# Create an access key and secret key for Nova EC2 register image -if is_service_enabled keystone && is_service_enabled swift3 && is_service_enabled nova; then - eval $(openstack ec2 credentials create --user nova --project $SERVICE_TENANT_NAME -f shell -c access -c secret) - iniset $NOVA_CONF DEFAULT s3_access_key "$access" - iniset $NOVA_CONF DEFAULT s3_secret_key "$secret" - iniset $NOVA_CONF DEFAULT s3_affix_tenant "True" +# NOTE(lyarwood): By default use a single hardcoded fixed_key across devstack +# deployments. This ensures the keys match across nova and cinder across all +# hosts. +FIXED_KEY=${FIXED_KEY:-bae3516cc1c0eb18b05440eba8012a4a880a2ee04d584a9c1579445e675b12defdc716ec} +if is_service_enabled nova; then + iniset $NOVA_CONF key_manager fixed_key "$FIXED_KEY" + iniset $NOVA_CPU_CONF key_manager fixed_key "$FIXED_KEY" fi -# Create a randomized default value for the keymgr's fixed_key -if is_service_enabled nova; then - iniset $NOVA_CONF keymgr fixed_key $(generate_hex_string 32) +if is_service_enabled cinder; then + iniset $CINDER_CONF key_manager fixed_key "$FIXED_KEY" fi # Launch the nova-api and wait for it to answer before continuing @@ -1206,10 +1289,13 @@ if is_service_enabled n-api; then start_nova_api fi -if is_service_enabled q-svc; then +if is_service_enabled neutron-api; then + echo_summary "Starting Neutron" + start_neutron_api +elif is_service_enabled q-svc; then echo_summary "Starting Neutron" + configure_neutron_after_post_config start_neutron_service_and_check - check_neutron_third_party_integration elif is_service_enabled $DATABASE_BACKENDS && is_service_enabled n-net; then NM_CONF=${NOVA_CONF} if is_service_enabled n-cell; then @@ -1226,41 +1312,38 @@ elif is_service_enabled $DATABASE_BACKENDS && is_service_enabled n-net; then $NOVA_BIN_DIR/nova-manage --config-file $NM_CONF floating create --ip_range=$TEST_FLOATING_RANGE --pool=$TEST_FLOATING_POOL fi +# Start placement before any of the service that are likely to want +# to use it to manage resource providers. +if is_service_enabled placement; then + echo_summary "Starting Placement" + start_placement +fi + if is_service_enabled neutron; then - start_neutron_agents + start_neutron fi # Once neutron agents are started setup initial network elements if is_service_enabled q-svc && [[ "$NEUTRON_CREATE_INITIAL_NETWORKS" == "True" ]]; then echo_summary "Creating initial neutron network elements" create_neutron_initial_network - setup_neutron_debug fi + if is_service_enabled nova; then echo_summary "Starting Nova" start_nova + create_flavors fi if is_service_enabled cinder; then echo_summary "Starting Cinder" start_cinder create_volume_types fi -if is_service_enabled ceilometer; then - echo_summary "Starting Ceilometer" - init_ceilometer - start_ceilometer -fi - -# Configure and launch Heat engine, api and metadata -if is_service_enabled heat; then - # Initialize heat - echo_summary "Configuring Heat" - init_heat - echo_summary "Starting Heat" - start_heat - if [ "$HEAT_BUILD_PIP_MIRROR" = "True" ]; then - echo_summary "Building Heat pip mirror" - build_heat_pip_mirror - fi + + +if is_service_enabled horizon; then + echo_summary "Starting Horizon" + init_horizon + start_horizon fi @@ -1278,21 +1361,12 @@ if is_service_enabled nova && is_service_enabled keystone; then USERRC_PARAMS="$USERRC_PARAMS --os-cacert $SSL_BUNDLE_FILE" fi - if [[ "$HEAT_STANDALONE" = "True" ]]; then - USERRC_PARAMS="$USERRC_PARAMS --heat-url http://$HEAT_API_HOST:$HEAT_API_PORT/v1" - fi - $TOP_DIR/tools/create_userrc.sh $USERRC_PARAMS fi # Save some values we generated for later use -CURRENT_RUN_TIME=$(date "+$TIMESTAMP_FORMAT") -echo "# $CURRENT_RUN_TIME" >$TOP_DIR/.stackenv -for i in BASE_SQL_CONN ENABLED_SERVICES HOST_IP LOGFILE \ - SERVICE_HOST SERVICE_PROTOCOL STACK_USER TLS_IP KEYSTONE_AUTH_PROTOCOL OS_CACERT; do - echo $i=${!i} >>$TOP_DIR/.stackenv -done +save_stackenv # Wrapup configuration @@ -1321,6 +1395,35 @@ run_phase stack extra merge_config_group $TOP_DIR/local.conf post-extra +# Sanity checks +# ============= + +# Check that computes are all ready +# +# TODO(sdague): there should be some generic phase here. +if is_service_enabled n-cpu; then + is_nova_ready +fi + +# Check the status of running services +service_check + +# Configure nova cellsv2 +# ---------------------- + +# Do this late because it requires compute hosts to have started +if is_service_enabled n-api; then + if is_service_enabled n-cpu; then + $TOP_DIR/tools/discover_hosts.sh + else + # Some CI systems like Hyper-V build the control plane on + # Linux, and join in non Linux Computes after setup. This + # allows them to delay the processing until after their whole + # environment is up. + echo_summary "SKIPPING Cell setup because n-cpu is not enabled. You will have to do this manually before you have a working environment." + fi +fi + # Run local script # ---------------- @@ -1330,10 +1433,6 @@ if [[ -x $TOP_DIR/local.sh ]]; then $TOP_DIR/local.sh fi -# Check the status of running services -service_check - - # Bash completion # =============== @@ -1350,6 +1449,15 @@ if is_service_enabled cinder; then fi fi +# Run test-config +# --------------- + +# Phase: test-config +run_phase stack test-config + +# Apply late configuration from ``local.conf`` if it exists for layer 2 services +# Phase: test-config +merge_config_group $TOP_DIR/local.conf test-config # Fin # === @@ -1365,6 +1473,8 @@ else exec 1>&3 fi +# Dump out the time totals +time_totals # Using the cloud # =============== @@ -1372,12 +1482,15 @@ fi echo "" echo "" echo "" -echo "This is your host ip: $HOST_IP" +echo "This is your host IP address: $HOST_IP" +if [ "$HOST_IPV6" != "" ]; then + echo "This is your host IPv6 address: $HOST_IPV6" +fi # If you installed Horizon on this server you should be able # to access the site using your browser. if is_service_enabled horizon; then - echo "Horizon is now available at http://$SERVICE_HOST/" + echo "Horizon is now available at http://$SERVICE_HOST$HORIZON_APACHE_ROOT" fi # If Keystone is present you can point ``nova`` cli to this server @@ -1389,12 +1502,28 @@ fi # Warn that a deprecated feature was used if [[ -n "$DEPRECATED_TEXT" ]]; then - echo_summary "WARNING: $DEPRECATED_TEXT" + echo + echo -e "WARNING: $DEPRECATED_TEXT" + echo +fi + +# If USE_SYSTEMD is enabled, tell the user about using it. +if [[ "$USE_SYSTEMD" == "True" ]]; then + echo + echo "Services are running under systemd unit files." + echo "For more information see: " + echo "https://docs.openstack.org/devstack/latest/systemd.html" + echo fi +# Useful info on current state +cat /etc/devstack-version +echo + # Indicate how long this took to run (bash maintained variable ``SECONDS``) echo_summary "stack.sh completed in $SECONDS seconds." + # Restore/close logging file descriptors exec 1>&3 exec 2>&3 diff --git a/stackrc b/stackrc index 938a09a56d..8463313625 100644 --- a/stackrc +++ b/stackrc @@ -2,12 +2,29 @@ # # stackrc # + +# ensure we don't re-source this in the same environment +[[ -z "$_DEVSTACK_STACKRC" ]] || return 0 +declare -r -g _DEVSTACK_STACKRC=1 + # Find the other rc files RC_DIR=$(cd $(dirname "${BASH_SOURCE:-$0}") && pwd) # Source required DevStack functions and globals source $RC_DIR/functions +# Set the target branch. This is used so that stable branching +# does not need to update each repo below. +TARGET_BRANCH=master + +# Cycle trailing projects need to branch later than the others. +TRAILING_TARGET_BRANCH=master + +# And some repos do not create stable branches, so this is used +# to make it explicit and avoid accidentally setting to a stable +# branch. +BRANCHLESS_TARGET_BRANCH=master + # Destination path for installation DEST=/opt/stack @@ -17,6 +34,9 @@ DATA_DIR=${DEST}/data # Destination for status files SERVICE_DIR=${DEST}/status +# Path for subunit output file +SUBUNIT_OUTPUT=${DEST}/devstack.subunit + # Determine stack user if [[ $EUID -eq 0 ]]; then STACK_USER=stack @@ -27,75 +47,107 @@ fi # Specify region name Region REGION_NAME=${REGION_NAME:-RegionOne} +# Specify name of region where identity service endpoint is registered. +# When deploying multiple DevStack instances in different regions with shared +# Keystone, set KEYSTONE_REGION_NAME to the region where Keystone is running +# for DevStack instances which do not host Keystone. +KEYSTONE_REGION_NAME=${KEYSTONE_REGION_NAME:-$REGION_NAME} + # Specify which services to launch. These generally correspond to # screen tabs. To change the default list, use the ``enable_service`` and # ``disable_service`` functions in ``local.conf``. -# For example, to enable Swift add this to ``local.conf``: -# enable_service s-proxy s-object s-container s-account -# In order to enable Neutron (a single node setup) add the following +# For example, to enable Swift as part of DevStack add the following # settings in ``local.conf``: # [[local|localrc]] -# disable_service n-net -# enable_service q-svc -# enable_service q-agt -# enable_service q-dhcp -# enable_service q-l3 -# enable_service q-meta -# # Optional, to enable tempest configuration as part of DevStack -# enable_service tempest - +# enable_service s-proxy s-object s-container s-account # This allows us to pass ``ENABLED_SERVICES`` if ! isset ENABLED_SERVICES ; then # Keystone - nothing works without keystone ENABLED_SERVICES=key # Nova - services to support libvirt based openstack clouds - ENABLED_SERVICES+=,n-api,n-cpu,n-net,n-cond,n-sch,n-novnc,n-crt,n-cauth + ENABLED_SERVICES+=,n-api,n-cpu,n-cond,n-sch,n-novnc,n-cauth,n-api-meta + # Placement service needed for Nova + ENABLED_SERVICES+=,placement-api,placement-client # Glance services needed for Nova ENABLED_SERVICES+=,g-api,g-reg # Cinder ENABLED_SERVICES+=,c-sch,c-api,c-vol + # Neutron + ENABLED_SERVICES+=,q-svc,q-dhcp,q-meta,q-agt,q-l3 # Dashboard ENABLED_SERVICES+=,horizon # Additional services - ENABLED_SERVICES+=,rabbit,tempest,mysql,dstat + ENABLED_SERVICES+=,rabbit,tempest,mysql,etcd3,dstat fi -# SQLAlchemy supports multiple database drivers for each database server -# type. For example, deployer may use MySQLdb, MySQLConnector, or oursql -# to access MySQL database. -# -# When defined, the variable controls which database driver is used to -# connect to database server. Otherwise using default driver defined for -# each database type. -# -# You can find the list of currently supported drivers for each database -# type at: http://docs.sqlalchemy.org/en/rel_0_9/core/engines.html -# SQLALCHEMY_DATABASE_DRIVER="mysqldb" - # Global toggle for enabling services under mod_wsgi. If this is set to # ``True`` all services that use HTTPD + mod_wsgi as the preferred method of # deployment, will be deployed under Apache. If this is set to ``False`` all # services will rely on the local toggle variable (e.g. ``KEYSTONE_USE_MOD_WSGI``) ENABLE_HTTPD_MOD_WSGI_SERVICES=True -# Tell Tempest which services are available. The default is set here as -# Tempest falls late in the configuration sequence. This differs from -# ``ENABLED_SERVICES`` in that the project names are used here rather than -# the service names, i.e.: ``TEMPEST_SERVICES="key,glance,nova"`` -TEMPEST_SERVICES="" - # Set the default Nova APIs to enable -NOVA_ENABLED_APIS=ec2,osapi_compute,metadata +NOVA_ENABLED_APIS=osapi_compute,metadata -# Configure Identity API version: 2.0, 3 -IDENTITY_API_VERSION=2.0 +# CELLSV2_SETUP - how we should configure services with cells v2 +# +# - superconductor - this is one conductor for the api services, and +# one per cell managing the compute services. This is preferred +# - singleconductor - this is one conductor for the whole deployment, +# this is not recommended, and will be removed in the future. +CELLSV2_SETUP=${CELLSV2_SETUP:-"superconductor"} + +# Set the root URL for Horizon +HORIZON_APACHE_ROOT="/dashboard" + +# Whether to use SYSTEMD to manage services, we only do this from +# Queens forward. +USE_SYSTEMD="True" +USER_UNITS=$(trueorfalse False USER_UNITS) +if [[ "$USER_UNITS" == "True" ]]; then + SYSTEMD_DIR="$HOME/.local/share/systemd/user" + SYSTEMCTL="systemctl --user" +else + SYSTEMD_DIR="/etc/systemd/system" + SYSTEMCTL="sudo systemctl" +fi + + +# Whether or not to enable Kernel Samepage Merging (KSM) if available. +# This allows programs that mark their memory as mergeable to share +# memory pages if they are identical. This is particularly useful with +# libvirt backends. This reduces memory usage at the cost of CPU overhead +# to scan memory. We default to enabling it because we tend to be more +# memory constrained than CPU bound. +ENABLE_KSM=$(trueorfalse True ENABLE_KSM) + +# Passwords generated by interactive devstack runs +if [[ -r $RC_DIR/.localrc.password ]]; then + source $RC_DIR/.localrc.password +fi + +# Control whether Python 3 should be used at all. +export USE_PYTHON3=$(trueorfalse False USE_PYTHON3) + +# Control whether Python 3 is enabled for specific services by the +# base name of the directory from which they are installed. See +# enable_python3_package to edit this variable and use_python3_for to +# test membership. +export ENABLED_PYTHON3_PACKAGES="nova,glance,cinder,uwsgi,python-openstackclient,openstacksdk" -# Whether to use 'dev mode' for screen windows. Dev mode works by -# stuffing text into the screen windows so that a developer can use -# ctrl-c, up-arrow, enter to restart the service. Starting services -# this way is slightly unreliable, and a bit slower, so this can -# be disabled for automated testing by setting this value to False. -USE_SCREEN=True +# Explicitly list services not to run under Python 3. See +# disable_python3_package to edit this variable. +export DISABLED_PYTHON3_PACKAGES="" + +# When Python 3 is supported by an application, adding the specific +# version of Python 3 to this variable will install the app using that +# version of the interpreter instead of 2.7. +_DEFAULT_PYTHON3_VERSION="$(_get_python_version python3)" +export PYTHON3_VERSION=${PYTHON3_VERSION:-${_DEFAULT_PYTHON3_VERSION:-3.5}} + +# Just to be more explicit on the Python 2 version to use. +_DEFAULT_PYTHON2_VERSION="$(_get_python_version python2)" +export PYTHON2_VERSION=${PYTHON2_VERSION:-${_DEFAULT_PYTHON2_VERSION:-2.7}} # allow local overrides of env variables, including repo config if [[ -f $RC_DIR/localrc ]]; then @@ -106,6 +158,49 @@ elif [[ -f $RC_DIR/.localrc.auto ]]; then source $RC_DIR/.localrc.auto fi +# Default for log coloring is based on interactive-or-not. +# Baseline assumption is that non-interactive invocations are for CI, +# where logs are to be presented as browsable text files; hence color +# codes should be omitted. +# Simply override LOG_COLOR if your environment is different. +if [ -t 1 ]; then + _LOG_COLOR_DEFAULT=True +else + _LOG_COLOR_DEFAULT=False +fi + +# Use color for logging output (only available if syslog is not used) +LOG_COLOR=$(trueorfalse $_LOG_COLOR_DEFAULT LOG_COLOR) + +# Make tracing more educational +if [[ "$LOG_COLOR" == "True" ]]; then + # tput requires TERM or -T. If neither is present, use vt100, a + # no-frills least common denominator supported everywhere. + TPUT_T= + if ! [ $TERM ]; then + TPUT_T='-T vt100' + fi + export PS4='+\[$(tput '$TPUT_T' setaf 242)\]$(short_source)\[$(tput '$TPUT_T' sgr0)\] ' +else + export PS4='+ $(short_source): ' +fi + +# Configure Identity API version: 2.0, 3 +IDENTITY_API_VERSION=${IDENTITY_API_VERSION:-3} + +# Set the option ENABLE_IDENTITY_V2 to True. It defines whether the DevStack +# deployment will be deploying the Identity v2 pipelines. If this option is set +# to ``False``, DevStack will: i) disable Identity v2; ii) configure Tempest to +# skip Identity v2 specific tests; and iii) configure Horizon to use Identity +# v3. When this option is set to ``False``, the option IDENTITY_API_VERSION +# will to be set to ``3`` in order to make DevStack register the Identity +# endpoint as v3. This flag is experimental and will be used as basis to +# identify the projects which still have issues to operate with Identity v3. +ENABLE_IDENTITY_V2=$(trueorfalse False ENABLE_IDENTITY_V2) +if [ "$ENABLE_IDENTITY_V2" == "False" ]; then + IDENTITY_API_VERSION=3 +fi + # Enable use of Python virtual environments. Individual project use of # venvs are controlled by the PROJECT_VENV array; every project with # an entry in the array will be installed into the named venv. @@ -116,11 +211,6 @@ USE_VENV=$(trueorfalse False USE_VENV) # requirmenets files here, in a comma-separated list ADDITIONAL_VENV_PACKAGES=${ADITIONAL_VENV_PACKAGES:-""} -# Configure wheel cache location -export WHEELHOUSE=${WHEELHOUSE:-$DEST/.wheelhouse} -export PIP_WHEEL_DIR=${PIP_WHEEL_DIR:-$WHEELHOUSE} -export PIP_FIND_LINKS=${PIP_FIND_LINKS:-file://$WHEELHOUSE} - # This can be used to turn database query logging on and off # (currently only implemented for MySQL backend) DATABASE_QUERY_LOGGING=$(trueorfalse False DATABASE_QUERY_LOGGING) @@ -136,17 +226,11 @@ DATABASE_QUERY_LOGGING=$(trueorfalse False DATABASE_QUERY_LOGGING) # Zero disables timeouts GIT_TIMEOUT=${GIT_TIMEOUT:-0} -# Requirements enforcing mode -# -# - strict (default) : ensure all project requirements files match -# what's in global requirements. -# -# - soft : enforce requirements on everything in -# requirements/projects.txt, but do soft updates on all other -# repositories (i.e. sync versions for requirements that are in g-r, -# but pass through any extras) -REQUIREMENTS_MODE=${REQUIREMENTS_MODE:-strict} - +# How should we be handling WSGI deployments. By default we're going +# to allow for 2 modes, which is "uwsgi" which runs with an apache +# proxy uwsgi in front of it, or "mod_wsgi", which runs in +# apache. mod_wsgi is deprecated, don't use it. +WSGI_MODE=${WSGI_MODE:-"uwsgi"} # Repositories # ------------ @@ -155,6 +239,9 @@ REQUIREMENTS_MODE=${REQUIREMENTS_MODE:-strict} # Another option is https://git.openstack.org GIT_BASE=${GIT_BASE:-git://git.openstack.org} +# The location of REQUIREMENTS once cloned +REQUIREMENTS_DIR=$DEST/requirements + # Which libraries should we install from git instead of using released # versions on pypi? # @@ -167,7 +254,11 @@ GIT_BASE=${GIT_BASE:-git://git.openstack.org} # ex: LIBS_FROM_GIT=python-keystoneclient,oslo.config # # Will install those 2 libraries from git, the rest from pypi. +# +# Setting the variable to 'ALL' will activate the download for all +# libraries. +DEVSTACK_SERIES="stein" ############## # @@ -175,61 +266,41 @@ GIT_BASE=${GIT_BASE:-git://git.openstack.org} # ############## -# telemetry service -CEILOMETER_REPO=${CEILOMETER_REPO:-${GIT_BASE}/openstack/ceilometer.git} -CEILOMETER_BRANCH=${CEILOMETER_BRANCH:-master} - # block storage service CINDER_REPO=${CINDER_REPO:-${GIT_BASE}/openstack/cinder.git} -CINDER_BRANCH=${CINDER_BRANCH:-master} +CINDER_BRANCH=${CINDER_BRANCH:-$TARGET_BRANCH} # image catalog service GLANCE_REPO=${GLANCE_REPO:-${GIT_BASE}/openstack/glance.git} -GLANCE_BRANCH=${GLANCE_BRANCH:-master} - -# heat service -HEAT_REPO=${HEAT_REPO:-${GIT_BASE}/openstack/heat.git} -HEAT_BRANCH=${HEAT_BRANCH:-master} +GLANCE_BRANCH=${GLANCE_BRANCH:-$TARGET_BRANCH} # django powered web control panel for openstack HORIZON_REPO=${HORIZON_REPO:-${GIT_BASE}/openstack/horizon.git} -HORIZON_BRANCH=${HORIZON_BRANCH:-master} - -# baremetal provisioning service -IRONIC_REPO=${IRONIC_REPO:-${GIT_BASE}/openstack/ironic.git} -IRONIC_BRANCH=${IRONIC_BRANCH:-master} +HORIZON_BRANCH=${HORIZON_BRANCH:-$TARGET_BRANCH} # unified auth system (manages accounts/tokens) KEYSTONE_REPO=${KEYSTONE_REPO:-${GIT_BASE}/openstack/keystone.git} -KEYSTONE_BRANCH=${KEYSTONE_BRANCH:-master} +KEYSTONE_BRANCH=${KEYSTONE_BRANCH:-$TARGET_BRANCH} # neutron service NEUTRON_REPO=${NEUTRON_REPO:-${GIT_BASE}/openstack/neutron.git} -NEUTRON_BRANCH=${NEUTRON_BRANCH:-master} +NEUTRON_BRANCH=${NEUTRON_BRANCH:-$TARGET_BRANCH} # neutron fwaas service NEUTRON_FWAAS_REPO=${NEUTRON_FWAAS_REPO:-${GIT_BASE}/openstack/neutron-fwaas.git} -NEUTRON_FWAAS_BRANCH=${NEUTRON_FWAAS_BRANCH:-master} - -# neutron lbaas service -NEUTRON_LBAAS_REPO=${NEUTRON_LBAAS_REPO:-${GIT_BASE}/openstack/neutron-lbaas.git} -NEUTRON_LBAAS_BRANCH=${NEUTRON_LBAAS_BRANCH:-master} - -# neutron vpnaas service -NEUTRON_VPNAAS_REPO=${NEUTRON_VPNAAS_REPO:-${GIT_BASE}/openstack/neutron-vpnaas.git} -NEUTRON_VPNAAS_BRANCH=${NEUTRON_VPNAAS_BRANCH:-master} +NEUTRON_FWAAS_BRANCH=${NEUTRON_FWAAS_BRANCH:-$TARGET_BRANCH} # compute service NOVA_REPO=${NOVA_REPO:-${GIT_BASE}/openstack/nova.git} -NOVA_BRANCH=${NOVA_BRANCH:-master} - -# data processing service -SAHARA_REPO=${SAHARA_REPO:-${GIT_BASE}/openstack/sahara.git} -SAHARA_BRANCH=${SAHARA_BRANCH:-master} +NOVA_BRANCH=${NOVA_BRANCH:-$TARGET_BRANCH} # object storage service SWIFT_REPO=${SWIFT_REPO:-${GIT_BASE}/openstack/swift.git} -SWIFT_BRANCH=${SWIFT_BRANCH:-master} +SWIFT_BRANCH=${SWIFT_BRANCH:-$TARGET_BRANCH} + +# placement service +PLACEMENT_REPO=${PLACEMENT_REPO:-${GIT_BASE}/openstack/placement.git} +PLACEMENT_BRANCH=${PLACEMENT_BRANCH:-$TARGET_BRANCH} ############## # @@ -239,159 +310,196 @@ SWIFT_BRANCH=${SWIFT_BRANCH:-master} # consolidated openstack requirements REQUIREMENTS_REPO=${REQUIREMENTS_REPO:-${GIT_BASE}/openstack/requirements.git} -REQUIREMENTS_BRANCH=${REQUIREMENTS_BRANCH:-master} +REQUIREMENTS_BRANCH=${REQUIREMENTS_BRANCH:-$TARGET_BRANCH} # Tempest test suite TEMPEST_REPO=${TEMPEST_REPO:-${GIT_BASE}/openstack/tempest.git} -TEMPEST_BRANCH=${TEMPEST_BRANCH:-master} - -# TODO(sdague): this should end up as a library component like below -GITREPO["tempest-lib"]=${TEMPEST_LIB_REPO:-${GIT_BASE}/openstack/tempest-lib.git} -GITBRANCH["tempest-lib"]=${TEMPEST_LIB_BRANCH:-master} +TEMPEST_BRANCH=${TEMPEST_BRANCH:-$BRANCHLESS_TARGET_BRANCH} ############## # -# OpenStack Client Library Componets +# OpenStack Client Library Components +# Note default install is from pip, see LIBS_FROM_GIT # ############## -# ceilometer client library -GITREPO["python-ceilometerclient"]=${CEILOMETERCLIENT_REPO:-${GIT_BASE}/openstack/python-ceilometerclient.git} -GITBRANCH["python-ceilometerclient"]=${CEILOMETERCLIENT_BRANCH:-master} - # volume client GITREPO["python-cinderclient"]=${CINDERCLIENT_REPO:-${GIT_BASE}/openstack/python-cinderclient.git} -GITBRANCH["python-cinderclient"]=${CINDERCLIENT_BRANCH:-master} +GITBRANCH["python-cinderclient"]=${CINDERCLIENT_BRANCH:-$TARGET_BRANCH} + +# os-brick client for local volume attachement +GITREPO["python-brick-cinderclient-ext"]=${BRICK_CINDERCLIENT_REPO:-${GIT_BASE}/openstack/python-brick-cinderclient-ext.git} +GITBRANCH["python-brick-cinderclient-ext"]=${BRICK_CINDERCLIENT_BRANCH:-$TARGET_BRANCH} + +# python barbican client library +GITREPO["python-barbicanclient"]=${BARBICANCLIENT_REPO:-${GIT_BASE}/openstack/python-barbicanclient.git} +GITBRANCH["python-barbicanclient"]=${BARBICANCLIENT_BRANCH:-$TARGET_BRANCH} +GITDIR["python-barbicanclient"]=$DEST/python-barbicanclient # python glance client library GITREPO["python-glanceclient"]=${GLANCECLIENT_REPO:-${GIT_BASE}/openstack/python-glanceclient.git} -GITBRANCH["python-glanceclient"]=${GLANCECLIENT_BRANCH:-master} - -# python heat client library -GITREPO["python-heatclient"]=${HEATCLIENT_REPO:-${GIT_BASE}/openstack/python-heatclient.git} -GITBRANCH["python-heatclient"]=${HEATCLIENT_BRANCH:-master} +GITBRANCH["python-glanceclient"]=${GLANCECLIENT_BRANCH:-$TARGET_BRANCH} # ironic client GITREPO["python-ironicclient"]=${IRONICCLIENT_REPO:-${GIT_BASE}/openstack/python-ironicclient.git} -GITBRANCH["python-ironicclient"]=${IRONICCLIENT_BRANCH:-master} +GITBRANCH["python-ironicclient"]=${IRONICCLIENT_BRANCH:-$TARGET_BRANCH} +# ironic plugin is out of tree, but nova uses it. set GITDIR here. +GITDIR["python-ironicclient"]=$DEST/python-ironicclient + +# the base authentication plugins that clients use to authenticate +GITREPO["keystoneauth"]=${KEYSTONEAUTH_REPO:-${GIT_BASE}/openstack/keystoneauth.git} +GITBRANCH["keystoneauth"]=${KEYSTONEAUTH_BRANCH:-$TARGET_BRANCH} # python keystone client library to nova that horizon uses GITREPO["python-keystoneclient"]=${KEYSTONECLIENT_REPO:-${GIT_BASE}/openstack/python-keystoneclient.git} -GITBRANCH["python-keystoneclient"]=${KEYSTONECLIENT_BRANCH:-master} +GITBRANCH["python-keystoneclient"]=${KEYSTONECLIENT_BRANCH:-$TARGET_BRANCH} # neutron client GITREPO["python-neutronclient"]=${NEUTRONCLIENT_REPO:-${GIT_BASE}/openstack/python-neutronclient.git} -GITBRANCH["python-neutronclient"]=${NEUTRONCLIENT_BRANCH:-master} +GITBRANCH["python-neutronclient"]=${NEUTRONCLIENT_BRANCH:-$TARGET_BRANCH} # python client library to nova that horizon (and others) use GITREPO["python-novaclient"]=${NOVACLIENT_REPO:-${GIT_BASE}/openstack/python-novaclient.git} -GITBRANCH["python-novaclient"]=${NOVACLIENT_BRANCH:-master} - -# python saharaclient -GITREPO["python-saharaclient"]=${SAHARACLIENT_REPO:-${GIT_BASE}/openstack/python-saharaclient.git} -GITBRANCH["python-saharaclient"]=${SAHARACLIENT_BRANCH:-master} +GITBRANCH["python-novaclient"]=${NOVACLIENT_BRANCH:-$TARGET_BRANCH} # python swift client library GITREPO["python-swiftclient"]=${SWIFTCLIENT_REPO:-${GIT_BASE}/openstack/python-swiftclient.git} -GITBRANCH["python-swiftclient"]=${SWIFTCLIENT_BRANCH:-master} +GITBRANCH["python-swiftclient"]=${SWIFTCLIENT_BRANCH:-$TARGET_BRANCH} # consolidated openstack python client GITREPO["python-openstackclient"]=${OPENSTACKCLIENT_REPO:-${GIT_BASE}/openstack/python-openstackclient.git} -GITBRANCH["python-openstackclient"]=${OPENSTACKCLIENT_BRANCH:-master} +GITBRANCH["python-openstackclient"]=${OPENSTACKCLIENT_BRANCH:-$TARGET_BRANCH} # this doesn't exist in a lib file, so set it here GITDIR["python-openstackclient"]=$DEST/python-openstackclient +# placement-api CLI +GITREPO["osc-placement"]=${OSC_PLACEMENT_REPO:-${GIT_BASE}/openstack/osc-placement.git} +GITBRANCH["osc-placement"]=${OSC_PLACEMENT_BRANCH:-$TARGET_BRANCH} + ################### # # Oslo Libraries +# Note default install is from pip, see LIBS_FROM_GIT # ################### +# castellan key manager interface +GITREPO["castellan"]=${CASTELLAN_REPO:-${GIT_BASE}/openstack/castellan.git} +GITBRANCH["castellan"]=${CASTELLAN_BRANCH:-$TARGET_BRANCH} + # cliff command line framework GITREPO["cliff"]=${CLIFF_REPO:-${GIT_BASE}/openstack/cliff.git} -GITBRANCH["cliff"]=${CLIFF_BRANCH:-master} +GITBRANCH["cliff"]=${CLIFF_BRANCH:-$TARGET_BRANCH} + +# async framework/helpers +GITREPO["futurist"]=${FUTURIST_REPO:-${GIT_BASE}/openstack/futurist.git} +GITBRANCH["futurist"]=${FUTURIST_BRANCH:-$TARGET_BRANCH} # debtcollector deprecation framework/helpers GITREPO["debtcollector"]=${DEBTCOLLECTOR_REPO:-${GIT_BASE}/openstack/debtcollector.git} -GITBRANCH["debtcollector"]=${DEBTCOLLECTOR_BRANCH:-master} +GITBRANCH["debtcollector"]=${DEBTCOLLECTOR_BRANCH:-$TARGET_BRANCH} + +# helpful state machines +GITREPO["automaton"]=${AUTOMATON_REPO:-${GIT_BASE}/openstack/automaton.git} +GITBRANCH["automaton"]=${AUTOMATON_BRANCH:-$TARGET_BRANCH} + +# oslo.cache +GITREPO["oslo.cache"]=${OSLOCACHE_REPO:-${GIT_BASE}/openstack/oslo.cache.git} +GITBRANCH["oslo.cache"]=${OSLOCACHE_BRANCH:-$TARGET_BRANCH} # oslo.concurrency GITREPO["oslo.concurrency"]=${OSLOCON_REPO:-${GIT_BASE}/openstack/oslo.concurrency.git} -GITBRANCH["oslo.concurrency"]=${OSLOCON_BRANCH:-master} +GITBRANCH["oslo.concurrency"]=${OSLOCON_BRANCH:-$TARGET_BRANCH} # oslo.config GITREPO["oslo.config"]=${OSLOCFG_REPO:-${GIT_BASE}/openstack/oslo.config.git} -GITBRANCH["oslo.config"]=${OSLOCFG_BRANCH:-master} +GITBRANCH["oslo.config"]=${OSLOCFG_BRANCH:-$TARGET_BRANCH} # oslo.context GITREPO["oslo.context"]=${OSLOCTX_REPO:-${GIT_BASE}/openstack/oslo.context.git} -GITBRANCH["oslo.context"]=${OSLOCTX_BRANCH:-master} +GITBRANCH["oslo.context"]=${OSLOCTX_BRANCH:-$TARGET_BRANCH} # oslo.db GITREPO["oslo.db"]=${OSLODB_REPO:-${GIT_BASE}/openstack/oslo.db.git} -GITBRANCH["oslo.db"]=${OSLODB_BRANCH:-master} +GITBRANCH["oslo.db"]=${OSLODB_BRANCH:-$TARGET_BRANCH} # oslo.i18n GITREPO["oslo.i18n"]=${OSLOI18N_REPO:-${GIT_BASE}/openstack/oslo.i18n.git} -GITBRANCH["oslo.i18n"]=${OSLOI18N_BRANCH:-master} +GITBRANCH["oslo.i18n"]=${OSLOI18N_BRANCH:-$TARGET_BRANCH} # oslo.log GITREPO["oslo.log"]=${OSLOLOG_REPO:-${GIT_BASE}/openstack/oslo.log.git} -GITBRANCH["oslo.log"]=${OSLOLOG_BRANCH:-master} +GITBRANCH["oslo.log"]=${OSLOLOG_BRANCH:-$TARGET_BRANCH} # oslo.messaging GITREPO["oslo.messaging"]=${OSLOMSG_REPO:-${GIT_BASE}/openstack/oslo.messaging.git} -GITBRANCH["oslo.messaging"]=${OSLOMSG_BRANCH:-master} +GITBRANCH["oslo.messaging"]=${OSLOMSG_BRANCH:-$TARGET_BRANCH} # oslo.middleware GITREPO["oslo.middleware"]=${OSLOMID_REPO:-${GIT_BASE}/openstack/oslo.middleware.git} -GITBRANCH["oslo.middleware"]=${OSLOMID_BRANCH:-master} +GITBRANCH["oslo.middleware"]=${OSLOMID_BRANCH:-$TARGET_BRANCH} # oslo.policy GITREPO["oslo.policy"]=${OSLOPOLICY_REPO:-${GIT_BASE}/openstack/oslo.policy.git} -GITBRANCH["oslo.policy"]=${OSLOPOLICY_BRANCH:-master} +GITBRANCH["oslo.policy"]=${OSLOPOLICY_BRANCH:-$TARGET_BRANCH} + +# oslo.privsep +GITREPO["oslo.privsep"]=${OSLOPRIVSEP_REPO:-${GIT_BASE}/openstack/oslo.privsep.git} +GITBRANCH["oslo.privsep"]=${OSLOPRIVSEP_BRANCH:-$TARGET_BRANCH} + +# oslo.reports +GITREPO["oslo.reports"]=${OSLOREPORTS_REPO:-${GIT_BASE}/openstack/oslo.reports.git} +GITBRANCH["oslo.reports"]=${OSLOREPORTS_BRANCH:-$TARGET_BRANCH} # oslo.rootwrap GITREPO["oslo.rootwrap"]=${OSLORWRAP_REPO:-${GIT_BASE}/openstack/oslo.rootwrap.git} -GITBRANCH["oslo.rootwrap"]=${OSLORWRAP_BRANCH:-master} +GITBRANCH["oslo.rootwrap"]=${OSLORWRAP_BRANCH:-$TARGET_BRANCH} # oslo.serialization GITREPO["oslo.serialization"]=${OSLOSERIALIZATION_REPO:-${GIT_BASE}/openstack/oslo.serialization.git} -GITBRANCH["oslo.serialization"]=${OSLOSERIALIZATION_BRANCH:-master} +GITBRANCH["oslo.serialization"]=${OSLOSERIALIZATION_BRANCH:-$TARGET_BRANCH} + +# oslo.service +GITREPO["oslo.service"]=${OSLOSERVICE_REPO:-${GIT_BASE}/openstack/oslo.service.git} +GITBRANCH["oslo.service"]=${OSLOSERVICE_BRANCH:-$TARGET_BRANCH} # oslo.utils GITREPO["oslo.utils"]=${OSLOUTILS_REPO:-${GIT_BASE}/openstack/oslo.utils.git} -GITBRANCH["oslo.utils"]=${OSLOUTILS_BRANCH:-master} +GITBRANCH["oslo.utils"]=${OSLOUTILS_BRANCH:-$TARGET_BRANCH} # oslo.versionedobjects GITREPO["oslo.versionedobjects"]=${OSLOVERSIONEDOBJECTS_REPO:-${GIT_BASE}/openstack/oslo.versionedobjects.git} -GITBRANCH["oslo.versionedobjects"]=${OSLOVERSIONEDOBJECTS_BRANCH:-master} +GITBRANCH["oslo.versionedobjects"]=${OSLOVERSIONEDOBJECTS_BRANCH:-$TARGET_BRANCH} # oslo.vmware GITREPO["oslo.vmware"]=${OSLOVMWARE_REPO:-${GIT_BASE}/openstack/oslo.vmware.git} -GITBRANCH["oslo.vmware"]=${OSLOVMWARE_BRANCH:-master} +GITBRANCH["oslo.vmware"]=${OSLOVMWARE_BRANCH:-$TARGET_BRANCH} + +# osprofiler +GITREPO["osprofiler"]=${OSPROFILER_REPO:-${GIT_BASE}/openstack/osprofiler.git} +GITBRANCH["osprofiler"]=${OSPROFILER_BRANCH:-$TARGET_BRANCH} # pycadf auditing library GITREPO["pycadf"]=${PYCADF_REPO:-${GIT_BASE}/openstack/pycadf.git} -GITBRANCH["pycadf"]=${PYCADF_BRANCH:-master} +GITBRANCH["pycadf"]=${PYCADF_BRANCH:-$TARGET_BRANCH} # stevedore plugin manager GITREPO["stevedore"]=${STEVEDORE_REPO:-${GIT_BASE}/openstack/stevedore.git} -GITBRANCH["stevedore"]=${STEVEDORE_BRANCH:-master} +GITBRANCH["stevedore"]=${STEVEDORE_BRANCH:-$TARGET_BRANCH} # taskflow plugin manager GITREPO["taskflow"]=${TASKFLOW_REPO:-${GIT_BASE}/openstack/taskflow.git} -GITBRANCH["taskflow"]=${TASKFLOW_BRANCH:-master} +GITBRANCH["taskflow"]=${TASKFLOW_BRANCH:-$TARGET_BRANCH} # tooz plugin manager GITREPO["tooz"]=${TOOZ_REPO:-${GIT_BASE}/openstack/tooz.git} -GITBRANCH["tooz"]=${TOOZ_BRANCH:-master} +GITBRANCH["tooz"]=${TOOZ_BRANCH:-$TARGET_BRANCH} # pbr drives the setuptools configs GITREPO["pbr"]=${PBR_REPO:-${GIT_BASE}/openstack-dev/pbr.git} -GITBRANCH["pbr"]=${PBR_BRANCH:-master} +GITBRANCH["pbr"]=${PBR_BRANCH:-$TARGET_BRANCH} ################## @@ -400,34 +508,67 @@ GITBRANCH["pbr"]=${PBR_BRANCH:-master} # ################## +# cursive library +GITREPO["cursive"]=${CURSIVE_REPO:-${GIT_BASE}/openstack/cursive.git} +GITBRANCH["cursive"]=${CURSIVE_BRANCH:-$TARGET_BRANCH} + # glance store library GITREPO["glance_store"]=${GLANCE_STORE_REPO:-${GIT_BASE}/openstack/glance_store.git} -GITBRANCH["glance_store"]=${GLANCE_STORE_BRANCH:-master} - -# heat-cfntools server agent -HEAT_CFNTOOLS_REPO=${HEAT_CFNTOOLS_REPO:-${GIT_BASE}/openstack/heat-cfntools.git} -HEAT_CFNTOOLS_BRANCH=${HEAT_CFNTOOLS_BRANCH:-master} - -# heat example templates and elements -HEAT_TEMPLATES_REPO=${HEAT_TEMPLATES_REPO:-${GIT_BASE}/openstack/heat-templates.git} -HEAT_TEMPLATES_BRANCH=${HEAT_TEMPLATES_BRANCH:-master} - -# django openstack_auth library -GITREPO["django_openstack_auth"]=${HORIZONAUTH_REPO:-${GIT_BASE}/openstack/django_openstack_auth.git} -GITBRANCH["django_openstack_auth"]=${HORIZONAUTH_BRANCH:-master} +GITBRANCH["glance_store"]=${GLANCE_STORE_BRANCH:-$TARGET_BRANCH} # keystone middleware GITREPO["keystonemiddleware"]=${KEYSTONEMIDDLEWARE_REPO:-${GIT_BASE}/openstack/keystonemiddleware.git} -GITBRANCH["keystonemiddleware"]=${KEYSTONEMIDDLEWARE_BRANCH:-master} +GITBRANCH["keystonemiddleware"]=${KEYSTONEMIDDLEWARE_BRANCH:-$TARGET_BRANCH} # s3 support for swift -SWIFT3_REPO=${SWIFT3_REPO:-${GIT_BASE}/stackforge/swift3.git} -SWIFT3_BRANCH=${SWIFT3_BRANCH:-master} +SWIFT3_REPO=${SWIFT3_REPO:-${GIT_BASE}/openstack/swift3.git} +SWIFT3_BRANCH=${SWIFT3_BRANCH:-$TARGET_BRANCH} # ceilometer middleware GITREPO["ceilometermiddleware"]=${CEILOMETERMIDDLEWARE_REPO:-${GIT_BASE}/openstack/ceilometermiddleware.git} -GITBRANCH["ceilometermiddleware"]=${CEILOMETERMIDDLEWARE_BRANCH:-master} +GITBRANCH["ceilometermiddleware"]=${CEILOMETERMIDDLEWARE_BRANCH:-$TARGET_BRANCH} +GITDIR["ceilometermiddleware"]=$DEST/ceilometermiddleware + +# openstacksdk OpenStack Python SDK +GITREPO["openstacksdk"]=${OPENSTACKSDK_REPO:-${GIT_BASE}/openstack/openstacksdk.git} +GITBRANCH["openstacksdk"]=${OPENSTACKSDK_BRANCH:-$TARGET_BRANCH} + +# os-brick library to manage local volume attaches +GITREPO["os-brick"]=${OS_BRICK_REPO:-${GIT_BASE}/openstack/os-brick.git} +GITBRANCH["os-brick"]=${OS_BRICK_BRANCH:-$TARGET_BRANCH} + +# os-client-config to manage clouds.yaml and friends +GITREPO["os-client-config"]=${OS_CLIENT_CONFIG_REPO:-${GIT_BASE}/openstack/os-client-config.git} +GITBRANCH["os-client-config"]=${OS_CLIENT_CONFIG_BRANCH:-$TARGET_BRANCH} +GITDIR["os-client-config"]=$DEST/os-client-config + +# os-vif library to communicate between Neutron to Nova +GITREPO["os-vif"]=${OS_VIF_REPO:-${GIT_BASE}/openstack/os-vif.git} +GITBRANCH["os-vif"]=${OS_VIF_BRANCH:-$TARGET_BRANCH} + +# osc-lib OpenStackClient common lib +GITREPO["osc-lib"]=${OSC_LIB_REPO:-${GIT_BASE}/openstack/osc-lib.git} +GITBRANCH["osc-lib"]=${OSC_LIB_BRANCH:-$TARGET_BRANCH} + +# ironic common lib +GITREPO["ironic-lib"]=${IRONIC_LIB_REPO:-${GIT_BASE}/openstack/ironic-lib.git} +GITBRANCH["ironic-lib"]=${IRONIC_LIB_BRANCH:-$TARGET_BRANCH} +# this doesn't exist in a lib file, so set it here +GITDIR["ironic-lib"]=$DEST/ironic-lib + +# diskimage-builder tool +GITREPO["diskimage-builder"]=${DIB_REPO:-${GIT_BASE}/openstack/diskimage-builder.git} +GITBRANCH["diskimage-builder"]=${DIB_BRANCH:-$TARGET_BRANCH} +GITDIR["diskimage-builder"]=$DEST/diskimage-builder +# neutron-lib library containing neutron stable non-REST interfaces +GITREPO["neutron-lib"]=${NEUTRON_LIB_REPO:-${GIT_BASE}/openstack/neutron-lib.git} +GITBRANCH["neutron-lib"]=${NEUTRON_LIB_BRANCH:-$TARGET_BRANCH} +GITDIR["neutron-lib"]=$DEST/neutron-lib + +# os-traits library for resource provider traits in the placement service +GITREPO["os-traits"]=${OS_TRAITS_REPO:-${GIT_BASE}/openstack/os-traits.git} +GITBRANCH["os-traits"]=${OS_TRAITS_BRANCH:-$TARGET_BRANCH} ################## # @@ -437,19 +578,19 @@ GITBRANCH["ceilometermiddleware"]=${CEILOMETERMIDDLEWARE_BRANCH:-master} # run-parts script required by os-refresh-config DIB_UTILS_REPO=${DIB_UTILS_REPO:-${GIT_BASE}/openstack/dib-utils.git} -DIB_UTILS_BRANCH=${DIB_UTILS_BRANCH:-master} +DIB_UTILS_BRANCH=${DIB_UTILS_BRANCH:-$BRANCHLESS_TARGET_BRANCH} # os-apply-config configuration template tool OAC_REPO=${OAC_REPO:-${GIT_BASE}/openstack/os-apply-config.git} -OAC_BRANCH=${OAC_BRANCH:-master} +OAC_BRANCH=${OAC_BRANCH:-$TRAILING_TARGET_BRANCH} # os-collect-config configuration agent OCC_REPO=${OCC_REPO:-${GIT_BASE}/openstack/os-collect-config.git} -OCC_BRANCH=${OCC_BRANCH:-master} +OCC_BRANCH=${OCC_BRANCH:-$TRAILING_TARGET_BRANCH} # os-refresh-config configuration run-parts tool ORC_REPO=${ORC_REPO:-${GIT_BASE}/openstack/os-refresh-config.git} -ORC_BRANCH=${ORC_BRANCH:-master} +ORC_BRANCH=${ORC_BRANCH:-$TRAILING_TARGET_BRANCH} ################# @@ -462,16 +603,21 @@ ORC_BRANCH=${ORC_BRANCH:-master} # ironic python agent IRONIC_PYTHON_AGENT_REPO=${IRONIC_PYTHON_AGENT_REPO:-${GIT_BASE}/openstack/ironic-python-agent.git} -IRONIC_PYTHON_AGENT_BRANCH=${IRONIC_PYTHON_AGENT_BRANCH:-master} +IRONIC_PYTHON_AGENT_BRANCH=${IRONIC_PYTHON_AGENT_BRANCH:-$TARGET_BRANCH} # a websockets/html5 or flash powered VNC console for vm instances -NOVNC_REPO=${NOVNC_REPO:-https://github.com/kanaka/noVNC.git} -NOVNC_BRANCH=${NOVNC_BRANCH:-master} +NOVNC_REPO=${NOVNC_REPO:-https://github.com/novnc/noVNC.git} +NOVNC_BRANCH=${NOVNC_BRANCH:-stable/v0.6} # a websockets/html5 or flash powered SPICE console for vm instances SPICE_REPO=${SPICE_REPO:-http://anongit.freedesktop.org/git/spice/spice-html5.git} -SPICE_BRANCH=${SPICE_BRANCH:-master} +SPICE_BRANCH=${SPICE_BRANCH:-$BRANCHLESS_TARGET_BRANCH} +# Global flag used to configure Tempest and potentially other services if +# volume multiattach is supported. In Queens, only the libvirt compute driver +# and lvm volume driver support multiattach, and qemu must be less than 2.10 +# or libvirt must be greater than or equal to 3.10. +ENABLE_VOLUME_MULTIATTACH=$(trueorfalse False ENABLE_VOLUME_MULTIATTACH) # Nova hypervisor configuration. We default to libvirt with **kvm** but will # drop back to **qemu** if we are unable to load the kvm module. ``stack.sh`` can @@ -483,12 +629,22 @@ VIRT_DRIVER=${VIRT_DRIVER:-$DEFAULT_VIRT_DRIVER} case "$VIRT_DRIVER" in ironic|libvirt) LIBVIRT_TYPE=${LIBVIRT_TYPE:-kvm} - if [[ "$os_VENDOR" =~ (Debian) ]]; then - LIBVIRT_GROUP=libvirt + if [[ "$os_VENDOR" =~ (Debian|Ubuntu) ]]; then + # The groups change with newer libvirt. Older Ubuntu used + # 'libvirtd', but now uses libvirt like Debian. Do a quick check + # to see if libvirtd group already exists to handle grenade's case. + LIBVIRT_GROUP=$(cut -d ':' -f 1 /etc/group | grep 'libvirtd$' || true) + LIBVIRT_GROUP=${LIBVIRT_GROUP:-libvirt} else LIBVIRT_GROUP=libvirtd fi ;; + lxd) + LXD_GROUP=${LXD_GROUP:-"lxd"} + ;; + docker|zun) + DOCKER_GROUP=${DOCKER_GROUP:-"docker"} + ;; fake) NUMBER_FAKE_NOVA_COMPUTE=${NUMBER_FAKE_NOVA_COMPUTE:-1} ;; @@ -504,6 +660,8 @@ case "$VIRT_DRIVER" in ;; esac +# By default, devstack will use Ubuntu Cloud Archive. +ENABLE_UBUNTU_CLOUD_ARCHIVE=$(trueorfalse True ENABLE_UBUNTU_CLOUD_ARCHIVE) # Images # ------ @@ -527,60 +685,104 @@ esac #IMAGE_URLS="http://smoser.brickies.net/ubuntu/ttylinux-uec/ttylinux-uec-amd64-11.2_2.6.35-15_1.tar.gz" # old ttylinux-uec image #IMAGE_URLS="http://download.cirros-cloud.net/${CIRROS_VERSION}/cirros-${CIRROS_VERSION}-${CIRROS_ARCH}-disk.img" # cirros full disk image -CIRROS_VERSION=${CIRROS_VERSION:-"0.3.4"} +CIRROS_VERSION=${CIRROS_VERSION:-"0.3.6"} CIRROS_ARCH=${CIRROS_ARCH:-"x86_64"} # Set default image based on ``VIRT_DRIVER`` and ``LIBVIRT_TYPE``, either of # which may be set in ``local.conf``. Also allow ``DEFAULT_IMAGE_NAME`` and # ``IMAGE_URLS`` to be set in the `localrc` section of ``local.conf``. -case "$VIRT_DRIVER" in - openvz) - DEFAULT_IMAGE_NAME=${DEFAULT_IMAGE_NAME:-ubuntu-12.04-x86_64} - IMAGE_URLS=${IMAGE_URLS:-"http://download.openvz.org/template/precreated/ubuntu-12.04-x86_64.tar.gz"};; - libvirt) - case "$LIBVIRT_TYPE" in - lxc) # the cirros root disk in the uec tarball is empty, so it will not work for lxc - DEFAULT_IMAGE_NAME=${DEFAULT_IMAGE_NAME:-cirros-${CIRROS_VERSION}-${CIRROS_ARCH}-rootfs} - IMAGE_URLS=${IMAGE_URLS:-"http://download.cirros-cloud.net/${CIRROS_VERSION}/cirros-${CIRROS_VERSION}-${CIRROS_ARCH}-rootfs.img.gz"};; - *) # otherwise, use the uec style image (with kernel, ramdisk, disk) - DEFAULT_IMAGE_NAME=${DEFAULT_IMAGE_NAME:-cirros-${CIRROS_VERSION}-${CIRROS_ARCH}-uec} - IMAGE_URLS=${IMAGE_URLS:-"http://download.cirros-cloud.net/${CIRROS_VERSION}/cirros-${CIRROS_VERSION}-${CIRROS_ARCH}-uec.tar.gz"};; - esac - ;; - vsphere) - DEFAULT_IMAGE_NAME=${DEFAULT_IMAGE_NAME:-cirros-0.3.2-i386-disk.vmdk} - IMAGE_URLS=${IMAGE_URLS:-"http://partnerweb.vmware.com/programs/vmdkimage/cirros-0.3.2-i386-disk.vmdk"};; - xenserver) - DEFAULT_IMAGE_NAME=${DEFAULT_IMAGE_NAME:-cirros-0.3.0-x86_64-disk} - IMAGE_URLS=${IMAGE_URLS:-"https://github.com/downloads/citrix-openstack/warehouse/cirros-0.3.0-x86_64-disk.vhd.tgz"} - IMAGE_URLS+=",http://download.cirros-cloud.net/${CIRROS_VERSION}/cirros-${CIRROS_VERSION}-x86_64-uec.tar.gz";; - ironic) - # Ironic can do both partition and full disk images, depending on the driver - if [[ "$IRONIC_DEPLOY_DRIVER" == "agent_ssh" ]]; then - DEFAULT_IMAGE_NAME=${DEFAULT_IMAGE_NAME:-cirros-${CIRROS_VERSION}-x86_64-disk} - else - DEFAULT_IMAGE_NAME=${DEFAULT_IMAGE_NAME:-cirros-${CIRROS_VERSION}-x86_64-uec} - fi - IMAGE_URLS=${IMAGE_URLS:-"http://download.cirros-cloud.net/${CIRROS_VERSION}/cirros-${CIRROS_VERSION}-x86_64-uec.tar.gz"} - IMAGE_URLS+=",http://download.cirros-cloud.net/${CIRROS_VERSION}/cirros-${CIRROS_VERSION}-x86_64-disk.img";; - *) # Default to Cirros with kernel, ramdisk and disk image - DEFAULT_IMAGE_NAME=${DEFAULT_IMAGE_NAME:-cirros-${CIRROS_VERSION}-${CIRROS_ARCH}-uec} - IMAGE_URLS=${IMAGE_URLS:-"http://download.cirros-cloud.net/${CIRROS_VERSION}/cirros-${CIRROS_VERSION}-${CIRROS_ARCH}-uec.tar.gz"};; -esac - -# Staging Area for New Images, have them here for at least 24hrs for nodepool -# to cache them otherwise the failure rates in the gate are too high -PRECACHE_IMAGES=$(trueorfalse False PRECACHE_IMAGES) -if [[ "$PRECACHE_IMAGES" == "True" ]]; then +DOWNLOAD_DEFAULT_IMAGES=$(trueorfalse True DOWNLOAD_DEFAULT_IMAGES) +if [[ "$DOWNLOAD_DEFAULT_IMAGES" == "True" ]]; then + if [[ -n "$IMAGE_URLS" ]]; then + IMAGE_URLS+="," + fi + case "$VIRT_DRIVER" in + libvirt) + case "$LIBVIRT_TYPE" in + lxc) # the cirros root disk in the uec tarball is empty, so it will not work for lxc + DEFAULT_IMAGE_NAME=${DEFAULT_IMAGE_NAME:-cirros-${CIRROS_VERSION}-${CIRROS_ARCH}-rootfs} + DEFAULT_IMAGE_FILE_NAME=${DEFAULT_IMAGE_FILE_NAME:-cirros-${CIRROS_VERSION}-${CIRROS_ARCH}-rootfs.img.gz} + IMAGE_URLS+="http://download.cirros-cloud.net/${CIRROS_VERSION}/${DEFAULT_IMAGE_FILE_NAME}";; + *) # otherwise, use the qcow image + DEFAULT_IMAGE_NAME=${DEFAULT_IMAGE_NAME:-cirros-${CIRROS_VERSION}-${CIRROS_ARCH}-disk} + DEFAULT_IMAGE_FILE_NAME=${DEFAULT_IMAGE_FILE_NAME:-cirros-${CIRROS_VERSION}-${CIRROS_ARCH}-disk.img} + IMAGE_URLS+="http://download.cirros-cloud.net/${CIRROS_VERSION}/${DEFAULT_IMAGE_FILE_NAME}";; + esac + ;; + vsphere) + DEFAULT_IMAGE_NAME=${DEFAULT_IMAGE_NAME:-cirros-0.3.2-i386-disk.vmdk} + DEFAULT_IMAGE_FILE_NAME=${DEFAULT_IMAGE_FILE_NAME:-$DEFAULT_IMAGE_NAME} + IMAGE_URLS+="http://partnerweb.vmware.com/programs/vmdkimage/${DEFAULT_IMAGE_FILE_NAME}";; + xenserver) + DEFAULT_IMAGE_NAME=${DEFAULT_IMAGE_NAME:-cirros-0.3.5-x86_64-disk} + DEFAULT_IMAGE_FILE_NAME=${DEFAULT_IMAGE_NAME:-cirros-0.3.5-x86_64-disk.vhd.tgz} + IMAGE_URLS+="http://ca.downloads.xensource.com/OpenStack/cirros-0.3.5-x86_64-disk.vhd.tgz" + IMAGE_URLS+=",http://download.cirros-cloud.net/${CIRROS_VERSION}/cirros-${CIRROS_VERSION}-x86_64-uec.tar.gz";; + fake) + # Use the same as the default for libvirt + DEFAULT_IMAGE_NAME=${DEFAULT_IMAGE_NAME:-cirros-${CIRROS_VERSION}-${CIRROS_ARCH}-disk} + DEFAULT_IMAGE_FILE_NAME=${DEFAULT_IMAGE_FILE_NAME:-cirros-${CIRROS_VERSION}-${CIRROS_ARCH}-disk.img} + IMAGE_URLS+="http://download.cirros-cloud.net/${CIRROS_VERSION}/${DEFAULT_IMAGE_FILE_NAME}";; + esac + DOWNLOAD_DEFAULT_IMAGES=False +fi - IMAGE_URL="http://tarballs.openstack.org/trove/images/ubuntu/mysql.qcow2" - if ! [[ "$IMAGE_URLS" =~ "$IMAGE_URL" ]]; then - IMAGE_URLS+=",$IMAGE_URL" +# This is a comma separated list of extra URLS to be listed for +# download by the tools/image_list.sh script. CI environments can +# pre-download these URLS and place them in $FILES. Later scripts can +# then use "get_extra_file " which will print out the path to the +# file; it will either be downloaded on demand or acquired from the +# cache if there. +EXTRA_CACHE_URLS="" + +# etcd3 defaults +ETCD_VERSION=${ETCD_VERSION:-v3.2.17} +ETCD_SHA256_AMD64=${ETCD_SHA256_AMD64:-"0a75e794502e2e76417b19da2807a9915fa58dcbf0985e397741d570f4f305cd"} +ETCD_SHA256_ARM64=${ETCD_SHA256_ARM64:-"0ab4621c44c79d17d94e43bd184d0f23b763a3669056ce4ae2d0b2942410a98f"} +ETCD_SHA256_PPC64=${ETCD_SHA256_PPC64:-"69e1279c4a2a52256b78d2a8dd23346ac46b836e678b971a459f2afaef3c275e"} +# etcd v3.2.x doesn't have anything for s390x +ETCD_SHA256_S390X=${ETCD_SHA256_S390X:-""} +# Make sure etcd3 downloads the correct architecture +if is_arch "x86_64"; then + ETCD_ARCH="amd64" + ETCD_SHA256=${ETCD_SHA256:-$ETCD_SHA256_AMD64} +elif is_arch "aarch64"; then + ETCD_ARCH="arm64" + ETCD_SHA256=${ETCD_SHA256:-$ETCD_SHA256_ARM64} +elif is_arch "ppc64le"; then + ETCD_ARCH="ppc64le" + ETCD_SHA256=${ETCD_SHA256:-$ETCD_SHA256_PPC64} +elif is_arch "s390x"; then + # An etcd3 binary for s390x is not available on github like it is + # for other arches. Only continue if a custom download URL was + # provided. + if [[ -n "${ETCD_DOWNLOAD_URL}" ]]; then + ETCD_ARCH="s390x" + ETCD_SHA256=${ETCD_SHA256:-$ETCD_SHA256_S390X} + else + exit_distro_not_supported "etcd3. No custom ETCD_DOWNLOAD_URL provided." fi +else + exit_distro_not_supported "invalid hardware type - $ETCD_ARCH" fi +ETCD_PORT=${ETCD_PORT:-2379} +ETCD_PEER_PORT=${ETCD_PEER_PORT:-2380} +ETCD_DOWNLOAD_URL=${ETCD_DOWNLOAD_URL:-https://github.com/etcd-io/etcd/releases/download} +ETCD_NAME=etcd-$ETCD_VERSION-linux-$ETCD_ARCH +ETCD_DOWNLOAD_FILE=$ETCD_NAME.tar.gz +ETCD_DOWNLOAD_LOCATION=$ETCD_DOWNLOAD_URL/$ETCD_VERSION/$ETCD_DOWNLOAD_FILE +# etcd is always required, so place it into list of pre-cached downloads +EXTRA_CACHE_URLS+=",$ETCD_DOWNLOAD_LOCATION" + +# Detect duplicate values in IMAGE_URLS +for image_url in ${IMAGE_URLS//,/ }; do + if [ $(echo "$IMAGE_URLS" | grep -o -F "$image_url" | wc -l) -gt 1 ]; then + die $LINENO "$image_url is duplicate, please remove it from IMAGE_URLS." + fi +done -# 10Gb default volume backing file size -VOLUME_BACKING_FILE_SIZE=${VOLUME_BACKING_FILE_SIZE:-10250M} +# 24Gb default volume backing file size +VOLUME_BACKING_FILE_SIZE=${VOLUME_BACKING_FILE_SIZE:-24G} # Prefixes for volume and instance names VOLUME_NAME_PREFIX=${VOLUME_NAME_PREFIX:-volume-} @@ -593,14 +795,7 @@ S3_SERVICE_PORT=${S3_SERVICE_PORT:-3333} PRIVATE_NETWORK_NAME=${PRIVATE_NETWORK_NAME:-"private"} PUBLIC_NETWORK_NAME=${PUBLIC_NETWORK_NAME:-"public"} -# Compatibility until it's eradicated from CI -USE_SCREEN=${SCREEN_DEV:-$USE_SCREEN} - -# Set default screen name -SCREEN_NAME=${SCREEN_NAME:-stack} - -# Undo requirements changes by global requirements -UNDO_REQUIREMENTS=${UNDO_REQUIREMENTS:-True} +PUBLIC_INTERFACE=${PUBLIC_INTERFACE:-""} # Allow the use of an alternate protocol (such as https) for service endpoints SERVICE_PROTOCOL=${SERVICE_PROTOCOL:-http} @@ -609,16 +804,28 @@ SERVICE_PROTOCOL=${SERVICE_PROTOCOL:-http} # the memory used where there are a large number of CPUs present # (the default number of workers for many services is the number of CPUs) # Also sets the minimum number of workers to 2. -API_WORKERS=${API_WORKERS:=$(( ($(nproc)/2)<2 ? 2 : ($(nproc)/2) ))} +API_WORKERS=${API_WORKERS:=$(( ($(nproc)/4)<2 ? 2 : ($(nproc)/4) ))} # Service startup timeout SERVICE_TIMEOUT=${SERVICE_TIMEOUT:-60} -# Support alternative yum -- in future Fedora 'dnf' will become the -# only supported installer, but for now 'yum' and 'dnf' are both -# available in parallel with compatible CLIs. Allow manual switching -# till we get to the point we need to handle this automatically -YUM=${YUM:-yum} +# Timeout for compute node registration in Nova +NOVA_READY_TIMEOUT=${NOVA_READY_TIMEOUT:-$SERVICE_TIMEOUT} + +# Service graceful shutdown timeout +SERVICE_GRACEFUL_SHUTDOWN_TIMEOUT=${SERVICE_GRACEFUL_SHUTDOWN_TIMEOUT:-5} + +# Service graceful shutdown timeout +WORKER_TIMEOUT=${WORKER_TIMEOUT:-90} + +# Choose DNF on RedHat/Fedora platforms with it, or otherwise default +# to YUM. Can remove this when only dnf is supported (i.e. centos7 +# disappears) +if [[ -e /usr/bin/dnf ]]; then + YUM=${YUM:-dnf} +else + YUM=${YUM:-yum} +fi # Common Configuration # -------------------- @@ -641,46 +848,78 @@ ENABLE_DEBUG_LOG_LEVEL=$(trueorfalse True ENABLE_DEBUG_LOG_LEVEL) # Note that setting ``FIXED_RANGE`` may be necessary when running DevStack # in an OpenStack cloud that uses either of these address ranges internally. FLOATING_RANGE=${FLOATING_RANGE:-172.24.4.0/24} -FIXED_RANGE=${FIXED_RANGE:-10.0.0.0/24} +IPV4_ADDRS_SAFE_TO_USE=${IPV4_ADDRS_SAFE_TO_USE:-10.0.0.0/22} +FIXED_RANGE=${FIXED_RANGE:-$IPV4_ADDRS_SAFE_TO_USE} FIXED_NETWORK_SIZE=${FIXED_NETWORK_SIZE:-256} HOST_IP_IFACE=${HOST_IP_IFACE:-} HOST_IP=${HOST_IP:-} +HOST_IPV6=${HOST_IPV6:-} -HOST_IP=$(get_default_host_ip $FIXED_RANGE $FLOATING_RANGE "$HOST_IP_IFACE" "$HOST_IP") +HOST_IP=$(get_default_host_ip "$FIXED_RANGE" "$FLOATING_RANGE" "$HOST_IP_IFACE" "$HOST_IP" "inet") if [ "$HOST_IP" == "" ]; then die $LINENO "Could not determine host ip address. See local.conf for suggestions on setting HOST_IP." fi -# Allow the use of an alternate hostname (such as localhost/127.0.0.1) for service endpoints. -SERVICE_HOST=${SERVICE_HOST:-$HOST_IP} +HOST_IPV6=$(get_default_host_ip "" "" "$HOST_IP_IFACE" "$HOST_IPV6" "inet6") + +# Whether or not the port_security extension should be enabled for Neutron. +NEUTRON_PORT_SECURITY=$(trueorfalse True NEUTRON_PORT_SECURITY) + +# SERVICE IP version +# This is the IP version that services should be listening on, as well +# as using to register their endpoints with keystone. +SERVICE_IP_VERSION=${SERVICE_IP_VERSION:-4} + +# Validate SERVICE_IP_VERSION +# It would be nice to support "4+6" here as well, but that will require +# multiple calls into keystone to register endpoints, so for now let's +# just support one or the other. +if [[ $SERVICE_IP_VERSION != "4" ]] && [[ $SERVICE_IP_VERSION != "6" ]]; then + die $LINENO "SERVICE_IP_VERSION must be either 4 or 6" +fi + +if [[ "$SERVICE_IP_VERSION" == 4 ]]; then + DEF_SERVICE_HOST=$HOST_IP + DEF_SERVICE_LOCAL_HOST=127.0.0.1 + DEF_SERVICE_LISTEN_ADDRESS=0.0.0.0 +fi + +if [[ "$SERVICE_IP_VERSION" == 6 ]]; then + if [ "$HOST_IPV6" == "" ]; then + die $LINENO "Could not determine host IPv6 address. See local.conf for suggestions on setting HOST_IPV6." + fi + + DEF_SERVICE_HOST=[$HOST_IPV6] + DEF_SERVICE_LOCAL_HOST=::1 + DEF_SERVICE_LISTEN_ADDRESS="[::]" +fi + +# This is either 0.0.0.0 for IPv4 or [::] for IPv6 +SERVICE_LISTEN_ADDRESS=${SERVICE_LISTEN_ADDRESS:-${DEF_SERVICE_LISTEN_ADDRESS}} + +# Allow the use of an alternate hostname (such as localhost/127.0.0.1) for +# service endpoints. Default is dependent on SERVICE_IP_VERSION above. +SERVICE_HOST=${SERVICE_HOST:-${DEF_SERVICE_HOST}} +# This is either 127.0.0.1 for IPv4 or ::1 for IPv6 +SERVICE_LOCAL_HOST=${SERVICE_LOCAL_HOST:-${DEF_SERVICE_LOCAL_HOST}} + +REGION_NAME=${REGION_NAME:-RegionOne} # Configure services to use syslog instead of writing to individual log files SYSLOG=$(trueorfalse False SYSLOG) SYSLOG_HOST=${SYSLOG_HOST:-$HOST_IP} SYSLOG_PORT=${SYSLOG_PORT:-516} -# Use color for logging output (only available if syslog is not used) -LOG_COLOR=$(trueorfalse True LOG_COLOR) - # Set global ``GIT_DEPTH=`` to limit the history depth of the git clone # Set to 0 to disable shallow cloning GIT_DEPTH=${GIT_DEPTH:-0} -# Use native SSL for servers in ``SSL_ENABLED_SERVICES`` -USE_SSL=$(trueorfalse False USE_SSL) - +# We may not need to recreate database in case 2 Keystone services +# sharing the same database. It would be useful for multinode Grenade tests. +RECREATE_KEYSTONE_DB=$(trueorfalse True RECREATE_KEYSTONE_DB) # Following entries need to be last items in file -# Compatibility bits required by other callers like Grenade - -# Old way was using SCREEN_LOGDIR to locate those logs and LOGFILE for the stack.sh trace log. -# LOGFILE SCREEN_LOGDIR output -# not set not set no log files -# set not set stack.sh log to LOGFILE -# not set set screen logs to SCREEN_LOGDIR -# set set stack.sh log to LOGFILE, screen logs to SCREEN_LOGDIR - # New way is LOGDIR for all logs and LOGFILE for stack.sh trace log, but if not fully-qualified will be in LOGDIR # LOGFILE LOGDIR output # not set not set (new) set LOGDIR from default @@ -688,9 +927,6 @@ USE_SSL=$(trueorfalse False USE_SSL) # not set set screen logs to LOGDIR # set set stack.sh log to LOGFILE, screen logs to LOGDIR -# For compat, if SCREEN_LOGDIR is set, it will be used to create back-compat symlinks to the LOGDIR -# symlinks to SCREEN_LOGDIR (compat) - # Set up new logging defaults if [[ -z "${LOGDIR:-}" ]]; then default_logdir=$DEST/logs @@ -705,18 +941,14 @@ if [[ -z "${LOGDIR:-}" ]]; then # LOGFILE had no path, set a default LOGDIR="$default_logdir" fi - - # Check for duplication - if [[ "${SCREEN_LOGDIR:-}" == "${LOGDIR}" ]]; then - # We don't need the symlinks since it's the same directory - unset SCREEN_LOGDIR - fi fi unset default_logdir logfile fi # ``LOGDIR`` is always set at this point so it is not useful as a 'enable' for service logs -# ``SCREEN_LOGDIR`` may be set, it is useful to enable the compat symlinks + +# System-wide ulimit file descriptors override +ULIMIT_NOFILE=${ULIMIT_NOFILE:-2048} # Local variables: # mode: shell-script diff --git a/tests/run-process.sh b/tests/run-process.sh deleted file mode 100755 index bdf1395d07..0000000000 --- a/tests/run-process.sh +++ /dev/null @@ -1,109 +0,0 @@ -#!/bin/bash -# tests/exec.sh - Test DevStack run_process() and stop_process() -# -# exec.sh start|stop|status -# -# Set USE_SCREEN True|False to change use of screen. -# -# This script emulates the basic exec envirnment in ``stack.sh`` to test -# the process spawn and kill operations. - -if [[ -z $1 ]]; then - echo "$0 start|stop" - exit 1 -fi - -TOP_DIR=$(cd $(dirname "$0")/.. && pwd) -source $TOP_DIR/functions - -USE_SCREEN=${USE_SCREEN:-False} - -ENABLED_SERVICES=fake-service - -SERVICE_DIR=/tmp -SCREEN_NAME=test -SCREEN_LOGDIR=${SERVICE_DIR}/${SCREEN_NAME} - - -# Kill background processes on exit -trap clean EXIT -clean() { - local r=$? - jobs -p - kill >/dev/null 2>&1 $(jobs -p) - exit $r -} - - -# Exit on any errors so that errors don't compound -trap failed ERR -failed() { - local r=$? - jobs -p - kill >/dev/null 2>&1 $(jobs -p) - set +o xtrace - [ -n "$LOGFILE" ] && echo "${0##*/} failed: full log in $LOGFILE" - exit $r -} - -function status { - if [[ -r $SERVICE_DIR/$SCREEN_NAME/fake-service.pid ]]; then - pstree -pg $(cat $SERVICE_DIR/$SCREEN_NAME/fake-service.pid) - fi - ps -ef | grep fake -} - -function setup_screen { -if [[ ! -d $SERVICE_DIR/$SCREEN_NAME ]]; then - rm -rf $SERVICE_DIR/$SCREEN_NAME - mkdir -p $SERVICE_DIR/$SCREEN_NAME -fi - -if [[ "$USE_SCREEN" == "True" ]]; then - # Create a new named screen to run processes in - screen -d -m -S $SCREEN_NAME -t shell -s /bin/bash - sleep 1 - - # Set a reasonable status bar - if [ -z "$SCREEN_HARDSTATUS" ]; then - SCREEN_HARDSTATUS='%{= .} %-Lw%{= .}%> %n%f %t*%{= .}%+Lw%< %-=%{g}(%{d}%H/%l%{g})' - fi - screen -r $SCREEN_NAME -X hardstatus alwayslastline "$SCREEN_HARDSTATUS" -fi - -# Clear screen rc file -SCREENRC=$TOP_DIR/tests/$SCREEN_NAME-screenrc -if [[ -e $SCREENRC ]]; then - echo -n > $SCREENRC -fi -} - -# Mimic logging - # Set up output redirection without log files - # Copy stdout to fd 3 - exec 3>&1 - if [[ "$VERBOSE" != "True" ]]; then - # Throw away stdout and stderr - #exec 1>/dev/null 2>&1 - : - fi - # Always send summary fd to original stdout - exec 6>&3 - - -if [[ "$1" == "start" ]]; then - echo "Start service" - setup_screen - run_process fake-service "$TOP_DIR/tests/fake-service.sh" - sleep 1 - status -elif [[ "$1" == "stop" ]]; then - echo "Stop service" - stop_process fake-service - status -elif [[ "$1" == "status" ]]; then - status -else - echo "Unknown command" - exit 1 -fi diff --git a/tests/test_functions.sh b/tests/test_functions.sh index 1d82792ca7..adf20cdb80 100755 --- a/tests/test_functions.sh +++ b/tests/test_functions.sh @@ -9,6 +9,22 @@ source $TOP/functions source $TOP/tests/unittest.sh +echo "Testing generate_hex_string()" + +VAL=$(generate_hex_string 16) +if [[ ${#VAL} -eq 32 ]]; then + passed "OK" +else + failed "generate_hex_string 16 failed ${#VAL}" +fi + +VAL=$(generate_hex_string 32) +if [[ ${#VAL} -eq 64 ]]; then + passed "OK" +else + failed "generate_hex_string 32 failed ${#VAL}" +fi + echo "Testing die_if_not_set()" bash -c "source $TOP/functions; X=`echo Y && true`; die_if_not_set $LINENO X 'not OK'" @@ -137,6 +153,31 @@ test_disable_negated_services 'a,aa,-a' 'aa' test_disable_negated_services 'a,av2,-a,a' 'av2' test_disable_negated_services 'a,-a,av2' 'av2' +echo "Testing remove_disabled_services()" + +function test_remove_disabled_services { + local service_list="$1" + local remove_list="$2" + local expected="$3" + + results=$(remove_disabled_services "$service_list" "$remove_list") + if [ "$results" = "$expected" ]; then + passed "OK: '$service_list' - '$remove_list' -> '$results'" + else + failed "getting '$expected' from '$service_list' - '$remove_list' failed: '$results'" + fi +} + +test_remove_disabled_services 'a,b,c' 'a,c' 'b' +test_remove_disabled_services 'a,b,c' 'b' 'a,c' +test_remove_disabled_services 'a,b,c,d' 'a,c d' 'b' +test_remove_disabled_services 'a,b c,d' 'a d' 'b,c' +test_remove_disabled_services 'a,b,c' 'a,b,c' '' +test_remove_disabled_services 'a,b,c' 'd' 'a,b,c' +test_remove_disabled_services 'a,b,c' '' 'a,b,c' +test_remove_disabled_services '' 'a,b,c' '' +test_remove_disabled_services '' '' '' + echo "Testing is_package_installed()" if [[ -z "$os_PACKAGE" ]]; then @@ -183,7 +224,7 @@ fi # test against removed package...was a bug on Ubuntu if is_ubuntu; then - PKG=cowsay + PKG=cowsay-off if ! (dpkg -s $PKG >/dev/null 2>&1); then # it was never installed...set up the condition sudo apt-get install -y cowsay >/dev/null 2>&1 @@ -220,4 +261,33 @@ else passed "OK" fi +function test_export_proxy_variables { + echo "Testing export_proxy_variables()" + + local expected results + + http_proxy=http_proxy_test + https_proxy=https_proxy_test + no_proxy=no_proxy_test + + export_proxy_variables + expected=$(echo -e "http_proxy=$http_proxy\nhttps_proxy=$https_proxy\nno_proxy=$no_proxy") + results=$(env | egrep '(http(s)?|no)_proxy=') + if [[ $expected = $results ]]; then + passed "OK: Proxy variables are exported when proxy variables are set" + else + failed "Expected: $expected, Failed: $results" + fi + + unset http_proxy https_proxy no_proxy + export_proxy_variables + results=$(env | egrep '(http(s)?|no)_proxy=') + if [[ "" = $results ]]; then + passed "OK: Proxy variables aren't exported when proxy variables aren't set" + else + failed "Expected: '', Failed: $results" + fi +} +test_export_proxy_variables + report_results diff --git a/tests/test_ini_config.sh b/tests/test_ini_config.sh index b2529ac4c9..f7dc89a28d 100755 --- a/tests/test_ini_config.sh +++ b/tests/test_ini_config.sh @@ -13,7 +13,13 @@ set -e echo "Testing INI functions" -cat >test.ini <${TEST_INI} < $file_localconf +[[local|localrc]] +LOCALRC_VAR1=localrc_val1 +LOCALRC_VAR2=localrc_val2 +LOCALRC_VAR3=localrc_val3 + +[[post-config|$file_conf1]] +[conf1_t1] +conf1_t1_opt1=conf1_t1_val1 +conf1_t1_opt2=conf1_t1_val2 +conf1_t1_opt3=conf1_t1_val3 +[conf1_t2] +conf1_t2_opt1=conf1_t2_val1 +conf1_t2_opt2=conf1_t2_val2 +conf1_t2_opt3=conf1_t2_val3 +[conf1_t3] +conf1_t3_opt1=conf1_t3_val1 +conf1_t3_opt2=conf1_t3_val2 +conf1_t3_opt3=conf1_t3_val3 + +[[post-extra|$file_conf2]] +[conf2_t1] +conf2_t1_opt1=conf2_t1_val1 +conf2_t1_opt2=conf2_t1_val2 +conf2_t1_opt3=conf2_t1_val3 +EOF + + localconf_has_section $file_localconf post-config $file_conf1 conf1_t1 + assert_equal $? 0 + localconf_has_section $file_localconf post-config $file_conf1 conf1_t2 + assert_equal $? 0 + localconf_has_section $file_localconf post-config $file_conf1 conf1_t3 + assert_equal $? 0 + localconf_has_section $file_localconf post-extra $file_conf2 conf2_t1 + assert_equal $? 0 + localconf_has_section $file_localconf post-config $file_conf1 conf1_t4 + assert_equal $? 1 + localconf_has_section $file_localconf post-install $file_conf1 conf1_t1 + assert_equal $? 1 + localconf_has_section $file_localconf local localrc conf1_t2 + assert_equal $? 1 + rm -f $file_localconf $file_conf1 $file_conf2 +} + +# test that can determine if file has option in specified meta-section and section +function test_localconf_has_option { + local file_localconf + local file_conf1 + local file_conf2 + file_localconf=`mktemp` + file_conf1=`mktemp` + file_conf2=`mktemp` + cat <<- EOF > $file_localconf +[[post-config|$file_conf1]] +[conf1_t1] +conf1_t1_opt1 = conf1_t1_val1 +conf1_t1_opt2 = conf1_t1_val2 +conf1_t1_opt3 = conf1_t1_val3 +[conf1_t2] +conf1_t2_opt1=conf1_t2_val1 +conf1_t2_opt2=conf1_t2_val2 +conf1_t2_opt3=conf1_t2_val3 +[conf1_t3] +conf1_t3_opt1=conf1_t3_val1 +conf1_t3_opt2=conf1_t3_val2 +conf1_t3_opt3=conf1_t3_val3 + +[[local|localrc]] +LOCALRC_VAR1=localrc_val1 +LOCALRC_VAR2=localrc_val2 +LOCALRC_VAR3=localrc_val3 + +[[post-extra|$file_conf2]] +[conf2_t1] +conf2_t1_opt1=conf2_t1_val1 +conf2_t1_opt2=conf2_t1_val2 +conf2_t1_opt3=conf2_t1_val3 +EOF + + localconf_has_option $file_localconf local localrc "" LOCALRC_VAR1 + assert_equal $? 0 + localconf_has_option $file_localconf local localrc "" LOCALRC_VAR2 + assert_equal $? 0 + localconf_has_option $file_localconf local localrc "" LOCALRC_VAR3 + assert_equal $? 0 + localconf_has_option $file_localconf post-config $file_conf1 conf1_t1 conf1_t1_opt1 + assert_equal $? 0 + localconf_has_option $file_localconf post-config $file_conf1 conf1_t2 conf1_t2_opt2 + assert_equal $? 0 + localconf_has_option $file_localconf post-config $file_conf1 conf1_t3 conf1_t3_opt3 + assert_equal $? 0 + localconf_has_option $file_localconf post-extra $file_conf2 conf2_t1 conf2_t1_opt2 + assert_equal $? 0 + localconf_has_option $file_localconf post-config $file_conf1 conf1_t1_opt4 + assert_equal $? 1 + localconf_has_option $file_localconf post-install $file_conf1 conf1_t1_opt1 + assert_equal $? 1 + localconf_has_option $file_localconf local localrc conf1_t2 conf1_t2_opt1 + assert_equal $? 1 + rm -f $file_localconf $file_conf1 $file_conf2 +} + +# test that update option in specified meta-section and section +function test_localconf_update_option { + local file_localconf + local file_localconf_expected + local file_conf1 + local file_conf2 + file_localconf=`mktemp` + file_localconf_expected=`mktemp` + file_conf1=`mktemp` + file_conf2=`mktemp` + cat <<- EOF > $file_localconf +[[local|localrc]] +LOCALRC_VAR1 = localrc_val1 +LOCALRC_VAR2 = localrc_val2 +LOCALRC_VAR3 = localrc_val3 + +[[post-config|$file_conf1]] +[conf1_t1] +conf1_t1_opt1=conf1_t1_val1 +conf1_t1_opt2=conf1_t1_val2 +conf1_t1_opt3=conf1_t1_val3 +[conf1_t2] +conf1_t2_opt1=conf1_t2_val1 +conf1_t2_opt2=conf1_t2_val2 +conf1_t2_opt3=conf1_t2_val3 +[conf1_t3] +conf1_t3_opt1=conf1_t3_val1 +conf1_t3_opt2=conf1_t3_val2 +conf1_t3_opt3=conf1_t3_val3 + +[[post-extra|$file_conf2]] +[conf2_t1] +conf2_t1_opt1=conf2_t1_val1 +conf2_t1_opt2=conf2_t1_val2 +conf2_t1_opt3=conf2_t1_val3 +EOF + cat <<- EOF > $file_localconf_expected +[[local|localrc]] +LOCALRC_VAR1 = localrc_val1 +LOCALRC_VAR2 = localrc_val2_update +LOCALRC_VAR3 = localrc_val3 + +[[post-config|$file_conf1]] +[conf1_t1] +conf1_t1_opt1=conf1_t1_val1_update +conf1_t1_opt2=conf1_t1_val2 +conf1_t1_opt3=conf1_t1_val3 +[conf1_t2] +conf1_t2_opt1=conf1_t2_val1 +conf1_t2_opt2=conf1_t2_val2_update +conf1_t2_opt3=conf1_t2_val3 +[conf1_t3] +conf1_t3_opt1=conf1_t3_val1 +conf1_t3_opt2=conf1_t3_val2 +conf1_t3_opt3=conf1_t3_val3_update + +[[post-extra|$file_conf2]] +[conf2_t1] +conf2_t1_opt1=conf2_t1_val1 +conf2_t1_opt2=conf2_t1_val2 +conf2_t1_opt3=conf2_t1_val3_update +EOF + + localconf_update_option "$SUDO" $file_localconf local localrc "" LOCALRC_VAR2 localrc_val2_update + localconf_update_option "$SUDO" $file_localconf post-config $file_conf1 conf1_t1 conf1_t1_opt1 conf1_t1_val1_update + localconf_update_option "$SUDO" $file_localconf post-config $file_conf1 conf1_t2 conf1_t2_opt2 conf1_t2_val2_update + localconf_update_option "$SUDO" $file_localconf post-config $file_conf1 conf1_t3 conf1_t3_opt3 conf1_t3_val3_update + localconf_update_option "$SUDO" $file_localconf post-extra $file_conf2 conf2_t1 conf2_t1_opt3 conf2_t1_val3_update + result=`cat $file_localconf` + result_expected=`cat $file_localconf_expected` + assert_equal "$result" "$result_expected" + localconf_update_option "$SUDO" $file_localconf post-config $file_conf1 conf1_t2 conf1_t3_opt1 conf1_t3_val1_update + localconf_update_option "$SUDO" $file_localconf post-extra $file_conf2 conf2_t1 conf2_t1_opt4 conf2_t1_val4_update + localconf_update_option "$SUDO" $file_localconf post-install $file_conf2 conf2_t1 conf2_t1_opt1 conf2_t1_val1_update + localconf_update_option "$SUDO" $file_localconf local localrc "" LOCALRC_VAR4 localrc_val4_update + result=`cat $file_localconf` + result_expected=`cat $file_localconf_expected` + assert_equal "$result" "$result_expected" + rm -f $file_localconf $file_localconf_expected $file_conf1 $file_conf2 +} + +# test that add option in specified meta-section and section +function test_localconf_add_option { + local file_localconf + local file_localconf_expected + local file_conf1 + local file_conf2 + file_localconf=`mktemp` + file_localconf_expected=`mktemp` + file_conf1=`mktemp` + file_conf2=`mktemp` + cat <<- EOF > $file_localconf +[[post-config|$file_conf1]] +[conf1_t1] +conf1_t1_opt1=conf1_t1_val1 +conf1_t1_opt2=conf1_t1_val2 +conf1_t1_opt3=conf1_t1_val3 +[conf1_t2] +conf1_t2_opt1=conf1_t2_val1 +conf1_t2_opt2=conf1_t2_val2 +conf1_t2_opt3=conf1_t2_val3 +[conf1_t3] +conf1_t3_opt1=conf1_t3_val1 +conf1_t3_opt2=conf1_t3_val2 +conf1_t3_opt3=conf1_t3_val3 + +[[local|localrc]] +LOCALRC_VAR1=localrc_val1 +LOCALRC_VAR2=localrc_val2 +LOCALRC_VAR3=localrc_val3 + +[[post-extra|$file_conf2]] +[conf2_t1] +conf2_t1_opt1 = conf2_t1_val1 +conf2_t1_opt2 = conf2_t1_val2 +conf2_t1_opt3 = conf2_t1_val3 +EOF + cat <<- EOF > $file_localconf_expected +[[post-config|$file_conf1]] +[conf1_t1] +conf1_t1_opt4 = conf1_t1_val4 +conf1_t1_opt1=conf1_t1_val1 +conf1_t1_opt2=conf1_t1_val2 +conf1_t1_opt3=conf1_t1_val3 +[conf1_t2] +conf1_t2_opt4 = conf1_t2_val4 +conf1_t2_opt1=conf1_t2_val1 +conf1_t2_opt2=conf1_t2_val2 +conf1_t2_opt3=conf1_t2_val3 +[conf1_t3] +conf1_t3_opt4 = conf1_t3_val4 +conf1_t3_opt1=conf1_t3_val1 +conf1_t3_opt2=conf1_t3_val2 +conf1_t3_opt3=conf1_t3_val3 + +[[local|localrc]] +LOCALRC_VAR4 = localrc_val4 +LOCALRC_VAR1=localrc_val1 +LOCALRC_VAR2=localrc_val2 +LOCALRC_VAR3=localrc_val3 + +[[post-extra|$file_conf2]] +[conf2_t1] +conf2_t1_opt4 = conf2_t1_val4 +conf2_t1_opt1 = conf2_t1_val1 +conf2_t1_opt2 = conf2_t1_val2 +conf2_t1_opt3 = conf2_t1_val3 +EOF + + localconf_add_option "$SUDO" $file_localconf local localrc "" LOCALRC_VAR4 localrc_val4 + localconf_add_option "$SUDO" $file_localconf post-config $file_conf1 conf1_t1 conf1_t1_opt4 conf1_t1_val4 + localconf_add_option "$SUDO" $file_localconf post-config $file_conf1 conf1_t2 conf1_t2_opt4 conf1_t2_val4 + localconf_add_option "$SUDO" $file_localconf post-config $file_conf1 conf1_t3 conf1_t3_opt4 conf1_t3_val4 + localconf_add_option "$SUDO" $file_localconf post-extra $file_conf2 conf2_t1 conf2_t1_opt4 conf2_t1_val4 + result=`cat $file_localconf` + result_expected=`cat $file_localconf_expected` + assert_equal "$result" "$result_expected" + localconf_add_option "$SUDO" $file_localconf local localrc.conf "" LOCALRC_VAR4 localrc_val4_update + localconf_add_option "$SUDO" $file_localconf post-config $file_conf1 conf1_t4 conf1_t4_opt1 conf1_t4_val1 + localconf_add_option "$SUDO" $file_localconf post-extra $file_conf2 conf2_t2 conf2_t2_opt4 conf2_t2_val4 + localconf_add_option "$SUDO" $file_localconf post-install $file_conf2 conf2_t1 conf2_t1_opt4 conf2_t2_val4 + result=`cat $file_localconf` + result_expected=`cat $file_localconf_expected` + assert_equal "$result" "$result_expected" + rm -f $file_localconf $file_localconf_expected $file_conf1 $file_conf2 +} + +# test that add section and option in specified meta-section +function test_localconf_add_section_and_option { + local file_localconf + local file_localconf_expected + local file_conf1 + local file_conf2 + file_localconf=`mktemp` + file_localconf_expected=`mktemp` + file_conf1=`mktemp` + file_conf2=`mktemp` + cat <<- EOF > $file_localconf +[[post-config|$file_conf1]] +[conf1_t1] +conf1_t1_opt1=conf1_t1_val1 +conf1_t1_opt2=conf1_t1_val2 +conf1_t1_opt3=conf1_t1_val3 +[conf1_t2] +conf1_t2_opt1=conf1_t2_val1 +conf1_t2_opt2=conf1_t2_val2 +conf1_t2_opt3=conf1_t2_val3 +[conf1_t3] +conf1_t3_opt1=conf1_t3_val1 +conf1_t3_opt2=conf1_t3_val2 +conf1_t3_opt3=conf1_t3_val3 + +[[local|localrc]] +LOCALRC_VAR1=localrc_val1 +LOCALRC_VAR2=localrc_val2 +LOCALRC_VAR3=localrc_val3 + +[[post-extra|$file_conf2]] +[conf2_t1] +conf2_t1_opt1=conf2_t1_val1 +conf2_t1_opt2=conf2_t1_val2 +conf2_t1_opt3=conf2_t1_val3 +EOF + cat <<- EOF > $file_localconf_expected +[[post-config|$file_conf1]] +[conf1_t4] +conf1_t4_opt1 = conf1_t4_val1 +[conf1_t1] +conf1_t1_opt1=conf1_t1_val1 +conf1_t1_opt2=conf1_t1_val2 +conf1_t1_opt3=conf1_t1_val3 +[conf1_t2] +conf1_t2_opt1=conf1_t2_val1 +conf1_t2_opt2=conf1_t2_val2 +conf1_t2_opt3=conf1_t2_val3 +[conf1_t3] +conf1_t3_opt1=conf1_t3_val1 +conf1_t3_opt2=conf1_t3_val2 +conf1_t3_opt3=conf1_t3_val3 + +[[local|localrc]] +LOCALRC_VAR1=localrc_val1 +LOCALRC_VAR2=localrc_val2 +LOCALRC_VAR3=localrc_val3 + +[[post-extra|$file_conf2]] +[conf2_t2] +conf2_t2_opt1 = conf2_t2_val1 +[conf2_t1] +conf2_t1_opt1=conf2_t1_val1 +conf2_t1_opt2=conf2_t1_val2 +conf2_t1_opt3=conf2_t1_val3 +EOF + + localconf_add_section_and_option "$SUDO" $file_localconf post-config $file_conf1 conf1_t4 conf1_t4_opt1 conf1_t4_val1 + localconf_add_section_and_option "$SUDO" $file_localconf post-extra $file_conf2 conf2_t2 conf2_t2_opt1 conf2_t2_val1 + result=`cat $file_localconf` + result_expected=`cat $file_localconf_expected` + assert_equal "$result" "$result_expected" + localconf_add_section_and_option "$SUDO" $file_localconf post-install $file_conf2 conf2_t2 conf2_t2_opt1 conf2_t2_val1 + result=`cat $file_localconf` + result_expected=`cat $file_localconf_expected` + assert_equal "$result" "$result_expected" + rm -f $file_localconf $file_localconf_expected $file_conf1 $file_conf2 +} + +# test that add section and option in specified meta-section +function test_localconf_set { + local file_localconf + local file_localconf_expected + local file_conf1 + local file_conf2 + file_localconf=`mktemp` + file_localconf_expected=`mktemp` + file_conf1=`mktemp` + file_conf2=`mktemp` + cat <<- EOF > $file_localconf +[[local|localrc]] +LOCALRC_VAR1=localrc_val1 +LOCALRC_VAR2=localrc_val2 +LOCALRC_VAR3=localrc_val3 + +[[post-config|$file_conf1]] +[conf1_t1] +conf1_t1_opt1=conf1_t1_val1 +conf1_t1_opt2=conf1_t1_val2 +conf1_t1_opt3=conf1_t1_val3 +[conf1_t2] +conf1_t2_opt1=conf1_t2_val1 +conf1_t2_opt2=conf1_t2_val2 +conf1_t2_opt3=conf1_t2_val3 +[conf1_t3] +conf1_t3_opt1=conf1_t3_val1 +conf1_t3_opt2=conf1_t3_val2 +conf1_t3_opt3=conf1_t3_val3 + +[[post-extra|$file_conf2]] +[conf2_t1] +conf2_t1_opt1=conf2_t1_val1 +conf2_t1_opt2=conf2_t1_val2 +conf2_t1_opt3=conf2_t1_val3 +EOF + cat <<- EOF > $file_localconf_expected +[[local|localrc]] +LOCALRC_VAR1=localrc_val1 +LOCALRC_VAR2=localrc_val2_update +LOCALRC_VAR3=localrc_val3 + +[[post-config|$file_conf1]] +[conf1_t4] +conf1_t4_opt1 = conf1_t4_val1 +[conf1_t1] +conf1_t1_opt1=conf1_t1_val1 +conf1_t1_opt2=conf1_t1_val2 +conf1_t1_opt3=conf1_t1_val3 +[conf1_t2] +conf1_t2_opt1=conf1_t2_val1 +conf1_t2_opt2=conf1_t2_val2 +conf1_t2_opt3=conf1_t2_val3 +[conf1_t3] +conf1_t3_opt1=conf1_t3_val1 +conf1_t3_opt2=conf1_t3_val2 +conf1_t3_opt3=conf1_t3_val3 + +[[post-extra|$file_conf2]] +[conf2_t1] +conf2_t1_opt4 = conf2_t1_val4 +conf2_t1_opt1=conf2_t1_val1 +conf2_t1_opt2=conf2_t1_val2 +conf2_t1_opt3=conf2_t1_val3 + +[[post-install|/etc/neutron/plugin/ml2/ml2_conf.ini]] +[ml2] +ml2_opt1 = ml2_val1 +EOF + + if [[ -n "$SUDO" ]]; then + SUDO_ARG="-sudo" + else + SUDO_ARG="" + fi + localconf_set $SUDO_ARG $file_localconf post-install /etc/neutron/plugin/ml2/ml2_conf.ini ml2 ml2_opt1 ml2_val1 + localconf_set $SUDO_ARG $file_localconf local localrc "" LOCALRC_VAR2 localrc_val2_update + localconf_set $SUDO_ARG $file_localconf post-config $file_conf1 conf1_t4 conf1_t4_opt1 conf1_t4_val1 + localconf_set $SUDO_ARG $file_localconf post-extra $file_conf2 conf2_t1 conf2_t1_opt4 conf2_t1_val4 + result=`cat $file_localconf` + result_expected=`cat $file_localconf_expected` + assert_equal "$result" "$result_expected" + rm -f $file_localconf $file_localconf_expected $file_conf1 $file_conf2 +} + + +test_localconf_has_section +test_localconf_has_option +test_localconf_update_option +test_localconf_add_option +test_localconf_add_section_and_option +test_localconf_set diff --git a/tests/test_meta_config.sh b/tests/test_meta_config.sh index a04c081854..087aaf468b 100755 --- a/tests/test_meta_config.sh +++ b/tests/test_meta_config.sh @@ -23,6 +23,16 @@ function check_result { fi } +# mock function-common:die so that it does not +# interrupt our test script +function die { + exit -1 +} + +function warn { + return 0 +} + TEST_1C_ADD="[eee] type=new multi = foo2" @@ -86,7 +96,7 @@ $TEST_1C_ADD [[test3|test-space.conf]] [DEFAULT] attribute=value - + # the above line has a single space [[test4|\$TEST4_DIR/\$TEST4_FILE]] @@ -110,6 +120,23 @@ attr = strip_trailing_space [DEFAULT] servers=10.11.12.13:80 +[[test8|/permission-denied.conf]] +foo=bar + +[[test9|\$UNDEF]] +foo=bar + +[[test10|does-not-exist-dir/test.conf]] +foo=bar + +[[test11|test-same.conf]] +[DEFAULT] +foo=bar + +[[test11|test-same.conf]] +[some] +random=config + [[test-multi-sections|test-multi-sections.conf]] [sec-1] cfg_item1 = abcd @@ -132,6 +159,9 @@ cfg_item1 = abcd cfg_item2 = efgh cfg_item2 = \${FOO_BAR_BAZ} +[[test11|test-same.conf]] +[another] +non = sense EOF echo -n "get_meta_section_files: test0 doesn't exist: " @@ -340,8 +370,53 @@ EXPECT_VAL=" servers = 10.11.12.13:80" check_result "$VAL" "$EXPECT_VAL" +echo "merge_config_file test8 non-touchable conf file: " +set +e +# function is expected to fail and exit, running it +# in a subprocess to let this script proceed +(merge_config_file test.conf test8 /permission-denied.conf) +VAL=$? +EXPECT_VAL=255 +check_result "$VAL" "$EXPECT_VAL" +set -e + +echo -n "merge_config_group test9 undefined conf file: " +set +e +# function is expected to trigger warn and continue +(merge_config_group test.conf test9) +VAL=$? +EXPECT_VAL=0 +check_result "$VAL" "$EXPECT_VAL" +set -e + +echo -n "merge_config_group test10 not directory: " +set +e +# function is expected to fail and exit, running it +# in a subprocess to let this script proceed +(merge_config_group test.conf test10) +VAL=$? +EXPECT_VAL=255 +check_result "$VAL" "$EXPECT_VAL" +set -e + +echo -n "merge_config_file test11 same section: " +rm -f test-same.conf +merge_config_group test.conf test11 +VAL=$(cat test-same.conf) +EXPECT_VAL=' +[DEFAULT] +foo = bar + +[some] +random = config + +[another] +non = sense' +check_result "$VAL" "$EXPECT_VAL" + + rm -f test.conf test1c.conf test2a.conf \ test-space.conf test-equals.conf test-strip.conf \ test-colon.conf test-env.conf test-multiline.conf \ - test-multi-sections.conf + test-multi-sections.conf test-same.conf rm -rf test-etc diff --git a/tests/test_package_ordering.sh b/tests/test_package_ordering.sh new file mode 100755 index 0000000000..bfc2a1954f --- /dev/null +++ b/tests/test_package_ordering.sh @@ -0,0 +1,33 @@ +#!/bin/bash + +# basic test to ensure that package-install files remain sorted +# alphabetically. + +TOP=$(cd $(dirname "$0")/.. && pwd) + +source $TOP/tests/unittest.sh + +export LC_ALL=en_US.UTF-8 +PKG_FILES=$(find $TOP/files/debs $TOP/files/rpms $TOP/files/rpms-suse -type f) + +TMPDIR=$(mktemp -d) + +SORTED=${TMPDIR}/sorted +UNSORTED=${TMPDIR}/unsorted + +for p in $PKG_FILES; do + grep -v '^#' $p > ${UNSORTED} + sort ${UNSORTED} > ${SORTED} + + if [ -n "$(diff -c ${UNSORTED} ${SORTED})" ]; then + failed "$p is unsorted" + # output this, it's helpful to see what exactly is unsorted + diff -c ${UNSORTED} ${SORTED} + else + passed "$p is sorted" + fi +done + +rm -rf ${TMPDIR} + +report_results diff --git a/tests/test_python.sh b/tests/test_python.sh new file mode 100755 index 0000000000..8652798778 --- /dev/null +++ b/tests/test_python.sh @@ -0,0 +1,30 @@ +#!/usr/bin/env bash + +# Tests for DevStack INI functions + +TOP=$(cd $(dirname "$0")/.. && pwd) + +source $TOP/functions-common +source $TOP/inc/python + +source $TOP/tests/unittest.sh + +echo "Testing Python 3 functions" + +# Initialize variables manipulated by functions under test. +export ENABLED_PYTHON3_PACKAGES="" +export DISABLED_PYTHON3_PACKAGES="" + +assert_false "should not be enabled yet" python3_enabled_for testpackage1 + +enable_python3_package testpackage1 +assert_equal "$ENABLED_PYTHON3_PACKAGES" "testpackage1" "unexpected result" +assert_true "should be enabled" python3_enabled_for testpackage1 + +assert_false "should not be disabled yet" python3_disabled_for testpackage2 + +disable_python3_package testpackage2 +assert_equal "$DISABLED_PYTHON3_PACKAGES" "testpackage2" "unexpected result" +assert_true "should be disabled" python3_disabled_for testpackage2 + +report_results diff --git a/tests/test_refs.sh b/tests/test_refs.sh index bccca5dff7..0f9aa4a5ca 100755 --- a/tests/test_refs.sh +++ b/tests/test_refs.sh @@ -15,10 +15,10 @@ echo "Ensuring we don't have crazy refs" -REFS=`grep BRANCH stackrc | grep -v -- '-master'` +REFS=`grep BRANCH stackrc | grep -v 'TARGET_BRANCH' | grep -v 'NOVNC_BRANCH'` rc=$? if [[ $rc -eq 0 ]]; then - echo "Branch defaults must be master. Found:" + echo "Branch defaults must be one of the *TARGET_BRANCH values. Found:" echo $REFS exit 1 fi diff --git a/tests/test_truefalse.sh b/tests/test_truefalse.sh index ebd9650649..03996ceab4 100755 --- a/tests/test_truefalse.sh +++ b/tests/test_truefalse.sh @@ -8,6 +8,14 @@ TOP=$(cd $(dirname "$0")/.. && pwd) source $TOP/functions source $TOP/tests/unittest.sh +# common mistake is to use $FOO instead of "FOO"; in that case we +# should die +bash -c "source $TOP/functions-common; VAR=\$(trueorfalse False \$FOO)" &> /dev/null +assert_equal 1 $? "missing test-value" + +VAL=$(trueorfalse False MISSING_VARIABLE) +assert_equal "False" $VAL "blank test-value" + function test_trueorfalse { local one=1 local captrue=True @@ -19,7 +27,8 @@ function test_trueorfalse { for default in True False; do for name in one captrue lowtrue uppertrue capyes lowyes upperyes; do - assert_equal "True" $(trueorfalse $default $name) "\$(trueorfalse $default $name)" + local msg="trueorfalse($default $name)" + assert_equal "True" $(trueorfalse $default $name) "$msg" done done @@ -33,7 +42,8 @@ function test_trueorfalse { for default in True False; do for name in zero capfalse lowfalse upperfalse capno lowno upperno; do - assert_equal "False" $(trueorfalse $default $name) "\$(trueorfalse $default $name)" + local msg="trueorfalse($default $name)" + assert_equal "False" $(trueorfalse $default $name) "$msg" done done } diff --git a/tests/test_vercmp.sh b/tests/test_vercmp.sh new file mode 100755 index 0000000000..c88bf86d7e --- /dev/null +++ b/tests/test_vercmp.sh @@ -0,0 +1,47 @@ +#!/usr/bin/env bash + +# Tests for DevStack vercmp functionality + +TOP=$(cd $(dirname "$0")/.. && pwd) + +# Import common functions +source $TOP/functions +source $TOP/tests/unittest.sh + +assert_true "numeric gt" vercmp 2.0 ">" 1.0 +assert_true "numeric gte" vercmp 2.0 ">=" 1.0 +assert_true "numeric gt" vercmp 1.0.1 ">" 1.0 +assert_true "numeric gte" vercmp 1.0.1 ">=" 1.0 +assert_true "alpha gt" vercmp 1.0.1b ">" 1.0.1a +assert_true "alpha gte" vercmp 1.0.1b ">=" 1.0.1a +assert_true "alpha gt" vercmp b ">" a +assert_true "alpha gte" vercmp b ">=" a +assert_true "alpha gt" vercmp 2.0-rc3 ">" 2.0-rc1 +assert_true "alpha gte" vercmp 2.0-rc3 ">=" 2.0-rc1 + +assert_false "numeric gt fail" vercmp 1.0 ">" 1.0 +assert_true "numeric gte" vercmp 1.0 ">=" 1.0 +assert_false "numeric gt fail" vercmp 0.9 ">" 1.0 +assert_false "numeric gte fail" vercmp 0.9 ">=" 1.0 +assert_false "numeric gt fail" vercmp 0.9.9 ">" 1.0 +assert_false "numeric gte fail" vercmp 0.9.9 ">=" 1.0 +assert_false "numeric gt fail" vercmp 0.9a.9 ">" 1.0.1 +assert_false "numeric gte fail" vercmp 0.9a.9 ">=" 1.0.1 + +assert_false "numeric lt" vercmp 1.0 "<" 1.0 +assert_true "numeric lte" vercmp 1.0 "<=" 1.0 +assert_true "numeric lt" vercmp 1.0 "<" 1.0.1 +assert_true "numeric lte" vercmp 1.0 "<=" 1.0.1 +assert_true "alpha lt" vercmp 1.0.1a "<" 1.0.1b +assert_true "alpha lte" vercmp 1.0.1a "<=" 1.0.1b +assert_true "alpha lt" vercmp a "<" b +assert_true "alpha lte" vercmp a "<=" b +assert_true "alpha lt" vercmp 2.0-rc1 "<" 2.0-rc3 +assert_true "alpha lte" vercmp 2.0-rc1 "<=" 2.0-rc3 + +assert_true "eq" vercmp 1.0 "==" 1.0 +assert_true "eq" vercmp 1.0.1 "==" 1.0.1 +assert_false "eq fail" vercmp 1.0.1 "==" 1.0.2 +assert_false "eq fail" vercmp 2.0-rc1 "==" 2.0-rc2 + +report_results diff --git a/tests/test_worlddump.sh b/tests/test_worlddump.sh new file mode 100755 index 0000000000..f407d407c0 --- /dev/null +++ b/tests/test_worlddump.sh @@ -0,0 +1,35 @@ +#!/bin/bash + +# Simple test of worlddump.py + +TOP=$(cd $(dirname "$0")/.. && pwd) + +source $TOP/tests/unittest.sh + +OUT_DIR=$(mktemp -d) + +$TOP/tools/worlddump.py -d $OUT_DIR + +if [[ $? -ne 0 ]]; then + fail "worlddump failed" +else + + # worlddump creates just one output file + OUT_FILE=($OUT_DIR/*.txt) + + if [ ! -r $OUT_FILE ]; then + failed "worlddump output not seen" + else + passed "worlddump output $OUT_FILE" + + if [[ $(stat -c %s $OUT_DIR/*.txt) -gt 0 ]]; then + passed "worlddump output is not zero sized" + fi + + # put more extensive examination here, if required. + fi +fi + +rm -rf $OUT_DIR + +report_results diff --git a/tests/test_write_devstack_local_conf_role.sh b/tests/test_write_devstack_local_conf_role.sh new file mode 100755 index 0000000000..b2bc0a2c46 --- /dev/null +++ b/tests/test_write_devstack_local_conf_role.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash + +TOP=$(cd $(dirname "$0")/.. && pwd) + +# Import common functions +source $TOP/functions +source $TOP/tests/unittest.sh + +python ./roles/write-devstack-local-conf/library/test.py diff --git a/tests/unittest.sh b/tests/unittest.sh index 69f19b7dae..3703ece91d 100644 --- a/tests/unittest.sh +++ b/tests/unittest.sh @@ -17,20 +17,28 @@ ERROR=0 PASS=0 FAILED_FUNCS="" +# pass a test, printing out MSG +# usage: passed message function passed { - local lineno=$(caller 0 | awk '{print $1}') - local function=$(caller 0 | awk '{print $2}') + local lineno + lineno=$(caller 0 | awk '{print $1}') + local function + function=$(caller 0 | awk '{print $2}') local msg="$1" if [ -z "$msg" ]; then msg="OK" fi PASS=$((PASS+1)) - echo $function:L$lineno $msg + echo "PASS: $function:L$lineno - $msg" } +# fail a test, printing out MSG +# usage: failed message function failed { - local lineno=$(caller 0 | awk '{print $1}') - local function=$(caller 0 | awk '{print $2}') + local lineno + lineno=$(caller 0 | awk '{print $1}') + local function + function=$(caller 0 | awk '{print $2}') local msg="$1" FAILED_FUNCS+="$function:L$lineno\n" echo "ERROR: $function:L$lineno!" @@ -38,10 +46,18 @@ function failed { ERROR=$((ERROR+1)) } +# assert string comparison of val1 equal val2, printing out msg +# usage: assert_equal val1 val2 msg function assert_equal { - local lineno=`caller 0 | awk '{print $1}'` - local function=`caller 0 | awk '{print $2}'` + local lineno + lineno=`caller 0 | awk '{print $1}'` + local function + function=`caller 0 | awk '{print $2}'` local msg=$3 + + if [ -z "$msg" ]; then + msg="OK" + fi if [[ "$1" != "$2" ]]; then FAILED_FUNCS+="$function:L$lineno\n" echo "ERROR: $1 != $2 in $function:L$lineno!" @@ -49,17 +65,89 @@ function assert_equal { ERROR=$((ERROR+1)) else PASS=$((PASS+1)) - echo "$function:L$lineno - ok" + echo "PASS: $function:L$lineno - $msg" + fi +} + +# assert variable is empty/blank, printing out msg +# usage: assert_empty VAR msg +function assert_empty { + local lineno + lineno=`caller 0 | awk '{print $1}'` + local function + function=`caller 0 | awk '{print $2}'` + local msg=$2 + + if [ -z "$msg" ]; then + msg="OK" + fi + if [[ ! -z ${!1} ]]; then + FAILED_FUNCS+="$function:L$lineno\n" + echo "ERROR: $1 not empty in $function:L$lineno!" + echo " $msg" + ERROR=$((ERROR+1)) + else + PASS=$((PASS+1)) + echo "PASS: $function:L$lineno - $msg" fi } +# assert the arguments evaluate to true +# assert_true "message" arg1 arg2 +function assert_true { + local lineno + lineno=`caller 0 | awk '{print $1}'` + local function + function=`caller 0 | awk '{print $2}'` + local msg=$1 + shift + + $@ + if [ $? -eq 0 ]; then + PASS=$((PASS+1)) + echo "PASS: $function:L$lineno - $msg" + else + FAILED_FUNCS+="$function:L$lineno\n" + echo "ERROR: test failed in $function:L$lineno!" + echo " $msg" + ERROR=$((ERROR+1)) + fi +} + +# assert the arguments evaluate to false +# assert_false "message" arg1 arg2 +function assert_false { + local lineno + lineno=`caller 0 | awk '{print $1}'` + local function + function=`caller 0 | awk '{print $2}'` + local msg=$1 + shift + + $@ + if [ $? -eq 0 ]; then + FAILED_FUNCS+="$function:L$lineno\n" + echo "ERROR: test failed in $function:L$lineno!" + echo " $msg" + ERROR=$((ERROR+1)) + else + PASS=$((PASS+1)) + echo "PASS: $function:L$lineno - $msg" + fi +} + + +# Print a summary of passing and failing tests and exit +# (with an error if we have failed tests) +# usage: report_results function report_results { echo "$PASS Tests PASSED" - if [[ $ERROR -gt 1 ]]; then + if [[ $ERROR -gt 0 ]]; then echo echo "The following $ERROR tests FAILED" echo -e "$FAILED_FUNCS" echo "---" exit 1 fi + exit 0 } diff --git a/tools/build_docs.sh b/tools/build_docs.sh deleted file mode 100755 index fda86c05cd..0000000000 --- a/tools/build_docs.sh +++ /dev/null @@ -1,100 +0,0 @@ -#!/usr/bin/env bash - -# **build_docs.sh** - Build the docs for DevStack -# -# - Install shocco if not found on ``PATH`` and ``INSTALL_SHOCCO`` is set -# - Clone ``MASTER_REPO`` branch ``MASTER_BRANCH`` -# - Re-creates ``doc/build/html`` directory from existing repo + new generated script docs - -# Usage: -## build_docs.sh [-o ] -## -o Write the static HTML output to -## (Note that will be deleted and re-created to ensure it is clean) - -# Defaults -# -------- - -HTML_BUILD=doc/build/html - -# Keep track of the DevStack directory -TOP_DIR=$(cd $(dirname "$0")/.. && pwd) - -# Uses this shocco branch: https://github.com/dtroyer/shocco/tree/rst_support -SHOCCO=${SHOCCO:-shocco} -if ! which shocco; then - if [[ ! -x $TOP_DIR/shocco/shocco ]]; then - if [[ -z "$INSTALL_SHOCCO" ]]; then - echo "shocco not found in \$PATH, please set environment variable SHOCCO" - exit 1 - fi - echo "Installing local copy of shocco" - if ! which pygmentize; then - sudo pip install Pygments - fi - if ! which rst2html.py; then - sudo pip install docutils - fi - git clone -b rst_support https://github.com/dtroyer/shocco shocco - cd shocco - ./configure - make || exit - cd .. - fi - SHOCCO=$TOP_DIR/shocco/shocco -fi - -# Process command-line args -while getopts o: c; do - case $c in - o) HTML_BUILD=$OPTARG - ;; - esac -done -shift `expr $OPTIND - 1` - - -# Processing -# ---------- - -# Ensure build dir exists -mkdir -p $HTML_BUILD - -# Get fully qualified dirs -FQ_HTML_BUILD=$(cd $HTML_BUILD && pwd) - -# Insert automated bits -GLOG=$(mktemp gitlogXXXX) -echo "
    " >$GLOG -git log \ - --pretty=format:'
  • %s - Commit %h %cd
  • ' \ - --date=short \ - --since '6 months ago' | grep -v Merge >>$GLOG -echo "
" >>$GLOG -sed -i~ -e $"/^.*%GIT_LOG%.*$/r $GLOG" -e $"/^.*%GIT_LOG%.*$/s/^.*%GIT_LOG%.*$//" $FQ_HTML_BUILD/changes.html -rm -f $GLOG - -# Build list of scripts to process -FILES="" -for f in $(find . -name .git -prune -o \( -type f -name \*.sh -not -path \*shocco/\* -print \)); do - echo $f - FILES+="$f " - mkdir -p $FQ_HTML_BUILD/`dirname $f`; - $SHOCCO $f > $FQ_HTML_BUILD/$f.html -done -for f in $(find functions functions-common inc lib pkg samples -type f -name \*); do - echo $f - FILES+="$f " - mkdir -p $FQ_HTML_BUILD/`dirname $f`; - $SHOCCO $f > $FQ_HTML_BUILD/$f.html -done -echo "$FILES" >doc/files - -# Clean up or report the temp workspace -if [[ -n REPO && -n $PUSH_REPO ]]; then - echo rm -rf $TMP_ROOT -else - if [[ -z "$TMP_ROOT" ]]; then - TMP_ROOT="$(pwd)" - fi - echo "Built docs in $HTML_BUILD" -fi diff --git a/tools/build_wheels.sh b/tools/build_wheels.sh deleted file mode 100755 index 14c2999c8f..0000000000 --- a/tools/build_wheels.sh +++ /dev/null @@ -1,86 +0,0 @@ -#!/usr/bin/env bash -# -# **tools/build_wheels.sh** - Build a cache of Python wheels -# -# build_wheels.sh [package [...]] -# -# System package prerequisites listed in ``files/*/devlibs`` will be installed -# -# Builds wheels for all virtual env requirements listed in -# ``venv-requirements.txt`` plus any supplied on the command line. -# -# Assumes: -# - ``tools/install_pip.sh`` has been run and a suitable ``pip/setuptools`` is available. - -# If ``TOP_DIR`` is set we're being sourced rather than running stand-alone -# or in a sub-shell -if [[ -z "$TOP_DIR" ]]; then - - set -o errexit - set -o nounset - - # Keep track of the DevStack directory - TOP_DIR=$(cd $(dirname "$0")/.. && pwd) - FILES=$TOP_DIR/files - - # Import common functions - source $TOP_DIR/functions - - GetDistro - - source $TOP_DIR/stackrc - - trap err_trap ERR - -fi - -# Get additional packages to build -MORE_PACKAGES="$@" - -# Exit on any errors so that errors don't compound -function err_trap { - local r=$? - set +o xtrace - - rm -rf $TMP_VENV_PATH - - exit $r -} - -# Get system prereqs -install_package $(get_packages devlibs) - -# Get a modern ``virtualenv`` -pip_install virtualenv - -# Prepare the workspace -TMP_VENV_PATH=$(mktemp -d tmp-venv-XXXX) -virtualenv $TMP_VENV_PATH - -# Install modern pip and wheel -PIP_VIRTUAL_ENV=$TMP_VENV_PATH pip_install -U pip wheel - -# BUG: cffi has a lot of issues. It has no stable ABI, if installed -# code is built with a different ABI than the one that's detected at -# load time, it tries to compile on the fly for the new ABI in the -# install location (which will probably be /usr and not -# writable). Also cffi is often included via setup_requires by -# packages, which have different install rules (allowing betas) than -# pip has. -# -# Because of this we must pip install cffi into the venv to build -# wheels. -PIP_VIRTUAL_ENV=$TMP_VENV_PATH pip_install_gr cffi - -# ``VENV_PACKAGES`` is a list of packages we want to pre-install -VENV_PACKAGE_FILE=$FILES/venv-requirements.txt -if [[ -r $VENV_PACKAGE_FILE ]]; then - VENV_PACKAGES=$(grep -v '^#' $VENV_PACKAGE_FILE) -fi - -for pkg in ${VENV_PACKAGES,/ } ${MORE_PACKAGES}; do - $TMP_VENV_PATH/bin/pip wheel $pkg -done - -# Clean up wheel workspace -rm -rf $TMP_VENV_PATH diff --git a/tools/cap-pip.txt b/tools/cap-pip.txt new file mode 100644 index 0000000000..f5278d7c86 --- /dev/null +++ b/tools/cap-pip.txt @@ -0,0 +1 @@ +pip!=8,<10 diff --git a/tools/cpu_map_update.py b/tools/cpu_map_update.py deleted file mode 100755 index 1938793114..0000000000 --- a/tools/cpu_map_update.py +++ /dev/null @@ -1,89 +0,0 @@ -#!/usr/bin/env python -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -# This small script updates the libvirt CPU map to add a gate64 cpu model -# that can be used to enable a common 64bit capable feature set across -# devstack nodes so that features like nova live migration work. - -import sys -import xml.etree.ElementTree as ET -from xml.dom import minidom - - -def update_cpu_map(tree): - root = tree.getroot() - cpus = root#.find("cpus") - x86 = None - for arch in cpus.findall("arch"): - if arch.get("name") == "x86": - x86 = arch - break - if x86 is not None: - # Create a gate64 cpu model that is core2duo less monitor and pse36 - gate64 = ET.SubElement(x86, "model") - gate64.set("name", "gate64") - ET.SubElement(gate64, "vendor").set("name", "Intel") - ET.SubElement(gate64, "feature").set("name", "fpu") - ET.SubElement(gate64, "feature").set("name", "de") - ET.SubElement(gate64, "feature").set("name", "pse") - ET.SubElement(gate64, "feature").set("name", "tsc") - ET.SubElement(gate64, "feature").set("name", "msr") - ET.SubElement(gate64, "feature").set("name", "pae") - ET.SubElement(gate64, "feature").set("name", "mce") - ET.SubElement(gate64, "feature").set("name", "cx8") - ET.SubElement(gate64, "feature").set("name", "apic") - ET.SubElement(gate64, "feature").set("name", "sep") - ET.SubElement(gate64, "feature").set("name", "pge") - ET.SubElement(gate64, "feature").set("name", "cmov") - ET.SubElement(gate64, "feature").set("name", "pat") - ET.SubElement(gate64, "feature").set("name", "mmx") - ET.SubElement(gate64, "feature").set("name", "fxsr") - ET.SubElement(gate64, "feature").set("name", "sse") - ET.SubElement(gate64, "feature").set("name", "sse2") - ET.SubElement(gate64, "feature").set("name", "vme") - ET.SubElement(gate64, "feature").set("name", "mtrr") - ET.SubElement(gate64, "feature").set("name", "mca") - ET.SubElement(gate64, "feature").set("name", "clflush") - ET.SubElement(gate64, "feature").set("name", "pni") - ET.SubElement(gate64, "feature").set("name", "nx") - ET.SubElement(gate64, "feature").set("name", "ssse3") - ET.SubElement(gate64, "feature").set("name", "syscall") - ET.SubElement(gate64, "feature").set("name", "lm") - - -def format_xml(root): - # Adapted from http://pymotw.com/2/xml/etree/ElementTree/create.html - # thank you dhellmann - rough_string = ET.tostring(root, encoding="UTF-8") - dom_parsed = minidom.parseString(rough_string) - return dom_parsed.toprettyxml(" ", encoding="UTF-8") - - -def main(): - if len(sys.argv) != 2: - raise Exception("Must pass path to cpu_map.xml to update") - cpu_map = sys.argv[1] - tree = ET.parse(cpu_map) - for model in tree.getroot().iter("model"): - if model.get("name") == "gate64": - # gate64 model is already present - return - update_cpu_map(tree) - pretty_xml = format_xml(tree.getroot()) - with open(cpu_map, 'w') as f: - f.write(pretty_xml) - - -if __name__ == "__main__": - main() diff --git a/tools/create-stack-user.sh b/tools/create-stack-user.sh index b49164b22a..c0b7ac70aa 100755 --- a/tools/create-stack-user.sh +++ b/tools/create-stack-user.sh @@ -24,7 +24,7 @@ TOP_DIR=$(cd $(dirname "$0")/.. && pwd) source $TOP_DIR/functions # Determine what system we are running on. This provides ``os_VENDOR``, -# ``os_RELEASE``, ``os_UPDATE``, ``os_PACKAGE``, ``os_CODENAME`` +# ``os_RELEASE``, ``os_PACKAGE``, ``os_CODENAME`` # and ``DISTRO`` GetDistro diff --git a/tools/create_userrc.sh b/tools/create_userrc.sh index f067ed1f4b..f4a4edcbe2 100755 --- a/tools/create_userrc.sh +++ b/tools/create_userrc.sh @@ -7,6 +7,25 @@ # Warning: This script just for development purposes set -o errexit + +# short_source prints out the current location of the caller in a way +# that strips redundant directories. This is useful for PS4 +# usage. Needed before we start tracing due to how we set +# PS4. Normally we'd pick this up from stackrc, but that's not sourced +# here. +function short_source { + saveIFS=$IFS + IFS=" " + called=($(caller 0)) + IFS=$saveIFS + file=${called[2]} + file=${file#$RC_DIR/} + printf "%-40s " "$file:${called[1]}:${called[0]}" +} +# PS4 is exported to child shells and uses the 'short_source' function, so +# export it so child shells have access to the 'short_source' function also. +export -f short_source + set -o xtrace ACCOUNT_DIR=./accrc @@ -16,45 +35,49 @@ cat < -This script creates certificates and sourcable rc files per tenant/user. +This script creates certificates and sourcable rc files per project/user. Target account directory hierarchy: target_dir-| |-cacert.pem - |-tenant1-name| - | |- user1 - | |- user1-cert.pem - | |- user1-pk.pem - | |- user2 - | .. - |-tenant2-name.. + |-project1-name| + | |- user1 + | |- user1-cert.pem + | |- user1-pk.pem + | |- user2 + | .. + |-project2-name.. .. Optional Arguments -P include password to the rc files; with -A it assume all users password is the same -A try with all user -u create files just for the specified user --C create user and tenant, the specifid tenant will be the user's tenant --r when combined with -C and the (-u) user exists it will be the user's tenant role in the (-C)tenant (default: Member) +-C create user and project, the specifid project will be the user's project +-r when combined with -C and the (-u) user exists it will be the user's project role in the (-C)project (default: Member) -p password for the user --heat-url --os-username --os-password ---os-tenant-name ---os-tenant-id +--os-project-name +--os-project-id +--os-user-domain-id +--os-user-domain-name +--os-project-domain-id +--os-project-domain-name --os-auth-url --os-cacert --target-dir ---skip-tenant +--skip-project --debug Example: $0 -AP -$0 -P -C mytenant -u myuser -p mypass +$0 -P -C myproject -u myuser -p mypass EOF } -if ! options=$(getopt -o hPAp:u:r:C: -l os-username:,os-password:,os-tenant-name:,os-tenant-id:,os-auth-url:,target-dir:,heat-url:,skip-tenant:,os-cacert:,help,debug -- "$@"); then +if ! options=$(getopt -o hPAp:u:r:C: -l os-username:,os-password:,os-tenant-id:,os-tenant-name:,os-project-name:,os-project-id:,os-project-domain-id:,os-project-domain-name:,os-user-domain-id:,os-user-domain-name:,os-auth-url:,target-dir:,heat-url:,skip-project:,os-cacert:,help,debug -- "$@"); then display_help exit 1 fi @@ -62,10 +85,10 @@ eval set -- $options ADDPASS="" HEAT_URL="" -# The services users usually in the service tenant. +# The services users usually in the service project. # rc files for service users, is out of scope. -# Supporting different tenant for services is out of scope. -SKIP_TENANT="service" +# Supporting different project for services is out of scope. +SKIP_PROJECT="service" MODE="" ROLE=Member USER_NAME="" @@ -75,9 +98,16 @@ while [ $# -gt 0 ]; do -h|--help) display_help; exit 0 ;; --os-username) export OS_USERNAME=$2; shift ;; --os-password) export OS_PASSWORD=$2; shift ;; - --os-tenant-name) export OS_TENANT_NAME=$2; shift ;; - --os-tenant-id) export OS_TENANT_ID=$2; shift ;; - --skip-tenant) SKIP_TENANT="$SKIP_TENANT$2,"; shift ;; + --os-tenant-name) export OS_PROJECT_NAME=$2; shift ;; + --os-tenant-id) export OS_PROJECT_ID=$2; shift ;; + --os-project-name) export OS_PROJECT_NAME=$2; shift ;; + --os-project-id) export OS_PROJECT_ID=$2; shift ;; + --os-user-domain-id) export OS_USER_DOMAIN_ID=$2; shift ;; + --os-user-domain-name) export OS_USER_DOMAIN_NAME=$2; shift ;; + --os-project-domain-id) export OS_PROJECT_DOMAIN_ID=$2; shift ;; + --os-project-domain-name) export OS_PROJECT_DOMAIN_NAME=$2; shift ;; + --skip-tenant) SKIP_PROJECT="$SKIP_PROJECT$2,"; shift ;; + --skip-project) SKIP_PROJECT="$SKIP_PROJECT$2,"; shift ;; --os-auth-url) export OS_AUTH_URL=$2; shift ;; --os-cacert) export OS_CACERT=$2; shift ;; --target-dir) ACCOUNT_DIR=$2; shift ;; @@ -87,7 +117,7 @@ while [ $# -gt 0 ]; do -p) USER_PASS=$2; shift ;; -A) MODE=all; ;; -P) ADDPASS="yes" ;; - -C) MODE=create; TENANT=$2; shift ;; + -C) MODE=create; PROJECT=$2; shift ;; -r) ROLE=$2; shift ;; (--) shift; break ;; (-*) echo "$0: error - unrecognized option $1" >&2; display_help; exit 1 ;; @@ -105,8 +135,16 @@ if [ -z "$OS_PASSWORD" ]; then fi fi -if [ -z "$OS_TENANT_NAME" -a -z "$OS_TENANT_ID" ]; then - export OS_TENANT_NAME=admin +if [ -z "$OS_PROJECT_ID" -a "$OS_TENANT_ID" ]; then + export OS_PROJECT_ID=$OS_TENANT_ID +fi + +if [ -z "$OS_PROJECT_NAME" -a "$OS_TENANT_NAME" ]; then + export OS_PROJECT_NAME=$OS_TENANT_NAME +fi + +if [ -z "$OS_PROJECT_NAME" -a -z "$OS_PROJECT_ID" ]; then + export OS_PROJECT_NAME=admin fi if [ -z "$OS_USERNAME" ]; then @@ -114,7 +152,17 @@ if [ -z "$OS_USERNAME" ]; then fi if [ -z "$OS_AUTH_URL" ]; then - export OS_AUTH_URL=http://localhost:5000/v2.0/ + export OS_AUTH_URL=http://localhost:5000/v3/ +fi + +if [ -z "$OS_USER_DOMAIN_ID" -a -z "$OS_USER_DOMAIN_NAME" ]; then + # purposefully not exported as it would force v3 auth within this file. + OS_USER_DOMAIN_ID=default +fi + +if [ -z "$OS_PROJECT_DOMAIN_ID" -a -z "$OS_PROJECT_DOMAIN_NAME" ]; then + # purposefully not exported as it would force v3 auth within this file. + OS_PROJECT_DOMAIN_ID=default fi USER_PASS=${USER_PASS:-$OS_PASSWORD} @@ -127,95 +175,39 @@ if [ -z "$MODE" ]; then exit 3 fi -export -n SERVICE_TOKEN SERVICE_ENDPOINT OS_SERVICE_TOKEN OS_SERVICE_ENDPOINT - -EC2_URL=$(openstack endpoint show -f value -c publicurl ec2 || true) -if [[ -z $EC2_URL ]]; then - EC2_URL=http://localhost:8773/ -fi - -S3_URL=$(openstack endpoint show -f value -c publicurl s3 || true) -if [[ -z $S3_URL ]]; then - S3_URL=http://localhost:3333 -fi - -mkdir -p "$ACCOUNT_DIR" -ACCOUNT_DIR=`readlink -f "$ACCOUNT_DIR"` -EUCALYPTUS_CERT=$ACCOUNT_DIR/cacert.pem -if [ -e "$EUCALYPTUS_CERT" ]; then - mv "$EUCALYPTUS_CERT" "$EUCALYPTUS_CERT.old" -fi -if ! nova x509-get-root-cert "$EUCALYPTUS_CERT"; then - echo "Failed to update the root certificate: $EUCALYPTUS_CERT" >&2 - if [ -e "$EUCALYPTUS_CERT.old" ]; then - mv "$EUCALYPTUS_CERT.old" "$EUCALYPTUS_CERT" - fi -fi - - function add_entry { local user_id=$1 local user_name=$2 - local tenant_id=$3 - local tenant_name=$4 + local project_id=$3 + local project_name=$4 local user_passwd=$5 - # The admin user can see all user's secret AWS keys, it does not looks good - local line=`openstack ec2 credentials list --user $user_id | grep " $tenant_id "` - if [ -z "$line" ]; then - openstack ec2 credentials create --user $user_id --project $tenant_id 1>&2 - line=`openstack ec2 credentials list --user $user_id | grep " $tenant_id "` - fi - local ec2_access_key ec2_secret_key - read ec2_access_key ec2_secret_key <<< `echo $line | awk '{print $2 " " $4 }'` - mkdir -p "$ACCOUNT_DIR/$tenant_name" - local rcfile="$ACCOUNT_DIR/$tenant_name/$user_name" - # The certs subject part are the tenant ID "dash" user ID, but the CN should be the first part of the DN - # Generally the subject DN parts should be in reverse order like the Issuer - # The Serial does not seams correctly marked either - local ec2_cert="$rcfile-cert.pem" - local ec2_private_key="$rcfile-pk.pem" - # Try to preserve the original file on fail (best effort) - if [ -e "$ec2_private_key" ]; then - mv -f "$ec2_private_key" "$ec2_private_key.old" - fi - if [ -e "$ec2_cert" ]; then - mv -f "$ec2_cert" "$ec2_cert.old" - fi - # It will not create certs when the password is incorrect - if ! nova --os-password "$user_passwd" --os-username "$user_name" --os-tenant-name "$tenant_name" x509-create-cert "$ec2_private_key" "$ec2_cert"; then - if [ -e "$ec2_private_key.old" ]; then - mv -f "$ec2_private_key.old" "$ec2_private_key" - fi - if [ -e "$ec2_cert.old" ]; then - mv -f "$ec2_cert.old" "$ec2_cert" - fi - fi + mkdir -p "$ACCOUNT_DIR/$project_name" + local rcfile="$ACCOUNT_DIR/$project_name/$user_name" + cat >"$rcfile" <>"$rcfile" fi if [ -n "$HEAT_URL" ]; then - echo "export HEAT_URL=\"$HEAT_URL/$tenant_id\"" >>"$rcfile" + echo "export HEAT_URL=\"$HEAT_URL/$project_id\"" >>"$rcfile" echo "export OS_NO_CLIENT_AUTH=True" >>"$rcfile" fi + for v in OS_USER_DOMAIN_ID OS_USER_DOMAIN_NAME OS_PROJECT_DOMAIN_ID OS_PROJECT_DOMAIN_NAME; do + if [ ${!v} ]; then + echo "export $v=${!v}" >>"$rcfile" + else + echo "unset $v" >>"$rcfile" + fi + done } #admin users expected @@ -245,9 +237,9 @@ function get_user_id { } if [ $MODE != "create" ]; then - # looks like I can't ask for all tenant related to a specified user - openstack project list --long --quote none -f csv | grep ',True' | grep -v "${SKIP_TENANT}" | while IFS=, read tenant_id tenant_name desc enabled; do - openstack user list --project $tenant_id --long --quote none -f csv | grep ',True' | while IFS=, read user_id user_name project email enabled; do + # looks like I can't ask for all project related to a specified user + openstack project list --long --quote none -f csv | grep ',True' | grep -v "${SKIP_PROJECT}" | while IFS=, read project_id project_name desc enabled; do + openstack user list --project $project_id --long --quote none -f csv | grep ',True' | while IFS=, read user_id user_name project email enabled; do if [ $MODE = one -a "$user_name" != "$USER_NAME" ]; then continue; fi @@ -259,21 +251,21 @@ if [ $MODE != "create" ]; then if [ -n "$SPECIFIC_UPASSWORD" ]; then USER_PASS=$SPECIFIC_UPASSWORD fi - add_entry "$user_id" "$user_name" "$tenant_id" "$tenant_name" "$USER_PASS" + add_entry "$user_id" "$user_name" "$project_id" "$project_name" "$USER_PASS" done done else - tenant_name=$TENANT - tenant_id=$(create_or_get_project "$TENANT") + project_name=$PROJECT + project_id=$(create_or_get_project "$PROJECT") user_name=$USER_NAME user_id=`get_user_id $user_name` if [ -z "$user_id" ]; then - eval $(openstack user create "$user_name" --project "$tenant_id" --password "$USER_PASS" --email "$user_name@example.com" -f shell -c id) + eval $(openstack user create "$user_name" --project "$project_id" --password "$USER_PASS" --email "$user_name@example.com" -f shell -c id) user_id=$id - add_entry "$user_id" "$user_name" "$tenant_id" "$tenant_name" "$USER_PASS" + add_entry "$user_id" "$user_name" "$project_id" "$project_name" "$USER_PASS" else role_id=$(create_or_get_role "$ROLE") - openstack role add "$role_id" --user "$user_id" --project "$tenant_id" - add_entry "$user_id" "$user_name" "$tenant_id" "$tenant_name" "$USER_PASS" + openstack role add "$role_id" --user "$user_id" --project "$project_id" + add_entry "$user_id" "$user_name" "$project_id" "$project_name" "$USER_PASS" fi fi diff --git a/tools/discover_hosts.sh b/tools/discover_hosts.sh new file mode 100755 index 0000000000..4ec6a40511 --- /dev/null +++ b/tools/discover_hosts.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash + +# **discover_hosts.sh** + +# This is just a very simple script to run the +# "nova-manage cell_v2 discover_hosts" command +# which is needed to discover compute nodes and +# register them with a parent cell in Nova. +# This assumes that /etc/nova/nova.conf exists +# and has the following entries filled in: +# +# [api_database] +# connection = This is the URL to the nova_api database +# +# In other words this should be run on the primary +# (API) node in a multi-node setup. + +if [[ -x $(which nova-manage) ]]; then + nova-manage cell_v2 discover_hosts --verbose +fi diff --git a/tools/dstat.sh b/tools/dstat.sh new file mode 100755 index 0000000000..01c6d9b7e9 --- /dev/null +++ b/tools/dstat.sh @@ -0,0 +1,32 @@ +#!/bin/bash + +# **tools/dstat.sh** - Execute instances of DStat to log system load info +# +# Multiple instances of DStat are executed in order to take advantage of +# incompatible features, particularly CSV output and the "top-cpu-adv" and +# "top-io-adv" flags. +# +# Assumes: +# - dstat command is installed + +# Retrieve log directory as argument from calling script. +LOGDIR=$1 + +# Command line arguments for primary DStat process. +DSTAT_OPTS="-tcmndrylpg --top-cpu-adv --top-io-adv --top-mem --swap --tcp" + +# Command-line arguments for secondary background DStat process. +DSTAT_CSV_OPTS="-tcmndrylpg --tcp --output $LOGDIR/dstat-csv.log" + +# Execute and background the secondary dstat process and discard its output. +dstat $DSTAT_CSV_OPTS >& /dev/null & + +# Execute and background the primary dstat process, but keep its output in this +# TTY. +dstat $DSTAT_OPTS & + +# Catch any exit signals, making sure to also terminate any child processes. +trap "kill -- -$$" EXIT + +# Keep this script running as long as child dstat processes are alive. +wait diff --git a/tools/fixup_stuff.sh b/tools/fixup_stuff.sh index 2efb4e0987..a939e30b02 100755 --- a/tools/fixup_stuff.sh +++ b/tools/fixup_stuff.sh @@ -45,28 +45,67 @@ fi # where Keystone will try and bind to the port and the port will already be # in use as an ephemeral port by another process. This places an explicit # exception into the Kernel for the Keystone AUTH ports. -keystone_ports=${KEYSTONE_AUTH_PORT:-35357},${KEYSTONE_AUTH_PORT_INT:-35358} - -# Only do the reserved ports when available, on some system (like containers) -# where it's not exposed we are almost pretty sure these ports would be -# exclusive for our DevStack. -if sysctl net.ipv4.ip_local_reserved_ports >/dev/null 2>&1; then - # Get any currently reserved ports, strip off leading whitespace - reserved_ports=$(sysctl net.ipv4.ip_local_reserved_ports | awk -F'=' '{print $2;}' | sed 's/^ //') - - if [[ -z "${reserved_ports}" ]]; then - # If there are no currently reserved ports, reserve the keystone ports - sudo sysctl -w net.ipv4.ip_local_reserved_ports=${keystone_ports} +function fixup_keystone { + keystone_ports=${KEYSTONE_AUTH_PORT:-35357},${KEYSTONE_AUTH_PORT_INT:-35358} + + # Only do the reserved ports when available, on some system (like containers) + # where it's not exposed we are almost pretty sure these ports would be + # exclusive for our DevStack. + if sysctl net.ipv4.ip_local_reserved_ports >/dev/null 2>&1; then + # Get any currently reserved ports, strip off leading whitespace + reserved_ports=$(sysctl net.ipv4.ip_local_reserved_ports | awk -F'=' '{print $2;}' | sed 's/^ //') + + if [[ -z "${reserved_ports}" ]]; then + # If there are no currently reserved ports, reserve the keystone ports + sudo sysctl -w net.ipv4.ip_local_reserved_ports=${keystone_ports} + else + # If there are currently reserved ports, keep those and also reserve the + # Keystone specific ports. Duplicate reservations are merged into a single + # reservation (or range) automatically by the kernel. + sudo sysctl -w net.ipv4.ip_local_reserved_ports=${keystone_ports},${reserved_ports} + fi else - # If there are currently reserved ports, keep those and also reserve the - # Keystone specific ports. Duplicate reservations are merged into a single - # reservation (or range) automatically by the kernel. - sudo sysctl -w net.ipv4.ip_local_reserved_ports=${keystone_ports},${reserved_ports} + echo_summary "WARNING: unable to reserve keystone ports" fi -else - echo_summary "WARNING: unable to reserve keystone ports" -fi +} +# Ubuntu Cloud Archive +#--------------------- +# We've found that Libvirt on Xenial is flaky and crashes enough to be +# a regular top e-r bug. Opt into Ubuntu Cloud Archive if on Xenial to +# get newer Libvirt. +# Make it possible to switch this based on an environment variable as +# libvirt 2.5.0 doesn't handle nested virtualization quite well and this +# is required for the trove development environment. +function fixup_uca { + if [[ "${ENABLE_UBUNTU_CLOUD_ARCHIVE}" == "False" || "$DISTRO" != "xenial" ]]; then + return + fi + + # This pulls in apt-add-repository + install_package "software-properties-common" + # Use UCA for newer libvirt. + if [[ -f /etc/ci/mirror_info.sh ]] ; then + # If we are on a nodepool provided host and it has told us about where + # we can find local mirrors then use that mirror. + source /etc/ci/mirror_info.sh + + sudo apt-add-repository -y "deb $NODEPOOL_UCA_MIRROR xenial-updates/queens main" + else + # Otherwise use upstream UCA + sudo add-apt-repository -y cloud-archive:queens + fi + + # Disable use of libvirt wheel since a cached wheel build might be + # against older libvirt binary. Particularly a problem if using + # the openstack wheel mirrors, but can hit locally too. + # TODO(clarkb) figure out how to use upstream wheel again. + iniset -sudo /etc/pip.conf "global" "no-binary" "libvirt-python" + + # Force update our APT repos, since we added UCA above. + REPOS_UPDATED=False + apt_get_update +} # Python Packages # --------------- @@ -81,51 +120,138 @@ function get_package_path { # Pre-install affected packages so we can fix the permissions # These can go away once we are confident that pip 1.4.1+ is available everywhere -# Fix prettytable 0.7.2 permissions -# Don't specify --upgrade so we use the existing package if present -pip_install 'prettytable>=0.7' -PACKAGE_DIR=$(get_package_path prettytable) -# Only fix version 0.7.2 -dir=$(echo $PACKAGE_DIR/prettytable-0.7.2*) -if [[ -d $dir ]]; then - sudo chmod +r $dir/* -fi +function fixup_python_packages { + # Fix prettytable 0.7.2 permissions + # Don't specify --upgrade so we use the existing package if present + pip_install 'prettytable>=0.7' + PACKAGE_DIR=$(get_package_path prettytable) + # Only fix version 0.7.2 + dir=$(echo $PACKAGE_DIR/prettytable-0.7.2*) + if [[ -d $dir ]]; then + sudo chmod +r $dir/* + fi -# Fix httplib2 0.8 permissions -# Don't specify --upgrade so we use the existing package if present -pip_install httplib2 -PACKAGE_DIR=$(get_package_path httplib2) -# Only fix version 0.8 -dir=$(echo $PACKAGE_DIR-0.8*) -if [[ -d $dir ]]; then - sudo chmod +r $dir/* -fi + # Fix httplib2 0.8 permissions + # Don't specify --upgrade so we use the existing package if present + pip_install httplib2 + PACKAGE_DIR=$(get_package_path httplib2) + # Only fix version 0.8 + dir=$(echo $PACKAGE_DIR-0.8*) + if [[ -d $dir ]]; then + sudo chmod +r $dir/* + fi +} -if is_fedora; then +function fixup_fedora { + if ! is_fedora; then + return + fi # Disable selinux to avoid configuring to allow Apache access # to Horizon files (LP#1175444) if selinuxenabled; then sudo setenforce 0 fi - FORCE_FIREWALLD=$(trueorfalse False $FORCE_FIREWALLD) - if [[ ${DISTRO} =~ (f20) && $FORCE_FIREWALLD == "False" ]]; then + FORCE_FIREWALLD=$(trueorfalse False FORCE_FIREWALLD) + if [[ $FORCE_FIREWALLD == "False" ]]; then # On Fedora 20 firewalld interacts badly with libvirt and - # slows things down significantly. However, for those cases - # where that combination is desired, allow this fix to be skipped. - - # There was also an additional issue with firewalld hanging - # after install of libvirt with polkit. See - # https://bugzilla.redhat.com/show_bug.cgi?id=1099031 + # slows things down significantly (this issue was fixed in + # later fedoras). There was also an additional issue with + # firewalld hanging after install of libvirt with polkit [1]. + # firewalld also causes problems with neturon+ipv6 [2] + # + # Note we do the same as the RDO packages and stop & disable, + # rather than remove. This is because other packages might + # have the dependency [3][4]. + # + # [1] https://bugzilla.redhat.com/show_bug.cgi?id=1099031 + # [2] https://bugs.launchpad.net/neutron/+bug/1455303 + # [3] https://github.com/redhat-openstack/openstack-puppet-modules/blob/master/firewall/manifests/linux/redhat.pp + # [4] https://docs.openstack.org/devstack/latest/guides/neutron.html if is_package_installed firewalld; then - uninstall_package firewalld + sudo systemctl disable firewalld + # The iptables service files are no longer included by default, + # at least on a baremetal Fedora 21 Server install. + install_package iptables-services + sudo systemctl enable iptables + sudo systemctl stop firewalld + sudo systemctl start iptables fi fi -fi + if [[ "$os_VENDOR" == "Fedora" ]] && [[ "$os_RELEASE" -ge "22" ]]; then + # requests ships vendored version of chardet/urllib3, but on + # fedora these are symlinked back to the primary versions to + # avoid duplication of code on disk. This is fine when + # maintainers keep things in sync, but since devstack takes + # over and installs later versions via pip we can end up with + # incompatible versions. + # + # The rpm package is not removed to preserve the dependent + # packages like cloud-init; rather we remove the symlinks and + # force a re-install of requests so the vendored versions it + # wants are present. + # + # Realted issues: + # https://bugs.launchpad.net/glance/+bug/1476770 + # https://bugzilla.redhat.com/show_bug.cgi?id=1253823 + + base_path=$(get_package_path requests)/packages + if [ -L $base_path/chardet -o -L $base_path/urllib3 ]; then + sudo rm -f $base_path/{chardet,urllib3} + # install requests with the bundled urllib3 to avoid conflicts + pip_install --upgrade --force-reinstall requests + fi + fi +} + +function fixup_suse { + if ! is_suse; then + return + fi + + # Disable apparmor profiles in openSUSE distros + # to avoid issues with haproxy and dnsmasq + if [ -x /usr/sbin/aa-enabled ] && sudo /usr/sbin/aa-enabled -q; then + sudo systemctl disable apparmor + sudo /usr/sbin/aa-teardown + fi +} # The version of pip(1.5.4) supported by python-virtualenv(1.11.4) has -# connection issues under proxy, hence uninstalling python-virtualenv package -# and installing the latest version using pip. -uninstall_package python-virtualenv -pip_install -U virtualenv +# connection issues under proxy so re-install the latest version using +# pip. To avoid having pip's virtualenv overwritten by the distro's +# package (e.g. due to installing a distro package with a dependency +# on python-virtualenv), first install the distro python-virtualenv +# to satisfy any dependencies then use pip to overwrite it. + +# ... but, for infra builds, the pip-and-virtualenv [1] element has +# already done this to ensure the latest pip, virtualenv and +# setuptools on the base image for all platforms. It has also added +# the packages to the yum/dnf ignore list to prevent them being +# overwritten with old versions. F26 and dnf 2.0 has changed +# behaviour that means re-installing python-virtualenv fails [2]. +# Thus we do a quick check if we're in the infra environment by +# looking for the mirror config script before doing this, and just +# skip it if so. + +# [1] https://git.openstack.org/cgit/openstack/diskimage-builder/tree/ \ +# diskimage_builder/elements/pip-and-virtualenv/ \ +# install.d/pip-and-virtualenv-source-install/04-install-pip +# [2] https://bugzilla.redhat.com/show_bug.cgi?id=1477823 + +function fixup_virtualenv { + if [[ ! -f /etc/ci/mirror_info.sh ]]; then + install_package python-virtualenv + pip_install -U --force-reinstall virtualenv + fi +} + +function fixup_all { + fixup_keystone + fixup_uca + fixup_python_packages + fixup_fedora + fixup_suse + fixup_virtualenv +} diff --git a/tools/generate-devstack-plugins-list.py b/tools/generate-devstack-plugins-list.py new file mode 100644 index 0000000000..56f12e7ab6 --- /dev/null +++ b/tools/generate-devstack-plugins-list.py @@ -0,0 +1,64 @@ +#! /usr/bin/env python + +# Copyright 2016 Hewlett Packard Enterprise Development Company, L.P. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +# This script is intended to be run as part of a periodic proposal bot +# job in OpenStack infrastructure. +# +# In order to function correctly, the environment in which the +# script runs must have +# * network access to the review.openstack.org Gerrit API +# working directory +# * network access to https://git.openstack.org/cgit + +import logging +import json +import requests + +logging.basicConfig(level=logging.DEBUG) + +url = 'https://review.openstack.org/projects/' + +# This is what a project looks like +''' + "openstack-attic/akanda": { + "id": "openstack-attic%2Fakanda", + "state": "READ_ONLY" + }, +''' + +def is_in_openstack_namespace(proj): + # only interested in openstack namespace (e.g. not retired + # stackforge, etc) + return proj.startswith('openstack/') + +# Check if this project has a plugin file +def has_devstack_plugin(proj): + # Don't link in the deb packaging repos + if "openstack/deb-" in proj: + return False + r = requests.get("https://git.openstack.org/cgit/%s/plain/devstack/plugin.sh" % proj) + return r.status_code == 200 + +logging.debug("Getting project list from %s" % url) +r = requests.get(url) +projects = sorted(filter(is_in_openstack_namespace, json.loads(r.text[4:]))) +logging.debug("Found %d projects" % len(projects)) + +found_plugins = filter(has_devstack_plugin, projects) + +for project in found_plugins: + # strip of openstack/ + print(project[10:]) diff --git a/tools/generate-devstack-plugins-list.sh b/tools/generate-devstack-plugins-list.sh new file mode 100755 index 0000000000..95f13318b8 --- /dev/null +++ b/tools/generate-devstack-plugins-list.sh @@ -0,0 +1,93 @@ +#!/bin/bash -ex + +# Copyright 2016 Hewlett Packard Enterprise Development Company, L.P. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +# This script is intended to be run as a periodic proposal bot job +# in OpenStack infrastructure, though you can run it as a one-off. +# +# In order to function correctly, the environment in which the +# script runs must have +# * a writable doc/source directory relative to the current +# working directory +# AND ( ( +# * git +# * all git repos meant to be searched for plugins cloned and +# at the desired level of up-to-datedness +# * the environment variable git_dir pointing to the location +# * of said git repositories +# ) OR ( +# * network access to the review.openstack.org Gerrit API +# working directory +# * network access to https://git.openstack.org/cgit +# )) +# +# If a file named data/devstack-plugins-registry.header or +# data/devstack-plugins-registry.footer is found relative to the +# current working directory, it will be prepended or appended to +# the generated reStructuredText plugins table respectively. + +# Print the title underline for a RST table. Argument is the length +# of the first column, second column is assumed to be "URL" +function title_underline { + local len=$1 + while [[ $len -gt 0 ]]; do + printf "=" + len=$(( len - 1)) + done + printf " ===\n" +} + +( +declare -A plugins + +if [[ -r data/devstack-plugins-registry.header ]]; then + cat data/devstack-plugins-registry.header +fi + +sorted_plugins=$(python tools/generate-devstack-plugins-list.py) + +# find the length of the name column & pad +name_col_len=$(echo "${sorted_plugins}" | wc -L) +name_col_len=$(( name_col_len + 2 )) + +# ====================== === +# Plugin Name URL +# ====================== === +# foobar `git://... `__ +# ... + +printf "\n\n" +title_underline ${name_col_len} +printf "%-${name_col_len}s %s\n" "Plugin Name" "URL" +title_underline ${name_col_len} + +for plugin in ${sorted_plugins}; do + giturl="git://git.openstack.org/openstack/${plugin}" + gitlink="https://git.openstack.org/cgit/openstack/${plugin}" + printf "%-${name_col_len}s %s\n" "${plugin}" "\`${giturl} <${gitlink}>\`__" +done + +title_underline ${name_col_len} + +printf "\n\n" + +if [[ -r data/devstack-plugins-registry.footer ]]; then + cat data/devstack-plugins-registry.footer +fi +) > doc/source/plugin-registry.rst + +if [[ -n ${1} ]]; then + cp doc/source/plugin-registry.rst ${1}/doc/source/plugin-registry.rst +fi diff --git a/tools/image_list.sh b/tools/image_list.sh index a27635effd..3a27c4acfd 100755 --- a/tools/image_list.sh +++ b/tools/image_list.sh @@ -1,8 +1,23 @@ #!/bin/bash +# Print out a list of image and other files to download for caching. +# This is mostly used by the OpenStack infrasturucture during daily +# image builds to save the large images to /opt/cache/files (see [1]) +# +# The two lists of URL's downloaded are the IMAGE_URLS and +# EXTRA_CACHE_URLS, which are setup in stackrc +# +# [1] project-config:nodepool/elements/cache-devstack/extra-data.d/55-cache-devstack-repos + # Keep track of the DevStack directory TOP_DIR=$(cd $(dirname "$0")/.. && pwd) +# The following "source" implicitly calls get_default_host_ip() in +# stackrc and will die if the selected default IP happens to lie +# in the default ranges for FIXED_RANGE or FLOATING_RANGE. Since we +# do not really need HOST_IP to be properly set in the remainder of +# this script, just set it to some dummy value and make stackrc happy. +HOST_IP=SKIP source $TOP_DIR/functions # Possible virt drivers, if we have more, add them here. Always keep @@ -25,12 +40,20 @@ for driver in $DRIVERS; do ALL_IMAGES+=$URLS done -# Make a nice list -echo $ALL_IMAGES | tr ',' '\n' | sort | uniq - # Sanity check - ensure we have a minimum number of images num=$(echo $ALL_IMAGES | tr ',' '\n' | sort | uniq | wc -l) -if [[ "$num" -lt 5 ]]; then +if [[ "$num" -lt 4 ]]; then echo "ERROR: We only found $num images in $ALL_IMAGES, which can't be right." exit 1 fi + +# This is extra non-image files that we want pre-cached. This is kept +# in a separate list because devstack loops over the IMAGE_LIST to +# upload files glance and these aren't images. (This was a bit of an +# after-thought which is why the naming around this is very +# image-centric) +URLS=$(source $TOP_DIR/stackrc && echo $EXTRA_CACHE_URLS) +ALL_IMAGES+=$URLS + +# Make a nice combined list +echo $ALL_IMAGES | tr ',' '\n' | sort | uniq diff --git a/tools/info.sh b/tools/info.sh index 433206e8ae..282667f9d0 100755 --- a/tools/info.sh +++ b/tools/info.sh @@ -8,7 +8,7 @@ # Output types are git,localrc,os,pip,pkg: # # git||[] -# localtc|= +# localrc|= # os|= # pip|| # pkg|| @@ -52,10 +52,6 @@ GetDistro echo "os|distro=$DISTRO" echo "os|vendor=$os_VENDOR" echo "os|release=$os_RELEASE" -if [ -n "$os_UPDATE" ]; then - echo "os|version=$os_UPDATE" -fi - # Repos # ----- diff --git a/tools/install_pip.sh b/tools/install_pip.sh index 0f7c962b2b..1bd7392b9d 100755 --- a/tools/install_pip.sh +++ b/tools/install_pip.sh @@ -2,15 +2,12 @@ # **install_pip.sh** -# install_pip.sh [--pip-version ] [--use-get-pip] [--force] -# # Update pip and friends to a known common version # Assumptions: -# - update pip to $INSTALL_PIP_VERSION +# - if USE_PYTHON3=True, PYTHON3_VERSION refers to a version already installed set -o errexit -set -o xtrace # Keep track of the current directory TOOLS_DIR=$(cd $(dirname "$0") && pwd) @@ -20,17 +17,35 @@ TOP_DIR=`cd $TOOLS_DIR/..; pwd` cd $TOP_DIR # Import common functions -source $TOP_DIR/functions +source $TOP_DIR/stackrc + +# don't start tracing until after we've sourced the world +set -o xtrace FILES=$TOP_DIR/files -PIP_GET_PIP_URL=https://bootstrap.pypa.io/get-pip.py +# The URL from where the get-pip.py file gets downloaded. If a local +# get-pip.py mirror is available, PIP_GET_PIP_URL can be set to that +# mirror in local.conf to avoid download timeouts. +# Example: +# PIP_GET_PIP_URL="http://local-server/get-pip.py" +# +# Note that if get-pip.py already exists in $FILES this script will +# not re-download or check for a new version. For example, this is +# done by openstack-infra diskimage-builder elements as part of image +# preparation [1]. This prevents any network access, which can be +# unreliable in CI situations. +# [1] http://git.openstack.org/cgit/openstack-infra/project-config/tree/nodepool/elements/cache-devstack/source-repository-pip + +PIP_GET_PIP_URL=${PIP_GET_PIP_URL:-"https://bootstrap.pypa.io/get-pip.py"} LOCAL_PIP="$FILES/$(basename $PIP_GET_PIP_URL)" GetDistro echo "Distro: $DISTRO" function get_versions { + # FIXME(dhellmann): Deal with multiple python versions here? This + # is just used for reporting, so maybe not? PIP=$(which pip 2>/dev/null || which pip-python 2>/dev/null || true) if [[ -n $PIP ]]; then PIP_VERSION=$($PIP --version | awk '{ print $2}') @@ -42,6 +57,15 @@ function get_versions { function install_get_pip { + # If get-pip.py isn't python, delete it. This was probably an + # outage on the server. + if [[ -r $LOCAL_PIP ]]; then + if ! head -1 $LOCAL_PIP | grep -q '#!/usr/bin/env python'; then + echo "WARNING: Corrupt $LOCAL_PIP found removing" + rm $LOCAL_PIP + fi + fi + # The OpenStack gate and others put a cached version of get-pip.py # for this to find, explicitly to avoid download issues. # @@ -53,12 +77,22 @@ function install_get_pip { # since and only download if a new version is out -- but only if # it seems we downloaded the file originally. if [[ ! -r $LOCAL_PIP || -r $LOCAL_PIP.downloaded ]]; then - curl --retry 6 --retry-delay 5 \ - -z $LOCAL_PIP -o $LOCAL_PIP $PIP_GET_PIP_URL || \ + # only test freshness if LOCAL_PIP is actually there, + # otherwise we generate a scary warning. + local timecond="" + if [[ -r $LOCAL_PIP ]]; then + timecond="-z $LOCAL_PIP" + fi + + curl -f --retry 6 --retry-delay 5 \ + $timecond -o $LOCAL_PIP $PIP_GET_PIP_URL || \ die $LINENO "Download of get-pip.py failed" touch $LOCAL_PIP.downloaded fi - sudo -H -E python $LOCAL_PIP + sudo -H -E python $LOCAL_PIP -c $TOOLS_DIR/cap-pip.txt + if python3_enabled; then + sudo -H -E python${PYTHON3_VERSION} $LOCAL_PIP -c $TOOLS_DIR/cap-pip.txt + fi } @@ -94,7 +128,14 @@ get_versions # Do pip # Eradicate any and all system packages -uninstall_package python-pip + +# Python in fedora/suse depends on the python-pip package so removing it +# results in a nonfunctional system. pip on fedora installs to /usr so pip +# can safely override the system pip for all versions of fedora +if ! is_fedora && ! is_suse; then + uninstall_package python-pip + uninstall_package python3-pip +fi install_get_pip @@ -102,6 +143,10 @@ if [[ -n $PYPI_ALTERNATIVE_URL ]]; then configure_pypi_alternative_url fi -pip_install -U setuptools +set -x + +# Note setuptools is part of requirements.txt and we want to make sure +# we obey any versioning as described there. +pip_install_gr setuptools get_versions diff --git a/tools/install_prereqs.sh b/tools/install_prereqs.sh index a07e58d3e6..da59093581 100755 --- a/tools/install_prereqs.sh +++ b/tools/install_prereqs.sh @@ -28,7 +28,7 @@ if [[ -z "$TOP_DIR" ]]; then source $TOP_DIR/functions # Determine what system we are running on. This provides ``os_VENDOR``, - # ``os_RELEASE``, ``os_UPDATE``, ``os_PACKAGE``, ``os_CODENAME`` + # ``os_RELEASE``, ``os_PACKAGE``, ``os_CODENAME`` # and ``DISTRO`` GetDistro @@ -61,7 +61,7 @@ export_proxy_variables # ================ # Install package requirements -PACKAGES=$(get_packages general $ENABLED_SERVICES) +PACKAGES=$(get_packages general,$ENABLED_SERVICES) PACKAGES="$PACKAGES $(get_plugin_packages)" if is_ubuntu && echo $PACKAGES | grep -q dkms ; then @@ -81,6 +81,12 @@ if [[ -n "$SYSLOG" && "$SYSLOG" != "False" ]]; then fi fi +if python3_enabled; then + install_python3 + export PYTHON=$(which python${PYTHON3_VERSION} 2>/dev/null || which python3 2>/dev/null) +else + export PYTHON=$(which python 2>/dev/null) +fi # Mark end of run # --------------- diff --git a/tools/ironic/scripts/cleanup-node b/tools/ironic/scripts/cleanup-node deleted file mode 100755 index c4e4e706f4..0000000000 --- a/tools/ironic/scripts/cleanup-node +++ /dev/null @@ -1,25 +0,0 @@ -#!/usr/bin/env bash - -# **cleanup-nodes** - -# Cleans up baremetal poseur nodes and volumes created during ironic setup -# Assumes calling user has proper libvirt group membership and access. - -set -exu - -LIBVIRT_STORAGE_POOL=${LIBVIRT_STORAGE_POOL:-"default"} -LIBVIRT_CONNECT_URI=${LIBVIRT_CONNECT_URI:-"qemu:///system"} - -NAME=$1 -NETWORK_BRIDGE=$2 - -export VIRSH_DEFAULT_CONNECT_URI=$LIBVIRT_CONNECT_URI - -VOL_NAME="$NAME.qcow2" -virsh list | grep -q $NAME && virsh destroy $NAME -virsh list --inactive | grep -q $NAME && virsh undefine $NAME - -if virsh pool-list | grep -q $LIBVIRT_STORAGE_POOL ; then - virsh vol-list $LIBVIRT_STORAGE_POOL | grep -q $VOL_NAME && - virsh vol-delete $VOL_NAME --pool $LIBVIRT_STORAGE_POOL -fi diff --git a/tools/ironic/scripts/configure-vm b/tools/ironic/scripts/configure-vm deleted file mode 100755 index 378fcb85ad..0000000000 --- a/tools/ironic/scripts/configure-vm +++ /dev/null @@ -1,93 +0,0 @@ -#!/usr/bin/env python - -import argparse -import os.path - -import libvirt - -templatedir = os.path.join(os.path.dirname(os.path.dirname(__file__)), - 'templates') - - -CONSOLE_LOG = """ - - - - - - - - - - - - - - - -""" - - -def main(): - parser = argparse.ArgumentParser( - description="Configure a kvm virtual machine for the seed image.") - parser.add_argument('--name', default='seed', - help='the name to give the machine in libvirt.') - parser.add_argument('--image', - help='Use a custom image file (must be qcow2).') - parser.add_argument('--engine', default='qemu', - help='The virtualization engine to use') - parser.add_argument('--arch', default='i686', - help='The architecture to use') - parser.add_argument('--memory', default='2097152', - help="Maximum memory for the VM in KB.") - parser.add_argument('--cpus', default='1', - help="CPU count for the VM.") - parser.add_argument('--bootdev', default='hd', - help="What boot device to use (hd/network).") - parser.add_argument('--network', default="brbm", - help='The libvirt network name to use') - parser.add_argument('--libvirt-nic-driver', default='e1000', - help='The libvirt network driver to use') - parser.add_argument('--console-log', - help='File to log console') - parser.add_argument('--emulator', default=None, - help='Path to emulator bin for vm template') - args = parser.parse_args() - with file(templatedir + '/vm.xml', 'rb') as f: - source_template = f.read() - params = { - 'name': args.name, - 'imagefile': args.image, - 'engine': args.engine, - 'arch': args.arch, - 'memory': args.memory, - 'cpus': args.cpus, - 'bootdev': args.bootdev, - 'network': args.network, - 'nicdriver': args.libvirt_nic_driver, - 'emulator': args.emulator, - } - - if args.emulator: - params['emulator'] = args.emulator - else: - if os.path.exists("/usr/bin/kvm"): # Debian - params['emulator'] = "/usr/bin/kvm" - elif os.path.exists("/usr/bin/qemu-kvm"): # Redhat - params['emulator'] = "/usr/bin/qemu-kvm" - - if args.console_log: - params['bios_serial'] = "" - params['console_log'] = CONSOLE_LOG % {'console_log': args.console_log} - else: - params['bios_serial'] = '' - params['console_log'] = '' - libvirt_template = source_template % params - conn = libvirt.open("qemu:///system") - - a = conn.defineXML(libvirt_template) - print ("Created machine %s with UUID %s" % (args.name, a.UUIDString())) - -if __name__ == '__main__': - main() diff --git a/tools/ironic/scripts/create-node b/tools/ironic/scripts/create-node deleted file mode 100755 index b018acddc9..0000000000 --- a/tools/ironic/scripts/create-node +++ /dev/null @@ -1,79 +0,0 @@ -#!/usr/bin/env bash - -# **create-nodes** - -# Creates baremetal poseur nodes for ironic testing purposes - -set -ex - -# Keep track of the DevStack directory -TOP_DIR=$(cd $(dirname "$0")/.. && pwd) - -NAME=$1 -CPU=$2 -MEM=$(( 1024 * $3 )) -# Extra G to allow fuzz for partition table : flavor size and registered size -# need to be different to actual size. -DISK=$(( $4 + 1)) - -case $5 in - i386) ARCH='i686' ;; - amd64) ARCH='x86_64' ;; - *) echo "Unsupported arch $4!" ; exit 1 ;; -esac - -BRIDGE=$6 -EMULATOR=$7 -LOGDIR=$8 - -LIBVIRT_NIC_DRIVER=${LIBVIRT_NIC_DRIVER:-"e1000"} -LIBVIRT_STORAGE_POOL=${LIBVIRT_STORAGE_POOL:-"default"} -LIBVIRT_CONNECT_URI=${LIBVIRT_CONNECT_URI:-"qemu:///system"} - -export VIRSH_DEFAULT_CONNECT_URI=$LIBVIRT_CONNECT_URI - -if ! virsh pool-list --all | grep -q $LIBVIRT_STORAGE_POOL; then - virsh pool-define-as --name $LIBVIRT_STORAGE_POOL dir --target /var/lib/libvirt/images >&2 - virsh pool-autostart $LIBVIRT_STORAGE_POOL >&2 - virsh pool-start $LIBVIRT_STORAGE_POOL >&2 -fi - -pool_state=$(virsh pool-info $LIBVIRT_STORAGE_POOL | grep State | awk '{ print $2 }') -if [ "$pool_state" != "running" ] ; then - [ ! -d /var/lib/libvirt/images ] && sudo mkdir /var/lib/libvirt/images - virsh pool-start $LIBVIRT_STORAGE_POOL >&2 -fi - -if [ -n "$LOGDIR" ] ; then - mkdir -p "$LOGDIR" -fi - -PREALLOC= -if [ -f /etc/debian_version ]; then - PREALLOC="--prealloc-metadata" -fi - -if [ -n "$LOGDIR" ] ; then - VM_LOGGING="--console-log $LOGDIR/${NAME}_console.log" -else - VM_LOGGING="" -fi -VOL_NAME="${NAME}.qcow2" - -if ! virsh list --all | grep -q $NAME; then - virsh vol-list --pool $LIBVIRT_STORAGE_POOL | grep -q $VOL_NAME && - virsh vol-delete $VOL_NAME --pool $LIBVIRT_STORAGE_POOL >&2 - virsh vol-create-as $LIBVIRT_STORAGE_POOL ${VOL_NAME} ${DISK}G --format qcow2 $PREALLOC >&2 - volume_path=$(virsh vol-path --pool $LIBVIRT_STORAGE_POOL $VOL_NAME) - # Pre-touch the VM to set +C, as it can only be set on empty files. - sudo touch "$volume_path" - sudo chattr +C "$volume_path" || true - $TOP_DIR/scripts/configure-vm \ - --bootdev network --name $NAME --image "$volume_path" \ - --arch $ARCH --cpus $CPU --memory $MEM --libvirt-nic-driver $LIBVIRT_NIC_DRIVER \ - --emulator $EMULATOR --network $BRIDGE $VM_LOGGING >&2 - -fi - -# echo mac -virsh dumpxml $NAME | grep "mac address" | head -1 | cut -d\' -f2 diff --git a/tools/ironic/scripts/setup-network b/tools/ironic/scripts/setup-network deleted file mode 100755 index 83308ed416..0000000000 --- a/tools/ironic/scripts/setup-network +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/env bash - -# **setup-network** - -# Setups openvswitch libvirt network suitable for -# running baremetal poseur nodes for ironic testing purposes - -set -exu - -LIBVIRT_CONNECT_URI=${LIBVIRT_CONNECT_URI:-"qemu:///system"} - -# Keep track of the DevStack directory -TOP_DIR=$(cd $(dirname "$0")/.. && pwd) -BRIDGE_SUFFIX=${1:-''} -BRIDGE_NAME=brbm$BRIDGE_SUFFIX - -export VIRSH_DEFAULT_CONNECT_URI="$LIBVIRT_CONNECT_URI" - -# Only add bridge if missing -(sudo ovs-vsctl list-br | grep ${BRIDGE_NAME}$) || sudo ovs-vsctl add-br ${BRIDGE_NAME} - -# Remove bridge before replacing it. -(virsh net-list | grep "${BRIDGE_NAME} ") && virsh net-destroy ${BRIDGE_NAME} -(virsh net-list --inactive | grep "${BRIDGE_NAME} ") && virsh net-undefine ${BRIDGE_NAME} - -virsh net-define <(sed s/brbm/$BRIDGE_NAME/ $TOP_DIR/templates/brbm.xml) -virsh net-autostart ${BRIDGE_NAME} -virsh net-start ${BRIDGE_NAME} diff --git a/tools/ironic/templates/brbm.xml b/tools/ironic/templates/brbm.xml deleted file mode 100644 index 0769d3f1d0..0000000000 --- a/tools/ironic/templates/brbm.xml +++ /dev/null @@ -1,6 +0,0 @@ - - brbm - - - - diff --git a/tools/ironic/templates/tftpd-xinetd.template b/tools/ironic/templates/tftpd-xinetd.template deleted file mode 100644 index 5f3d03f3bb..0000000000 --- a/tools/ironic/templates/tftpd-xinetd.template +++ /dev/null @@ -1,14 +0,0 @@ -service tftp -{ - protocol = udp - port = 69 - socket_type = dgram - wait = yes - user = root - server = /usr/sbin/in.tftpd - server_args = -v -v -v -v -v --map-file %TFTPBOOT_DIR%/map-file %TFTPBOOT_DIR% - disable = no - # This is a workaround for Fedora, where TFTP will listen only on - # IPv6 endpoint, if IPv4 flag is not used. - flags = IPv4 -} diff --git a/tools/ironic/templates/vm.xml b/tools/ironic/templates/vm.xml deleted file mode 100644 index ae7d685256..0000000000 --- a/tools/ironic/templates/vm.xml +++ /dev/null @@ -1,49 +0,0 @@ - - %(name)s - %(memory)s - %(cpus)s - - hvm - - - %(bios_serial)s - - - - - - - - destroy - restart - restart - - %(emulator)s - - - - -
- - -
- - - - - -
- - - -