├── .gitignore
├── .gitreview
├── .project
├── .pydevproject
├── .stestr.conf
├── .zuul.yaml
├── LICENSE
├── Makefile
├── README.md
├── actions.yaml
├── actions
├── actions.py
├── openstack-upgrade
├── openstack_upgrade.py
├── pause
├── resume
├── security-checklist
└── security_checklist.py
├── bindep.txt
├── charm-helpers-hooks.yaml
├── charmcraft.yaml
├── config.yaml
├── copyright
├── files
├── midokura.key
└── midonet.key
├── hardening.yaml
├── hooks
├── amqp-relation-broken
├── amqp-relation-changed
├── amqp-relation-departed
├── amqp-relation-joined
├── certificates-relation-changed
├── certificates-relation-departed
├── certificates-relation-joined
├── charmhelpers
│ ├── __init__.py
│ ├── cli
│ │ ├── __init__.py
│ │ ├── benchmark.py
│ │ ├── commands.py
│ │ ├── hookenv.py
│ │ ├── host.py
│ │ └── unitdata.py
│ ├── contrib
│ │ ├── __init__.py
│ │ ├── charmsupport
│ │ │ ├── __init__.py
│ │ │ ├── nrpe.py
│ │ │ └── volumes.py
│ │ ├── hahelpers
│ │ │ ├── __init__.py
│ │ │ ├── apache.py
│ │ │ └── cluster.py
│ │ ├── hardening
│ │ │ ├── README.hardening.md
│ │ │ ├── __init__.py
│ │ │ ├── apache
│ │ │ │ ├── __init__.py
│ │ │ │ ├── checks
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── config.py
│ │ │ │ └── templates
│ │ │ │ │ ├── 99-hardening.conf
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── alias.conf
│ │ │ ├── audits
│ │ │ │ ├── __init__.py
│ │ │ │ ├── apache.py
│ │ │ │ ├── apt.py
│ │ │ │ └── file.py
│ │ │ ├── defaults
│ │ │ │ ├── __init__.py
│ │ │ │ ├── apache.yaml
│ │ │ │ ├── apache.yaml.schema
│ │ │ │ ├── mysql.yaml
│ │ │ │ ├── mysql.yaml.schema
│ │ │ │ ├── os.yaml
│ │ │ │ ├── os.yaml.schema
│ │ │ │ ├── ssh.yaml
│ │ │ │ └── ssh.yaml.schema
│ │ │ ├── harden.py
│ │ │ ├── host
│ │ │ │ ├── __init__.py
│ │ │ │ ├── checks
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── apt.py
│ │ │ │ │ ├── limits.py
│ │ │ │ │ ├── login.py
│ │ │ │ │ ├── minimize_access.py
│ │ │ │ │ ├── pam.py
│ │ │ │ │ ├── profile.py
│ │ │ │ │ ├── securetty.py
│ │ │ │ │ ├── suid_sgid.py
│ │ │ │ │ └── sysctl.py
│ │ │ │ └── templates
│ │ │ │ │ ├── 10.hardcore.conf
│ │ │ │ │ ├── 99-hardening.sh
│ │ │ │ │ ├── 99-juju-hardening.conf
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── login.defs
│ │ │ │ │ ├── modules
│ │ │ │ │ ├── passwdqc.conf
│ │ │ │ │ ├── pinerolo_profile.sh
│ │ │ │ │ ├── securetty
│ │ │ │ │ └── tally2
│ │ │ ├── mysql
│ │ │ │ ├── __init__.py
│ │ │ │ ├── checks
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── config.py
│ │ │ │ └── templates
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── hardening.cnf
│ │ │ ├── ssh
│ │ │ │ ├── __init__.py
│ │ │ │ ├── checks
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── config.py
│ │ │ │ └── templates
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── ssh_config
│ │ │ │ │ └── sshd_config
│ │ │ ├── templating.py
│ │ │ └── utils.py
│ │ ├── hardware
│ │ │ ├── __init__.py
│ │ │ └── pci.py
│ │ ├── network
│ │ │ ├── __init__.py
│ │ │ ├── ip.py
│ │ │ └── ovs
│ │ │ │ ├── __init__.py
│ │ │ │ ├── ovn.py
│ │ │ │ ├── ovsdb.py
│ │ │ │ └── utils.py
│ │ ├── openstack
│ │ │ ├── __init__.py
│ │ │ ├── alternatives.py
│ │ │ ├── audits
│ │ │ │ ├── __init__.py
│ │ │ │ └── openstack_security_guide.py
│ │ │ ├── cert_utils.py
│ │ │ ├── context.py
│ │ │ ├── deferred_events.py
│ │ │ ├── exceptions.py
│ │ │ ├── files
│ │ │ │ ├── __init__.py
│ │ │ │ ├── check_deferred_restarts.py
│ │ │ │ ├── check_haproxy.sh
│ │ │ │ ├── check_haproxy_queue_depth.sh
│ │ │ │ └── policy_rc_d_script.py
│ │ │ ├── ha
│ │ │ │ ├── __init__.py
│ │ │ │ └── utils.py
│ │ │ ├── ip.py
│ │ │ ├── keystone.py
│ │ │ ├── neutron.py
│ │ │ ├── policy_rcd.py
│ │ │ ├── policyd.py
│ │ │ ├── ssh_migrations.py
│ │ │ ├── templates
│ │ │ │ ├── __init__.py
│ │ │ │ ├── ceph.conf
│ │ │ │ ├── git.upstart
│ │ │ │ ├── haproxy.cfg
│ │ │ │ ├── logrotate
│ │ │ │ ├── memcached.conf
│ │ │ │ ├── openstack_https_frontend
│ │ │ │ ├── openstack_https_frontend.conf
│ │ │ │ ├── section-audit-middleware-notifications
│ │ │ │ ├── section-ceph-bluestore-compression
│ │ │ │ ├── section-filter-audit
│ │ │ │ ├── section-keystone-authtoken
│ │ │ │ ├── section-keystone-authtoken-legacy
│ │ │ │ ├── section-keystone-authtoken-mitaka
│ │ │ │ ├── section-keystone-authtoken-v3only
│ │ │ │ ├── section-oslo-cache
│ │ │ │ ├── section-oslo-messaging-rabbit
│ │ │ │ ├── section-oslo-messaging-rabbit-ocata
│ │ │ │ ├── section-oslo-middleware
│ │ │ │ ├── section-oslo-notifications
│ │ │ │ ├── section-placement
│ │ │ │ ├── section-rabbitmq-oslo
│ │ │ │ ├── section-service-user
│ │ │ │ ├── section-zeromq
│ │ │ │ ├── vendor_data.json
│ │ │ │ ├── wsgi-openstack-api.conf
│ │ │ │ └── wsgi-openstack-metadata.conf
│ │ │ ├── templating.py
│ │ │ ├── utils.py
│ │ │ └── vaultlocker.py
│ │ ├── python.py
│ │ └── storage
│ │ │ ├── __init__.py
│ │ │ └── linux
│ │ │ ├── __init__.py
│ │ │ ├── bcache.py
│ │ │ ├── ceph.py
│ │ │ ├── loopback.py
│ │ │ ├── lvm.py
│ │ │ └── utils.py
│ ├── core
│ │ ├── __init__.py
│ │ ├── decorators.py
│ │ ├── files.py
│ │ ├── fstab.py
│ │ ├── hookenv.py
│ │ ├── host.py
│ │ ├── host_factory
│ │ │ ├── __init__.py
│ │ │ ├── centos.py
│ │ │ └── ubuntu.py
│ │ ├── hugepage.py
│ │ ├── kernel.py
│ │ ├── kernel_factory
│ │ │ ├── __init__.py
│ │ │ ├── centos.py
│ │ │ └── ubuntu.py
│ │ ├── services
│ │ │ ├── __init__.py
│ │ │ ├── base.py
│ │ │ └── helpers.py
│ │ ├── strutils.py
│ │ ├── sysctl.py
│ │ ├── templating.py
│ │ └── unitdata.py
│ ├── fetch
│ │ ├── __init__.py
│ │ ├── archiveurl.py
│ │ ├── bzrurl.py
│ │ ├── centos.py
│ │ ├── giturl.py
│ │ ├── python
│ │ │ ├── __init__.py
│ │ │ ├── debug.py
│ │ │ ├── packages.py
│ │ │ ├── rpdb.py
│ │ │ └── version.py
│ │ ├── snap.py
│ │ ├── ubuntu.py
│ │ └── ubuntu_apt_pkg.py
│ ├── osplatform.py
│ └── payload
│ │ ├── __init__.py
│ │ ├── archive.py
│ │ └── execd.py
├── cluster-relation-changed
├── cluster-relation-departed
├── cluster-relation-joined
├── config-changed
├── etcd-proxy-relation-broken
├── etcd-proxy-relation-changed
├── etcd-proxy-relation-departed
├── etcd-proxy-relation-joined
├── external-dns-relation-broken
├── external-dns-relation-changed
├── external-dns-relation-departed
├── external-dns-relation-joined
├── ha-relation-changed
├── ha-relation-joined
├── identity-service-relation-broken
├── identity-service-relation-changed
├── identity-service-relation-joined
├── infoblox-neutron-relation-broken
├── infoblox-neutron-relation-changed
├── infoblox-neutron-relation-departed
├── install
├── midonet-relation-broken
├── midonet-relation-changed
├── midonet-relation-joined
├── neutron-api-relation-broken
├── neutron-api-relation-changed
├── neutron-api-relation-joined
├── neutron-load-balancer-relation-changed
├── neutron-load-balancer-relation-joined
├── neutron-plugin-api-relation-joined
├── neutron-plugin-api-subordinate-relation-changed
├── neutron-plugin-api-subordinate-relation-departed
├── neutron-plugin-api-subordinate-relation-joined
├── neutron_api_context.py
├── neutron_api_hooks.py
├── neutron_api_utils.py
├── nrpe-external-master-relation-changed
├── nrpe-external-master-relation-joined
├── post-series-upgrade
├── pre-series-upgrade
├── shared-db-relation-broken
├── shared-db-relation-changed
├── shared-db-relation-joined
├── start
├── stop
├── update-status
├── upgrade-charm
├── vsd-rest-api-relation-changed
└── vsd-rest-api-relation-joined
├── icon.svg
├── lib
└── .keep
├── metadata.yaml
├── osci.yaml
├── rename.sh
├── requirements.txt
├── setup.cfg
├── templates
├── api-paste.ini
├── etcd
├── icehouse
│ ├── etcd.conf
│ ├── ml2_conf.ini
│ ├── neutron-server
│ ├── neutron.conf
│ ├── nsx.ini
│ ├── nuage_plugin.ini
│ └── plumgrid.ini
├── juno
│ ├── midonet.ini
│ └── neutron.conf
├── kilo
│ ├── api-paste.ini
│ ├── ml2_conf.ini
│ ├── ml2_conf_sriov.ini
│ ├── neutron.conf
│ └── nuage_plugin.ini
├── liberty
│ ├── neutron.conf
│ ├── neutron_lbaas.conf
│ └── neutron_vpnaas.conf
├── mitaka
│ ├── api-paste.ini
│ ├── ml2_conf.ini
│ └── neutron.conf
├── newton
│ ├── api-paste.ini
│ └── neutron.conf
├── ocata
│ └── neutron.conf
├── parts
│ ├── database
│ ├── rabbitmq
│ ├── section-database
│ ├── section-designate
│ ├── section-infoblox
│ ├── section-nova
│ └── section-placement
├── pike
│ └── neutron.conf
├── ports.conf
├── queens
│ ├── ml2_conf.ini
│ └── neutron.conf
├── rocky
│ ├── api-paste.ini
│ └── neutron.conf
├── train
│ └── neutron.conf
├── ussuri
│ └── neutron.conf
└── yoga
│ ├── api-paste.ini
│ ├── api_audit_map.conf
│ └── neutron.conf
├── test-requirements.txt
├── tests
├── bundles
│ └── noble-caracal.yaml
└── tests.yaml
├── tox.ini
└── unit_tests
├── __init__.py
├── test_actions.py
├── test_actions_openstack_upgrade.py
├── test_neutron_api_context.py
├── test_neutron_api_hooks.py
├── test_neutron_api_utils.py
└── test_utils.py
/.gitignore:
--------------------------------------------------------------------------------
1 | bin
2 | .coverage
3 | .testrepository
4 | .tox
5 | tags
6 | *.sw[nop]
7 | *.pyc
8 | .unit-state.db
9 | trusty/
10 | xenial/
11 | .stestr
12 | __pycache__
13 | func-results.json
14 | .idea
15 | *.charm
16 |
--------------------------------------------------------------------------------
/.gitreview:
--------------------------------------------------------------------------------
1 | [gerrit]
2 | host=review.opendev.org
3 | port=29418
4 | project=openstack/charm-neutron-api.git
5 |
--------------------------------------------------------------------------------
/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | neutron-api
4 |
5 |
6 |
7 |
8 |
9 | org.python.pydev.PyDevBuilder
10 |
11 |
12 |
13 |
14 |
15 | org.python.pydev.pythonNature
16 |
17 |
18 |
--------------------------------------------------------------------------------
/.pydevproject:
--------------------------------------------------------------------------------
1 |
2 |
3 | python 2.7
4 | Default
5 |
6 | /neutron-api/hooks
7 | /neutron-api/unit_tests
8 |
9 |
10 |
--------------------------------------------------------------------------------
/.stestr.conf:
--------------------------------------------------------------------------------
1 | [DEFAULT]
2 | test_path=./unit_tests
3 | top_dir=./
4 |
--------------------------------------------------------------------------------
/.zuul.yaml:
--------------------------------------------------------------------------------
1 | - project:
2 | templates:
3 | - openstack-python3-charm-jobs
4 | - openstack-cover-jobs
5 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | #!/usr/bin/make
2 | PYTHON := /usr/bin/env python3
3 |
4 | lint:
5 | @tox -e pep8
6 |
7 | test:
8 | @echo Starting unit tests...
9 | @tox -e py27
10 |
11 | functional_test:
12 | @echo Starting Amulet tests...
13 | @tox -e func27
14 |
15 | bin/charm_helpers_sync.py:
16 | @mkdir -p bin
17 | @curl -o bin/charm_helpers_sync.py https://raw.githubusercontent.com/juju/charm-helpers/master/tools/charm_helpers_sync/charm_helpers_sync.py
18 |
19 |
20 | sync: bin/charm_helpers_sync.py
21 | @$(PYTHON) bin/charm_helpers_sync.py -c charm-helpers-hooks.yaml
22 |
23 | publish: lint test
24 | bzr push lp:charms/neutron-api
25 | bzr push lp:charms/trusty/neutron-api
26 |
--------------------------------------------------------------------------------
/actions.yaml:
--------------------------------------------------------------------------------
1 | openstack-upgrade:
2 | description: Perform openstack upgrades. Config option action-managed-upgrade must be set to True.
3 | pause:
4 | description: |
5 | Pause neutron-api services.
6 | If the neutron-api deployment is clustered using the hacluster charm, the
7 | corresponding hacluster unit on the node must first be paused as well.
8 | Not doing so may lead to an interruption of service.
9 | resume:
10 | description: |
11 | Resume neutron-api services.
12 | If the neutron-api deployment is clustered using the hacluster charm, the
13 | corresponding hacluster unit on the node must be resumed as well.
14 | security-checklist:
15 | description: Validate the running configuration against the OpenStack security guides checklist
16 |
--------------------------------------------------------------------------------
/actions/actions.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | #
3 | # Copyright 2016 Canonical Ltd
4 | #
5 | # Licensed under the Apache License, Version 2.0 (the "License");
6 | # you may not use this file except in compliance with the License.
7 | # You may obtain a copy of the License at
8 | #
9 | # http://www.apache.org/licenses/LICENSE-2.0
10 | #
11 | # Unless required by applicable law or agreed to in writing, software
12 | # distributed under the License is distributed on an "AS IS" BASIS,
13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | # See the License for the specific language governing permissions and
15 | # limitations under the License.
16 |
17 | import os
18 | import sys
19 |
20 | sys.path.append('hooks/')
21 |
22 | from charmhelpers.core.hookenv import action_fail
23 | from neutron_api_utils import (
24 | pause_unit_helper,
25 | resume_unit_helper,
26 | register_configs,
27 | )
28 |
29 |
30 | def pause(args):
31 | """Pause the Ceilometer services.
32 | @raises Exception should the service fail to stop.
33 | """
34 | pause_unit_helper(register_configs())
35 |
36 |
37 | def resume(args):
38 | """Resume the Ceilometer services.
39 | @raises Exception should the service fail to start."""
40 | resume_unit_helper(register_configs())
41 |
42 |
43 | # A dictionary of all the defined actions to callables (which take
44 | # parsed arguments).
45 | ACTIONS = {"pause": pause, "resume": resume}
46 |
47 |
48 | def main(args):
49 | action_name = os.path.basename(args[0])
50 | try:
51 | action = ACTIONS[action_name]
52 | except KeyError:
53 | return "Action %s undefined" % action_name
54 | else:
55 | try:
56 | action(args)
57 | except Exception as e:
58 | action_fail(str(e))
59 |
60 |
61 | if __name__ == "__main__":
62 | sys.exit(main(sys.argv))
63 |
--------------------------------------------------------------------------------
/actions/openstack-upgrade:
--------------------------------------------------------------------------------
1 | openstack_upgrade.py
--------------------------------------------------------------------------------
/actions/openstack_upgrade.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | #
3 | # Copyright 2016 Canonical Ltd
4 | #
5 | # Licensed under the Apache License, Version 2.0 (the "License");
6 | # you may not use this file except in compliance with the License.
7 | # You may obtain a copy of the License at
8 | #
9 | # http://www.apache.org/licenses/LICENSE-2.0
10 | #
11 | # Unless required by applicable law or agreed to in writing, software
12 | # distributed under the License is distributed on an "AS IS" BASIS,
13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | # See the License for the specific language governing permissions and
15 | # limitations under the License.
16 |
17 | import sys
18 |
19 | sys.path.append('hooks/')
20 |
21 | from charmhelpers.contrib.openstack.utils import (
22 | do_action_openstack_upgrade,
23 | )
24 |
25 | from neutron_api_hooks import (
26 | config_changed,
27 | CONFIGS,
28 | )
29 |
30 | from neutron_api_utils import (
31 | do_openstack_upgrade,
32 | )
33 |
34 |
35 | def openstack_upgrade():
36 | """Upgrade packages to config-set Openstack version.
37 |
38 | If the charm was installed from source we cannot upgrade it.
39 | For backwards compatibility a config flag must be set for this
40 | code to run, otherwise a full service level upgrade will fire
41 | on config-changed."""
42 |
43 | if (do_action_openstack_upgrade('neutron-common',
44 | do_openstack_upgrade,
45 | CONFIGS)):
46 | config_changed()
47 |
48 |
49 | if __name__ == '__main__':
50 | openstack_upgrade()
51 |
--------------------------------------------------------------------------------
/actions/pause:
--------------------------------------------------------------------------------
1 | actions.py
--------------------------------------------------------------------------------
/actions/resume:
--------------------------------------------------------------------------------
1 | actions.py
--------------------------------------------------------------------------------
/actions/security-checklist:
--------------------------------------------------------------------------------
1 | security_checklist.py
--------------------------------------------------------------------------------
/actions/security_checklist.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | #
3 | # Copyright 2019 Canonical Ltd
4 | #
5 | # Licensed under the Apache License, Version 2.0 (the "License");
6 | # you may not use this file except in compliance with the License.
7 | # You may obtain a copy of the License at
8 | #
9 | # http://www.apache.org/licenses/LICENSE-2.0
10 | #
11 | # Unless required by applicable law or agreed to in writing, software
12 | # distributed under the License is distributed on an "AS IS" BASIS,
13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | # See the License for the specific language governing permissions and
15 | # limitations under the License.
16 |
17 | import configparser
18 | import sys
19 |
20 | sys.path.append('hooks')
21 |
22 | import charmhelpers.contrib.openstack.audits as audits
23 | from charmhelpers.contrib.openstack.audits import (
24 | openstack_security_guide,
25 | )
26 |
27 |
28 | # Via the openstack_security_guide above, we are running the following
29 | # security assertions automatically:
30 | #
31 | # - Check-Neutron-01 - validate-file-ownership
32 | # - Check-Neutron-02 - validate-file-permissions
33 | # - Check-Neutron-03 - validate-uses-keystone
34 | # - Check-Neutron-04 - validate-uses-tls-for-keystone
35 |
36 | @audits.audit(audits.is_audit_type(audits.AuditType.OpenStackSecurityGuide))
37 | def validate_enables_tls(audit_options):
38 | """Verify that TLS is enabled on Neutron.
39 |
40 | Security Guide Check Name: Check-Neutron-05
41 |
42 | :param audit_options: Dictionary of options for audit configuration
43 | :type audit_options: Dict
44 | :raises: AssertionError if the assertion fails.
45 | """
46 | section = audit_options['neutron_config']['DEFAULT']
47 | assert section.get('use_ssl') == "True", \
48 | "SSL should be enabled on neutron-api"
49 |
50 |
51 | def main():
52 | config = {
53 | 'config_path': '/etc/neutron',
54 | 'config_file': 'neutron.conf',
55 | 'audit_type': audits.AuditType.OpenStackSecurityGuide,
56 | 'files': openstack_security_guide.FILE_ASSERTIONS['neutron-api'],
57 | 'excludes': [
58 | 'validate-uses-tls-for-glance',
59 | ],
60 | }
61 | conf = configparser.ConfigParser(strict=False)
62 | conf.read("/etc/neutron/neutron.conf")
63 | config['neutron_config'] = dict(conf)
64 | return audits.action_parse_results(audits.run(config))
65 |
66 |
67 | if __name__ == "__main__":
68 | sys.exit(main())
69 |
--------------------------------------------------------------------------------
/bindep.txt:
--------------------------------------------------------------------------------
1 | libffi-dev [platform:dpkg]
2 | libxml2-dev [platform:dpkg]
3 | libxslt1-dev [platform:dpkg]
4 |
--------------------------------------------------------------------------------
/charm-helpers-hooks.yaml:
--------------------------------------------------------------------------------
1 | repo: https://github.com/juju/charm-helpers
2 | destination: hooks/charmhelpers
3 | include:
4 | - core
5 | - osplatform
6 | - cli
7 | - fetch
8 | - contrib.openstack|inc=*
9 | - contrib.hardware.pci
10 | - contrib.hahelpers
11 | - contrib.network.ovs
12 | - contrib.storage.linux
13 | - payload.execd
14 | - payload.archive
15 | - contrib.network.ip
16 | - contrib.python
17 | - contrib.charmsupport
18 | - contrib.hardening|inc=*
19 | - contrib.openstack.policyd
20 |
--------------------------------------------------------------------------------
/charmcraft.yaml:
--------------------------------------------------------------------------------
1 | type: charm
2 |
3 | parts:
4 | charm:
5 | plugin: dump
6 | source: .
7 |
8 | base: ubuntu@24.04
9 | platforms:
10 | amd64:
11 | build-on: amd64
12 | build-for: amd64
13 | arm64:
14 | build-on: arm64
15 | build-for: arm64
16 | ppc64el:
17 | build-on: ppc64el
18 | build-for: ppc64el
19 | s390x:
20 | build-on: s390x
21 | build-for: s390x
22 |
--------------------------------------------------------------------------------
/copyright:
--------------------------------------------------------------------------------
1 | Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0
2 |
3 | Files: *
4 | Copyright: 2012, Canonical Ltd.
5 | License: Apache-2.0
6 | Licensed under the Apache License, Version 2.0 (the "License"); you may
7 | not use this file except in compliance with the License. You may obtain
8 | a copy of the License at
9 |
10 | http://www.apache.org/licenses/LICENSE-2.0
11 |
12 | Unless required by applicable law or agreed to in writing, software
13 | distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
14 | WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
15 | License for the specific language governing permissions and limitations
16 | under the License.
17 |
--------------------------------------------------------------------------------
/files/midokura.key:
--------------------------------------------------------------------------------
1 | -----BEGIN PGP PUBLIC KEY BLOCK-----
2 | Version: SKS 1.1.5
3 | Comment: Hostname: keyserver.ubuntu.com
4 |
5 | mI0ETb6aOgEEAMVw8Vnwk+zpDtsc0gSW10JEe48zKr2vpl9tQgWAFOPgOA1NglYMw/xT6Rns
6 | 7CrYxPR0cb3DeMFtFdMkfWXO0R6x4yHrozMDY/DpvwgYQclIIbcYYe0p83nlBp793D2dSq60
7 | HWuXJu3oi0wQQuR0/jTmOnjxzCzu5jKdJeXihl95ABEBAAG0Jk1pZG9rdXJhIChNaWRva3Vy
8 | YSkgPGluZm9AbWlkb2t1cmEuanA+iLgEEwECACIFAk2+mjoCGwMGCwkIBwMCBhUIAgkKCwQW
9 | AgMBAh4BAheAAAoJEGezjToFQxTNAp0D/2c+PLnRFzEXCztXT+05xoO1mPzpm3x2p5ecVPGH
10 | R8IxhozlN9DDGDdnvNfMOhi6nv/G2l86+9Fj8Dz01ne0RZzZHSS1DF/zb6dMYrPJqiT1DXKH
11 | 0Y73OL/+M7rsutEq0B/DKhjdBfFPutk3gerEUZPNfIhScE3tnwCnVGJKPQbFuI0ETb6aOgEE
12 | ANLJK3gmXrsp1VKnt663RoxZgoFQgQ6wHaZZWhULTteafjoThX9tj7FidR2+7qJLwpa57M9d
13 | rib4OlbW+rE4PW199/Uqfy86gLv76Q2GZMpzaYB1ZZow0Ny1RTCwh7apkhR/8fCUpq37aODQ
14 | 4YwBpZC54iXVKfcntpdJFoObIqXtABEBAAGInwQYAQIACQUCTb6aOgIbDAAKCRBns406BUMU
15 | zfzOBACKx4jChKTAl6HfldOxVN7o8DQpd5rgkHIEj062ym4Zq5t2v3oaz0H0P2WV66MAhOuj
16 | gX0V1duZi8fKHdIsdk0nvEa/mV0QS6pEAeZh+dbLkKyu1J4MSi5l+L+te5XjYBGpoRa3ZGrI
17 | R3CkA0oQDCOh312SrcH6Tn9RBPChVSigzg==
18 | =zF5K
19 | -----END PGP PUBLIC KEY BLOCK-----
20 |
--------------------------------------------------------------------------------
/files/midonet.key:
--------------------------------------------------------------------------------
1 | -----BEGIN PGP PUBLIC KEY BLOCK-----
2 | Version: SKS 1.1.5
3 | Comment: Hostname: keyserver.ubuntu.com
4 |
5 | mQGiBFRF760RBADwIz8rK0K1qiXbq0/cda42oKZW+jvcqUIDsNeKYSWI5YRfS4NX+jRJM/rL
6 | PzQD+JZtLeFHeLK0qxpr5b2acxleOgNfw3hzxz4DNQsVbkts3n1s7YT80DwNdYPBbFCAOOkJ
7 | jH7CL2PN4fTs5eP/0QpMOZT+s5DTqozPDgTYWhhVrwCgoc5H2zYVW86Ok3c0fOru9VZPJxsE
8 | AIexw3sBv9FZyvVr6rehiVlzOtwfHwSEQZQ511so46H5GdLqQFwThKmWVvxyDAGshtpjLJbs
9 | KHilEJVkfzhs/xyCjwAPl8VbIYgUy/FlhKtFWWxkQLlUwuC5iOPLdzhoL1PEzZuCYmMkSr0E
10 | XASN83nbzIIqdQgvEZrAUGUzTf68A/9eSiry88vEIIGL7hT2rw/NockwCGsc2xrjqrfs9PpU
11 | rg7ksTPua1UQUkMeWoKEoYpGppGd5XXEvo6287i8eAB4B9qr4AGbz8NKmVI2lC9V641Ecu3/
12 | kmhaGQRBmCZgcW3B987rTyY5lsLc66+tNai6L72y1fj5nBtY2MVYg6ixZrRNTWlkb2t1cmEg
13 | UlBNICYgREVCIFJlcG9zaXRvcnkgQXV0b21hdGljIFNpZ25pbmcgS2V5ICgyMDE0KSA8b3Bz
14 | QG1pZG9rdXJhLmNvbT6IYgQTEQIAIgUCVEXvrQIbAwYLCQgHAwIGFQgCCQoLBBYCAwECHgEC
15 | F4AACgkQ/ONA0lDxj8+EZgCdEqXQrZ8PiemTgQK7044Deed5OpsAnjL8Cw4GnGJZHmW24pKQ
16 | IkzTvb1SuQENBFRF760QBADJD9aLzLYAehNITLlrNao+bZsSAAeKRYWjtyf6Z620/WiQw6a+
17 | 01/ZwrthvXNUcnIVIKKokPVpXR29AUV0T7npDMTkQCXfw24X+9NedBCquJpHnBS/YySHP+EJ
18 | vNeLc0xdwnOcGehe7IeaDN0eEWx+HVhEfC/lXa/Pebs4OpIo/wADBwQAwyCTQ7Vod3jO7JFP
19 | 6R6mS5gX3Sx6s3ocE4laDFBmh9d8GPWpdzHwzPzrVaIw/xSaxP2zXeWFcDoY3zT7PH3dm+xj
20 | cEG23iTqvmMAr7EXirKu9pL/DKuBPncNMTS6JoltGGVzZLoJF2OJZX81c+U1mGyLpWg/hK3K
21 | t9VpzNjFGc2ISQQYEQIACQUCVEXvrQIbDAAKCRD840DSUPGPz0PiAJ9QXGyMCTymuuCdYyEX
22 | 3D94y0Z8FgCaAwYNRahgGw/HN04xkqfrN7bXajE=
23 | =hLRg
24 | -----END PGP PUBLIC KEY BLOCK-----
25 |
--------------------------------------------------------------------------------
/hardening.yaml:
--------------------------------------------------------------------------------
1 | # Overrides file for contrib.hardening. See README.hardening in
2 | # contrib.hardening for info on how to use this file.
3 | ssh:
4 | server:
5 | use_pam: 'yes' # juju requires this
6 |
--------------------------------------------------------------------------------
/hooks/amqp-relation-broken:
--------------------------------------------------------------------------------
1 | neutron_api_hooks.py
--------------------------------------------------------------------------------
/hooks/amqp-relation-changed:
--------------------------------------------------------------------------------
1 | neutron_api_hooks.py
--------------------------------------------------------------------------------
/hooks/amqp-relation-departed:
--------------------------------------------------------------------------------
1 | neutron_api_hooks.py
--------------------------------------------------------------------------------
/hooks/amqp-relation-joined:
--------------------------------------------------------------------------------
1 | neutron_api_hooks.py
--------------------------------------------------------------------------------
/hooks/certificates-relation-changed:
--------------------------------------------------------------------------------
1 | neutron_api_hooks.py
--------------------------------------------------------------------------------
/hooks/certificates-relation-departed:
--------------------------------------------------------------------------------
1 | neutron_api_hooks.py
--------------------------------------------------------------------------------
/hooks/certificates-relation-joined:
--------------------------------------------------------------------------------
1 | neutron_api_hooks.py
--------------------------------------------------------------------------------
/hooks/charmhelpers/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2014-2015 Canonical Limited.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | # Bootstrap charm-helpers, installing its dependencies if necessary using
16 | # only standard libraries.
17 | import functools
18 | import inspect
19 | import subprocess
20 |
21 |
22 | try:
23 | import yaml # NOQA:F401
24 | except ImportError:
25 | subprocess.check_call(['apt-get', 'install', '-y', 'python3-yaml'])
26 | import yaml # NOQA:F401
27 |
28 |
29 | # Holds a list of mapping of mangled function names that have been deprecated
30 | # using the @deprecate decorator below. This is so that the warning is only
31 | # printed once for each usage of the function.
32 | __deprecated_functions = {}
33 |
34 |
35 | def deprecate(warning, date=None, log=None):
36 | """Add a deprecation warning the first time the function is used.
37 |
38 | The date which is a string in semi-ISO8660 format indicates the year-month
39 | that the function is officially going to be removed.
40 |
41 | usage:
42 |
43 | @deprecate('use core/fetch/add_source() instead', '2017-04')
44 | def contributed_add_source_thing(...):
45 | ...
46 |
47 | And it then prints to the log ONCE that the function is deprecated.
48 | The reason for passing the logging function (log) is so that hookenv.log
49 | can be used for a charm if needed.
50 |
51 | :param warning: String to indicate what is to be used instead.
52 | :param date: Optional string in YYYY-MM format to indicate when the
53 | function will definitely (probably) be removed.
54 | :param log: The log function to call in order to log. If None, logs to
55 | stdout
56 | """
57 | def wrap(f):
58 |
59 | @functools.wraps(f)
60 | def wrapped_f(*args, **kwargs):
61 | try:
62 | module = inspect.getmodule(f)
63 | file = inspect.getsourcefile(f)
64 | lines = inspect.getsourcelines(f)
65 | f_name = "{}-{}-{}..{}-{}".format(
66 | module.__name__, file, lines[0], lines[-1], f.__name__)
67 | except (IOError, TypeError):
68 | # assume it was local, so just use the name of the function
69 | f_name = f.__name__
70 | if f_name not in __deprecated_functions:
71 | __deprecated_functions[f_name] = True
72 | s = "DEPRECATION WARNING: Function {} is being removed".format(
73 | f.__name__)
74 | if date:
75 | s = "{} on/around {}".format(s, date)
76 | if warning:
77 | s = "{} : {}".format(s, warning)
78 | if log:
79 | log(s)
80 | else:
81 | print(s)
82 | return f(*args, **kwargs)
83 | return wrapped_f
84 | return wrap
85 |
--------------------------------------------------------------------------------
/hooks/charmhelpers/cli/benchmark.py:
--------------------------------------------------------------------------------
1 | # Copyright 2014-2015 Canonical Limited.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | from . import cmdline
16 | from charmhelpers.contrib.benchmark import Benchmark
17 |
18 |
19 | @cmdline.subcommand(command_name='benchmark-start')
20 | def start():
21 | Benchmark.start()
22 |
23 |
24 | @cmdline.subcommand(command_name='benchmark-finish')
25 | def finish():
26 | Benchmark.finish()
27 |
28 |
29 | @cmdline.subcommand_builder('benchmark-composite', description="Set the benchmark composite score")
30 | def service(subparser):
31 | subparser.add_argument("value", help="The composite score.")
32 | subparser.add_argument("units", help="The units the composite score represents, i.e., 'reads/sec'.")
33 | subparser.add_argument("direction", help="'asc' if a lower score is better, 'desc' if a higher score is better.")
34 | return Benchmark.set_composite_score
35 |
--------------------------------------------------------------------------------
/hooks/charmhelpers/cli/commands.py:
--------------------------------------------------------------------------------
1 | # Copyright 2014-2015 Canonical Limited.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | """
16 | This module loads sub-modules into the python runtime so they can be
17 | discovered via the inspect module. In order to prevent flake8 from (rightfully)
18 | telling us these are unused modules, throw a ' # noqa' at the end of each import
19 | so that the warning is suppressed.
20 | """
21 |
22 | from . import CommandLine # noqa
23 |
24 | """
25 | Import the sub-modules which have decorated subcommands to register with chlp.
26 | """
27 | from . import host # noqa
28 | from . import benchmark # noqa
29 | from . import unitdata # noqa
30 | from . import hookenv # noqa
31 |
--------------------------------------------------------------------------------
/hooks/charmhelpers/cli/hookenv.py:
--------------------------------------------------------------------------------
1 | # Copyright 2014-2015 Canonical Limited.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | from . import cmdline
16 | from charmhelpers.core import hookenv
17 |
18 |
19 | cmdline.subcommand('relation-id')(hookenv.relation_id._wrapped)
20 | cmdline.subcommand('service-name')(hookenv.service_name)
21 | cmdline.subcommand('remote-service-name')(hookenv.remote_service_name._wrapped)
22 |
--------------------------------------------------------------------------------
/hooks/charmhelpers/cli/host.py:
--------------------------------------------------------------------------------
1 | # Copyright 2014-2015 Canonical Limited.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | from . import cmdline
16 | from charmhelpers.core import host
17 |
18 |
19 | @cmdline.subcommand()
20 | def mounts():
21 | "List mounts"
22 | return host.mounts()
23 |
24 |
25 | @cmdline.subcommand_builder('service', description="Control system services")
26 | def service(subparser):
27 | subparser.add_argument("action", help="The action to perform (start, stop, etc...)")
28 | subparser.add_argument("service_name", help="Name of the service to control")
29 | return host.service
30 |
--------------------------------------------------------------------------------
/hooks/charmhelpers/cli/unitdata.py:
--------------------------------------------------------------------------------
1 | # Copyright 2014-2015 Canonical Limited.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | from . import cmdline
16 | from charmhelpers.core import unitdata
17 |
18 |
19 | @cmdline.subcommand_builder('unitdata', description="Store and retrieve data")
20 | def unitdata_cmd(subparser):
21 | nested = subparser.add_subparsers()
22 |
23 | get_cmd = nested.add_parser('get', help='Retrieve data')
24 | get_cmd.add_argument('key', help='Key to retrieve the value of')
25 | get_cmd.set_defaults(action='get', value=None)
26 |
27 | getrange_cmd = nested.add_parser('getrange', help='Retrieve multiple data')
28 | getrange_cmd.add_argument('key', metavar='prefix',
29 | help='Prefix of the keys to retrieve')
30 | getrange_cmd.set_defaults(action='getrange', value=None)
31 |
32 | set_cmd = nested.add_parser('set', help='Store data')
33 | set_cmd.add_argument('key', help='Key to set')
34 | set_cmd.add_argument('value', help='Value to store')
35 | set_cmd.set_defaults(action='set')
36 |
37 | def _unitdata_cmd(action, key, value):
38 | if action == 'get':
39 | return unitdata.kv().get(key)
40 | elif action == 'getrange':
41 | return unitdata.kv().getrange(key)
42 | elif action == 'set':
43 | unitdata.kv().set(key, value)
44 | unitdata.kv().flush()
45 | return ''
46 | return _unitdata_cmd
47 |
--------------------------------------------------------------------------------
/hooks/charmhelpers/contrib/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2014-2015 Canonical Limited.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
--------------------------------------------------------------------------------
/hooks/charmhelpers/contrib/charmsupport/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2014-2015 Canonical Limited.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
--------------------------------------------------------------------------------
/hooks/charmhelpers/contrib/hahelpers/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2014-2015 Canonical Limited.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
--------------------------------------------------------------------------------
/hooks/charmhelpers/contrib/hahelpers/apache.py:
--------------------------------------------------------------------------------
1 | # Copyright 2014-2015 Canonical Limited.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | #
16 | # Copyright 2012 Canonical Ltd.
17 | #
18 | # This file is sourced from lp:openstack-charm-helpers
19 | #
20 | # Authors:
21 | # James Page
22 | # Adam Gandelman
23 | #
24 |
25 | import os
26 |
27 | from charmhelpers.core import host
28 | from charmhelpers.core.hookenv import (
29 | config as config_get,
30 | relation_get,
31 | relation_ids,
32 | related_units as relation_list,
33 | log,
34 | INFO,
35 | )
36 |
37 | # This file contains the CA cert from the charms ssl_ca configuration
38 | # option, in future the file name should be updated reflect that.
39 | CONFIG_CA_CERT_FILE = 'keystone_juju_ca_cert'
40 |
41 |
42 | def get_cert(cn=None):
43 | # TODO: deal with multiple https endpoints via charm config
44 | cert = config_get('ssl_cert')
45 | key = config_get('ssl_key')
46 | if not (cert and key):
47 | log("Inspecting identity-service relations for SSL certificate.",
48 | level=INFO)
49 | cert = key = None
50 | if cn:
51 | ssl_cert_attr = 'ssl_cert_{}'.format(cn)
52 | ssl_key_attr = 'ssl_key_{}'.format(cn)
53 | else:
54 | ssl_cert_attr = 'ssl_cert'
55 | ssl_key_attr = 'ssl_key'
56 | for r_id in relation_ids('identity-service'):
57 | for unit in relation_list(r_id):
58 | if not cert:
59 | cert = relation_get(ssl_cert_attr,
60 | rid=r_id, unit=unit)
61 | if not key:
62 | key = relation_get(ssl_key_attr,
63 | rid=r_id, unit=unit)
64 | return (cert, key)
65 |
66 |
67 | def get_ca_cert():
68 | ca_cert = config_get('ssl_ca')
69 | if ca_cert is None:
70 | log("Inspecting identity-service relations for CA SSL certificate.",
71 | level=INFO)
72 | for r_id in (relation_ids('identity-service') +
73 | relation_ids('identity-credentials')):
74 | for unit in relation_list(r_id):
75 | if ca_cert is None:
76 | ca_cert = relation_get('ca_cert',
77 | rid=r_id, unit=unit)
78 | return ca_cert
79 |
80 |
81 | def retrieve_ca_cert(cert_file):
82 | cert = None
83 | if os.path.isfile(cert_file):
84 | with open(cert_file, 'rb') as crt:
85 | cert = crt.read()
86 | return cert
87 |
88 |
89 | def install_ca_cert(ca_cert):
90 | host.install_ca_cert(ca_cert, CONFIG_CA_CERT_FILE)
91 |
--------------------------------------------------------------------------------
/hooks/charmhelpers/contrib/hardening/README.hardening.md:
--------------------------------------------------------------------------------
1 | # Juju charm-helpers hardening library
2 |
3 | ## Description
4 |
5 | This library provides multiple implementations of system and application
6 | hardening that conform to the standards of http://hardening.io/.
7 |
8 | Current implementations include:
9 |
10 | * OS
11 | * SSH
12 | * MySQL
13 | * Apache
14 |
15 | ## Requirements
16 |
17 | * Juju Charms
18 |
19 | ## Usage
20 |
21 | 1. Synchronise this library into your charm and add the harden() decorator
22 | (from contrib.hardening.harden) to any functions or methods you want to use
23 | to trigger hardening of your application/system.
24 |
25 | 2. Add a config option called 'harden' to your charm config.yaml and set it to
26 | a space-delimited list of hardening modules you want to run e.g. "os ssh"
27 |
28 | 3. Override any config defaults (contrib.hardening.defaults) by adding a file
29 | called hardening.yaml to your charm root containing the name(s) of the
30 | modules whose settings you want override at root level and then any settings
31 | with overrides e.g.
32 |
33 | os:
34 | general:
35 | desktop_enable: True
36 |
37 | 4. Now just run your charm as usual and hardening will be applied each time the
38 | hook runs.
39 |
--------------------------------------------------------------------------------
/hooks/charmhelpers/contrib/hardening/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2016 Canonical Limited.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
--------------------------------------------------------------------------------
/hooks/charmhelpers/contrib/hardening/apache/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2016 Canonical Limited.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | from os import path
16 |
17 | TEMPLATES_DIR = path.join(path.dirname(__file__), 'templates')
18 |
--------------------------------------------------------------------------------
/hooks/charmhelpers/contrib/hardening/apache/checks/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2016 Canonical Limited.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | from charmhelpers.core.hookenv import (
16 | log,
17 | DEBUG,
18 | )
19 | from charmhelpers.contrib.hardening.apache.checks import config
20 |
21 |
22 | def run_apache_checks():
23 | log("Starting Apache hardening checks.", level=DEBUG)
24 | checks = config.get_audits()
25 | for check in checks:
26 | log("Running '%s' check" % (check.__class__.__name__), level=DEBUG)
27 | check.ensure_compliance()
28 |
29 | log("Apache hardening checks complete.", level=DEBUG)
30 |
--------------------------------------------------------------------------------
/hooks/charmhelpers/contrib/hardening/apache/templates/99-hardening.conf:
--------------------------------------------------------------------------------
1 | ###############################################################################
2 | # WARNING: This configuration file is maintained by Juju. Local changes may
3 | # be overwritten.
4 | ###############################################################################
5 |
6 |
7 |
8 | # http://httpd.apache.org/docs/2.4/upgrading.html
9 | {% if apache_version > '2.2' -%}
10 | Require all granted
11 | {% else -%}
12 | Order Allow,Deny
13 | Deny from all
14 | {% endif %}
15 |
16 |
17 |
18 |
19 | Options -Indexes -FollowSymLinks
20 | AllowOverride None
21 |
22 |
23 |
24 | Options -Indexes -FollowSymLinks
25 | AllowOverride None
26 |
27 |
28 | TraceEnable {{ traceenable }}
29 | ServerTokens {{ servertokens }}
30 |
31 | SSLHonorCipherOrder {{ honor_cipher_order }}
32 | SSLCipherSuite {{ cipher_suite }}
33 |
--------------------------------------------------------------------------------
/hooks/charmhelpers/contrib/hardening/apache/templates/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstack/charm-neutron-api/6d5021e58d06e8fc112000b9e9867b4a898222fb/hooks/charmhelpers/contrib/hardening/apache/templates/__init__.py
--------------------------------------------------------------------------------
/hooks/charmhelpers/contrib/hardening/apache/templates/alias.conf:
--------------------------------------------------------------------------------
1 | ###############################################################################
2 | # WARNING: This configuration file is maintained by Juju. Local changes may
3 | # be overwritten.
4 | ###############################################################################
5 |
6 | #
7 | # Aliases: Add here as many aliases as you need (with no limit). The format is
8 | # Alias fakename realname
9 | #
10 | # Note that if you include a trailing / on fakename then the server will
11 | # require it to be present in the URL. So "/icons" isn't aliased in this
12 | # example, only "/icons/". If the fakename is slash-terminated, then the
13 | # realname must also be slash terminated, and if the fakename omits the
14 | # trailing slash, the realname must also omit it.
15 | #
16 | # We include the /icons/ alias for FancyIndexed directory listings. If
17 | # you do not use FancyIndexing, you may comment this out.
18 | #
19 | Alias /icons/ "{{ apache_icondir }}/"
20 |
21 |
22 | Options -Indexes -MultiViews -FollowSymLinks
23 | AllowOverride None
24 | {% if apache_version == '2.4' -%}
25 | Require all granted
26 | {% else -%}
27 | Order allow,deny
28 | Allow from all
29 | {% endif %}
30 |
31 |
32 |
--------------------------------------------------------------------------------
/hooks/charmhelpers/contrib/hardening/audits/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2016 Canonical Limited.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 |
16 | class BaseAudit(object): # NO-QA
17 | """Base class for hardening checks.
18 |
19 | The lifecycle of a hardening check is to first check to see if the system
20 | is in compliance for the specified check. If it is not in compliance, the
21 | check method will return a value which will be supplied to the.
22 | """
23 | def __init__(self, *args, **kwargs):
24 | self.unless = kwargs.get('unless', None)
25 | super(BaseAudit, self).__init__()
26 |
27 | def ensure_compliance(self):
28 | """Checks to see if the current hardening check is in compliance or
29 | not.
30 |
31 | If the check that is performed is not in compliance, then an exception
32 | should be raised.
33 | """
34 | pass
35 |
36 | def _take_action(self):
37 | """Determines whether to perform the action or not.
38 |
39 | Checks whether or not an action should be taken. This is determined by
40 | the truthy value for the unless parameter. If unless is a callback
41 | method, it will be invoked with no parameters in order to determine
42 | whether or not the action should be taken. Otherwise, the truthy value
43 | of the unless attribute will determine if the action should be
44 | performed.
45 | """
46 | # Do the action if there isn't an unless override.
47 | if self.unless is None:
48 | return True
49 |
50 | # Invoke the callback if there is one.
51 | if hasattr(self.unless, '__call__'):
52 | return not self.unless()
53 |
54 | return not self.unless
55 |
--------------------------------------------------------------------------------
/hooks/charmhelpers/contrib/hardening/defaults/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstack/charm-neutron-api/6d5021e58d06e8fc112000b9e9867b4a898222fb/hooks/charmhelpers/contrib/hardening/defaults/__init__.py
--------------------------------------------------------------------------------
/hooks/charmhelpers/contrib/hardening/defaults/apache.yaml:
--------------------------------------------------------------------------------
1 | # NOTE: this file contains the default configuration for the 'apache' hardening
2 | # code. If you want to override any settings you must add them to a file
3 | # called hardening.yaml in the root directory of your charm using the
4 | # name 'apache' as the root key followed by any of the following with new
5 | # values.
6 |
7 | common:
8 | apache_dir: '/etc/apache2'
9 |
10 | hardening:
11 | traceenable: 'off'
12 | allowed_http_methods: "GET POST"
13 | modules_to_disable: [ cgi, cgid ]
14 | servertokens: 'Prod'
15 | honor_cipher_order: 'on'
16 | cipher_suite: 'ALL:+MEDIUM:+HIGH:!LOW:!MD5:!RC4:!eNULL:!aNULL:!3DES'
17 |
--------------------------------------------------------------------------------
/hooks/charmhelpers/contrib/hardening/defaults/apache.yaml.schema:
--------------------------------------------------------------------------------
1 | # NOTE: this schema must contain all valid keys from it's associated defaults
2 | # file. It is used to validate user-provided overrides.
3 | common:
4 | apache_dir:
5 | traceenable:
6 |
7 | hardening:
8 | allowed_http_methods:
9 | modules_to_disable:
10 | servertokens:
11 | honor_cipher_order:
12 | cipher_suite:
13 |
--------------------------------------------------------------------------------
/hooks/charmhelpers/contrib/hardening/defaults/mysql.yaml:
--------------------------------------------------------------------------------
1 | # NOTE: this file contains the default configuration for the 'mysql' hardening
2 | # code. If you want to override any settings you must add them to a file
3 | # called hardening.yaml in the root directory of your charm using the
4 | # name 'mysql' as the root key followed by any of the following with new
5 | # values.
6 |
7 | hardening:
8 | mysql-conf: /etc/mysql/my.cnf
9 | hardening-conf: /etc/mysql/conf.d/hardening.cnf
10 |
11 | security:
12 | # @see http://www.symantec.com/connect/articles/securing-mysql-step-step
13 | # @see http://dev.mysql.com/doc/refman/5.7/en/server-options.html#option_mysqld_chroot
14 | chroot: None
15 |
16 | # @see http://dev.mysql.com/doc/refman/5.7/en/server-options.html#option_mysqld_safe-user-create
17 | safe-user-create: 1
18 |
19 | # @see http://dev.mysql.com/doc/refman/5.7/en/server-options.html#option_mysqld_secure-auth
20 | secure-auth: 1
21 |
22 | # @see http://dev.mysql.com/doc/refman/5.7/en/server-options.html#option_mysqld_symbolic-links
23 | skip-symbolic-links: 1
24 |
25 | # @see http://dev.mysql.com/doc/refman/5.7/en/server-options.html#option_mysqld_skip-show-database
26 | skip-show-database: True
27 |
28 | # @see http://dev.mysql.com/doc/refman/5.7/en/server-system-variables.html#sysvar_local_infile
29 | local-infile: 0
30 |
31 | # @see https://dev.mysql.com/doc/refman/5.7/en/server-options.html#option_mysqld_allow-suspicious-udfs
32 | allow-suspicious-udfs: 0
33 |
34 | # @see https://dev.mysql.com/doc/refman/5.7/en/server-system-variables.html#sysvar_automatic_sp_privileges
35 | automatic-sp-privileges: 0
36 |
37 | # @see https://dev.mysql.com/doc/refman/5.7/en/server-options.html#option_mysqld_secure-file-priv
38 | secure-file-priv: /tmp
39 |
--------------------------------------------------------------------------------
/hooks/charmhelpers/contrib/hardening/defaults/mysql.yaml.schema:
--------------------------------------------------------------------------------
1 | # NOTE: this schema must contain all valid keys from it's associated defaults
2 | # file. It is used to validate user-provided overrides.
3 | hardening:
4 | mysql-conf:
5 | hardening-conf:
6 | security:
7 | chroot:
8 | safe-user-create:
9 | secure-auth:
10 | skip-symbolic-links:
11 | skip-show-database:
12 | local-infile:
13 | allow-suspicious-udfs:
14 | automatic-sp-privileges:
15 | secure-file-priv:
16 |
--------------------------------------------------------------------------------
/hooks/charmhelpers/contrib/hardening/defaults/os.yaml:
--------------------------------------------------------------------------------
1 | # NOTE: this file contains the default configuration for the 'os' hardening
2 | # code. If you want to override any settings you must add them to a file
3 | # called hardening.yaml in the root directory of your charm using the
4 | # name 'os' as the root key followed by any of the following with new
5 | # values.
6 |
7 | general:
8 | desktop_enable: False # (type:boolean)
9 |
10 | environment:
11 | extra_user_paths: []
12 | umask: 027
13 | root_path: /
14 |
15 | auth:
16 | pw_max_age: 60
17 | # discourage password cycling
18 | pw_min_age: 7
19 | retries: 5
20 | lockout_time: 600
21 | timeout: 60
22 | allow_homeless: False # (type:boolean)
23 | pam_passwdqc_enable: True # (type:boolean)
24 | pam_passwdqc_options: 'min=disabled,disabled,16,12,8'
25 | root_ttys:
26 | console
27 | tty1
28 | tty2
29 | tty3
30 | tty4
31 | tty5
32 | tty6
33 | uid_min: 1000
34 | gid_min: 1000
35 | sys_uid_min: 100
36 | sys_uid_max: 999
37 | sys_gid_min: 100
38 | sys_gid_max: 999
39 | chfn_restrict:
40 |
41 | security:
42 | users_allow: []
43 | suid_sgid_enforce: True # (type:boolean)
44 | # user-defined blacklist and whitelist
45 | suid_sgid_blacklist: []
46 | suid_sgid_whitelist: []
47 | # if this is True, remove any suid/sgid bits from files that were not in the whitelist
48 | suid_sgid_dry_run_on_unknown: False # (type:boolean)
49 | suid_sgid_remove_from_unknown: False # (type:boolean)
50 | # remove packages with known issues
51 | packages_clean: True # (type:boolean)
52 | packages_list:
53 | xinetd
54 | inetd
55 | ypserv
56 | telnet-server
57 | rsh-server
58 | rsync
59 | kernel_enable_module_loading: True # (type:boolean)
60 | kernel_enable_core_dump: False # (type:boolean)
61 | ssh_tmout: 300
62 |
63 | sysctl:
64 | kernel_secure_sysrq: 244 # 4 + 16 + 32 + 64 + 128
65 | kernel_enable_sysrq: False # (type:boolean)
66 | forwarding: False # (type:boolean)
67 | ipv6_enable: False # (type:boolean)
68 | arp_restricted: True # (type:boolean)
69 |
--------------------------------------------------------------------------------
/hooks/charmhelpers/contrib/hardening/defaults/os.yaml.schema:
--------------------------------------------------------------------------------
1 | # NOTE: this schema must contain all valid keys from it's associated defaults
2 | # file. It is used to validate user-provided overrides.
3 | general:
4 | desktop_enable:
5 | environment:
6 | extra_user_paths:
7 | umask:
8 | root_path:
9 | auth:
10 | pw_max_age:
11 | pw_min_age:
12 | retries:
13 | lockout_time:
14 | timeout:
15 | allow_homeless:
16 | pam_passwdqc_enable:
17 | pam_passwdqc_options:
18 | root_ttys:
19 | uid_min:
20 | gid_min:
21 | sys_uid_min:
22 | sys_uid_max:
23 | sys_gid_min:
24 | sys_gid_max:
25 | chfn_restrict:
26 | security:
27 | users_allow:
28 | suid_sgid_enforce:
29 | suid_sgid_blacklist:
30 | suid_sgid_whitelist:
31 | suid_sgid_dry_run_on_unknown:
32 | suid_sgid_remove_from_unknown:
33 | packages_clean:
34 | packages_list:
35 | kernel_enable_module_loading:
36 | kernel_enable_core_dump:
37 | ssh_tmout:
38 | sysctl:
39 | kernel_secure_sysrq:
40 | kernel_enable_sysrq:
41 | forwarding:
42 | ipv6_enable:
43 | arp_restricted:
44 |
--------------------------------------------------------------------------------
/hooks/charmhelpers/contrib/hardening/defaults/ssh.yaml:
--------------------------------------------------------------------------------
1 | # NOTE: this file contains the default configuration for the 'ssh' hardening
2 | # code. If you want to override any settings you must add them to a file
3 | # called hardening.yaml in the root directory of your charm using the
4 | # name 'ssh' as the root key followed by any of the following with new
5 | # values.
6 |
7 | common:
8 | service_name: 'ssh'
9 | network_ipv6_enable: False # (type:boolean)
10 | ports: [22]
11 | remote_hosts: []
12 |
13 | client:
14 | package: 'openssh-client'
15 | cbc_required: False # (type:boolean)
16 | weak_hmac: False # (type:boolean)
17 | weak_kex: False # (type:boolean)
18 | roaming: False
19 | password_authentication: 'no'
20 |
21 | server:
22 | host_key_files: ['/etc/ssh/ssh_host_rsa_key', '/etc/ssh/ssh_host_dsa_key',
23 | '/etc/ssh/ssh_host_ecdsa_key']
24 | cbc_required: False # (type:boolean)
25 | weak_hmac: False # (type:boolean)
26 | weak_kex: False # (type:boolean)
27 | allow_root_with_key: False # (type:boolean)
28 | allow_tcp_forwarding: 'no'
29 | allow_agent_forwarding: 'no'
30 | allow_x11_forwarding: 'no'
31 | use_privilege_separation: 'sandbox'
32 | listen_to: ['0.0.0.0']
33 | use_pam: 'no'
34 | package: 'openssh-server'
35 | password_authentication: 'no'
36 | alive_interval: '600'
37 | alive_count: '3'
38 | sftp_enable: False # (type:boolean)
39 | sftp_group: 'sftponly'
40 | sftp_chroot: '/home/%u'
41 | deny_users: []
42 | allow_users: []
43 | deny_groups: []
44 | allow_groups: []
45 | print_motd: 'no'
46 | print_last_log: 'no'
47 | use_dns: 'no'
48 | max_auth_tries: 2
49 | max_sessions: 10
50 |
--------------------------------------------------------------------------------
/hooks/charmhelpers/contrib/hardening/defaults/ssh.yaml.schema:
--------------------------------------------------------------------------------
1 | # NOTE: this schema must contain all valid keys from it's associated defaults
2 | # file. It is used to validate user-provided overrides.
3 | common:
4 | service_name:
5 | network_ipv6_enable:
6 | ports:
7 | remote_hosts:
8 | client:
9 | package:
10 | cbc_required:
11 | weak_hmac:
12 | weak_kex:
13 | roaming:
14 | password_authentication:
15 | server:
16 | host_key_files:
17 | cbc_required:
18 | weak_hmac:
19 | weak_kex:
20 | allow_root_with_key:
21 | allow_tcp_forwarding:
22 | allow_agent_forwarding:
23 | allow_x11_forwarding:
24 | use_privilege_separation:
25 | listen_to:
26 | use_pam:
27 | package:
28 | password_authentication:
29 | alive_interval:
30 | alive_count:
31 | sftp_enable:
32 | sftp_group:
33 | sftp_chroot:
34 | deny_users:
35 | allow_users:
36 | deny_groups:
37 | allow_groups:
38 | print_motd:
39 | print_last_log:
40 | use_dns:
41 | max_auth_tries:
42 | max_sessions:
43 |
--------------------------------------------------------------------------------
/hooks/charmhelpers/contrib/hardening/host/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2016 Canonical Limited.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | from os import path
16 |
17 | TEMPLATES_DIR = path.join(path.dirname(__file__), 'templates')
18 |
--------------------------------------------------------------------------------
/hooks/charmhelpers/contrib/hardening/host/checks/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2016 Canonical Limited.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | from charmhelpers.core.hookenv import (
16 | log,
17 | DEBUG,
18 | )
19 | from charmhelpers.contrib.hardening.host.checks import (
20 | apt,
21 | limits,
22 | login,
23 | minimize_access,
24 | pam,
25 | profile,
26 | securetty,
27 | suid_sgid,
28 | sysctl
29 | )
30 |
31 |
32 | def run_os_checks():
33 | log("Starting OS hardening checks.", level=DEBUG)
34 | checks = apt.get_audits()
35 | checks.extend(limits.get_audits())
36 | checks.extend(login.get_audits())
37 | checks.extend(minimize_access.get_audits())
38 | checks.extend(pam.get_audits())
39 | checks.extend(profile.get_audits())
40 | checks.extend(securetty.get_audits())
41 | checks.extend(suid_sgid.get_audits())
42 | checks.extend(sysctl.get_audits())
43 |
44 | for check in checks:
45 | log("Running '%s' check" % (check.__class__.__name__), level=DEBUG)
46 | check.ensure_compliance()
47 |
48 | log("OS hardening checks complete.", level=DEBUG)
49 |
--------------------------------------------------------------------------------
/hooks/charmhelpers/contrib/hardening/host/checks/apt.py:
--------------------------------------------------------------------------------
1 | # Copyright 2016 Canonical Limited.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | from charmhelpers.contrib.hardening.utils import get_settings
16 | from charmhelpers.contrib.hardening.audits.apt import (
17 | AptConfig,
18 | RestrictedPackages,
19 | )
20 |
21 |
22 | def get_audits():
23 | """Get OS hardening apt audits.
24 |
25 | :returns: dictionary of audits
26 | """
27 | audits = [AptConfig([{'key': 'APT::Get::AllowUnauthenticated',
28 | 'expected': 'false'}])]
29 |
30 | settings = get_settings('os')
31 | clean_packages = settings['security']['packages_clean']
32 | if clean_packages:
33 | security_packages = settings['security']['packages_list']
34 | if security_packages:
35 | audits.append(RestrictedPackages(security_packages))
36 |
37 | return audits
38 |
--------------------------------------------------------------------------------
/hooks/charmhelpers/contrib/hardening/host/checks/limits.py:
--------------------------------------------------------------------------------
1 | # Copyright 2016 Canonical Limited.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | from charmhelpers.contrib.hardening.audits.file import (
16 | DirectoryPermissionAudit,
17 | TemplatedFile,
18 | )
19 | from charmhelpers.contrib.hardening.host import TEMPLATES_DIR
20 | from charmhelpers.contrib.hardening import utils
21 |
22 |
23 | def get_audits():
24 | """Get OS hardening security limits audits.
25 |
26 | :returns: dictionary of audits
27 | """
28 | audits = []
29 | settings = utils.get_settings('os')
30 |
31 | # Ensure that the /etc/security/limits.d directory is only writable
32 | # by the root user, but others can execute and read.
33 | audits.append(DirectoryPermissionAudit('/etc/security/limits.d',
34 | user='root', group='root',
35 | mode=0o755))
36 |
37 | # If core dumps are not enabled, then don't allow core dumps to be
38 | # created as they may contain sensitive information.
39 | if not settings['security']['kernel_enable_core_dump']:
40 | audits.append(TemplatedFile('/etc/security/limits.d/10.hardcore.conf',
41 | SecurityLimitsContext(),
42 | template_dir=TEMPLATES_DIR,
43 | user='root', group='root', mode=0o0440))
44 | return audits
45 |
46 |
47 | class SecurityLimitsContext(object):
48 |
49 | def __call__(self):
50 | settings = utils.get_settings('os')
51 | ctxt = {'disable_core_dump':
52 | not settings['security']['kernel_enable_core_dump']}
53 | return ctxt
54 |
--------------------------------------------------------------------------------
/hooks/charmhelpers/contrib/hardening/host/checks/login.py:
--------------------------------------------------------------------------------
1 | # Copyright 2016 Canonical Limited.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | from charmhelpers.contrib.hardening.audits.file import TemplatedFile
16 | from charmhelpers.contrib.hardening.host import TEMPLATES_DIR
17 | from charmhelpers.contrib.hardening import utils
18 |
19 |
20 | def get_audits():
21 | """Get OS hardening login.defs audits.
22 |
23 | :returns: dictionary of audits
24 | """
25 | audits = [TemplatedFile('/etc/login.defs', LoginContext(),
26 | template_dir=TEMPLATES_DIR,
27 | user='root', group='root', mode=0o0444)]
28 | return audits
29 |
30 |
31 | class LoginContext(object):
32 |
33 | def __call__(self):
34 | settings = utils.get_settings('os')
35 |
36 | # Octal numbers in yaml end up being turned into decimal,
37 | # so check if the umask is entered as a string (e.g. '027')
38 | # or as an octal umask as we know it (e.g. 002). If its not
39 | # a string assume it to be octal and turn it into an octal
40 | # string.
41 | umask = settings['environment']['umask']
42 | if not isinstance(umask, str):
43 | umask = '%s' % oct(umask)
44 |
45 | ctxt = {
46 | 'additional_user_paths':
47 | settings['environment']['extra_user_paths'],
48 | 'umask': umask,
49 | 'pwd_max_age': settings['auth']['pw_max_age'],
50 | 'pwd_min_age': settings['auth']['pw_min_age'],
51 | 'uid_min': settings['auth']['uid_min'],
52 | 'sys_uid_min': settings['auth']['sys_uid_min'],
53 | 'sys_uid_max': settings['auth']['sys_uid_max'],
54 | 'gid_min': settings['auth']['gid_min'],
55 | 'sys_gid_min': settings['auth']['sys_gid_min'],
56 | 'sys_gid_max': settings['auth']['sys_gid_max'],
57 | 'login_retries': settings['auth']['retries'],
58 | 'login_timeout': settings['auth']['timeout'],
59 | 'chfn_restrict': settings['auth']['chfn_restrict'],
60 | 'allow_login_without_home': settings['auth']['allow_homeless']
61 | }
62 |
63 | return ctxt
64 |
--------------------------------------------------------------------------------
/hooks/charmhelpers/contrib/hardening/host/checks/minimize_access.py:
--------------------------------------------------------------------------------
1 | # Copyright 2016 Canonical Limited.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | from charmhelpers.contrib.hardening.audits.file import (
16 | FilePermissionAudit,
17 | ReadOnly,
18 | )
19 | from charmhelpers.contrib.hardening import utils
20 |
21 |
22 | def get_audits():
23 | """Get OS hardening access audits.
24 |
25 | :returns: dictionary of audits
26 | """
27 | audits = []
28 | settings = utils.get_settings('os')
29 |
30 | # Remove write permissions from $PATH folders for all regular users.
31 | # This prevents changing system-wide commands from normal users.
32 | path_folders = {'/usr/local/sbin',
33 | '/usr/local/bin',
34 | '/usr/sbin',
35 | '/usr/bin',
36 | '/bin'}
37 | extra_user_paths = settings['environment']['extra_user_paths']
38 | path_folders.update(extra_user_paths)
39 | audits.append(ReadOnly(path_folders))
40 |
41 | # Only allow the root user to have access to the shadow file.
42 | audits.append(FilePermissionAudit('/etc/shadow', 'root', 'root', 0o0600))
43 |
44 | if 'change_user' not in settings['security']['users_allow']:
45 | # su should only be accessible to user and group root, unless it is
46 | # expressly defined to allow users to change to root via the
47 | # security_users_allow config option.
48 | audits.append(FilePermissionAudit('/bin/su', 'root', 'root', 0o750))
49 |
50 | return audits
51 |
--------------------------------------------------------------------------------
/hooks/charmhelpers/contrib/hardening/host/checks/profile.py:
--------------------------------------------------------------------------------
1 | # Copyright 2016 Canonical Limited.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | from charmhelpers.contrib.hardening.audits.file import TemplatedFile
16 | from charmhelpers.contrib.hardening.host import TEMPLATES_DIR
17 | from charmhelpers.contrib.hardening import utils
18 |
19 |
20 | def get_audits():
21 | """Get OS hardening profile audits.
22 |
23 | :returns: dictionary of audits
24 | """
25 | audits = []
26 |
27 | settings = utils.get_settings('os')
28 | # If core dumps are not enabled, then don't allow core dumps to be
29 | # created as they may contain sensitive information.
30 | if not settings['security']['kernel_enable_core_dump']:
31 | audits.append(TemplatedFile('/etc/profile.d/pinerolo_profile.sh',
32 | ProfileContext(),
33 | template_dir=TEMPLATES_DIR,
34 | mode=0o0755, user='root', group='root'))
35 | if settings['security']['ssh_tmout']:
36 | audits.append(TemplatedFile('/etc/profile.d/99-hardening.sh',
37 | ProfileContext(),
38 | template_dir=TEMPLATES_DIR,
39 | mode=0o0644, user='root', group='root'))
40 | return audits
41 |
42 |
43 | class ProfileContext(object):
44 |
45 | def __call__(self):
46 | settings = utils.get_settings('os')
47 | ctxt = {'ssh_tmout':
48 | settings['security']['ssh_tmout']}
49 | return ctxt
50 |
--------------------------------------------------------------------------------
/hooks/charmhelpers/contrib/hardening/host/checks/securetty.py:
--------------------------------------------------------------------------------
1 | # Copyright 2016 Canonical Limited.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | from charmhelpers.contrib.hardening.audits.file import TemplatedFile
16 | from charmhelpers.contrib.hardening.host import TEMPLATES_DIR
17 | from charmhelpers.contrib.hardening import utils
18 |
19 |
20 | def get_audits():
21 | """Get OS hardening Secure TTY audits.
22 |
23 | :returns: dictionary of audits
24 | """
25 | audits = []
26 | audits.append(TemplatedFile('/etc/securetty', SecureTTYContext(),
27 | template_dir=TEMPLATES_DIR,
28 | mode=0o0400, user='root', group='root'))
29 | return audits
30 |
31 |
32 | class SecureTTYContext(object):
33 |
34 | def __call__(self):
35 | settings = utils.get_settings('os')
36 | ctxt = {'ttys': settings['auth']['root_ttys']}
37 | return ctxt
38 |
--------------------------------------------------------------------------------
/hooks/charmhelpers/contrib/hardening/host/templates/10.hardcore.conf:
--------------------------------------------------------------------------------
1 | ###############################################################################
2 | # WARNING: This configuration file is maintained by Juju. Local changes may
3 | # be overwritten.
4 | ###############################################################################
5 | {% if disable_core_dump -%}
6 | # Prevent core dumps for all users. These are usually only needed by developers and may contain sensitive information.
7 | * hard core 0
8 | {% endif %}
--------------------------------------------------------------------------------
/hooks/charmhelpers/contrib/hardening/host/templates/99-hardening.sh:
--------------------------------------------------------------------------------
1 | TMOUT={{ tmout }}
2 | readonly TMOUT
3 | export TMOUT
4 |
5 | readonly HISTFILE
6 |
--------------------------------------------------------------------------------
/hooks/charmhelpers/contrib/hardening/host/templates/99-juju-hardening.conf:
--------------------------------------------------------------------------------
1 | ###############################################################################
2 | # WARNING: This configuration file is maintained by Juju. Local changes may
3 | # be overwritten.
4 | ###############################################################################
5 | {% for key, value in sysctl_settings -%}
6 | {{ key }}={{ value }}
7 | {% endfor -%}
8 |
--------------------------------------------------------------------------------
/hooks/charmhelpers/contrib/hardening/host/templates/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstack/charm-neutron-api/6d5021e58d06e8fc112000b9e9867b4a898222fb/hooks/charmhelpers/contrib/hardening/host/templates/__init__.py
--------------------------------------------------------------------------------
/hooks/charmhelpers/contrib/hardening/host/templates/modules:
--------------------------------------------------------------------------------
1 | ###############################################################################
2 | # WARNING: This configuration file is maintained by Juju. Local changes may
3 | # be overwritten.
4 | ###############################################################################
5 | # /etc/modules: kernel modules to load at boot time.
6 | #
7 | # This file contains the names of kernel modules that should be loaded
8 | # at boot time, one per line. Lines beginning with "#" are ignored.
9 | # Parameters can be specified after the module name.
10 |
11 | # Arch
12 | # ----
13 | #
14 | # Modules for certains builds, contains support modules and some CPU-specific optimizations.
15 |
16 | {% if arch == "x86_64" -%}
17 | # Optimize for x86_64 cryptographic features
18 | twofish-x86_64-3way
19 | twofish-x86_64
20 | aes-x86_64
21 | salsa20-x86_64
22 | blowfish-x86_64
23 | {% endif -%}
24 |
25 | {% if cpuVendor == "intel" -%}
26 | # Intel-specific optimizations
27 | ghash-clmulni-intel
28 | aesni-intel
29 | kvm-intel
30 | {% endif -%}
31 |
32 | {% if cpuVendor == "amd" -%}
33 | # AMD-specific optimizations
34 | kvm-amd
35 | {% endif -%}
36 |
37 | kvm
38 |
39 |
40 | # Crypto
41 | # ------
42 |
43 | # Some core modules which comprise strong cryptography.
44 | blowfish_common
45 | blowfish_generic
46 | ctr
47 | cts
48 | lrw
49 | lzo
50 | rmd160
51 | rmd256
52 | rmd320
53 | serpent
54 | sha512_generic
55 | twofish_common
56 | twofish_generic
57 | xts
58 | zlib
59 |
60 |
61 | # Drivers
62 | # -------
63 |
64 | # Basics
65 | lp
66 | rtc
67 | loop
68 |
69 | # Filesystems
70 | ext2
71 | btrfs
72 |
73 | {% if desktop_enable -%}
74 | # Desktop
75 | psmouse
76 | snd
77 | snd_ac97_codec
78 | snd_intel8x0
79 | snd_page_alloc
80 | snd_pcm
81 | snd_timer
82 | soundcore
83 | usbhid
84 | {% endif -%}
85 |
86 | # Lib
87 | # ---
88 | xz
89 |
90 |
91 | # Net
92 | # ---
93 |
94 | # All packets needed for netfilter rules (ie iptables, ebtables).
95 | ip_tables
96 | x_tables
97 | iptable_filter
98 | iptable_nat
99 |
100 | # Targets
101 | ipt_LOG
102 | ipt_REJECT
103 |
104 | # Modules
105 | xt_connlimit
106 | xt_tcpudp
107 | xt_recent
108 | xt_limit
109 | xt_conntrack
110 | nf_conntrack
111 | nf_conntrack_ipv4
112 | nf_defrag_ipv4
113 | xt_state
114 | nf_nat
115 |
116 | # Addons
117 | xt_pknock
--------------------------------------------------------------------------------
/hooks/charmhelpers/contrib/hardening/host/templates/passwdqc.conf:
--------------------------------------------------------------------------------
1 | ###############################################################################
2 | # WARNING: This configuration file is maintained by Juju. Local changes may
3 | # be overwritten.
4 | ###############################################################################
5 | Name: passwdqc password strength enforcement
6 | Default: yes
7 | Priority: 1024
8 | Conflicts: cracklib
9 | Password-Type: Primary
10 | Password:
11 | requisite pam_passwdqc.so {{ auth_pam_passwdqc_options }}
12 |
--------------------------------------------------------------------------------
/hooks/charmhelpers/contrib/hardening/host/templates/pinerolo_profile.sh:
--------------------------------------------------------------------------------
1 | ###############################################################################
2 | # WARNING: This configuration file is maintained by Juju. Local changes may
3 | # be overwritten.
4 | ###############################################################################
5 | # Disable core dumps via soft limits for all users. Compliance to this setting
6 | # is voluntary and can be modified by users up to a hard limit. This setting is
7 | # a sane default.
8 | ulimit -S -c 0 > /dev/null 2>&1
9 |
--------------------------------------------------------------------------------
/hooks/charmhelpers/contrib/hardening/host/templates/securetty:
--------------------------------------------------------------------------------
1 | ###############################################################################
2 | # WARNING: This configuration file is maintained by Juju. Local changes may
3 | # be overwritten.
4 | ###############################################################################
5 | # A list of TTYs, from which root can log in
6 | # see `man securetty` for reference
7 | {% if ttys -%}
8 | {% for tty in ttys -%}
9 | {{ tty }}
10 | {% endfor -%}
11 | {% endif -%}
12 |
--------------------------------------------------------------------------------
/hooks/charmhelpers/contrib/hardening/host/templates/tally2:
--------------------------------------------------------------------------------
1 | ###############################################################################
2 | # WARNING: This configuration file is maintained by Juju. Local changes may
3 | # be overwritten.
4 | ###############################################################################
5 | Name: tally2 lockout after failed attempts enforcement
6 | Default: yes
7 | Priority: 1024
8 | Conflicts: cracklib
9 | Auth-Type: Primary
10 | Auth-Initial:
11 | required pam_tally2.so deny={{ auth_retries }} onerr=fail unlock_time={{ auth_lockout_time }}
12 | Account-Type: Primary
13 | Account-Initial:
14 | required pam_tally2.so
15 |
--------------------------------------------------------------------------------
/hooks/charmhelpers/contrib/hardening/mysql/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2016 Canonical Limited.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | from os import path
16 |
17 | TEMPLATES_DIR = path.join(path.dirname(__file__), 'templates')
18 |
--------------------------------------------------------------------------------
/hooks/charmhelpers/contrib/hardening/mysql/checks/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2016 Canonical Limited.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | from charmhelpers.core.hookenv import (
16 | log,
17 | DEBUG,
18 | )
19 | from charmhelpers.contrib.hardening.mysql.checks import config
20 |
21 |
22 | def run_mysql_checks():
23 | log("Starting MySQL hardening checks.", level=DEBUG)
24 | checks = config.get_audits()
25 | for check in checks:
26 | log("Running '%s' check" % (check.__class__.__name__), level=DEBUG)
27 | check.ensure_compliance()
28 |
29 | log("MySQL hardening checks complete.", level=DEBUG)
30 |
--------------------------------------------------------------------------------
/hooks/charmhelpers/contrib/hardening/mysql/checks/config.py:
--------------------------------------------------------------------------------
1 | # Copyright 2016 Canonical Limited.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | import subprocess
16 |
17 | from charmhelpers.core.hookenv import (
18 | log,
19 | WARNING,
20 | )
21 | from charmhelpers.contrib.hardening.audits.file import (
22 | FilePermissionAudit,
23 | DirectoryPermissionAudit,
24 | TemplatedFile,
25 | )
26 | from charmhelpers.contrib.hardening.mysql import TEMPLATES_DIR
27 | from charmhelpers.contrib.hardening import utils
28 |
29 |
30 | def get_audits():
31 | """Get MySQL hardening config audits.
32 |
33 | :returns: dictionary of audits
34 | """
35 | if subprocess.call(['which', 'mysql'], stdout=subprocess.PIPE) != 0:
36 | log("MySQL does not appear to be installed on this node - "
37 | "skipping mysql hardening", level=WARNING)
38 | return []
39 |
40 | settings = utils.get_settings('mysql')
41 | hardening_settings = settings['hardening']
42 | my_cnf = hardening_settings['mysql-conf']
43 |
44 | audits = [
45 | FilePermissionAudit(paths=[my_cnf], user='root',
46 | group='root', mode=0o0600),
47 |
48 | TemplatedFile(hardening_settings['hardening-conf'],
49 | MySQLConfContext(),
50 | TEMPLATES_DIR,
51 | mode=0o0750,
52 | user='mysql',
53 | group='root',
54 | service_actions=[{'service': 'mysql',
55 | 'actions': ['restart']}]),
56 |
57 | # MySQL and Percona charms do not allow configuration of the
58 | # data directory, so use the default.
59 | DirectoryPermissionAudit('/var/lib/mysql',
60 | user='mysql',
61 | group='mysql',
62 | recursive=False,
63 | mode=0o755),
64 |
65 | DirectoryPermissionAudit('/etc/mysql',
66 | user='root',
67 | group='root',
68 | recursive=False,
69 | mode=0o700),
70 | ]
71 |
72 | return audits
73 |
74 |
75 | class MySQLConfContext(object):
76 | """Defines the set of key/value pairs to set in a mysql config file.
77 |
78 | This context, when called, will return a dictionary containing the
79 | key/value pairs of setting to specify in the
80 | /etc/mysql/conf.d/hardening.cnf file.
81 | """
82 | def __call__(self):
83 | settings = utils.get_settings('mysql')
84 | return {
85 | 'mysql_settings': [(k, v) for k, v in settings['security'].items()]
86 | }
87 |
--------------------------------------------------------------------------------
/hooks/charmhelpers/contrib/hardening/mysql/templates/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstack/charm-neutron-api/6d5021e58d06e8fc112000b9e9867b4a898222fb/hooks/charmhelpers/contrib/hardening/mysql/templates/__init__.py
--------------------------------------------------------------------------------
/hooks/charmhelpers/contrib/hardening/mysql/templates/hardening.cnf:
--------------------------------------------------------------------------------
1 | ###############################################################################
2 | # WARNING: This configuration file is maintained by Juju. Local changes may
3 | # be overwritten.
4 | ###############################################################################
5 | [mysqld]
6 | {% for setting, value in mysql_settings -%}
7 | {% if value == 'True' -%}
8 | {{ setting }}
9 | {% elif value != 'None' and value != None -%}
10 | {{ setting }} = {{ value }}
11 | {% endif -%}
12 | {% endfor -%}
13 |
--------------------------------------------------------------------------------
/hooks/charmhelpers/contrib/hardening/ssh/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2016 Canonical Limited.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | from os import path
16 |
17 | TEMPLATES_DIR = path.join(path.dirname(__file__), 'templates')
18 |
--------------------------------------------------------------------------------
/hooks/charmhelpers/contrib/hardening/ssh/checks/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2016 Canonical Limited.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | from charmhelpers.core.hookenv import (
16 | log,
17 | DEBUG,
18 | )
19 | from charmhelpers.contrib.hardening.ssh.checks import config
20 |
21 |
22 | def run_ssh_checks():
23 | log("Starting SSH hardening checks.", level=DEBUG)
24 | checks = config.get_audits()
25 | for check in checks:
26 | log("Running '%s' check" % (check.__class__.__name__), level=DEBUG)
27 | check.ensure_compliance()
28 |
29 | log("SSH hardening checks complete.", level=DEBUG)
30 |
--------------------------------------------------------------------------------
/hooks/charmhelpers/contrib/hardening/ssh/templates/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstack/charm-neutron-api/6d5021e58d06e8fc112000b9e9867b4a898222fb/hooks/charmhelpers/contrib/hardening/ssh/templates/__init__.py
--------------------------------------------------------------------------------
/hooks/charmhelpers/contrib/hardening/ssh/templates/ssh_config:
--------------------------------------------------------------------------------
1 | ###############################################################################
2 | # WARNING: This configuration file is maintained by Juju. Local changes may
3 | # be overwritten.
4 | ###############################################################################
5 | # This is the ssh client system-wide configuration file. See
6 | # ssh_config(5) for more information. This file provides defaults for
7 | # users, and the values can be changed in per-user configuration files
8 | # or on the command line.
9 |
10 | # Configuration data is parsed as follows:
11 | # 1. command line options
12 | # 2. user-specific file
13 | # 3. system-wide file
14 | # Any configuration value is only changed the first time it is set.
15 | # Thus, host-specific definitions should be at the beginning of the
16 | # configuration file, and defaults at the end.
17 |
18 | # Site-wide defaults for some commonly used options. For a comprehensive
19 | # list of available options, their meanings and defaults, please see the
20 | # ssh_config(5) man page.
21 |
22 | # Restrict the following configuration to be limited to this Host.
23 | {% if remote_hosts -%}
24 | Host {{ ' '.join(remote_hosts) }}
25 | {% endif %}
26 | ForwardAgent no
27 | ForwardX11 no
28 | ForwardX11Trusted yes
29 | RhostsRSAAuthentication no
30 | RSAAuthentication yes
31 | PasswordAuthentication {{ password_auth_allowed }}
32 | HostbasedAuthentication no
33 | GSSAPIAuthentication no
34 | GSSAPIDelegateCredentials no
35 | GSSAPIKeyExchange no
36 | GSSAPITrustDNS no
37 | BatchMode no
38 | CheckHostIP yes
39 | AddressFamily {{ addr_family }}
40 | ConnectTimeout 0
41 | StrictHostKeyChecking ask
42 | IdentityFile ~/.ssh/identity
43 | IdentityFile ~/.ssh/id_rsa
44 | IdentityFile ~/.ssh/id_dsa
45 | # The port at the destination should be defined
46 | {% for port in ports -%}
47 | Port {{ port }}
48 | {% endfor %}
49 | Protocol 2
50 | Cipher 3des
51 | {% if ciphers -%}
52 | Ciphers {{ ciphers }}
53 | {%- endif %}
54 | {% if macs -%}
55 | MACs {{ macs }}
56 | {%- endif %}
57 | {% if kexs -%}
58 | KexAlgorithms {{ kexs }}
59 | {%- endif %}
60 | EscapeChar ~
61 | Tunnel no
62 | TunnelDevice any:any
63 | PermitLocalCommand no
64 | VisualHostKey no
65 | RekeyLimit 1G 1h
66 | SendEnv LANG LC_*
67 | HashKnownHosts yes
68 | {% if roaming -%}
69 | UseRoaming {{ roaming }}
70 | {% endif %}
71 |
--------------------------------------------------------------------------------
/hooks/charmhelpers/contrib/hardening/templating.py:
--------------------------------------------------------------------------------
1 | # Copyright 2016 Canonical Limited.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | import os
16 |
17 | from charmhelpers.core.hookenv import (
18 | log,
19 | DEBUG,
20 | WARNING,
21 | )
22 |
23 | try:
24 | from jinja2 import FileSystemLoader, Environment
25 | except ImportError:
26 | from charmhelpers.fetch import apt_install
27 | from charmhelpers.fetch import apt_update
28 | apt_update(fatal=True)
29 | apt_install('python3-jinja2', fatal=True)
30 | from jinja2 import FileSystemLoader, Environment
31 |
32 |
33 | # NOTE: function separated from main rendering code to facilitate easier
34 | # mocking in unit tests.
35 | def write(path, data):
36 | with open(path, 'wb') as out:
37 | out.write(data)
38 |
39 |
40 | def get_template_path(template_dir, path):
41 | """Returns the template file which would be used to render the path.
42 |
43 | The path to the template file is returned.
44 | :param template_dir: the directory the templates are located in
45 | :param path: the file path to be written to.
46 | :returns: path to the template file
47 | """
48 | return os.path.join(template_dir, os.path.basename(path))
49 |
50 |
51 | def render_and_write(template_dir, path, context):
52 | """Renders the specified template into the file.
53 |
54 | :param template_dir: the directory to load the template from
55 | :param path: the path to write the templated contents to
56 | :param context: the parameters to pass to the rendering engine
57 | """
58 | env = Environment(loader=FileSystemLoader(template_dir))
59 | template_file = os.path.basename(path)
60 | template = env.get_template(template_file)
61 | log('Rendering from template: %s' % template.name, level=DEBUG)
62 | rendered_content = template.render(context)
63 | if not rendered_content:
64 | log("Render returned None - skipping '%s'" % path,
65 | level=WARNING)
66 | return
67 |
68 | write(path, rendered_content.encode('utf-8').strip())
69 | log('Wrote template %s' % path, level=DEBUG)
70 |
--------------------------------------------------------------------------------
/hooks/charmhelpers/contrib/hardware/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2022 Canonical Limited.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
--------------------------------------------------------------------------------
/hooks/charmhelpers/contrib/network/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2014-2015 Canonical Limited.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
--------------------------------------------------------------------------------
/hooks/charmhelpers/contrib/network/ovs/utils.py:
--------------------------------------------------------------------------------
1 | # Copyright 2019 Canonical Ltd
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 | import subprocess
15 |
16 |
17 | def _run(*args):
18 | """Run a process, check result, capture decoded output from STDOUT.
19 |
20 | :param args: Command and arguments to run
21 | :type args: Tuple[str, ...]
22 | :returns: Information about the completed process
23 | :rtype: str
24 | :raises subprocess.CalledProcessError
25 | """
26 | return subprocess.check_output(args, universal_newlines=True)
27 |
--------------------------------------------------------------------------------
/hooks/charmhelpers/contrib/openstack/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2014-2015 Canonical Limited.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
--------------------------------------------------------------------------------
/hooks/charmhelpers/contrib/openstack/alternatives.py:
--------------------------------------------------------------------------------
1 | # Copyright 2014-2015 Canonical Limited.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | ''' Helper for managing alternatives for file conflict resolution '''
16 |
17 | import subprocess
18 | import shutil
19 | import os
20 |
21 |
22 | def install_alternative(name, target, source, priority=50):
23 | ''' Install alternative configuration '''
24 | if (os.path.exists(target) and not os.path.islink(target)):
25 | # Move existing file/directory away before installing
26 | shutil.move(target, '{}.bak'.format(target))
27 | cmd = [
28 | 'update-alternatives', '--force', '--install',
29 | target, name, source, str(priority)
30 | ]
31 | subprocess.check_call(cmd)
32 |
33 |
34 | def remove_alternative(name, source):
35 | """Remove an installed alternative configuration file
36 |
37 | :param name: string name of the alternative to remove
38 | :param source: string full path to alternative to remove
39 | """
40 | cmd = [
41 | 'update-alternatives', '--remove',
42 | name, source
43 | ]
44 | subprocess.check_call(cmd)
45 |
--------------------------------------------------------------------------------
/hooks/charmhelpers/contrib/openstack/exceptions.py:
--------------------------------------------------------------------------------
1 | # Copyright 2016 Canonical Ltd
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 |
16 | class OSContextError(Exception):
17 | """Raised when an error occurs during context generation.
18 |
19 | This exception is principally used in contrib.openstack.context
20 | """
21 | pass
22 |
23 |
24 | class ServiceActionError(Exception):
25 | """Raised when a service action (stop/start/ etc) failed."""
26 | pass
27 |
--------------------------------------------------------------------------------
/hooks/charmhelpers/contrib/openstack/files/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2014-2015 Canonical Limited.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | # dummy __init__.py to fool syncer into thinking this is a syncable python
16 | # module
17 |
--------------------------------------------------------------------------------
/hooks/charmhelpers/contrib/openstack/files/check_haproxy.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | #--------------------------------------------
3 | # This file is managed by Juju
4 | #--------------------------------------------
5 | #
6 | # Copyright 2009,2012 Canonical Ltd.
7 | # Author: Tom Haddon
8 |
9 | CRITICAL=0
10 | NOTACTIVE=''
11 | LOGFILE=/var/log/nagios/check_haproxy.log
12 | AUTH=$(grep -r "stats auth" /etc/haproxy/haproxy.cfg | awk 'NR=1{print $3}')
13 |
14 | typeset -i N_INSTANCES=0
15 | for appserver in $(awk '/^\s+server/{print $2}' /etc/haproxy/haproxy.cfg)
16 | do
17 | N_INSTANCES=N_INSTANCES+1
18 | output=$(/usr/lib/nagios/plugins/check_http -a ${AUTH} -I 127.0.0.1 -p 8888 -u '/;csv' --regex=",${appserver},.*,UP.*" -e ' 200 OK')
19 | if [ $? != 0 ]; then
20 | date >> $LOGFILE
21 | echo $output >> $LOGFILE
22 | /usr/lib/nagios/plugins/check_http -a ${AUTH} -I 127.0.0.1 -p 8888 -u '/;csv' -v | grep ",${appserver}," >> $LOGFILE 2>&1
23 | CRITICAL=1
24 | NOTACTIVE="${NOTACTIVE} $appserver"
25 | fi
26 | done
27 |
28 | if [ $CRITICAL = 1 ]; then
29 | echo "CRITICAL:${NOTACTIVE}"
30 | exit 2
31 | fi
32 |
33 | echo "OK: All haproxy instances ($N_INSTANCES) looking good"
34 | exit 0
35 |
--------------------------------------------------------------------------------
/hooks/charmhelpers/contrib/openstack/files/check_haproxy_queue_depth.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | #--------------------------------------------
3 | # This file is managed by Juju
4 | #--------------------------------------------
5 | #
6 | # Copyright 2009,2012 Canonical Ltd.
7 | # Author: Tom Haddon
8 |
9 | # These should be config options at some stage
10 | CURRQthrsh=0
11 | MAXQthrsh=100
12 |
13 | AUTH=$(grep -r "stats auth" /etc/haproxy/haproxy.cfg | awk 'NR=1{print $3}')
14 |
15 | HAPROXYSTATS=$(/usr/lib/nagios/plugins/check_http -a ${AUTH} -I 127.0.0.1 -p 8888 -u '/;csv' -v)
16 |
17 | for BACKEND in $(echo $HAPROXYSTATS| xargs -n1 | grep BACKEND | awk -F , '{print $1}')
18 | do
19 | CURRQ=$(echo "$HAPROXYSTATS" | grep $BACKEND | grep BACKEND | cut -d , -f 3)
20 | MAXQ=$(echo "$HAPROXYSTATS" | grep $BACKEND | grep BACKEND | cut -d , -f 4)
21 |
22 | if [[ $CURRQ -gt $CURRQthrsh || $MAXQ -gt $MAXQthrsh ]] ; then
23 | echo "CRITICAL: queue depth for $BACKEND - CURRENT:$CURRQ MAX:$MAXQ"
24 | exit 2
25 | fi
26 | done
27 |
28 | echo "OK: All haproxy queue depths looking good"
29 | exit 0
30 |
31 |
--------------------------------------------------------------------------------
/hooks/charmhelpers/contrib/openstack/ha/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2016 Canonical Ltd
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
--------------------------------------------------------------------------------
/hooks/charmhelpers/contrib/openstack/templates/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2014-2015 Canonical Limited.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | # dummy __init__.py to fool syncer into thinking this is a syncable python
16 | # module
17 |
--------------------------------------------------------------------------------
/hooks/charmhelpers/contrib/openstack/templates/ceph.conf:
--------------------------------------------------------------------------------
1 | ###############################################################################
2 | # [ WARNING ]
3 | # ceph configuration file maintained by Juju
4 | # local changes may be overwritten.
5 | ###############################################################################
6 | [global]
7 | {% if auth -%}
8 | auth_supported = {{ auth }}
9 | keyring = /etc/ceph/$cluster.$name.keyring
10 | mon host = {{ mon_hosts }}
11 | {% endif -%}
12 | log to syslog = {{ use_syslog }}
13 | err to syslog = {{ use_syslog }}
14 | clog to syslog = {{ use_syslog }}
15 | {% if rbd_features %}
16 | rbd default features = {{ rbd_features }}
17 | {% endif %}
18 |
19 | [client]
20 | {% if rbd_client_cache_settings -%}
21 | {% for key, value in rbd_client_cache_settings.items() -%}
22 | {{ key }} = {{ value }}
23 | {% endfor -%}
24 | {%- endif %}
25 |
26 | {% if rbd_default_data_pool -%}
27 | rbd default data pool = {{ rbd_default_data_pool }}
28 | {% endif %}
29 |
--------------------------------------------------------------------------------
/hooks/charmhelpers/contrib/openstack/templates/git.upstart:
--------------------------------------------------------------------------------
1 | description "{{ service_description }}"
2 | author "Juju {{ service_name }} Charm "
3 |
4 | start on runlevel [2345]
5 | stop on runlevel [!2345]
6 |
7 | respawn
8 |
9 | exec start-stop-daemon --start --chuid {{ user_name }} \
10 | --chdir {{ start_dir }} --name {{ process_name }} \
11 | --exec {{ executable_name }} -- \
12 | {% for config_file in config_files -%}
13 | --config-file={{ config_file }} \
14 | {% endfor -%}
15 | {% if log_file -%}
16 | --log-file={{ log_file }}
17 | {% endif -%}
18 |
--------------------------------------------------------------------------------
/hooks/charmhelpers/contrib/openstack/templates/haproxy.cfg:
--------------------------------------------------------------------------------
1 | global
2 | # NOTE: on startup haproxy chroot's to /var/lib/haproxy.
3 | #
4 | # Unfortunately the program will open some files prior to the call to
5 | # chroot never to reopen them, and some after. So looking at the on-disk
6 | # layout of haproxy resources you will find some resources relative to /
7 | # such as the admin socket, and some relative to /var/lib/haproxy such as
8 | # the log socket.
9 | #
10 | # The logging socket is (re-)opened after the chroot and must be relative
11 | # to /var/lib/haproxy.
12 | log /dev/log local0
13 | log /dev/log local1 notice
14 | maxconn 20000
15 | user haproxy
16 | group haproxy
17 | spread-checks 0
18 | # The admin socket is opened prior to the chroot never to be reopened, so
19 | # it lives outside the chroot directory in the filesystem.
20 | stats socket /var/run/haproxy/admin.sock mode 600 level admin
21 | stats timeout 2m
22 |
23 | defaults
24 | log global
25 | mode tcp
26 | option tcplog
27 | option dontlognull
28 | retries 3
29 | {%- if haproxy_queue_timeout %}
30 | timeout queue {{ haproxy_queue_timeout }}
31 | {%- else %}
32 | timeout queue 9000
33 | {%- endif %}
34 | {%- if haproxy_connect_timeout %}
35 | timeout connect {{ haproxy_connect_timeout }}
36 | {%- else %}
37 | timeout connect 9000
38 | {%- endif %}
39 | {%- if haproxy_client_timeout %}
40 | timeout client {{ haproxy_client_timeout }}
41 | {%- else %}
42 | timeout client 90000
43 | {%- endif %}
44 | {%- if haproxy_server_timeout %}
45 | timeout server {{ haproxy_server_timeout }}
46 | {%- else %}
47 | timeout server 90000
48 | {%- endif %}
49 |
50 | listen stats
51 | bind {{ local_host }}:{{ stat_port }}
52 | {%- if stats_exporter_host and stats_exporter_port %}
53 | bind {{ stats_exporter_host }}:{{ stats_exporter_port }}
54 | option http-use-htx
55 | http-request use-service prometheus-exporter if { path /metrics }
56 | {%- endif %}
57 | mode http
58 | stats enable
59 | stats hide-version
60 | stats realm Haproxy\ Statistics
61 | stats uri /
62 | stats auth admin:{{ stat_password }}
63 |
64 | {% if frontends -%}
65 | {% for service, ports in service_ports.items() -%}
66 | frontend tcp-in_{{ service }}
67 | bind *:{{ ports[0] }}
68 | {% if ipv6_enabled -%}
69 | bind :::{{ ports[0] }}
70 | {% endif -%}
71 | {% for frontend in frontends -%}
72 | acl net_{{ frontend }} dst {{ frontends[frontend]['network'] }}
73 | use_backend {{ service }}_{{ frontend }} if net_{{ frontend }}
74 | {% endfor -%}
75 | default_backend {{ service }}_{{ default_backend }}
76 |
77 | {% for frontend in frontends -%}
78 | backend {{ service }}_{{ frontend }}
79 | balance leastconn
80 | {% if backend_options -%}
81 | {% if backend_options[service] -%}
82 | {% for option in backend_options[service] -%}
83 | {% for key, value in option.items() -%}
84 | {{ key }} {{ value }}
85 | {% endfor -%}
86 | {% endfor -%}
87 | {% endif -%}
88 | {% endif -%}
89 | {% for unit, address in frontends[frontend]['backends'].items() -%}
90 | {% if https -%}
91 | server {{ unit }} {{ address }}:{{ ports[1] }} check check-ssl verify none
92 | {% else -%}
93 | server {{ unit }} {{ address }}:{{ ports[1] }} check
94 | {% endif -%}
95 | {% endfor %}
96 | {% endfor -%}
97 | {% endfor -%}
98 | {% endif -%}
99 |
--------------------------------------------------------------------------------
/hooks/charmhelpers/contrib/openstack/templates/logrotate:
--------------------------------------------------------------------------------
1 | /var/log/{{ logrotate_logs_location }}/*.log {
2 | {{ logrotate_interval }}
3 | {{ logrotate_count }}
4 | compress
5 | delaycompress
6 | missingok
7 | notifempty
8 | copytruncate
9 | }
10 |
--------------------------------------------------------------------------------
/hooks/charmhelpers/contrib/openstack/templates/memcached.conf:
--------------------------------------------------------------------------------
1 | ###############################################################################
2 | # [ WARNING ]
3 | # memcached configuration file maintained by Juju
4 | # local changes may be overwritten.
5 | ###############################################################################
6 |
7 | # memcached default config file
8 | # 2003 - Jay Bonci
9 | # This configuration file is read by the start-memcached script provided as
10 | # part of the Debian GNU/Linux distribution.
11 |
12 | # Run memcached as a daemon. This command is implied, and is not needed for the
13 | # daemon to run. See the README.Debian that comes with this package for more
14 | # information.
15 | -d
16 |
17 | # Log memcached's output to /var/log/memcached
18 | logfile /var/log/memcached.log
19 |
20 | # Be verbose
21 | # -v
22 |
23 | # Be even more verbose (print client commands as well)
24 | # -vv
25 |
26 | # Start with a cap of 64 megs of memory. It's reasonable, and the daemon default
27 | # Note that the daemon will grow to this size, but does not start out holding this much
28 | # memory
29 | -m 64
30 |
31 | # Default connection port is 11211
32 | -p {{ memcache_port }}
33 |
34 | # Run the daemon as root. The start-memcached will default to running as root if no
35 | # -u command is present in this config file
36 | -u memcache
37 |
38 | # Specify which IP address to listen on. The default is to listen on all IP addresses
39 | # This parameter is one of the only security measures that memcached has, so make sure
40 | # it's listening on a firewalled interface.
41 | -l {{ memcache_server }}
42 |
43 | # Limit the number of simultaneous incoming connections. The daemon default is 1024
44 | # -c 1024
45 |
46 | # Lock down all paged memory. Consult with the README and homepage before you do this
47 | # -k
48 |
49 | # Return error when memory is exhausted (rather than removing items)
50 | # -M
51 |
52 | # Maximize core file limit
53 | # -r
54 |
--------------------------------------------------------------------------------
/hooks/charmhelpers/contrib/openstack/templates/openstack_https_frontend:
--------------------------------------------------------------------------------
1 | {% if endpoints -%}
2 | {% for ext_port in ext_ports -%}
3 | Listen {{ ext_port }}
4 | {% endfor -%}
5 | {% for address, endpoint, ext, int in endpoints -%}
6 |
7 | ServerName {{ endpoint }}
8 | SSLEngine on
9 |
10 | # This section is based on Mozilla's recommendation
11 | # as the "intermediate" profile as of July 7th, 2020.
12 | # https://wiki.mozilla.org/Security/Server_Side_TLS
13 | SSLProtocol all -SSLv3 -TLSv1 -TLSv1.1
14 | SSLCipherSuite ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384
15 | SSLHonorCipherOrder off
16 |
17 | SSLCertificateFile /etc/apache2/ssl/{{ namespace }}/cert_{{ endpoint }}
18 | # See LP 1484489 - this is to support <= 2.4.7 and >= 2.4.8
19 | SSLCertificateChainFile /etc/apache2/ssl/{{ namespace }}/cert_{{ endpoint }}
20 | SSLCertificateKeyFile /etc/apache2/ssl/{{ namespace }}/key_{{ endpoint }}
21 | ProxyPass / http://localhost:{{ int }}/
22 | ProxyPassReverse / http://localhost:{{ int }}/
23 | ProxyPreserveHost on
24 | RequestHeader set X-Forwarded-Proto "https"
25 | KeepAliveTimeout 75
26 | MaxKeepAliveRequests 1000
27 |
28 | {% endfor -%}
29 |
30 | Order deny,allow
31 | Allow from all
32 |
33 |
34 | Order allow,deny
35 | Allow from all
36 |
37 | {% endif -%}
38 |
--------------------------------------------------------------------------------
/hooks/charmhelpers/contrib/openstack/templates/openstack_https_frontend.conf:
--------------------------------------------------------------------------------
1 | {% if endpoints -%}
2 | {% for ext_port in ext_ports -%}
3 | Listen {{ ext_port }}
4 | {% endfor -%}
5 | {% for address, endpoint, ext, int in endpoints -%}
6 |
7 | ServerName {{ endpoint }}
8 | SSLEngine on
9 |
10 | # This section is based on Mozilla's recommendation
11 | # as the "intermediate" profile as of July 7th, 2020.
12 | # https://wiki.mozilla.org/Security/Server_Side_TLS
13 | SSLProtocol all -SSLv3 -TLSv1 -TLSv1.1
14 | SSLCipherSuite ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384
15 | SSLHonorCipherOrder off
16 |
17 | SSLCertificateFile /etc/apache2/ssl/{{ namespace }}/cert_{{ endpoint }}
18 | # See LP 1484489 - this is to support <= 2.4.7 and >= 2.4.8
19 | SSLCertificateChainFile /etc/apache2/ssl/{{ namespace }}/cert_{{ endpoint }}
20 | SSLCertificateKeyFile /etc/apache2/ssl/{{ namespace }}/key_{{ endpoint }}
21 | ProxyPass / http://localhost:{{ int }}/
22 | ProxyPassReverse / http://localhost:{{ int }}/
23 | ProxyPreserveHost on
24 | RequestHeader set X-Forwarded-Proto "https"
25 | KeepAliveTimeout 75
26 | MaxKeepAliveRequests 1000
27 |
28 | {% endfor -%}
29 |
30 | Order deny,allow
31 | Allow from all
32 |
33 |
34 | Order allow,deny
35 | Allow from all
36 |
37 | {% endif -%}
38 |
--------------------------------------------------------------------------------
/hooks/charmhelpers/contrib/openstack/templates/section-audit-middleware-notifications:
--------------------------------------------------------------------------------
1 | {% if audit_middleware -%}
2 | [audit_middleware_notifications]
3 | driver = log
4 | {% endif -%}
--------------------------------------------------------------------------------
/hooks/charmhelpers/contrib/openstack/templates/section-ceph-bluestore-compression:
--------------------------------------------------------------------------------
1 | {# section header omitted as options can belong to multiple sections #}
2 | {% if bluestore_compression_algorithm -%}
3 | bluestore compression algorithm = {{ bluestore_compression_algorithm }}
4 | {% endif -%}
5 | {% if bluestore_compression_mode -%}
6 | bluestore compression mode = {{ bluestore_compression_mode }}
7 | {% endif -%}
8 | {% if bluestore_compression_required_ratio -%}
9 | bluestore compression required ratio = {{ bluestore_compression_required_ratio }}
10 | {% endif -%}
11 | {% if bluestore_compression_min_blob_size -%}
12 | bluestore compression min blob size = {{ bluestore_compression_min_blob_size }}
13 | {% endif -%}
14 | {% if bluestore_compression_min_blob_size_hdd -%}
15 | bluestore compression min blob size hdd = {{ bluestore_compression_min_blob_size_hdd }}
16 | {% endif -%}
17 | {% if bluestore_compression_min_blob_size_ssd -%}
18 | bluestore compression min blob size ssd = {{ bluestore_compression_min_blob_size_ssd }}
19 | {% endif -%}
20 | {% if bluestore_compression_max_blob_size -%}
21 | bluestore compression max blob size = {{ bluestore_compression_max_blob_size }}
22 | {% endif -%}
23 | {% if bluestore_compression_max_blob_size_hdd -%}
24 | bluestore compression max blob size hdd = {{ bluestore_compression_max_blob_size_hdd }}
25 | {% endif -%}
26 | {% if bluestore_compression_max_blob_size_ssd -%}
27 | bluestore compression max blob size ssd = {{ bluestore_compression_max_blob_size_ssd }}
28 | {% endif -%}
29 |
--------------------------------------------------------------------------------
/hooks/charmhelpers/contrib/openstack/templates/section-filter-audit:
--------------------------------------------------------------------------------
1 | {% if audit_middleware and service_name -%}
2 | [filter:audit]
3 | paste.filter_factory = keystonemiddleware.audit:filter_factory
4 | audit_map_file = /etc/{{ service_name }}/api_audit_map.conf
5 | service_name = {{ service_name }}
6 | {% endif -%}
--------------------------------------------------------------------------------
/hooks/charmhelpers/contrib/openstack/templates/section-keystone-authtoken:
--------------------------------------------------------------------------------
1 | {% if auth_host -%}
2 | [keystone_authtoken]
3 | auth_uri = {{ service_protocol }}://{{ service_host }}:{{ service_port }}
4 | auth_url = {{ auth_protocol }}://{{ auth_host }}:{{ auth_port }}
5 | auth_plugin = password
6 | project_domain_id = default
7 | user_domain_id = default
8 | project_name = {{ admin_tenant_name }}
9 | username = {{ admin_user }}
10 | password = {{ admin_password }}
11 | signing_dir = {{ signing_dir }}
12 | {% if service_type -%}
13 | service_type = {{ service_type }}
14 | {% endif -%}
15 | {% if admin_role -%}
16 | service_token_roles = {{ admin_role }}
17 | service_token_roles_required = True
18 | {% endif -%}
19 | {% endif -%}
20 |
--------------------------------------------------------------------------------
/hooks/charmhelpers/contrib/openstack/templates/section-keystone-authtoken-legacy:
--------------------------------------------------------------------------------
1 | {% if auth_host -%}
2 | [keystone_authtoken]
3 | # Juno specific config (Bug #1557223)
4 | auth_uri = {{ service_protocol }}://{{ service_host }}:{{ service_port }}/{{ service_admin_prefix }}
5 | identity_uri = {{ auth_protocol }}://{{ auth_host }}:{{ auth_port }}
6 | admin_tenant_name = {{ admin_tenant_name }}
7 | admin_user = {{ admin_user }}
8 | admin_password = {{ admin_password }}
9 | signing_dir = {{ signing_dir }}
10 | {% endif -%}
11 |
--------------------------------------------------------------------------------
/hooks/charmhelpers/contrib/openstack/templates/section-keystone-authtoken-mitaka:
--------------------------------------------------------------------------------
1 | {% if auth_host -%}
2 | [keystone_authtoken]
3 | auth_type = password
4 | {% if api_version == "3" -%}
5 | auth_uri = {{ service_protocol }}://{{ service_host }}:{{ service_port }}/v3
6 | auth_url = {{ auth_protocol }}://{{ auth_host }}:{{ auth_port }}/v3
7 | project_domain_name = {{ admin_domain_name }}
8 | user_domain_name = {{ admin_domain_name }}
9 | {% if service_type -%}
10 | service_type = {{ service_type }}
11 | {% endif -%}
12 | {% else -%}
13 | auth_uri = {{ service_protocol }}://{{ service_host }}:{{ service_port }}
14 | auth_url = {{ auth_protocol }}://{{ auth_host }}:{{ auth_port }}
15 | project_domain_name = default
16 | user_domain_name = default
17 | {% endif -%}
18 | project_name = {{ admin_tenant_name }}
19 | username = {{ admin_user }}
20 | password = {{ admin_password }}
21 | signing_dir = {{ signing_dir }}
22 | {% if use_memcache == true %}
23 | memcached_servers = {{ memcache_url }}
24 | {% endif -%}
25 | {% if admin_role -%}
26 | service_token_roles = {{ admin_role }}
27 | service_token_roles_required = True
28 | {% endif -%}
29 | {% endif -%}
30 |
--------------------------------------------------------------------------------
/hooks/charmhelpers/contrib/openstack/templates/section-keystone-authtoken-v3only:
--------------------------------------------------------------------------------
1 | {% if auth_host -%}
2 | [keystone_authtoken]
3 | {% for option_name, option_value in keystone_authtoken.items() -%}
4 | {{ option_name }} = {{ option_value }}
5 | {% endfor -%}
6 | {% if use_memcache == true %}
7 | memcached_servers = {{ memcache_url }}
8 | {% endif -%}
9 | {% endif -%}
10 |
--------------------------------------------------------------------------------
/hooks/charmhelpers/contrib/openstack/templates/section-oslo-cache:
--------------------------------------------------------------------------------
1 | [cache]
2 | {% if memcache_url %}
3 | enabled = true
4 | backend = oslo_cache.memcache_pool
5 | memcache_servers = {{ memcache_url }}
6 | {% endif %}
7 |
--------------------------------------------------------------------------------
/hooks/charmhelpers/contrib/openstack/templates/section-oslo-messaging-rabbit:
--------------------------------------------------------------------------------
1 | [oslo_messaging_rabbit]
2 | {% if rabbitmq_ha_queues -%}
3 | rabbit_ha_queues = True
4 | {% endif -%}
5 | {% if rabbit_ssl_port -%}
6 | ssl = True
7 | {% endif -%}
8 | {% if rabbit_ssl_ca -%}
9 | ssl_ca_file = {{ rabbit_ssl_ca }}
10 | {% endif -%}
11 |
--------------------------------------------------------------------------------
/hooks/charmhelpers/contrib/openstack/templates/section-oslo-messaging-rabbit-ocata:
--------------------------------------------------------------------------------
1 | [oslo_messaging_rabbit]
2 | {% if rabbitmq_ha_queues -%}
3 | rabbit_ha_queues = True
4 | {% endif -%}
5 | {% if rabbit_ssl_port -%}
6 | rabbit_use_ssl = True
7 | {% endif -%}
8 | {% if rabbit_ssl_ca -%}
9 | ssl_ca_file = {{ rabbit_ssl_ca }}
10 | {% endif -%}
11 |
--------------------------------------------------------------------------------
/hooks/charmhelpers/contrib/openstack/templates/section-oslo-middleware:
--------------------------------------------------------------------------------
1 | [oslo_middleware]
2 |
3 | # Bug #1758675
4 | enable_proxy_headers_parsing = true
5 |
6 |
--------------------------------------------------------------------------------
/hooks/charmhelpers/contrib/openstack/templates/section-oslo-notifications:
--------------------------------------------------------------------------------
1 | {% if transport_url -%}
2 | [oslo_messaging_notifications]
3 | driver = {{ oslo_messaging_driver }}
4 | transport_url = {{ transport_url }}
5 | {% if send_notifications_to_logs %}
6 | driver = log
7 | {% endif %}
8 | {% if notification_topics -%}
9 | topics = {{ notification_topics }}
10 | {% endif -%}
11 | {% if notification_format -%}
12 | [notifications]
13 | notification_format = {{ notification_format }}
14 | {% endif -%}
15 | {% endif -%}
16 |
--------------------------------------------------------------------------------
/hooks/charmhelpers/contrib/openstack/templates/section-placement:
--------------------------------------------------------------------------------
1 | [placement]
2 | {% if auth_host -%}
3 | auth_url = {{ auth_protocol }}://{{ auth_host }}:{{ auth_port }}
4 | auth_type = password
5 | {% if api_version == "3" -%}
6 | project_domain_name = {{ admin_domain_name }}
7 | user_domain_name = {{ admin_domain_name }}
8 | {% else -%}
9 | project_domain_name = default
10 | user_domain_name = default
11 | {% endif -%}
12 | project_name = {{ admin_tenant_name }}
13 | username = {{ admin_user }}
14 | password = {{ admin_password }}
15 | {% endif -%}
16 | {% if region -%}
17 | os_region_name = {{ region }}
18 | region_name = {{ region }}
19 | {% endif -%}
20 | randomize_allocation_candidates = true
21 |
--------------------------------------------------------------------------------
/hooks/charmhelpers/contrib/openstack/templates/section-rabbitmq-oslo:
--------------------------------------------------------------------------------
1 | {% if rabbitmq_host or rabbitmq_hosts -%}
2 | [oslo_messaging_rabbit]
3 | rabbit_userid = {{ rabbitmq_user }}
4 | rabbit_virtual_host = {{ rabbitmq_virtual_host }}
5 | rabbit_password = {{ rabbitmq_password }}
6 | {% if rabbitmq_hosts -%}
7 | rabbit_hosts = {{ rabbitmq_hosts }}
8 | {% if rabbitmq_ha_queues -%}
9 | rabbit_ha_queues = True
10 | rabbit_durable_queues = False
11 | {% endif -%}
12 | {% else -%}
13 | rabbit_host = {{ rabbitmq_host }}
14 | {% endif -%}
15 | {% if rabbit_ssl_port -%}
16 | rabbit_use_ssl = True
17 | rabbit_port = {{ rabbit_ssl_port }}
18 | {% if rabbit_ssl_ca -%}
19 | kombu_ssl_ca_certs = {{ rabbit_ssl_ca }}
20 | {% endif -%}
21 | {% endif -%}
22 | {% endif -%}
23 |
--------------------------------------------------------------------------------
/hooks/charmhelpers/contrib/openstack/templates/section-service-user:
--------------------------------------------------------------------------------
1 | {% if auth_host -%}
2 | [service_user]
3 | send_service_user_token = true
4 | auth_type = password
5 | auth_url = {{ auth_protocol }}://{{ auth_host }}:{{ auth_port }}
6 | project_domain_name = service_domain
7 | user_domain_name = service_domain
8 | project_name = {{ admin_tenant_name }}
9 | username = {{ admin_user }}
10 | password = {{ admin_password }}
11 | {% endif -%}
12 |
--------------------------------------------------------------------------------
/hooks/charmhelpers/contrib/openstack/templates/section-zeromq:
--------------------------------------------------------------------------------
1 | {% if zmq_host -%}
2 | # ZeroMQ configuration (restart-nonce: {{ zmq_nonce }})
3 | rpc_backend = zmq
4 | rpc_zmq_host = {{ zmq_host }}
5 | {% if zmq_redis_address -%}
6 | rpc_zmq_matchmaker = redis
7 | matchmaker_heartbeat_freq = 15
8 | matchmaker_heartbeat_ttl = 30
9 | [matchmaker_redis]
10 | host = {{ zmq_redis_address }}
11 | {% else -%}
12 | rpc_zmq_matchmaker = ring
13 | {% endif -%}
14 | {% endif -%}
15 |
--------------------------------------------------------------------------------
/hooks/charmhelpers/contrib/openstack/templates/vendor_data.json:
--------------------------------------------------------------------------------
1 | {{ vendor_data_json }}
--------------------------------------------------------------------------------
/hooks/charmhelpers/contrib/python.py:
--------------------------------------------------------------------------------
1 | # Copyright 2014-2019 Canonical Limited.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | # deprecated aliases for backwards compatibility
16 | from charmhelpers.fetch.python import debug # noqa
17 | from charmhelpers.fetch.python import packages # noqa
18 | from charmhelpers.fetch.python import rpdb # noqa
19 | from charmhelpers.fetch.python import version # noqa
20 |
--------------------------------------------------------------------------------
/hooks/charmhelpers/contrib/storage/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2014-2015 Canonical Limited.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
--------------------------------------------------------------------------------
/hooks/charmhelpers/contrib/storage/linux/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2014-2015 Canonical Limited.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
--------------------------------------------------------------------------------
/hooks/charmhelpers/contrib/storage/linux/bcache.py:
--------------------------------------------------------------------------------
1 | # Copyright 2017 Canonical Limited.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 | import os
15 | import json
16 |
17 | from charmhelpers.core.hookenv import log
18 |
19 | stats_intervals = ['stats_day', 'stats_five_minute',
20 | 'stats_hour', 'stats_total']
21 |
22 | SYSFS = '/sys'
23 |
24 |
25 | class Bcache(object):
26 | """Bcache behaviour
27 | """
28 |
29 | def __init__(self, cachepath):
30 | self.cachepath = cachepath
31 |
32 | @classmethod
33 | def fromdevice(cls, devname):
34 | return cls('{}/block/{}/bcache'.format(SYSFS, devname))
35 |
36 | def __str__(self):
37 | return self.cachepath
38 |
39 | def get_stats(self, interval):
40 | """Get cache stats
41 | """
42 | intervaldir = 'stats_{}'.format(interval)
43 | path = "{}/{}".format(self.cachepath, intervaldir)
44 | out = dict()
45 | for elem in os.listdir(path):
46 | out[elem] = open('{}/{}'.format(path, elem)).read().strip()
47 | return out
48 |
49 |
50 | def get_bcache_fs():
51 | """Return all cache sets
52 | """
53 | cachesetroot = "{}/fs/bcache".format(SYSFS)
54 | try:
55 | dirs = os.listdir(cachesetroot)
56 | except OSError:
57 | log("No bcache fs found")
58 | return []
59 | cacheset = set([Bcache('{}/{}'.format(cachesetroot, d)) for d in dirs if not d.startswith('register')])
60 | return cacheset
61 |
62 |
63 | def get_stats_action(cachespec, interval):
64 | """Action for getting bcache statistics for a given cachespec.
65 | Cachespec can either be a device name, eg. 'sdb', which will retrieve
66 | cache stats for the given device, or 'global', which will retrieve stats
67 | for all cachesets
68 | """
69 | if cachespec == 'global':
70 | caches = get_bcache_fs()
71 | else:
72 | caches = [Bcache.fromdevice(cachespec)]
73 | res = dict((c.cachepath, c.get_stats(interval)) for c in caches)
74 | return json.dumps(res, indent=4, separators=(',', ': '))
75 |
--------------------------------------------------------------------------------
/hooks/charmhelpers/contrib/storage/linux/loopback.py:
--------------------------------------------------------------------------------
1 | # Copyright 2014-2015 Canonical Limited.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | import os
16 | import re
17 | from subprocess import (
18 | check_call,
19 | check_output,
20 | )
21 |
22 |
23 | ##################################################
24 | # loopback device helpers.
25 | ##################################################
26 | def loopback_devices():
27 | '''
28 | Parse through 'losetup -a' output to determine currently mapped
29 | loopback devices. Output is expected to look like:
30 |
31 | /dev/loop0: [0807]:961814 (/tmp/my.img)
32 |
33 | or:
34 |
35 | /dev/loop0: [0807]:961814 (/tmp/my.img (deleted))
36 |
37 | :returns: dict: a dict mapping {loopback_dev: backing_file}
38 | '''
39 | loopbacks = {}
40 | cmd = ['losetup', '-a']
41 | output = check_output(cmd).decode('utf-8')
42 | devs = [d.strip().split(' ', 2) for d in output.splitlines() if d != '']
43 | for dev, _, f in devs:
44 | loopbacks[dev.replace(':', '')] = re.search(r'\((.+)\)', f).groups()[0]
45 | return loopbacks
46 |
47 |
48 | def create_loopback(file_path):
49 | '''
50 | Create a loopback device for a given backing file.
51 |
52 | :returns: str: Full path to new loopback device (eg, /dev/loop0)
53 | '''
54 | file_path = os.path.abspath(file_path)
55 | check_call(['losetup', '--find', file_path])
56 | for d, f in loopback_devices().items():
57 | if f == file_path:
58 | return d
59 |
60 |
61 | def ensure_loopback_device(path, size):
62 | '''
63 | Ensure a loopback device exists for a given backing file path and size.
64 | If it a loopback device is not mapped to file, a new one will be created.
65 |
66 | TODO: Confirm size of found loopback device.
67 |
68 | :returns: str: Full path to the ensured loopback device (eg, /dev/loop0)
69 | '''
70 | for d, f in loopback_devices().items():
71 | if f == path:
72 | return d
73 |
74 | if not os.path.exists(path):
75 | cmd = ['truncate', '--size', size, path]
76 | check_call(cmd)
77 |
78 | return create_loopback(path)
79 |
80 |
81 | def is_mapped_loopback_device(device):
82 | """
83 | Checks if a given device name is an existing/mapped loopback device.
84 | :param device: str: Full path to the device (eg, /dev/loop1).
85 | :returns: str: Path to the backing file if is a loopback device
86 | empty string otherwise
87 | """
88 | return loopback_devices().get(device, "")
89 |
--------------------------------------------------------------------------------
/hooks/charmhelpers/core/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2014-2015 Canonical Limited.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
--------------------------------------------------------------------------------
/hooks/charmhelpers/core/files.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 |
4 | # Copyright 2014-2015 Canonical Limited.
5 | #
6 | # Licensed under the Apache License, Version 2.0 (the "License");
7 | # you may not use this file except in compliance with the License.
8 | # You may obtain a copy of the License at
9 | #
10 | # http://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing, software
13 | # distributed under the License is distributed on an "AS IS" BASIS,
14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | # See the License for the specific language governing permissions and
16 | # limitations under the License.
17 |
18 | __author__ = 'Jorge Niedbalski '
19 |
20 | import os
21 | import subprocess
22 |
23 |
24 | def sed(filename, before, after, flags='g'):
25 | """
26 | Search and replaces the given pattern on filename.
27 |
28 | :param filename: relative or absolute file path.
29 | :param before: expression to be replaced (see 'man sed')
30 | :param after: expression to replace with (see 'man sed')
31 | :param flags: sed-compatible regex flags in example, to make
32 | the search and replace case insensitive, specify ``flags="i"``.
33 | The ``g`` flag is always specified regardless, so you do not
34 | need to remember to include it when overriding this parameter.
35 | :returns: If the sed command exit code was zero then return,
36 | otherwise raise CalledProcessError.
37 | """
38 | expression = r's/{0}/{1}/{2}'.format(before,
39 | after, flags)
40 |
41 | return subprocess.check_call(["sed", "-i", "-r", "-e",
42 | expression,
43 | os.path.expanduser(filename)])
44 |
--------------------------------------------------------------------------------
/hooks/charmhelpers/core/host_factory/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstack/charm-neutron-api/6d5021e58d06e8fc112000b9e9867b4a898222fb/hooks/charmhelpers/core/host_factory/__init__.py
--------------------------------------------------------------------------------
/hooks/charmhelpers/core/host_factory/centos.py:
--------------------------------------------------------------------------------
1 | import subprocess
2 | import yum
3 | import os
4 |
5 | from charmhelpers.core.strutils import BasicStringComparator
6 |
7 |
8 | class CompareHostReleases(BasicStringComparator):
9 | """Provide comparisons of Host releases.
10 |
11 | Use in the form of
12 |
13 | if CompareHostReleases(release) > 'trusty':
14 | # do something with mitaka
15 | """
16 |
17 | def __init__(self, item):
18 | raise NotImplementedError(
19 | "CompareHostReleases() is not implemented for CentOS")
20 |
21 |
22 | def service_available(service_name):
23 | # """Determine whether a system service is available."""
24 | if os.path.isdir('/run/systemd/system'):
25 | cmd = ['systemctl', 'is-enabled', service_name]
26 | else:
27 | cmd = ['service', service_name, 'is-enabled']
28 | return subprocess.call(cmd) == 0
29 |
30 |
31 | def add_new_group(group_name, system_group=False, gid=None):
32 | cmd = ['groupadd']
33 | if gid:
34 | cmd.extend(['--gid', str(gid)])
35 | if system_group:
36 | cmd.append('-r')
37 | cmd.append(group_name)
38 | subprocess.check_call(cmd)
39 |
40 |
41 | def lsb_release():
42 | """Return /etc/os-release in a dict."""
43 | d = {}
44 | with open('/etc/os-release', 'r') as lsb:
45 | for l in lsb:
46 | s = l.split('=')
47 | if len(s) != 2:
48 | continue
49 | d[s[0].strip()] = s[1].strip()
50 | return d
51 |
52 |
53 | def cmp_pkgrevno(package, revno, pkgcache=None):
54 | """Compare supplied revno with the revno of the installed package.
55 |
56 | * 1 => Installed revno is greater than supplied arg
57 | * 0 => Installed revno is the same as supplied arg
58 | * -1 => Installed revno is less than supplied arg
59 |
60 | This function imports YumBase function if the pkgcache argument
61 | is None.
62 | """
63 | if not pkgcache:
64 | y = yum.YumBase()
65 | packages = y.doPackageLists()
66 | pkgcache = {i.Name: i.version for i in packages['installed']}
67 | pkg = pkgcache[package]
68 | if pkg > revno:
69 | return 1
70 | if pkg < revno:
71 | return -1
72 | return 0
73 |
--------------------------------------------------------------------------------
/hooks/charmhelpers/core/hugepage.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | # Copyright 2014-2015 Canonical Limited.
4 | #
5 | # Licensed under the Apache License, Version 2.0 (the "License");
6 | # you may not use this file except in compliance with the License.
7 | # You may obtain a copy of the License at
8 | #
9 | # http://www.apache.org/licenses/LICENSE-2.0
10 | #
11 | # Unless required by applicable law or agreed to in writing, software
12 | # distributed under the License is distributed on an "AS IS" BASIS,
13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | # See the License for the specific language governing permissions and
15 | # limitations under the License.
16 |
17 | import yaml
18 | from charmhelpers.core import fstab
19 | from charmhelpers.core import sysctl
20 | from charmhelpers.core.host import (
21 | add_group,
22 | add_user_to_group,
23 | fstab_mount,
24 | mkdir,
25 | )
26 | from charmhelpers.core.strutils import bytes_from_string
27 | from subprocess import check_output
28 |
29 |
30 | def hugepage_support(user, group='hugetlb', nr_hugepages=256,
31 | max_map_count=65536, mnt_point='/run/hugepages/kvm',
32 | pagesize='2MB', mount=True, set_shmmax=False):
33 | """Enable hugepages on system.
34 |
35 | Args:
36 | user (str) -- Username to allow access to hugepages to
37 | group (str) -- Group name to own hugepages
38 | nr_hugepages (int) -- Number of pages to reserve
39 | max_map_count (int) -- Number of Virtual Memory Areas a process can own
40 | mnt_point (str) -- Directory to mount hugepages on
41 | pagesize (str) -- Size of hugepages
42 | mount (bool) -- Whether to Mount hugepages
43 | """
44 | group_info = add_group(group)
45 | gid = group_info.gr_gid
46 | add_user_to_group(user, group)
47 | if max_map_count < 2 * nr_hugepages:
48 | max_map_count = 2 * nr_hugepages
49 | sysctl_settings = {
50 | 'vm.nr_hugepages': nr_hugepages,
51 | 'vm.max_map_count': max_map_count,
52 | 'vm.hugetlb_shm_group': gid,
53 | }
54 | if set_shmmax:
55 | shmmax_current = int(check_output(['sysctl', '-n', 'kernel.shmmax']))
56 | shmmax_minsize = bytes_from_string(pagesize) * nr_hugepages
57 | if shmmax_minsize > shmmax_current:
58 | sysctl_settings['kernel.shmmax'] = shmmax_minsize
59 | sysctl.create(yaml.dump(sysctl_settings), '/etc/sysctl.d/10-hugepage.conf')
60 | mkdir(mnt_point, owner='root', group='root', perms=0o755, force=False)
61 | lfstab = fstab.Fstab()
62 | fstab_entry = lfstab.get_entry_by_attr('mountpoint', mnt_point)
63 | if fstab_entry:
64 | lfstab.remove_entry(fstab_entry)
65 | entry = lfstab.Entry('nodev', mnt_point, 'hugetlbfs',
66 | 'mode=1770,gid={},pagesize={}'.format(gid, pagesize), 0, 0)
67 | lfstab.add_entry(entry)
68 | if mount:
69 | fstab_mount(mnt_point)
70 |
--------------------------------------------------------------------------------
/hooks/charmhelpers/core/kernel.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 |
4 | # Copyright 2014-2015 Canonical Limited.
5 | #
6 | # Licensed under the Apache License, Version 2.0 (the "License");
7 | # you may not use this file except in compliance with the License.
8 | # You may obtain a copy of the License at
9 | #
10 | # http://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing, software
13 | # distributed under the License is distributed on an "AS IS" BASIS,
14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | # See the License for the specific language governing permissions and
16 | # limitations under the License.
17 |
18 | import re
19 | import subprocess
20 |
21 | from charmhelpers.osplatform import get_platform
22 | from charmhelpers.core.hookenv import (
23 | log,
24 | INFO
25 | )
26 |
27 | __platform__ = get_platform()
28 | if __platform__ == "ubuntu":
29 | from charmhelpers.core.kernel_factory.ubuntu import ( # NOQA:F401
30 | persistent_modprobe,
31 | update_initramfs,
32 | ) # flake8: noqa -- ignore F401 for this import
33 | elif __platform__ == "centos":
34 | from charmhelpers.core.kernel_factory.centos import ( # NOQA:F401
35 | persistent_modprobe,
36 | update_initramfs,
37 | ) # flake8: noqa -- ignore F401 for this import
38 |
39 | __author__ = "Jorge Niedbalski "
40 |
41 |
42 | def modprobe(module, persist=True):
43 | """Load a kernel module and configure for auto-load on reboot."""
44 | cmd = ['modprobe', module]
45 |
46 | log('Loading kernel module %s' % module, level=INFO)
47 |
48 | subprocess.check_call(cmd)
49 | if persist:
50 | persistent_modprobe(module)
51 |
52 |
53 | def rmmod(module, force=False):
54 | """Remove a module from the linux kernel"""
55 | cmd = ['rmmod']
56 | if force:
57 | cmd.append('-f')
58 | cmd.append(module)
59 | log('Removing kernel module %s' % module, level=INFO)
60 | return subprocess.check_call(cmd)
61 |
62 |
63 | def lsmod():
64 | """Shows what kernel modules are currently loaded"""
65 | return subprocess.check_output(['lsmod'],
66 | universal_newlines=True)
67 |
68 |
69 | def is_module_loaded(module):
70 | """Checks if a kernel module is already loaded"""
71 | matches = re.findall('^%s[ ]+' % module, lsmod(), re.M)
72 | return len(matches) > 0
73 |
--------------------------------------------------------------------------------
/hooks/charmhelpers/core/kernel_factory/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstack/charm-neutron-api/6d5021e58d06e8fc112000b9e9867b4a898222fb/hooks/charmhelpers/core/kernel_factory/__init__.py
--------------------------------------------------------------------------------
/hooks/charmhelpers/core/kernel_factory/centos.py:
--------------------------------------------------------------------------------
1 | import subprocess
2 | import os
3 |
4 |
5 | def persistent_modprobe(module):
6 | """Load a kernel module and configure for auto-load on reboot."""
7 | if not os.path.exists('/etc/rc.modules'):
8 | open('/etc/rc.modules', 'a')
9 | os.chmod('/etc/rc.modules', 111)
10 | with open('/etc/rc.modules', 'r+') as modules:
11 | if module not in modules.read():
12 | modules.write('modprobe %s\n' % module)
13 |
14 |
15 | def update_initramfs(version='all'):
16 | """Updates an initramfs image."""
17 | return subprocess.check_call(["dracut", "-f", version])
18 |
--------------------------------------------------------------------------------
/hooks/charmhelpers/core/kernel_factory/ubuntu.py:
--------------------------------------------------------------------------------
1 | import subprocess
2 |
3 |
4 | def persistent_modprobe(module):
5 | """Load a kernel module and configure for auto-load on reboot."""
6 | with open('/etc/modules', 'r+') as modules:
7 | if module not in modules.read():
8 | modules.write(module + "\n")
9 |
10 |
11 | def update_initramfs(version='all'):
12 | """Updates an initramfs image."""
13 | return subprocess.check_call(["update-initramfs", "-k", version, "-u"])
14 |
--------------------------------------------------------------------------------
/hooks/charmhelpers/core/services/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2014-2015 Canonical Limited.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | from .base import * # NOQA
16 | from .helpers import * # NOQA
17 |
--------------------------------------------------------------------------------
/hooks/charmhelpers/core/sysctl.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 |
4 | # Copyright 2014-2015 Canonical Limited.
5 | #
6 | # Licensed under the Apache License, Version 2.0 (the "License");
7 | # you may not use this file except in compliance with the License.
8 | # You may obtain a copy of the License at
9 | #
10 | # http://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing, software
13 | # distributed under the License is distributed on an "AS IS" BASIS,
14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | # See the License for the specific language governing permissions and
16 | # limitations under the License.
17 |
18 | import yaml
19 |
20 | from subprocess import check_call, CalledProcessError
21 |
22 | from charmhelpers.core.hookenv import (
23 | log,
24 | DEBUG,
25 | ERROR,
26 | WARNING,
27 | )
28 |
29 | from charmhelpers.core.host import is_container
30 |
31 | __author__ = 'Jorge Niedbalski R. '
32 |
33 |
34 | def create(sysctl_dict, sysctl_file, ignore=False):
35 | """Creates a sysctl.conf file from a YAML associative array
36 |
37 | :param sysctl_dict: a dict or YAML-formatted string of sysctl
38 | options eg "{ 'kernel.max_pid': 1337 }"
39 | :type sysctl_dict: str
40 | :param sysctl_file: path to the sysctl file to be saved
41 | :type sysctl_file: str or unicode
42 | :param ignore: If True, ignore "unknown variable" errors.
43 | :type ignore: bool
44 | :returns: None
45 | """
46 | if type(sysctl_dict) is not dict:
47 | try:
48 | sysctl_dict_parsed = yaml.safe_load(sysctl_dict)
49 | except yaml.YAMLError:
50 | log("Error parsing YAML sysctl_dict: {}".format(sysctl_dict),
51 | level=ERROR)
52 | return
53 | else:
54 | sysctl_dict_parsed = sysctl_dict
55 |
56 | with open(sysctl_file, "w") as fd:
57 | for key, value in sysctl_dict_parsed.items():
58 | fd.write("{}={}\n".format(key, value))
59 |
60 | log("Updating sysctl_file: {} values: {}".format(sysctl_file,
61 | sysctl_dict_parsed),
62 | level=DEBUG)
63 |
64 | call = ["sysctl", "-p", sysctl_file]
65 | if ignore:
66 | call.append("-e")
67 |
68 | try:
69 | check_call(call)
70 | except CalledProcessError as e:
71 | if is_container():
72 | log("Error setting some sysctl keys in this container: {}".format(e.output),
73 | level=WARNING)
74 | else:
75 | raise e
76 |
--------------------------------------------------------------------------------
/hooks/charmhelpers/fetch/bzrurl.py:
--------------------------------------------------------------------------------
1 | # Copyright 2014-2015 Canonical Limited.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | import os
16 | from subprocess import STDOUT, check_output
17 | from charmhelpers.fetch import (
18 | BaseFetchHandler,
19 | UnhandledSource,
20 | filter_installed_packages,
21 | install,
22 | )
23 | from charmhelpers.core.host import mkdir
24 |
25 |
26 | if filter_installed_packages(['bzr']) != []:
27 | install(['bzr'])
28 | if filter_installed_packages(['bzr']) != []:
29 | raise NotImplementedError('Unable to install bzr')
30 |
31 |
32 | class BzrUrlFetchHandler(BaseFetchHandler):
33 | """Handler for bazaar branches via generic and lp URLs."""
34 |
35 | def can_handle(self, source):
36 | url_parts = self.parse_url(source)
37 | if url_parts.scheme not in ('bzr+ssh', 'lp', ''):
38 | return False
39 | elif not url_parts.scheme:
40 | return os.path.exists(os.path.join(source, '.bzr'))
41 | else:
42 | return True
43 |
44 | def branch(self, source, dest, revno=None):
45 | if not self.can_handle(source):
46 | raise UnhandledSource("Cannot handle {}".format(source))
47 | cmd_opts = []
48 | if revno:
49 | cmd_opts += ['-r', str(revno)]
50 | if os.path.exists(dest):
51 | cmd = ['bzr', 'pull']
52 | cmd += cmd_opts
53 | cmd += ['--overwrite', '-d', dest, source]
54 | else:
55 | cmd = ['bzr', 'branch']
56 | cmd += cmd_opts
57 | cmd += [source, dest]
58 | check_output(cmd, stderr=STDOUT)
59 |
60 | def install(self, source, dest=None, revno=None):
61 | url_parts = self.parse_url(source)
62 | branch_name = url_parts.path.strip("/").split("/")[-1]
63 | if dest:
64 | dest_dir = os.path.join(dest, branch_name)
65 | else:
66 | dest_dir = os.path.join(os.environ.get('CHARM_DIR'), "fetched",
67 | branch_name)
68 |
69 | if dest and not os.path.exists(dest):
70 | mkdir(dest, perms=0o755)
71 |
72 | try:
73 | self.branch(source, dest_dir, revno)
74 | except OSError as e:
75 | raise UnhandledSource(e.strerror)
76 | return dest_dir
77 |
--------------------------------------------------------------------------------
/hooks/charmhelpers/fetch/giturl.py:
--------------------------------------------------------------------------------
1 | # Copyright 2014-2015 Canonical Limited.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | import os
16 | from subprocess import check_output, CalledProcessError, STDOUT
17 | from charmhelpers.fetch import (
18 | BaseFetchHandler,
19 | UnhandledSource,
20 | filter_installed_packages,
21 | install,
22 | )
23 |
24 | if filter_installed_packages(['git']) != []:
25 | install(['git'])
26 | if filter_installed_packages(['git']) != []:
27 | raise NotImplementedError('Unable to install git')
28 |
29 |
30 | class GitUrlFetchHandler(BaseFetchHandler):
31 | """Handler for git branches via generic and github URLs."""
32 |
33 | def can_handle(self, source):
34 | url_parts = self.parse_url(source)
35 | # TODO (mattyw) no support for ssh git@ yet
36 | if url_parts.scheme not in ('http', 'https', 'git', ''):
37 | return False
38 | elif not url_parts.scheme:
39 | return os.path.exists(os.path.join(source, '.git'))
40 | else:
41 | return True
42 |
43 | def clone(self, source, dest, branch="master", depth=None):
44 | if not self.can_handle(source):
45 | raise UnhandledSource("Cannot handle {}".format(source))
46 |
47 | if os.path.exists(dest):
48 | cmd = ['git', '-C', dest, 'pull', source, branch]
49 | else:
50 | cmd = ['git', 'clone', source, dest, '--branch', branch]
51 | if depth:
52 | cmd.extend(['--depth', depth])
53 | check_output(cmd, stderr=STDOUT)
54 |
55 | def install(self, source, branch="master", dest=None, depth=None):
56 | url_parts = self.parse_url(source)
57 | branch_name = url_parts.path.strip("/").split("/")[-1]
58 | if dest:
59 | dest_dir = os.path.join(dest, branch_name)
60 | else:
61 | dest_dir = os.path.join(os.environ.get('CHARM_DIR'), "fetched",
62 | branch_name)
63 | try:
64 | self.clone(source, dest_dir, branch, depth)
65 | except CalledProcessError as e:
66 | raise UnhandledSource(e)
67 | except OSError as e:
68 | raise UnhandledSource(e.strerror)
69 | return dest_dir
70 |
--------------------------------------------------------------------------------
/hooks/charmhelpers/fetch/python/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2014-2019 Canonical Limited.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
--------------------------------------------------------------------------------
/hooks/charmhelpers/fetch/python/debug.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # coding: utf-8
3 |
4 | # Copyright 2014-2015 Canonical Limited.
5 | #
6 | # Licensed under the Apache License, Version 2.0 (the "License");
7 | # you may not use this file except in compliance with the License.
8 | # You may obtain a copy of the License at
9 | #
10 | # http://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing, software
13 | # distributed under the License is distributed on an "AS IS" BASIS,
14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | # See the License for the specific language governing permissions and
16 | # limitations under the License.
17 |
18 | import atexit
19 | import sys
20 |
21 | from charmhelpers.fetch.python.rpdb import Rpdb
22 | from charmhelpers.core.hookenv import (
23 | open_port,
24 | close_port,
25 | ERROR,
26 | log
27 | )
28 |
29 | __author__ = "Jorge Niedbalski "
30 |
31 | DEFAULT_ADDR = "0.0.0.0"
32 | DEFAULT_PORT = 4444
33 |
34 |
35 | def _error(message):
36 | log(message, level=ERROR)
37 |
38 |
39 | def set_trace(addr=DEFAULT_ADDR, port=DEFAULT_PORT):
40 | """
41 | Set a trace point using the remote debugger
42 | """
43 | atexit.register(close_port, port)
44 | try:
45 | log("Starting a remote python debugger session on %s:%s" % (addr,
46 | port))
47 | open_port(port)
48 | debugger = Rpdb(addr=addr, port=port)
49 | debugger.set_trace(sys._getframe().f_back)
50 | except Exception:
51 | _error("Cannot start a remote debug session on %s:%s" % (addr,
52 | port))
53 |
--------------------------------------------------------------------------------
/hooks/charmhelpers/fetch/python/rpdb.py:
--------------------------------------------------------------------------------
1 | # Copyright 2014-2015 Canonical Limited.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | """Remote Python Debugger (pdb wrapper)."""
16 |
17 | import pdb
18 | import socket
19 | import sys
20 |
21 | __author__ = "Bertrand Janin "
22 | __version__ = "0.1.3"
23 |
24 |
25 | class Rpdb(pdb.Pdb):
26 |
27 | def __init__(self, addr="127.0.0.1", port=4444):
28 | """Initialize the socket and initialize pdb."""
29 |
30 | # Backup stdin and stdout before replacing them by the socket handle
31 | self.old_stdout = sys.stdout
32 | self.old_stdin = sys.stdin
33 |
34 | # Open a 'reusable' socket to let the webapp reload on the same port
35 | self.skt = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
36 | self.skt.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
37 | self.skt.bind((addr, port))
38 | self.skt.listen(1)
39 | (clientsocket, address) = self.skt.accept()
40 | handle = clientsocket.makefile('rw')
41 | pdb.Pdb.__init__(self, completekey='tab', stdin=handle, stdout=handle)
42 | sys.stdout = sys.stdin = handle
43 |
44 | def shutdown(self):
45 | """Revert stdin and stdout, close the socket."""
46 | sys.stdout = self.old_stdout
47 | sys.stdin = self.old_stdin
48 | self.skt.close()
49 | self.set_continue()
50 |
51 | def do_continue(self, arg):
52 | """Stop all operation on ``continue``."""
53 | self.shutdown()
54 | return 1
55 |
56 | do_EOF = do_quit = do_exit = do_c = do_cont = do_continue
57 |
--------------------------------------------------------------------------------
/hooks/charmhelpers/fetch/python/version.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # coding: utf-8
3 |
4 | # Copyright 2014-2015 Canonical Limited.
5 | #
6 | # Licensed under the Apache License, Version 2.0 (the "License");
7 | # you may not use this file except in compliance with the License.
8 | # You may obtain a copy of the License at
9 | #
10 | # http://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing, software
13 | # distributed under the License is distributed on an "AS IS" BASIS,
14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | # See the License for the specific language governing permissions and
16 | # limitations under the License.
17 |
18 | import sys
19 |
20 | __author__ = "Jorge Niedbalski "
21 |
22 |
23 | def current_version():
24 | """Current system python version"""
25 | return sys.version_info
26 |
27 |
28 | def current_version_string():
29 | """Current system python version as string major.minor.micro"""
30 | return "{0}.{1}.{2}".format(sys.version_info.major,
31 | sys.version_info.minor,
32 | sys.version_info.micro)
33 |
--------------------------------------------------------------------------------
/hooks/charmhelpers/osplatform.py:
--------------------------------------------------------------------------------
1 | import platform
2 | import os
3 |
4 |
5 | def get_platform():
6 | """Return the current OS platform.
7 |
8 | For example: if current os platform is Ubuntu then a string "ubuntu"
9 | will be returned (which is the name of the module).
10 | This string is used to decide which platform module should be imported.
11 | """
12 | current_platform = _get_current_platform()
13 |
14 | if "Ubuntu" in current_platform:
15 | return "ubuntu"
16 | elif "CentOS" in current_platform:
17 | return "centos"
18 | elif "debian" in current_platform or "Debian" in current_platform:
19 | # Stock Python does not detect Ubuntu and instead returns debian.
20 | # Or at least it does in some build environments like Travis CI
21 | return "ubuntu"
22 | elif "elementary" in current_platform:
23 | # ElementaryOS fails to run tests locally without this.
24 | return "ubuntu"
25 | elif "Pop!_OS" in current_platform:
26 | # Pop!_OS also fails to run tests locally without this.
27 | return "ubuntu"
28 | else:
29 | raise RuntimeError("This module is not supported on {}."
30 | .format(current_platform))
31 |
32 |
33 | def _get_current_platform():
34 | """Return the current platform information for the OS.
35 |
36 | Attempts to lookup linux distribution information from the platform
37 | module for releases of python < 3.7. For newer versions of python,
38 | the platform is determined from the /etc/os-release file.
39 | """
40 | # linux_distribution is deprecated and will be removed in Python 3.7
41 | # Warnings *not* disabled, as we certainly need to fix this.
42 | if hasattr(platform, 'linux_distribution'):
43 | tuple_platform = platform.linux_distribution()
44 | current_platform = tuple_platform[0]
45 | else:
46 | current_platform = _get_platform_from_fs()
47 |
48 | return current_platform
49 |
50 |
51 | def _get_platform_from_fs():
52 | """Get Platform from /etc/os-release."""
53 | with open(os.path.join(os.sep, 'etc', 'os-release')) as fin:
54 | content = dict(
55 | line.split('=', 1)
56 | for line in fin.read().splitlines()
57 | if '=' in line
58 | )
59 | for k, v in content.items():
60 | content[k] = v.strip('"')
61 | return content["NAME"]
62 |
--------------------------------------------------------------------------------
/hooks/charmhelpers/payload/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2014-2015 Canonical Limited.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | "Tools for working with files injected into a charm just before deployment."
16 |
--------------------------------------------------------------------------------
/hooks/charmhelpers/payload/archive.py:
--------------------------------------------------------------------------------
1 | # Copyright 2014-2015 Canonical Limited.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | import os
16 | import tarfile
17 | import zipfile
18 | from charmhelpers.core import (
19 | host,
20 | hookenv,
21 | )
22 |
23 |
24 | class ArchiveError(Exception):
25 | pass
26 |
27 |
28 | def get_archive_handler(archive_name):
29 | if os.path.isfile(archive_name):
30 | if tarfile.is_tarfile(archive_name):
31 | return extract_tarfile
32 | elif zipfile.is_zipfile(archive_name):
33 | return extract_zipfile
34 | else:
35 | # look at the file name
36 | for ext in ('.tar', '.tar.gz', '.tgz', 'tar.bz2', '.tbz2', '.tbz'):
37 | if archive_name.endswith(ext):
38 | return extract_tarfile
39 | for ext in ('.zip', '.jar'):
40 | if archive_name.endswith(ext):
41 | return extract_zipfile
42 |
43 |
44 | def archive_dest_default(archive_name):
45 | archive_file = os.path.basename(archive_name)
46 | return os.path.join(hookenv.charm_dir(), "archives", archive_file)
47 |
48 |
49 | def extract(archive_name, destpath=None):
50 | handler = get_archive_handler(archive_name)
51 | if handler:
52 | if not destpath:
53 | destpath = archive_dest_default(archive_name)
54 | if not os.path.isdir(destpath):
55 | host.mkdir(destpath)
56 | handler(archive_name, destpath)
57 | return destpath
58 | else:
59 | raise ArchiveError("No handler for archive")
60 |
61 |
62 | def extract_tarfile(archive_name, destpath):
63 | "Unpack a tar archive, optionally compressed"
64 | archive = tarfile.open(archive_name)
65 | archive.extractall(destpath)
66 |
67 |
68 | def extract_zipfile(archive_name, destpath):
69 | "Unpack a zip file"
70 | archive = zipfile.ZipFile(archive_name)
71 | archive.extractall(destpath)
72 |
--------------------------------------------------------------------------------
/hooks/charmhelpers/payload/execd.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | # Copyright 2014-2015 Canonical Limited.
4 | #
5 | # Licensed under the Apache License, Version 2.0 (the "License");
6 | # you may not use this file except in compliance with the License.
7 | # You may obtain a copy of the License at
8 | #
9 | # http://www.apache.org/licenses/LICENSE-2.0
10 | #
11 | # Unless required by applicable law or agreed to in writing, software
12 | # distributed under the License is distributed on an "AS IS" BASIS,
13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | # See the License for the specific language governing permissions and
15 | # limitations under the License.
16 |
17 | import os
18 | import sys
19 | import subprocess
20 | from charmhelpers.core import hookenv
21 |
22 |
23 | def default_execd_dir():
24 | return os.path.join(os.environ['CHARM_DIR'], 'exec.d')
25 |
26 |
27 | def execd_module_paths(execd_dir=None):
28 | """Generate a list of full paths to modules within execd_dir."""
29 | if not execd_dir:
30 | execd_dir = default_execd_dir()
31 |
32 | if not os.path.exists(execd_dir):
33 | return
34 |
35 | for subpath in os.listdir(execd_dir):
36 | module = os.path.join(execd_dir, subpath)
37 | if os.path.isdir(module):
38 | yield module
39 |
40 |
41 | def execd_submodule_paths(command, execd_dir=None):
42 | """Generate a list of full paths to the specified command within exec_dir.
43 | """
44 | for module_path in execd_module_paths(execd_dir):
45 | path = os.path.join(module_path, command)
46 | if os.access(path, os.X_OK) and os.path.isfile(path):
47 | yield path
48 |
49 |
50 | def execd_run(command, execd_dir=None, die_on_error=True, stderr=subprocess.STDOUT):
51 | """Run command for each module within execd_dir which defines it."""
52 | for submodule_path in execd_submodule_paths(command, execd_dir):
53 | try:
54 | subprocess.check_output(submodule_path, stderr=stderr,
55 | universal_newlines=True)
56 | except subprocess.CalledProcessError as e:
57 | hookenv.log("Error ({}) running {}. Output: {}".format(
58 | e.returncode, e.cmd, e.output))
59 | if die_on_error:
60 | sys.exit(e.returncode)
61 |
62 |
63 | def execd_preinstall(execd_dir=None):
64 | """Run charm-pre-install for each module within execd_dir."""
65 | execd_run('charm-pre-install', execd_dir=execd_dir)
66 |
--------------------------------------------------------------------------------
/hooks/cluster-relation-changed:
--------------------------------------------------------------------------------
1 | neutron_api_hooks.py
--------------------------------------------------------------------------------
/hooks/cluster-relation-departed:
--------------------------------------------------------------------------------
1 | neutron_api_hooks.py
--------------------------------------------------------------------------------
/hooks/cluster-relation-joined:
--------------------------------------------------------------------------------
1 | neutron_api_hooks.py
--------------------------------------------------------------------------------
/hooks/config-changed:
--------------------------------------------------------------------------------
1 | neutron_api_hooks.py
--------------------------------------------------------------------------------
/hooks/etcd-proxy-relation-broken:
--------------------------------------------------------------------------------
1 | neutron_api_hooks.py
--------------------------------------------------------------------------------
/hooks/etcd-proxy-relation-changed:
--------------------------------------------------------------------------------
1 | neutron_api_hooks.py
--------------------------------------------------------------------------------
/hooks/etcd-proxy-relation-departed:
--------------------------------------------------------------------------------
1 | neutron_api_hooks.py
--------------------------------------------------------------------------------
/hooks/etcd-proxy-relation-joined:
--------------------------------------------------------------------------------
1 | neutron_api_hooks.py
--------------------------------------------------------------------------------
/hooks/external-dns-relation-broken:
--------------------------------------------------------------------------------
1 | neutron_api_hooks.py
--------------------------------------------------------------------------------
/hooks/external-dns-relation-changed:
--------------------------------------------------------------------------------
1 | neutron_api_hooks.py
--------------------------------------------------------------------------------
/hooks/external-dns-relation-departed:
--------------------------------------------------------------------------------
1 | neutron_api_hooks.py
--------------------------------------------------------------------------------
/hooks/external-dns-relation-joined:
--------------------------------------------------------------------------------
1 | neutron_api_hooks.py
--------------------------------------------------------------------------------
/hooks/ha-relation-changed:
--------------------------------------------------------------------------------
1 | neutron_api_hooks.py
--------------------------------------------------------------------------------
/hooks/ha-relation-joined:
--------------------------------------------------------------------------------
1 | neutron_api_hooks.py
--------------------------------------------------------------------------------
/hooks/identity-service-relation-broken:
--------------------------------------------------------------------------------
1 | neutron_api_hooks.py
--------------------------------------------------------------------------------
/hooks/identity-service-relation-changed:
--------------------------------------------------------------------------------
1 | neutron_api_hooks.py
--------------------------------------------------------------------------------
/hooks/identity-service-relation-joined:
--------------------------------------------------------------------------------
1 | neutron_api_hooks.py
--------------------------------------------------------------------------------
/hooks/infoblox-neutron-relation-broken:
--------------------------------------------------------------------------------
1 | neutron_api_hooks.py
--------------------------------------------------------------------------------
/hooks/infoblox-neutron-relation-changed:
--------------------------------------------------------------------------------
1 | neutron_api_hooks.py
--------------------------------------------------------------------------------
/hooks/infoblox-neutron-relation-departed:
--------------------------------------------------------------------------------
1 | neutron_api_hooks.py
--------------------------------------------------------------------------------
/hooks/install:
--------------------------------------------------------------------------------
1 | neutron_api_hooks.py
--------------------------------------------------------------------------------
/hooks/midonet-relation-broken:
--------------------------------------------------------------------------------
1 | neutron_api_hooks.py
--------------------------------------------------------------------------------
/hooks/midonet-relation-changed:
--------------------------------------------------------------------------------
1 | neutron_api_hooks.py
--------------------------------------------------------------------------------
/hooks/midonet-relation-joined:
--------------------------------------------------------------------------------
1 | neutron_api_hooks.py
--------------------------------------------------------------------------------
/hooks/neutron-api-relation-broken:
--------------------------------------------------------------------------------
1 | neutron_api_hooks.py
--------------------------------------------------------------------------------
/hooks/neutron-api-relation-changed:
--------------------------------------------------------------------------------
1 | neutron_api_hooks.py
--------------------------------------------------------------------------------
/hooks/neutron-api-relation-joined:
--------------------------------------------------------------------------------
1 | neutron_api_hooks.py
--------------------------------------------------------------------------------
/hooks/neutron-load-balancer-relation-changed:
--------------------------------------------------------------------------------
1 | neutron_api_hooks.py
--------------------------------------------------------------------------------
/hooks/neutron-load-balancer-relation-joined:
--------------------------------------------------------------------------------
1 | neutron_api_hooks.py
--------------------------------------------------------------------------------
/hooks/neutron-plugin-api-relation-joined:
--------------------------------------------------------------------------------
1 | neutron_api_hooks.py
--------------------------------------------------------------------------------
/hooks/neutron-plugin-api-subordinate-relation-changed:
--------------------------------------------------------------------------------
1 | neutron_api_hooks.py
--------------------------------------------------------------------------------
/hooks/neutron-plugin-api-subordinate-relation-departed:
--------------------------------------------------------------------------------
1 | neutron_api_hooks.py
--------------------------------------------------------------------------------
/hooks/neutron-plugin-api-subordinate-relation-joined:
--------------------------------------------------------------------------------
1 | neutron_api_hooks.py
--------------------------------------------------------------------------------
/hooks/nrpe-external-master-relation-changed:
--------------------------------------------------------------------------------
1 | neutron_api_hooks.py
--------------------------------------------------------------------------------
/hooks/nrpe-external-master-relation-joined:
--------------------------------------------------------------------------------
1 | neutron_api_hooks.py
--------------------------------------------------------------------------------
/hooks/post-series-upgrade:
--------------------------------------------------------------------------------
1 | neutron_api_hooks.py
--------------------------------------------------------------------------------
/hooks/pre-series-upgrade:
--------------------------------------------------------------------------------
1 | neutron_api_hooks.py
--------------------------------------------------------------------------------
/hooks/shared-db-relation-broken:
--------------------------------------------------------------------------------
1 | neutron_api_hooks.py
--------------------------------------------------------------------------------
/hooks/shared-db-relation-changed:
--------------------------------------------------------------------------------
1 | neutron_api_hooks.py
--------------------------------------------------------------------------------
/hooks/shared-db-relation-joined:
--------------------------------------------------------------------------------
1 | neutron_api_hooks.py
--------------------------------------------------------------------------------
/hooks/start:
--------------------------------------------------------------------------------
1 | neutron_api_hooks.py
--------------------------------------------------------------------------------
/hooks/stop:
--------------------------------------------------------------------------------
1 | neutron_api_hooks.py
--------------------------------------------------------------------------------
/hooks/update-status:
--------------------------------------------------------------------------------
1 | neutron_api_hooks.py
--------------------------------------------------------------------------------
/hooks/upgrade-charm:
--------------------------------------------------------------------------------
1 | neutron_api_hooks.py
--------------------------------------------------------------------------------
/hooks/vsd-rest-api-relation-changed:
--------------------------------------------------------------------------------
1 | neutron_api_hooks.py
--------------------------------------------------------------------------------
/hooks/vsd-rest-api-relation-joined:
--------------------------------------------------------------------------------
1 | neutron_api_hooks.py
--------------------------------------------------------------------------------
/lib/.keep:
--------------------------------------------------------------------------------
1 | This file was created by release-tools to ensure that this empty
2 | directory is preserved in vcs re: lint check definitions in global
3 | tox.ini files. This file can be removed if/when this dir is actually in use.
4 |
--------------------------------------------------------------------------------
/metadata.yaml:
--------------------------------------------------------------------------------
1 | name: neutron-api
2 | summary: OpenStack Networking API service
3 | maintainer: OpenStack Charmers
4 | description: |
5 | Neutron is a virtual network service for OpenStack, and a part of
6 | Netstack. Just like OpenStack Nova provides an API to dynamically
7 | request and configure virtual servers, Neutron provides an API to
8 | dynamically request and configure virtual networks. These networks
9 | connect "interfaces" from other OpenStack services (e.g., virtual NICs
10 | from Nova VMs). The Neutron API supports extensions to provide
11 | advanced network capabilities (e.g., QoS, ACLs, network monitoring,
12 | etc.)
13 | .
14 | This charm provides the OpenStack Neutron API service.
15 | docs: https://discourse.charmhub.io/t/neutron-api-docs-index/10555
16 | tags:
17 | - openstack
18 | series:
19 | - jammy
20 | extra-bindings:
21 | public:
22 | admin:
23 | internal:
24 | provides:
25 | nrpe-external-master:
26 | interface: nrpe-external-master
27 | scope: container
28 | neutron-api:
29 | interface: neutron-api
30 | neutron-plugin-api:
31 | interface: neutron-plugin-api
32 | neutron-load-balancer:
33 | interface: neutron-load-balancer
34 | requires:
35 | shared-db:
36 | interface: mysql-shared
37 | amqp:
38 | interface: rabbitmq
39 | identity-service:
40 | interface: keystone
41 | ha:
42 | interface: hacluster
43 | scope: container
44 | vsd-rest-api:
45 | interface: vsd-rest-api
46 | neutron-plugin-api-subordinate:
47 | interface: neutron-plugin-api-subordinate
48 | scope: container
49 | etcd-proxy:
50 | interface: etcd-proxy
51 | midonet:
52 | interface: midonet
53 | external-dns:
54 | interface: designate
55 | infoblox-neutron:
56 | interface: infoblox
57 | scope: container
58 | certificates:
59 | interface: tls-certificates
60 | peers:
61 | cluster:
62 | interface: neutron-api-ha
63 | resources:
64 | policyd-override:
65 | type: file
66 | filename: policyd-override.zip
67 | description: The policy.d overrides file
68 |
--------------------------------------------------------------------------------
/osci.yaml:
--------------------------------------------------------------------------------
1 | - project:
2 | templates:
3 | - charm-unit-jobs-py310
4 | - charm-functional-jobs
5 | vars:
6 | needs_charm_build: true
7 | charm_build_name: neutron-api
8 | build_type: charmcraft
9 | charmcraft_channel: 3.x/beta
10 |
--------------------------------------------------------------------------------
/rename.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | charm=$(grep "charm_build_name" osci.yaml | awk '{print $2}')
3 | echo "renaming ${charm}_*.charm to ${charm}.charm"
4 | echo -n "pwd: "
5 | pwd
6 | ls -al
7 | echo "Removing bad downloaded charm maybe?"
8 | if [[ -e "${charm}.charm" ]];
9 | then
10 | rm "${charm}.charm"
11 | fi
12 | echo "Renaming charm here."
13 | mv ${charm}_*.charm ${charm}.charm
14 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | # This file is managed centrally by release-tools and should not be modified
2 | # within individual charm repos. See the 'global' dir contents for available
3 | # choices of *requirements.txt files for OpenStack Charms:
4 | # https://github.com/openstack-charmers/release-tools
5 | #
6 | # TODO: Distill the func test requirements from the lint/unit test
7 | # requirements. They are intertwined. Also, Zaza itself should specify
8 | # all of its own requirements and if it doesn't, fix it there.
9 | #
10 | pbr==5.6.0
11 | simplejson>=2.2.0
12 | netifaces>=0.10.4
13 |
14 | # NOTE: newer versions of cryptography require a Rust compiler to build,
15 | # see
16 | # * https://github.com/openstack-charmers/zaza/issues/421
17 | # * https://mail.python.org/pipermail/cryptography-dev/2021-January/001003.html
18 | #
19 | cryptography<3.4
20 |
21 | # Strange import error with newer netaddr:
22 | netaddr>0.7.16,<0.8.0
23 |
24 | Jinja2>=2.6 # BSD License (3 clause)
25 | six>=1.9.0
26 |
27 | dnspython
28 |
29 | psutil>=1.1.1,<2.0.0
30 |
--------------------------------------------------------------------------------
/setup.cfg:
--------------------------------------------------------------------------------
1 | [metadata]
2 | name = charm-neutron-api
3 | summary = Charm module for OpenStack Neutron API
4 | description_file =
5 | README.md
6 | author = OpenStack
7 | author_email = openstack-discuss@lists.openstack.org
8 | home_page = https://docs.openstack.org/charm-guide/latest/
9 | classifier =
10 | Intended Audience :: Developers
11 | Intended Audience :: System Administrators
12 | License :: OSI Approved :: Apache Software License
13 | Operating System :: POSIX :: Linux
14 | Programming Language :: Python
15 | Programming Language :: Python :: 3
16 | Programming Language :: Python :: 3.5
17 | Programming Language :: Python :: 3.6
18 | Programming Language :: Python :: 3.7
19 |
20 | [nosetests]
21 | verbosity=1
22 | with-coverage=1
23 | cover-erase=1
24 | cover-package=hooks
25 |
--------------------------------------------------------------------------------
/templates/api-paste.ini:
--------------------------------------------------------------------------------
1 | [composite:neutron]
2 | use = egg:Paste#urlmap
3 | /: neutronversions
4 | /v2.0: neutronapi_v2_0
5 |
6 | [composite:neutronapi_v2_0]
7 | use = call:neutron.auth:pipeline_factory
8 | noauth = request_id catch_errors extensions neutronapiapp_v2_0
9 | keystone = {% for m in extra_middleware %}{{ m.name }} {% endfor %}request_id catch_errors authtoken keystonecontext extensions neutronapiapp_v2_0
10 |
11 | {% for m in extra_middleware -%}
12 | [{{ m.type }}:{{ m.name }}]
13 | {% for k, v in m.config.items() -%}
14 | {{ k }} = {{ v }}
15 | {% endfor %}
16 | {% endfor -%}
17 |
18 | [filter:request_id]
19 | paste.filter_factory = neutron.openstack.common.middleware.request_id:RequestIdMiddleware.factory
20 |
21 | [filter:catch_errors]
22 | paste.filter_factory = neutron.openstack.common.middleware.catch_errors:CatchErrorsMiddleware.factory
23 |
24 | [filter:keystonecontext]
25 | paste.filter_factory = neutron.auth:NeutronKeystoneContext.factory
26 |
27 | [filter:authtoken]
28 | paste.filter_factory = keystoneclient.middleware.auth_token:filter_factory
29 |
30 | [filter:extensions]
31 | paste.filter_factory = neutron.api.extensions:plugin_aware_extension_middleware_factory
32 |
33 | [app:neutronversions]
34 | paste.app_factory = neutron.api.versions:Versions.factory
35 |
36 | [app:neutronapiapp_v2_0]
37 | paste.app_factory = neutron.api.v2.router:APIRouter.factory
38 |
--------------------------------------------------------------------------------
/templates/etcd:
--------------------------------------------------------------------------------
1 | ETCD_PROXY=on
2 | ETCD_INITIAL_CLUSTER={{ cluster }}
3 | ETCD_DATA_DIR=/var/lib/etcd
4 |
--------------------------------------------------------------------------------
/templates/icehouse/etcd.conf:
--------------------------------------------------------------------------------
1 | # managed by juju, DO NOT EDIT
2 | description "etcd"
3 | author "etcd maintainers"
4 |
5 | start on stopped rc RUNLEVEL=[2345]
6 | stop on runlevel [!2345]
7 |
8 | respawn
9 |
10 | setuid etcd
11 |
12 | script
13 | set -a
14 | . /etc/default/etcd
15 | exec /usr/bin/etcd
16 | end script
17 |
--------------------------------------------------------------------------------
/templates/icehouse/ml2_conf.ini:
--------------------------------------------------------------------------------
1 | # icehouse
2 | ###############################################################################
3 | # [ WARNING ]
4 | # Configuration file maintained by Juju. Local changes may be overwritten.
5 | ###############################################################################
6 | [ml2]
7 | {% if neutron_plugin == 'Calico' -%}
8 | type_drivers = local,flat
9 | mechanism_drivers = calico
10 | {% else -%}
11 | type_drivers = {{ tenant_network_types }}
12 | tenant_network_types = {{ tenant_network_types }}
13 | mechanism_drivers = openvswitch,hyperv,l2population
14 |
15 | [ml2_type_gre]
16 | tunnel_id_ranges = 1:1000
17 |
18 | [ml2_type_vxlan]
19 | vni_ranges = {{ vni_ranges }}
20 |
21 | [ml2_type_vlan]
22 | network_vlan_ranges = {{ vlan_ranges }}
23 |
24 | [ml2_type_flat]
25 | flat_networks = {{ network_providers }}
26 |
27 | [ovs]
28 | enable_tunneling = True
29 | local_ip = {{ local_ip }}
30 |
31 | [agent]
32 | tunnel_types = {{ overlay_network_type }}
33 | {% endif -%}
34 |
35 | [securitygroup]
36 | {% if neutron_security_groups -%}
37 | enable_security_group = True
38 | {% if neutron_plugin == 'Calico' -%}
39 | firewall_driver = neutron.agent.linux.iptables_firewall.IptablesFirewallDriver
40 | {% else -%}
41 | firewall_driver = neutron.agent.linux.iptables_firewall.OVSHybridIptablesFirewallDriver
42 | {% endif -%}
43 | {% else -%}
44 | enable_security_group = False
45 | {% endif -%}
46 |
--------------------------------------------------------------------------------
/templates/icehouse/neutron-server:
--------------------------------------------------------------------------------
1 | # havana
2 | ###############################################################################
3 | # [ WARNING ]
4 | # Configuration file maintained by Juju. Local changes may be overwritten.
5 | ###############################################################################
6 | NEUTRON_PLUGIN_CONFIG="{{ config }}"
--------------------------------------------------------------------------------
/templates/icehouse/nsx.ini:
--------------------------------------------------------------------------------
1 | # icehouse
2 | ###############################################################################
3 | # [ WARNING ]
4 | # Configuration file maintained by Juju. Local changes may be overwritten.
5 | ###############################################################################
6 | [DEFAULT]
7 | nsx_user = {{ nsx_username }}
8 | nsx_password = {{ nsx_password }}
9 | nsx_controllers = {{ nsx_controllers }}
10 | default_tz_uuid = {{ nsx_tz_uuid }}
11 | default_l3_gw_service_uuid = {{ nsx_l3_uuid }}
12 |
--------------------------------------------------------------------------------
/templates/icehouse/nuage_plugin.ini:
--------------------------------------------------------------------------------
1 | # icehouse
2 | ###############################################################################
3 | # [ WARNING ]
4 | # Configuration file maintained by Juju. Local changes may be overwritten.
5 | ###############################################################################
6 | [restproxy]
7 | server = {{ vsd_server }}
8 | serverauth = {{ vsd_auth }}
9 | auth_resource = {{ vsd_auth_resource }}
10 | organization = {{ vsd_organization }}
11 | serverssl = {{ vsd_auth_ssl }}
12 | base_uri = {{ vsd_base_uri }}
13 | default_net_partition_name = {{ vsd_netpart_name }}
14 |
--------------------------------------------------------------------------------
/templates/icehouse/plumgrid.ini:
--------------------------------------------------------------------------------
1 | # icehouse
2 | ###############################################################################
3 | # [ WARNING ]
4 | # Configuration file maintained by Juju. Local changes may be overwritten.
5 | ###############################################################################
6 | [plumgriddirector]
7 | # This line should be pointing to the PLUMgrid Director,
8 | # for the PLUMgrid platform.
9 | director_server={{ virtual_ip }}
10 | director_server_port=443
11 | # Authentification parameters for the Director.
12 | # These are the admin credentials to manage and control
13 | # the PLUMgrid Director server.
14 | username={{ pg_username }}
15 | password={{ pg_password }}
16 | servertimeout=70
17 |
18 | {% if database_host -%}
19 | connection = {{ database_type }}://{{ database_user }}:{{ database_password }}@{{ database_host }}/{{ database }}{% if database_ssl_ca %}?ssl_ca={{ database_ssl_ca }}{% if database_ssl_cert %}&ssl_cert={{ database_ssl_cert }}&ssl_key={{ database_ssl_key }}{% endif %}{% endif %}
20 | {% endif -%}
21 |
--------------------------------------------------------------------------------
/templates/juno/midonet.ini:
--------------------------------------------------------------------------------
1 | ###############################################################################
2 | # [ WARNING ]
3 | # Configuration file maintained by Juju. Local changes may be overwritten.
4 | ###############################################################################
5 | [MIDONET]
6 | # MidoNet API URL
7 | midonet_uri = http://{{ midonet_api_ip }}:{{ midonet_api_port }}/midonet-api
8 | # credentials
9 | username = {{ admin_user }}
10 | password = {{ admin_password }}
11 | project_id = {{ admin_tenant_name }}
12 |
--------------------------------------------------------------------------------
/templates/kilo/api-paste.ini:
--------------------------------------------------------------------------------
1 | [composite:neutron]
2 | use = egg:Paste#urlmap
3 | /: neutronversions
4 | /v2.0: neutronapi_v2_0
5 |
6 | [composite:neutronapi_v2_0]
7 | use = call:neutron.auth:pipeline_factory
8 | noauth = request_id catch_errors extensions neutronapiapp_v2_0
9 | keystone = {% for m in extra_middleware %}{{ m.name }} {% endfor %}request_id catch_errors authtoken keystonecontext extensions neutronapiapp_v2_0
10 |
11 | {% for m in extra_middleware -%}
12 | [{{ m.type }}:{{ m.name }}]
13 | {% for k, v in m.config.items() -%}
14 | {{ k }} = {{ v }}
15 | {% endfor %}
16 | {% endfor -%}
17 |
18 | [filter:request_id]
19 | paste.filter_factory = oslo.middleware:RequestId.factory
20 |
21 | [filter:catch_errors]
22 | paste.filter_factory = oslo.middleware:CatchErrors.factory
23 |
24 | [filter:keystonecontext]
25 | paste.filter_factory = neutron.auth:NeutronKeystoneContext.factory
26 |
27 | [filter:authtoken]
28 | paste.filter_factory = keystonemiddleware.auth_token:filter_factory
29 |
30 | [filter:extensions]
31 | paste.filter_factory = neutron.api.extensions:plugin_aware_extension_middleware_factory
32 |
33 | [app:neutronversions]
34 | paste.app_factory = neutron.api.versions:Versions.factory
35 |
36 | [app:neutronapiapp_v2_0]
37 | paste.app_factory = neutron.api.v2.router:APIRouter.factory
38 |
--------------------------------------------------------------------------------
/templates/kilo/ml2_conf.ini:
--------------------------------------------------------------------------------
1 | # kilo
2 | ###############################################################################
3 | # [ WARNING ]
4 | # Configuration file maintained by Juju. Local changes may be overwritten.
5 | ###############################################################################
6 | [ml2]
7 | {% if extension_drivers -%}
8 | extension_drivers={{ extension_drivers }}
9 | {% endif -%}
10 |
11 | {% if neutron_plugin == 'Calico' -%}
12 | type_drivers = local,flat
13 | mechanism_drivers = calico
14 | {% else -%}
15 | type_drivers = {{ tenant_network_types }}
16 | tenant_network_types = {{ tenant_network_types }}
17 | mechanism_drivers = {{ mechanism_drivers }}
18 |
19 | [ml2_type_gre]
20 | tunnel_id_ranges = 1:1000
21 |
22 | [ml2_type_vxlan]
23 | vni_ranges = {{ vni_ranges }}
24 |
25 | [ml2_type_vlan]
26 | network_vlan_ranges = {{ vlan_ranges }}
27 |
28 | [ml2_type_flat]
29 | flat_networks = {{ network_providers }}
30 |
31 | [ovs]
32 | enable_tunneling = True
33 | local_ip = {{ local_ip }}
34 |
35 | [agent]
36 | tunnel_types = {{ overlay_network_type }}
37 | {% endif -%}
38 |
39 | [securitygroup]
40 | {% if neutron_security_groups -%}
41 | enable_security_group = True
42 | {% if neutron_plugin == 'Calico' -%}
43 | firewall_driver = neutron.agent.linux.iptables_firewall.IptablesFirewallDriver
44 | {% else -%}
45 | firewall_driver = neutron.agent.linux.iptables_firewall.OVSHybridIptablesFirewallDriver
46 | {% endif -%}
47 | {% else -%}
48 | enable_security_group = False
49 | {% endif -%}
50 |
51 | {% if supported_pci_vendor_devs %}
52 | [ml2_sriov]
53 | supported_pci_vendor_devs = {{ supported_pci_vendor_devs }}
54 | {% endif -%}
55 |
--------------------------------------------------------------------------------
/templates/kilo/ml2_conf_sriov.ini:
--------------------------------------------------------------------------------
1 | ###############################################################################
2 | # [ WARNING ]
3 | # Configuration file maintained by Juju. Local changes may be overwritten.
4 | #
5 | # __NOTE__ [ml2_sriov] section is maintained in ml2_conf.ini
6 | #
7 | ###############################################################################
8 |
--------------------------------------------------------------------------------
/templates/kilo/nuage_plugin.ini:
--------------------------------------------------------------------------------
1 | ###############################################################################
2 | # [ WARNING ]
3 | # Configuration file maintained by Juju. Local changes may be overwritten.
4 | ###############################################################################
5 | [restproxy]
6 | server = {{ vsd_server }}
7 | serverauth = {{ vsd_auth }}
8 | auth_resource = {{ vsd_auth_resource }}
9 | organization = {{ vsd_organization }}
10 | serverssl = {{ vsd_auth_ssl }}
11 | base_uri = {{ vsd_base_uri }}
12 | default_net_partition_name = {{ vsd_netpart_name }}
13 | cms_id = {{ vsd_cms_id }}
14 |
--------------------------------------------------------------------------------
/templates/liberty/neutron_lbaas.conf:
--------------------------------------------------------------------------------
1 | # liberty
2 | ###############################################################################
3 | # [ WARNING ]
4 | # Configuration file maintained by Juju. Local changes may be overwritten.
5 | ###############################################################################
6 | # [service_auth]
7 | # auth_url = http://127.0.0.1:5000/v2.0
8 | # admin_tenant_name = %SERVICE_TENANT_NAME%
9 | # admin_user = %SERVICE_USER%
10 | # admin_password = %SERVICE_PASSWORD%
11 | # admin_user_domain = %SERVICE_USER_DOMAIN%
12 | # admin_project_domain = %SERVICE_PROJECT_DOMAIN%
13 | # region = %REGION%
14 | # service_name = lbaas
15 | # auth_version = 2
16 |
17 | [service_providers]
18 | {% if neutron_plugin and neutron_plugin == 'midonet' -%}
19 | service_provider = LOADBALANCER:Midonet:midonet.neutron.services.loadbalancer.driver.MidonetLoadbalancerDriver:default
20 | {% else -%}
21 | service_provider=LOADBALANCER:Haproxy:neutron_lbaas.services.loadbalancer.drivers.haproxy.plugin_driver.HaproxyOnHostPluginDriver:default
22 | # service_provider=LOADBALANCERV2:Haproxy:neutron_lbaas.drivers.haproxy.plugin_driver.HaproxyOnHostPluginDriver:default
23 | {% endif %}
24 |
--------------------------------------------------------------------------------
/templates/liberty/neutron_vpnaas.conf:
--------------------------------------------------------------------------------
1 | # liberty
2 | ###############################################################################
3 | # [ WARNING ]
4 | # Configuration file maintained by Juju. Local changes may be overwritten.
5 | ###############################################################################
6 | [service_providers]
7 | service_provider=VPN:openswan:neutron_vpnaas.services.vpn.service_drivers.ipsec.IPsecVPNDriver:default
--------------------------------------------------------------------------------
/templates/mitaka/api-paste.ini:
--------------------------------------------------------------------------------
1 | [composite:neutron]
2 | use = egg:Paste#urlmap
3 | /: neutronversions
4 | /v2.0: neutronapi_v2_0
5 |
6 | [composite:neutronapi_v2_0]
7 | use = call:neutron.auth:pipeline_factory
8 | noauth = cors request_id catch_errors extensions neutronapiapp_v2_0
9 | keystone = {% for m in extra_middleware %}{{ m.name }} {% endfor %}cors request_id catch_errors authtoken keystonecontext extensions neutronapiapp_v2_0
10 |
11 | {% for m in extra_middleware -%}
12 | [{{ m.type }}:{{ m.name }}]
13 | {% for k, v in m.config.items() -%}
14 | {{ k }} = {{ v }}
15 | {% endfor %}
16 | {% endfor -%}
17 |
18 | [filter:request_id]
19 | paste.filter_factory = oslo_middleware:RequestId.factory
20 |
21 | [filter:catch_errors]
22 | paste.filter_factory = oslo_middleware:CatchErrors.factory
23 |
24 | [filter:cors]
25 | paste.filter_factory = oslo_middleware.cors:filter_factory
26 | oslo_config_project = neutron
27 |
28 | [filter:keystonecontext]
29 | paste.filter_factory = neutron.auth:NeutronKeystoneContext.factory
30 |
31 | [filter:authtoken]
32 | paste.filter_factory = keystonemiddleware.auth_token:filter_factory
33 |
34 | [filter:extensions]
35 | paste.filter_factory = neutron.api.extensions:plugin_aware_extension_middleware_factory
36 |
37 | [app:neutronversions]
38 | paste.app_factory = neutron.api.versions:Versions.factory
39 |
40 | [app:neutronapiapp_v2_0]
41 | paste.app_factory = neutron.api.v2.router:APIRouter.factory
42 |
--------------------------------------------------------------------------------
/templates/mitaka/ml2_conf.ini:
--------------------------------------------------------------------------------
1 | # mitaka
2 | ###############################################################################
3 | # [ WARNING ]
4 | # Configuration file maintained by Juju. Local changes may be overwritten.
5 | ###############################################################################
6 | [ml2]
7 | {% if extension_drivers -%}
8 | extension_drivers={{ extension_drivers }}
9 | {% endif -%}
10 |
11 | {% if neutron_plugin == 'Calico' -%}
12 | type_drivers = local,flat
13 | mechanism_drivers = calico
14 | {% else -%}
15 | type_drivers = {{ tenant_network_types }}
16 | tenant_network_types = {{ tenant_network_types }}
17 | mechanism_drivers = {{ mechanism_drivers }}
18 |
19 | {% if physical_network_mtus -%}
20 | physical_network_mtus = {{ physical_network_mtus }}
21 | {% endif -%}
22 | {% if path_mtu -%}
23 | path_mtu = {{ path_mtu }}
24 | {% endif -%}
25 |
26 | [ml2_type_gre]
27 | tunnel_id_ranges = 1:1000
28 |
29 | [ml2_type_vxlan]
30 | vni_ranges = {{ vni_ranges }}
31 |
32 | [ml2_type_vlan]
33 | network_vlan_ranges = {{ vlan_ranges }}
34 |
35 | [ml2_type_flat]
36 | flat_networks = {{ network_providers }}
37 |
38 | [ovs]
39 | enable_tunneling = True
40 | local_ip = {{ local_ip }}
41 |
42 | [agent]
43 | tunnel_types = {{ overlay_network_type }}
44 | {% endif -%}
45 |
46 | [securitygroup]
47 | {% if neutron_security_groups -%}
48 | enable_security_group = True
49 | {% if neutron_plugin == 'Calico' -%}
50 | firewall_driver = neutron.agent.linux.iptables_firewall.IptablesFirewallDriver
51 | {% else -%}
52 | firewall_driver = neutron.agent.linux.iptables_firewall.OVSHybridIptablesFirewallDriver
53 | {% endif -%}
54 | {% else -%}
55 | enable_security_group = False
56 | {% endif -%}
57 |
58 | {% if supported_pci_vendor_devs %}
59 | [ml2_sriov]
60 | supported_pci_vendor_devs = {{ supported_pci_vendor_devs }}
61 | {% endif -%}
62 |
--------------------------------------------------------------------------------
/templates/newton/api-paste.ini:
--------------------------------------------------------------------------------
1 | [composite:neutron]
2 | use = egg:Paste#urlmap
3 | /: neutronversions_composite
4 | /v2.0: neutronapi_v2_0
5 |
6 | [composite:neutronapi_v2_0]
7 | use = call:neutron.auth:pipeline_factory
8 | noauth = cors http_proxy_to_wsgi request_id catch_errors extensions neutronapiapp_v2_0
9 | keystone = {% for m in extra_middleware %}{{ m.name }} {% endfor %}cors http_proxy_to_wsgi request_id catch_errors authtoken keystonecontext extensions neutronapiapp_v2_0
10 |
11 | {% for m in extra_middleware -%}
12 | [{{ m.type }}:{{ m.name }}]
13 | {% for k, v in m.config.items() -%}
14 | {{ k }} = {{ v }}
15 | {% endfor %}
16 | {% endfor -%}
17 |
18 | [composite:neutronversions_composite]
19 | use = call:neutron.auth:pipeline_factory
20 | noauth = cors http_proxy_to_wsgi neutronversions
21 | keystone = cors http_proxy_to_wsgi neutronversions
22 |
23 | [filter:request_id]
24 | paste.filter_factory = oslo_middleware:RequestId.factory
25 |
26 | [filter:catch_errors]
27 | paste.filter_factory = oslo_middleware:CatchErrors.factory
28 |
29 | [filter:cors]
30 | paste.filter_factory = oslo_middleware.cors:filter_factory
31 | oslo_config_project = neutron
32 |
33 | [filter:http_proxy_to_wsgi]
34 | paste.filter_factory = oslo_middleware.http_proxy_to_wsgi:HTTPProxyToWSGI.factory
35 |
36 | [filter:keystonecontext]
37 | paste.filter_factory = neutron.auth:NeutronKeystoneContext.factory
38 |
39 | [filter:authtoken]
40 | paste.filter_factory = keystonemiddleware.auth_token:filter_factory
41 |
42 | [filter:extensions]
43 | paste.filter_factory = neutron.api.extensions:plugin_aware_extension_middleware_factory
44 |
45 | [app:neutronversions]
46 | paste.app_factory = neutron.api.versions:Versions.factory
47 |
48 | [app:neutronapiapp_v2_0]
49 | paste.app_factory = neutron.api.v2.router:APIRouter.factory
50 |
51 | [filter:osprofiler]
52 | paste.filter_factory = osprofiler.web:WsgiMiddleware.factory
53 |
--------------------------------------------------------------------------------
/templates/parts/database:
--------------------------------------------------------------------------------
1 | {% if database_host -%}
2 | sql_connection = {{ database_type }}://{{ database_user }}:{{ database_password }}@{{ database_host }}/{{ database }}{% if database_ssl_ca %}?ssl_ca={{ database_ssl_ca }}{% if database_ssl_cert %}&ssl_cert={{ database_ssl_cert }}&ssl_key={{ database_ssl_key }}{% endif %}{% endif %}
3 | {% endif -%}
4 |
--------------------------------------------------------------------------------
/templates/parts/rabbitmq:
--------------------------------------------------------------------------------
1 | {% if rabbitmq_host or rabbitmq_hosts -%}
2 | rabbit_userid = {{ rabbitmq_user }}
3 | rabbit_virtual_host = {{ rabbitmq_virtual_host }}
4 | rabbit_password = {{ rabbitmq_password }}
5 | {% if rabbitmq_hosts -%}
6 | rabbit_hosts = {{ rabbitmq_hosts }}
7 | {% if rabbitmq_ha_queues -%}
8 | rabbit_ha_queues = True
9 | rabbit_durable_queues = False
10 | {% endif -%}
11 | {% else -%}
12 | rabbit_host = {{ rabbitmq_host }}
13 | {% endif -%}
14 | {% if rabbit_ssl_port -%}
15 | rabbit_use_ssl = True
16 | rabbit_port = {{ rabbit_ssl_port }}
17 | {% if rabbit_ssl_ca -%}
18 | kombu_ssl_ca_certs = {{ rabbit_ssl_ca }}
19 | {% endif -%}
20 | {% endif -%}
21 | {% endif -%}
--------------------------------------------------------------------------------
/templates/parts/section-database:
--------------------------------------------------------------------------------
1 | {% if database_host -%}
2 | [database]
3 | connection = {{ database_type }}://{{ database_user }}:{{ database_password }}@{{ database_host }}/{{ database }}{% if database_ssl_ca %}?ssl_ca={{ database_ssl_ca }}{% if database_ssl_cert %}&ssl_cert={{ database_ssl_cert }}&ssl_key={{ database_ssl_key }}{% endif %}{% endif %}
4 | {% endif -%}
5 |
--------------------------------------------------------------------------------
/templates/parts/section-designate:
--------------------------------------------------------------------------------
1 | [designate]
2 | url = {{ designate_endpoint }}/v2
3 | {% if api_version == "3" -%}
4 | auth_uri = {{ service_protocol }}://{{ service_host }}:{{ service_port }}
5 | auth_url = {{ auth_protocol }}://{{ auth_host }}:{{ auth_port }}
6 | auth_type = password
7 | project_domain_name = {{ admin_domain_name }}
8 | user_domain_name = {{ admin_domain_name }}
9 | project_name = {{ admin_tenant_name }}
10 | username = {{ admin_user }}
11 | password = {{ admin_password }}
12 | signing_dir = {{ signing_dir }}
13 | {% else -%}
14 | admin_auth_url = {{ auth_protocol }}://{{ auth_host }}:{{ auth_port }}
15 | admin_username = {{ admin_user }}
16 | admin_password = {{ admin_password }}
17 | admin_tenant_name = {{ admin_tenant_name }}
18 | {% endif -%}
19 | allow_reverse_dns_lookup = {{ allow_reverse_dns_lookup }}
20 | {% if allow_reverse_dns_lookup -%}
21 | ipv4_ptr_zone_prefix_size = {{ ipv4_ptr_zone_prefix_size }}
22 | ipv6_ptr_zone_prefix_size = {{ ipv6_ptr_zone_prefix_size }}
23 | {% endif -%}
24 |
--------------------------------------------------------------------------------
/templates/parts/section-infoblox:
--------------------------------------------------------------------------------
1 | [infoblox]
2 | cloud_data_center_id = {{ cloud_data_center_id }}
3 |
4 | [infoblox-dc:{{ cloud_data_center_id }}]
5 | grid_master_host = {{ grid_master_host }}
6 | grid_master_name = {{ grid_master_name }}
7 | admin_user_name = {{ infoblox_admin_user_name }}
8 | admin_password = {{ infoblox_admin_password }}
9 | wapi_version = {{ wapi_version }}
10 | wapi_max_results = {{ wapi_max_results }}
11 | wapi_paging = {{ wapi_paging }}
12 |
--------------------------------------------------------------------------------
/templates/parts/section-nova:
--------------------------------------------------------------------------------
1 | [nova]
2 | {% if enable_infoblox -%}
3 | # TODO - Exceptionally we added the content of [keystone_authtoken] due to an
4 | # internal mechanism of Infoblox plugin lp-1688039.
5 | {% if auth_host -%}
6 | auth_type = password
7 | {% if api_version == "3" -%}
8 | auth_uri = {{ service_protocol }}://{{ service_host }}:{{ service_port }}/v3
9 | auth_url = {{ auth_protocol }}://{{ auth_host }}:{{ auth_port }}/v3
10 | project_domain_name = {{ admin_domain_name }}
11 | user_domain_name = {{ admin_domain_name }}
12 | {% else -%}
13 | auth_uri = {{ service_protocol }}://{{ service_host }}:{{ service_port }}
14 | auth_url = {{ auth_protocol }}://{{ auth_host }}:{{ auth_port }}
15 | project_domain_name = default
16 | user_domain_name = default
17 | {% endif -%}
18 | project_name = {{ admin_tenant_name }}
19 | username = {{ admin_user }}
20 | password = {{ admin_password }}
21 | signing_dir = {{ signing_dir }}
22 | {% if use_memcache == true %}
23 | memcached_servers = {{ memcache_url }}
24 | {% endif -%}
25 | {% endif -%}
26 | {% else %}
27 | auth_section = keystone_authtoken
28 | {% endif %}
29 | region_name = {{ region }}
30 | {% if use_internal_endpoints -%}
31 | endpoint_type = internal
32 | {% endif %}
33 |
--------------------------------------------------------------------------------
/templates/parts/section-placement:
--------------------------------------------------------------------------------
1 | [placement]
2 | {% if auth_host -%}
3 | auth_url = {{ auth_protocol }}://{{ auth_host }}:{{ auth_port }}
4 | auth_type = password
5 | {% if api_version == "3" -%}
6 | project_domain_name = {{ admin_domain_name }}
7 | user_domain_name = {{ admin_domain_name }}
8 | {% else -%}
9 | project_domain_name = default
10 | user_domain_name = default
11 | {% endif -%}
12 | project_name = {{ admin_tenant_name }}
13 | username = {{ admin_user }}
14 | password = {{ admin_password }}
15 | {% endif -%}
16 | {% if region -%}
17 | os_region_name = {{ region }}
18 | {% endif -%}
19 | {% if use_internal_endpoints -%}
20 | os_interface = internal
21 | {% endif -%}
22 |
--------------------------------------------------------------------------------
/templates/ports.conf:
--------------------------------------------------------------------------------
1 | # File written by Juju: don't open default ports on SSL environments (see LP 1845665).
2 |
3 | Listen 80
4 |
5 |
--------------------------------------------------------------------------------
/templates/queens/ml2_conf.ini:
--------------------------------------------------------------------------------
1 | # queens
2 | ###############################################################################
3 | # [ WARNING ]
4 | # Configuration file maintained by Juju. Local changes may be overwritten.
5 | ###############################################################################
6 | [ml2]
7 | {% if extension_drivers -%}
8 | extension_drivers={{ extension_drivers }}
9 | {% endif -%}
10 |
11 | {% if neutron_plugin == 'Calico' -%}
12 | type_drivers = local,flat
13 | mechanism_drivers = calico
14 | {% else -%}
15 | type_drivers = {{ tenant_network_types }}
16 | tenant_network_types = {{ tenant_network_types }}
17 | mechanism_drivers = {{ mechanism_drivers }}
18 |
19 | {% if physical_network_mtus -%}
20 | physical_network_mtus = {{ physical_network_mtus }}
21 | {% endif -%}
22 | {% if path_mtu -%}
23 | path_mtu = {{ path_mtu }}
24 | {% endif -%}
25 |
26 | [ml2_type_gre]
27 | tunnel_id_ranges = 1:1000
28 |
29 | [ml2_type_vxlan]
30 | vni_ranges = {{ vni_ranges }}
31 |
32 | [ml2_type_vlan]
33 | network_vlan_ranges = {{ vlan_ranges }}
34 |
35 | [ml2_type_flat]
36 | flat_networks = {{ network_providers }}
37 |
38 | [ovs]
39 | enable_tunneling = True
40 | local_ip = {{ local_ip }}
41 |
42 | [agent]
43 | tunnel_types = {{ overlay_network_type }}
44 | {% if 'log' in service_plugins -%}
45 | extensions = log
46 |
47 | {% endif -%}
48 |
49 | {% endif -%}
50 |
51 | [securitygroup]
52 | {% if neutron_security_groups -%}
53 | enable_security_group = True
54 | {% else -%}
55 | enable_security_group = False
56 | {% endif -%}
57 |
58 | {% if supported_pci_vendor_devs %}
59 | [ml2_sriov]
60 | supported_pci_vendor_devs = {{ supported_pci_vendor_devs }}
61 | {% endif -%}
62 |
63 | {% for section in sections -%}
64 | {% if section != 'DEFAULT' -%}
65 | [{{ section }}]
66 | {% for key, value in sections[section] -%}
67 | {{ key }} = {{ value }}
68 | {% endfor %}
69 | {% endif %}
70 | {%- endfor %}
71 |
--------------------------------------------------------------------------------
/templates/rocky/api-paste.ini:
--------------------------------------------------------------------------------
1 | [composite:neutron]
2 | use = egg:Paste#urlmap
3 | /: neutronversions_composite
4 | /healthcheck: healthcheck
5 | /v2.0: neutronapi_v2_0
6 |
7 | [composite:neutronapi_v2_0]
8 | use = call:neutron.auth:pipeline_factory
9 | noauth = cors http_proxy_to_wsgi request_id catch_errors extensions neutronapiapp_v2_0
10 | keystone = {% for m in extra_middleware %}{{ m.name }} {% endfor %}cors http_proxy_to_wsgi request_id catch_errors authtoken keystonecontext extensions neutronapiapp_v2_0
11 |
12 | {% for m in extra_middleware -%}
13 | [{{ m.type }}:{{ m.name }}]
14 | {% for k, v in m.config.items() -%}
15 | {{ k }} = {{ v }}
16 | {% endfor %}
17 | {% endfor -%}
18 |
19 | [composite:neutronversions_composite]
20 | use = call:neutron.auth:pipeline_factory
21 | noauth = cors http_proxy_to_wsgi neutronversions
22 | keystone = cors http_proxy_to_wsgi neutronversions
23 |
24 | [filter:request_id]
25 | paste.filter_factory = oslo_middleware:RequestId.factory
26 |
27 | [filter:catch_errors]
28 | paste.filter_factory = oslo_middleware:CatchErrors.factory
29 |
30 | [filter:cors]
31 | paste.filter_factory = oslo_middleware.cors:filter_factory
32 | oslo_config_project = neutron
33 |
34 | [filter:http_proxy_to_wsgi]
35 | paste.filter_factory = oslo_middleware.http_proxy_to_wsgi:HTTPProxyToWSGI.factory
36 |
37 | [filter:keystonecontext]
38 | paste.filter_factory = neutron.auth:NeutronKeystoneContext.factory
39 |
40 | [filter:authtoken]
41 | paste.filter_factory = keystonemiddleware.auth_token:filter_factory
42 |
43 | [filter:extensions]
44 | paste.filter_factory = neutron.api.extensions:plugin_aware_extension_middleware_factory
45 |
46 | [app:neutronversions]
47 | paste.app_factory = neutron.pecan_wsgi.app:versions_factory
48 |
49 | [app:neutronapiapp_v2_0]
50 | paste.app_factory = neutron.api.v2.router:APIRouter.factory
51 |
52 | [filter:osprofiler]
53 | paste.filter_factory = osprofiler.web:WsgiMiddleware.factory
54 |
55 | [app:healthcheck]
56 | paste.app_factory = oslo_middleware:Healthcheck.app_factory
57 | backends = disable_by_file
58 | disable_by_file_path = /var/lib/neutron/healthcheck_disable
59 |
--------------------------------------------------------------------------------
/templates/yoga/api-paste.ini:
--------------------------------------------------------------------------------
1 | [composite:neutron]
2 | use = egg:Paste#urlmap
3 | /: neutronversions_composite
4 | /healthcheck: healthcheck
5 | /v2.0: neutronapi_v2_0
6 |
7 | [composite:neutronapi_v2_0]
8 | use = call:neutron.auth:pipeline_factory
9 | noauth = cors http_proxy_to_wsgi request_id catch_errors extensions neutronapiapp_v2_0
10 | {% if audit_middleware and service_name -%}
11 | keystone = {% for m in extra_middleware %}{{ m.name }} {% endfor %}cors http_proxy_to_wsgi request_id catch_errors authtoken keystonecontext audit extensions neutronapiapp_v2_0
12 | {% else -%}
13 | keystone = {% for m in extra_middleware %}{{ m.name }} {% endfor %}cors http_proxy_to_wsgi request_id catch_errors authtoken keystonecontext extensions neutronapiapp_v2_0
14 | {% endif %}
15 |
16 | {% for m in extra_middleware -%}
17 | [{{ m.type }}:{{ m.name }}]
18 | {% for k, v in m.config.items() -%}
19 | {{ k }} = {{ v }}
20 | {% endfor %}
21 | {% endfor -%}
22 |
23 | [composite:neutronversions_composite]
24 | use = call:neutron.auth:pipeline_factory
25 | noauth = cors http_proxy_to_wsgi neutronversions
26 | keystone = cors http_proxy_to_wsgi neutronversions
27 |
28 | [filter:request_id]
29 | paste.filter_factory = oslo_middleware:RequestId.factory
30 |
31 | [filter:catch_errors]
32 | paste.filter_factory = oslo_middleware:CatchErrors.factory
33 |
34 | [filter:cors]
35 | paste.filter_factory = oslo_middleware.cors:filter_factory
36 | oslo_config_project = neutron
37 |
38 | [filter:http_proxy_to_wsgi]
39 | paste.filter_factory = oslo_middleware.http_proxy_to_wsgi:HTTPProxyToWSGI.factory
40 |
41 | [filter:keystonecontext]
42 | paste.filter_factory = neutron.auth:NeutronKeystoneContext.factory
43 |
44 | [filter:authtoken]
45 | paste.filter_factory = keystonemiddleware.auth_token:filter_factory
46 |
47 | [filter:extensions]
48 | paste.filter_factory = neutron.api.extensions:plugin_aware_extension_middleware_factory
49 |
50 | [app:neutronversions]
51 | paste.app_factory = neutron.pecan_wsgi.app:versions_factory
52 |
53 | [app:neutronapiapp_v2_0]
54 | paste.app_factory = neutron.api.v2.router:APIRouter.factory
55 |
56 | [filter:osprofiler]
57 | paste.filter_factory = osprofiler.web:WsgiMiddleware.factory
58 |
59 | [app:healthcheck]
60 | paste.app_factory = oslo_middleware:Healthcheck.app_factory
61 | backends = disable_by_file
62 | disable_by_file_path = /var/lib/neutron/healthcheck_disable
63 |
64 | {% include "section-filter-audit" %}
--------------------------------------------------------------------------------
/templates/yoga/api_audit_map.conf:
--------------------------------------------------------------------------------
1 | [DEFAULT]
2 | # default target endpoint type
3 | # should match the endpoint type defined in service catalog
4 | target_endpoint_type = None
5 |
6 | [custom_actions]
7 | add_router_interface = update/add
8 | remove_router_interface = update/remove
9 |
10 | # possible end path of api requests
11 | [path_keywords]
12 | floatingips = ip
13 | healthmonitors = healthmonitor
14 | health_monitors = health_monitor
15 | lb = None
16 | members = member
17 | metering-labels = label
18 | metering-label-rules = rule
19 | networks = network
20 | pools = pool
21 | ports = port
22 | routers = router
23 | quotas = quota
24 | security-groups = security-group
25 | security-group-rules = rule
26 | subnets = subnet
27 | vips = vip
28 |
29 | # map endpoint type defined in service catalog to CADF typeURI
30 | [service_endpoints]
31 | network = service/network
--------------------------------------------------------------------------------
/test-requirements.txt:
--------------------------------------------------------------------------------
1 | # This file is managed centrally by release-tools and should not be modified
2 | # within individual charm repos. See the 'global' dir contents for available
3 | # choices of *requirements.txt files for OpenStack Charms:
4 | # https://github.com/openstack-charmers/release-tools
5 | #
6 | # TODO: Distill the func test requirements from the lint/unit test
7 | # requirements. They are intertwined. Also, Zaza itself should specify
8 | # all of its own requirements and if it doesn't, fix it there.
9 | #
10 | pyparsing<3.0.0 # aodhclient is pinned in zaza and needs pyparsing < 3.0.0, but cffi also needs it, so pin here.
11 |
12 | requests>=2.18.4
13 |
14 | stestr>=2.2.0
15 |
16 | # Dependency of stestr. Workaround for
17 | # https://github.com/mtreinish/stestr/issues/145
18 | cliff<3.0.0
19 |
20 | coverage>=4.5.2
21 | pyudev # for ceph-* charm unit tests (need to fix the ceph-* charm unit tests/mocking)
22 | git+https://github.com/openstack-charmers/zaza.git#egg=zaza
23 | git+https://github.com/openstack-charmers/zaza-openstack-tests.git#egg=zaza.openstack
24 |
25 | # Needed for charm-glance:
26 | git+https://opendev.org/openstack/tempest.git#egg=tempest
27 |
28 | croniter # needed for charm-rabbitmq-server unit tests
29 | psutil
30 |
--------------------------------------------------------------------------------
/tests/bundles/noble-caracal.yaml:
--------------------------------------------------------------------------------
1 | variables:
2 | openstack-origin: &openstack-origin distro
3 |
4 | series: &series noble
5 |
6 | applications:
7 | keystone-mysql-router:
8 | charm: ch:mysql-router
9 | channel: latest/edge
10 | neutron-mysql-router:
11 | charm: ch:mysql-router
12 | channel: latest/edge
13 | mysql-innodb-cluster:
14 | charm: ch:mysql-innodb-cluster
15 | num_units: 3
16 | options:
17 | source: *openstack-origin
18 | channel: latest/edge
19 | rabbitmq-server:
20 | charm: ch:rabbitmq-server
21 | num_units: 1
22 | channel: latest/edge
23 | neutron-api:
24 | charm: ../../neutron-api.charm
25 | num_units: 1
26 | options:
27 | manage-neutron-plugin-legacy-mode: True
28 | flat-network-providers: physnet1
29 | neutron-security-groups: true
30 | openstack-origin: *openstack-origin
31 | keystone:
32 | charm: ch:keystone
33 | num_units: 1
34 | options:
35 | openstack-origin: *openstack-origin
36 | channel: latest/edge
37 | relations:
38 | - - neutron-api:amqp
39 | - rabbitmq-server:amqp
40 | - - neutron-api:identity-service
41 | - keystone:identity-service
42 | - ["keystone:shared-db", "keystone-mysql-router:shared-db"]
43 | - ["neutron-api:shared-db", "neutron-mysql-router:shared-db"]
44 | - ["keystone-mysql-router:db-router", "mysql-innodb-cluster:db-router"]
45 | - ["neutron-mysql-router:db-router", "mysql-innodb-cluster:db-router"]
46 |
--------------------------------------------------------------------------------
/tests/tests.yaml:
--------------------------------------------------------------------------------
1 | charm_name: neutron-api
2 |
3 | gate_bundles:
4 | - noble-caracal
5 | smoke_bundles:
6 | - jammy-caracal
7 | dev_bundles:
8 | - noble-caracal
9 | tests:
10 | - zaza.openstack.charm_tests.neutron.tests.NeutronApiTest
11 | - zaza.openstack.charm_tests.neutron.tests.NeutronCreateNetworkTest
12 | - zaza.openstack.charm_tests.neutron.tests.SecurityTest
13 | - zaza.openstack.charm_tests.policyd.tests.NeutronApiTests
14 | - zaza.openstack.charm_tests.audit.tests.KeystoneAuditMiddlewareTest
15 |
16 | configure:
17 | - zaza.openstack.charm_tests.keystone.setup.add_demo_user
18 |
19 | tests_options:
20 | audit-middleware:
21 | service: neutron
22 | application: neutron-api
23 | policyd:
24 | service: neutron
25 |
--------------------------------------------------------------------------------
/unit_tests/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2016 Canonical Ltd
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | import sys
16 | from unittest import mock
17 |
18 | # python-apt is not installed as part of test-requirements but is imported by
19 | # some charmhelpers modules so create a fake import.
20 | sys.modules['apt'] = mock.MagicMock()
21 | sys.modules['apt_pkg'] = mock.MagicMock()
22 |
23 | sys.path.append('actions/')
24 | sys.path.append('hooks/')
25 | sys.path.append('unit_tests')
26 |
27 | # Patch out lsb_release() and get_platform() as unit tests should be fully
28 | # insulated from the underlying platform. Unit tests assume that the system is
29 | # ubuntu jammy.
30 | mock.patch(
31 | 'charmhelpers.osplatform.get_platform', return_value='ubuntu'
32 | ).start()
33 | mock.patch(
34 | 'charmhelpers.core.host.lsb_release',
35 | return_value={
36 | 'DISTRIB_CODENAME': 'jammy'
37 | }).start()
38 |
--------------------------------------------------------------------------------
/unit_tests/test_actions.py:
--------------------------------------------------------------------------------
1 | # Copyright 2016 Canonical Ltd
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | from unittest import mock
16 |
17 | mock.patch('charmhelpers.core.hookenv.status_set').start()
18 | with mock.patch('charmhelpers.core.hookenv.config') as config:
19 | config.return_value = 'neutron'
20 | import neutron_api_utils as utils # noqa
21 |
22 | # Need to do some early patching to get the module loaded.
23 | _reg = utils.register_configs
24 | _map = utils.restart_map
25 |
26 | utils.register_configs = mock.MagicMock()
27 | utils.restart_map = mock.MagicMock()
28 |
29 | import actions
30 |
31 | # Unpatch it now that its loaded.
32 | utils.register_configs = _reg
33 | utils.restart_map = _map
34 |
35 | from test_utils import (
36 | CharmTestCase
37 | )
38 |
39 | TO_PATCH = [
40 | ]
41 |
42 |
43 | class PauseTestCase(CharmTestCase):
44 |
45 | def setUp(self):
46 | super(PauseTestCase, self).setUp(
47 | actions, ["register_configs", "pause_unit_helper"])
48 | self.register_configs.return_value = 'test-config'
49 |
50 | def test_pauses_services(self):
51 | actions.pause([])
52 | self.pause_unit_helper.assert_called_once_with('test-config')
53 |
54 |
55 | class ResumeTestCase(CharmTestCase):
56 |
57 | def setUp(self):
58 | super(ResumeTestCase, self).setUp(
59 | actions, ["register_configs", "resume_unit_helper"])
60 | self.register_configs.return_value = 'test-config'
61 |
62 | def test_resumes_services(self):
63 | actions.resume([])
64 | self.resume_unit_helper.assert_called_once_with('test-config')
65 |
66 |
67 | class MainTestCase(CharmTestCase):
68 |
69 | def setUp(self):
70 | super(MainTestCase, self).setUp(actions, ["register_configs",
71 | "action_fail"])
72 | self.register_configs.return_value = 'test-config'
73 |
74 | def test_invokes_action(self):
75 | dummy_calls = []
76 |
77 | def dummy_action(args):
78 | dummy_calls.append(True)
79 |
80 | with mock.patch.dict(actions.ACTIONS, {"foo": dummy_action}):
81 | actions.main(["foo"])
82 | self.assertEqual(dummy_calls, [True])
83 |
84 | def test_unknown_action(self):
85 | """Unknown actions aren't a traceback."""
86 | exit_string = actions.main(["foo"])
87 | self.assertEqual("Action foo undefined", exit_string)
88 |
89 | def test_failing_action(self):
90 | """Actions which traceback trigger action_fail() calls."""
91 | dummy_calls = []
92 |
93 | self.action_fail.side_effect = dummy_calls.append
94 |
95 | def dummy_action(args):
96 | raise ValueError("uh oh")
97 |
98 | with mock.patch.dict(actions.ACTIONS, {"foo": dummy_action}):
99 | actions.main(["foo"])
100 | self.assertEqual(dummy_calls, ["uh oh"])
101 |
--------------------------------------------------------------------------------
/unit_tests/test_actions_openstack_upgrade.py:
--------------------------------------------------------------------------------
1 | # Copyright 2016 Canonical Ltd
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | import os
16 |
17 | from unittest.mock import patch
18 |
19 | os.environ['JUJU_UNIT_NAME'] = 'neutron-api'
20 |
21 | with patch('charmhelpers.core.hookenv.config') as config:
22 | with patch('neutron_api_utils.restart_map'):
23 | config.return_value = 'ovs'
24 | with patch('neutron_api_utils.register_configs') as register_configs:
25 | import openstack_upgrade
26 |
27 | from test_utils import CharmTestCase
28 |
29 | TO_PATCH = [
30 | 'do_openstack_upgrade',
31 | 'config_changed',
32 | ]
33 |
34 |
35 | class TestNeutronAPIUpgradeActions(CharmTestCase):
36 |
37 | def setUp(self):
38 | super(TestNeutronAPIUpgradeActions, self).setUp(openstack_upgrade,
39 | TO_PATCH)
40 |
41 | @patch('charmhelpers.contrib.openstack.utils.juju_log')
42 | @patch('charmhelpers.contrib.openstack.utils.config')
43 | @patch('charmhelpers.contrib.openstack.utils.action_set')
44 | @patch('charmhelpers.contrib.openstack.utils.openstack_upgrade_available')
45 | def test_openstack_upgrade_true(self, upgrade_avail,
46 | action_set, config, log):
47 | upgrade_avail.return_value = True
48 | config.return_value = True
49 |
50 | openstack_upgrade.openstack_upgrade()
51 |
52 | self.assertTrue(self.do_openstack_upgrade.called)
53 | self.assertTrue(self.config_changed.called)
54 |
55 | @patch('charmhelpers.contrib.openstack.utils.juju_log')
56 | @patch('charmhelpers.contrib.openstack.utils.config')
57 | @patch('charmhelpers.contrib.openstack.utils.action_set')
58 | @patch('charmhelpers.contrib.openstack.utils.openstack_upgrade_available')
59 | def test_openstack_upgrade_false(self, upgrade_avail,
60 | action_set, config, log):
61 | upgrade_avail.return_value = True
62 | config.return_value = False
63 |
64 | openstack_upgrade.openstack_upgrade()
65 |
66 | self.assertFalse(self.do_openstack_upgrade.called)
67 | self.assertFalse(self.config_changed.called)
68 |
--------------------------------------------------------------------------------