├── .gitignore
├── .gitreview
├── .project
├── .pydevproject
├── .stestr.conf
├── .zuul.yaml
├── LICENSE
├── Makefile
├── README.Swift_ring_management
├── README.md
├── actions.yaml
├── actions
├── __init__.py
├── actions.py
├── add-user
├── add_user.py
├── diskusage
├── dispersion-populate
├── dispersion-report
├── openstack-upgrade
├── openstack_upgrade.py
├── pause
├── remove-devices
├── resume
└── set-weight
├── bindep.txt
├── charm-helpers-hooks.yaml
├── charmcraft.yaml
├── 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
│ ├── 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
│ ├── peerstorage
│ │ └── __init__.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
│ └── execd.py
├── config.yaml
├── copyright
├── files
└── .gitkeep
├── hardening.yaml
├── hooks
├── __init__.py
├── amqp-relation-broken
├── amqp-relation-changed
├── amqp-relation-departed
├── amqp-relation-joined
├── certificates-relation-changed
├── certificates-relation-departed
├── certificates-relation-joined
├── cluster-relation-changed
├── cluster-relation-departed
├── cluster-relation-joined
├── config-changed
├── ha-relation-changed
├── ha-relation-joined
├── identity-service-relation-changed
├── identity-service-relation-joined
├── install
├── install.real
├── leader-deposed
├── leader-elected
├── leader-settings-changed
├── nrpe-external-master-relation-changed
├── nrpe-external-master-relation-joined
├── object-store-relation-joined
├── post-series-upgrade
├── pre-series-upgrade
├── rings-consumer-relation-changed
├── rings-consumer-relation-departed
├── rings-consumer-relation-joined
├── rings-distributor-relation-changed
├── rings-distributor-relation-departed
├── rings-distributor-relation-joined
├── start
├── stop
├── swift-storage-relation-broken
├── swift-storage-relation-changed
├── swift-storage-relation-joined
├── swift_hooks.py
├── update-status
└── upgrade-charm
├── icon.svg
├── lib
├── __init__.py
├── swift_context.py
└── swift_utils.py
├── metadata.yaml
├── osci.yaml
├── rename.sh
├── requirements.txt
├── revision
├── scripts
├── add_to_cluster
└── remove_from_cluster
├── setup.cfg
├── swift_manager
├── .stestr.conf
├── manager.py
└── test_manager.py
├── templates
├── memcached.conf
├── mitaka
│ ├── dispersion.conf
│ └── proxy-server.conf
├── ports.conf
├── queens
│ ├── dispersion.conf
│ └── proxy-server.conf
├── rocky
│ └── proxy-server.conf
├── swift-rings
├── swift-rings.conf
├── swift.conf
├── train
│ └── proxy-server.conf
└── yoga
│ └── proxy-server.conf
├── test-requirements.txt
├── tests
├── bundles
│ ├── noble-caracal.yaml
│ └── overlays
│ │ ├── noble-caracal-gr-r1.yaml.j2
│ │ └── noble-caracal-gr-r2.yaml.j2
└── tests.yaml
├── tox.ini
└── unit_tests
├── __init__.py
├── swift-test
├── test_actions.py
├── test_actions_openstack_upgrade.py
├── test_swift_context.py
├── test_swift_hooks.py
├── test_swift_utils.py
└── test_templates.py
/.gitignore:
--------------------------------------------------------------------------------
1 | bin
2 | .coverage
3 | .testrepository
4 | .stestr
5 | .tox
6 | tags
7 | *.sw[nop]
8 | *.pyc
9 | *.charm
10 | func-results.json
11 | __pycache__
12 |
--------------------------------------------------------------------------------
/.gitreview:
--------------------------------------------------------------------------------
1 | [gerrit]
2 | host=review.opendev.org
3 | port=29418
4 | project=openstack/charm-swift-proxy.git
5 |
--------------------------------------------------------------------------------
/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | swift-proxy
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 | /${PROJECT_DIR_NAME}/tests
7 | /${PROJECT_DIR_NAME}/lib
8 | /${PROJECT_DIR_NAME}/actions
9 | /${PROJECT_DIR_NAME}/hooks
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.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 | PYTHON := /usr/bin/env python3
2 |
3 | lint:
4 | @tox -e pep8
5 |
6 | test:
7 | @echo Starting unit tests...
8 | @tox -e py27
9 |
10 | functional_test:
11 | @echo Starting Amulet tests...
12 | @tox -e func27
13 |
14 | bin/charm_helpers_sync.py:
15 | @mkdir -p bin
16 | @curl -o bin/charm_helpers_sync.py https://raw.githubusercontent.com/juju/charm-helpers/master/tools/charm_helpers_sync/charm_helpers_sync.py
17 |
18 | sync: bin/charm_helpers_sync.py
19 | @$(PYTHON) bin/charm_helpers_sync.py -c charm-helpers-hooks.yaml
20 |
21 | publish: lint test
22 | bzr push lp:charms/swift-proxy
23 | bzr push lp:charms/trusty/swift-proxy
24 |
25 | .PHONY: lint unit_test test sync publish
26 |
--------------------------------------------------------------------------------
/README.Swift_ring_management:
--------------------------------------------------------------------------------
1 | == Swift Charm Ring Management ==
2 |
3 | Swift uses rings and builders to manage data distribution across storage devices
4 | in the cluster. More information on this can be found in the upstream
5 | documentation [0].
6 |
7 | In order to function correctly, the rings and builders need to be the same
8 | across all swift proxy units and the rings need to be distributed to storage
9 | units. The swift proxy charm achieves this by electing a leader unit and having
10 | that unit manage ring and builder files by updating them when new nodes or
11 | devices are added to the cluster and distributing those files to other nodes in
12 | the cluster.
13 |
14 | Since over time the leader may change, rings syncs use acknowledgements from
15 | peer units to determine whether a synchronisation has completed. This way if
16 | the leader switches to another unit, we are able to know that the new leader
17 | has up-to-date ring and builder files.
18 |
19 | When new devices are added to storage units, the leader proxy unit is notified
20 | and adds them to the ring. Once complete, the leader unit will broadcast a
21 | notification that rings and builders are ready to be synced across the cluster
22 | (only proxy units get builders) and each unit in the cluster should then begin
23 | syncing from the leader and acknowledge receipt.
24 |
25 | During synchronisation, swift-proxy services are stopped in order to avoid
26 | having requests being handled while rings are being updated.
27 |
28 |
29 | [0] http://docs.openstack.org/developer/swift/overview_ring.html
30 |
--------------------------------------------------------------------------------
/actions.yaml:
--------------------------------------------------------------------------------
1 | add-user:
2 | description: |
3 | Add a user to swauth.
4 | This adds a given user / pass to swauth. Auth-type must be set to swauth.
5 | Note that swauth is not supported for OpenStack Train and later.
6 | params:
7 | account:
8 | type: string
9 | description: account to add this user to
10 | username:
11 | type: string
12 | description: username for the newly created user
13 | password:
14 | type: string
15 | description: password for the newly created user
16 | required:
17 | - account
18 | - username
19 | - password
20 | pause:
21 | description: |
22 | Pause swift-proxy services.
23 | If the swift-proxy deployment is clustered using the hacluster charm, the
24 | corresponding hacluster unit on the node must first be paused as well.
25 | Not doing so may lead to an interruption of service.
26 | resume:
27 | description: |
28 | Resume swift-proxy services.
29 | If the swift-proxy deployment is clustered using the hacluster charm, the
30 | corresponding hacluster unit on the node must be resumed as well.
31 | openstack-upgrade:
32 | description: |
33 | Perform openstack upgrades. Config option action-managed-upgrade must be
34 | set to True.
35 | diskusage:
36 | description: Run swift-recon -d on the specified unit. Returns values in GB.
37 | remove-devices:
38 | description: |
39 | Removes the device(s) from the ring. This should normally just be used for
40 | a device that has failed. For a device you wish to decommission, it's best
41 | to set its weight to 0, wait for it to drain all its data, then use this
42 | remove-from-ring action.
43 | params:
44 | ring:
45 | type: string
46 | description: |
47 | Swift ring to remove the device(s) from. Valid options are 'account',
48 | 'container', 'object' or 'all'.
49 | search-value:
50 | type: string
51 | description: |
52 | The search-value can be of the form:
53 | .
54 | drz-:R:/
55 | _
56 | .
57 | Where and are replication ip and port. Any part is
58 | optional, but you must include at least one part.
59 | required:
60 | - ring
61 | - search-value
62 | set-weight:
63 | description: Sets the device's weight.
64 | params:
65 | ring:
66 | type: string
67 | description: |
68 | Swift ring to set the weight for. Valid options are 'account',
69 | 'container', 'object' or 'all'.
70 | search-value:
71 | type: string
72 | description: |
73 | The search-value can be of the form:
74 | .
75 | drz-:R:/
76 | _
77 | .
78 | Where and are replication ip and port. Any part is
79 | optional, but you must include at least one part.
80 | weight:
81 | type: number
82 | description: The device's weight
83 | required:
84 | - ring
85 | - search-value
86 | - weight
87 | dispersion-populate:
88 | description: Run swift-dispersion-populate command on the specified unit.
89 | dispersion-report:
90 | description: Run swift-dispersion-report command on the specified unit.
91 |
--------------------------------------------------------------------------------
/actions/__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 |
--------------------------------------------------------------------------------
/actions/add-user:
--------------------------------------------------------------------------------
1 | add_user.py
--------------------------------------------------------------------------------
/actions/add_user.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 | _path = os.path.dirname(os.path.realpath(__file__))
21 | _parent = os.path.abspath(os.path.join(_path, '..'))
22 |
23 |
24 | def _add_path(path):
25 | if path not in sys.path:
26 | sys.path.insert(1, path)
27 |
28 |
29 | _add_path(_parent)
30 |
31 |
32 | from subprocess import (
33 | check_call,
34 | CalledProcessError
35 | )
36 |
37 | from charmhelpers.core.hookenv import (
38 | action_get,
39 | config,
40 | action_set,
41 | action_fail,
42 | leader_get,
43 | log,
44 | )
45 |
46 | from charmhelpers.contrib.openstack.utils import (
47 | os_release,
48 | CompareOpenStackReleases,
49 | )
50 |
51 | from charmhelpers.contrib.hahelpers.cluster import (
52 | determine_api_port,
53 | )
54 |
55 | from lib.swift_utils import (
56 | try_initialize_swauth,
57 | )
58 |
59 |
60 | def add_user():
61 | """Add a swauth user to swift."""
62 | if config('auth-type') == 'swauth':
63 | cmp_openstack = CompareOpenStackReleases(os_release('swift'))
64 | if cmp_openstack >= 'train':
65 | message = "swauth is not supported for OpenStack Train and later"
66 | log(message)
67 | action_fail(message)
68 | return None
69 | try_initialize_swauth()
70 | account = action_get('account')
71 | username = action_get('username')
72 | password = action_get('password')
73 | bind_port = config('bind-port')
74 | bind_port = determine_api_port(bind_port, singlenode_mode=True)
75 | success = True
76 | try:
77 | check_call([
78 | "swauth-add-user",
79 | "-A", "http://localhost:{}/auth/".format(bind_port),
80 | "-K", leader_get('swauth-admin-key'),
81 | "-a", account, username, password])
82 | except CalledProcessError as e:
83 | success = False
84 | log("Has a problem adding user: {}".format(e.output))
85 | action_fail(
86 | "Adding user {} failed with: \"{}\""
87 | .format(username, str(e)))
88 | if success:
89 | message = "Successfully added the user {}".format(username)
90 | action_set({
91 | 'add-user.result': 'Success',
92 | 'add-user.message': message,
93 | })
94 |
95 |
96 | if __name__ == '__main__':
97 | add_user()
98 |
--------------------------------------------------------------------------------
/actions/diskusage:
--------------------------------------------------------------------------------
1 | actions.py
--------------------------------------------------------------------------------
/actions/dispersion-populate:
--------------------------------------------------------------------------------
1 | actions.py
--------------------------------------------------------------------------------
/actions/dispersion-report:
--------------------------------------------------------------------------------
1 | actions.py
--------------------------------------------------------------------------------
/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 | import os
17 | import sys
18 |
19 | _path = os.path.dirname(os.path.realpath(__file__))
20 | _parent = os.path.abspath(os.path.join(_path, '..'))
21 |
22 |
23 | def _add_path(path):
24 | if path not in sys.path:
25 | sys.path.insert(1, path)
26 |
27 |
28 | _add_path(_parent)
29 |
30 |
31 | from charmhelpers.contrib.openstack.utils import (
32 | do_action_openstack_upgrade,
33 | )
34 |
35 | from hooks.swift_hooks import (
36 | config_changed,
37 | CONFIGS,
38 | )
39 |
40 | from lib.swift_utils import (
41 | do_openstack_upgrade,
42 | )
43 |
44 |
45 | def openstack_upgrade():
46 | """Upgrade packages to config-set Openstack version.
47 |
48 | If the charm was installed from source we cannot upgrade it.
49 | For backwards compatibility a config flag must be set for this
50 | code to run, otherwise a full service level upgrade will fire
51 | on config-changed."""
52 |
53 | if (do_action_openstack_upgrade('swift',
54 | do_openstack_upgrade,
55 | CONFIGS)):
56 | config_changed()
57 |
58 |
59 | if __name__ == '__main__':
60 | openstack_upgrade()
61 |
--------------------------------------------------------------------------------
/actions/pause:
--------------------------------------------------------------------------------
1 | actions.py
--------------------------------------------------------------------------------
/actions/remove-devices:
--------------------------------------------------------------------------------
1 | actions.py
--------------------------------------------------------------------------------
/actions/resume:
--------------------------------------------------------------------------------
1 | actions.py
--------------------------------------------------------------------------------
/actions/set-weight:
--------------------------------------------------------------------------------
1 | actions.py
--------------------------------------------------------------------------------
/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: charmhelpers
3 | include:
4 | - core
5 | - osplatform
6 | - cli
7 | - fetch
8 | - contrib.openstack|inc=*
9 | - contrib.storage.linux
10 | - contrib.hardware.pci
11 | - contrib.hahelpers:
12 | - apache
13 | - cluster
14 | - payload.execd
15 | - contrib.network.ip
16 | - contrib.peerstorage
17 | - contrib.python
18 | - contrib.charmsupport
19 | - contrib.hardening|inc=*
20 | - contrib.openstack.policyd
21 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/charmhelpers/contrib/hardening/apache/templates/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstack/charm-swift-proxy/b4aa3c978b8be71585d43475598394451dbad11c/charmhelpers/contrib/hardening/apache/templates/__init__.py
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/charmhelpers/contrib/hardening/audits/apache.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 re
16 | import subprocess
17 |
18 | from charmhelpers.core.hookenv import (
19 | log,
20 | INFO,
21 | ERROR,
22 | )
23 |
24 | from charmhelpers.contrib.hardening.audits import BaseAudit
25 |
26 |
27 | class DisabledModuleAudit(BaseAudit):
28 | """Audits Apache2 modules.
29 |
30 | Determines if the apache2 modules are enabled. If the modules are enabled
31 | then they are removed in the ensure_compliance.
32 | """
33 | def __init__(self, modules):
34 | if modules is None:
35 | self.modules = []
36 | elif isinstance(modules, str):
37 | self.modules = [modules]
38 | else:
39 | self.modules = modules
40 |
41 | def ensure_compliance(self):
42 | """Ensures that the modules are not loaded."""
43 | if not self.modules:
44 | return
45 |
46 | try:
47 | loaded_modules = self._get_loaded_modules()
48 | non_compliant_modules = []
49 | for module in self.modules:
50 | if module in loaded_modules:
51 | log("Module '%s' is enabled but should not be." %
52 | (module), level=INFO)
53 | non_compliant_modules.append(module)
54 |
55 | if len(non_compliant_modules) == 0:
56 | return
57 |
58 | for module in non_compliant_modules:
59 | self._disable_module(module)
60 | self._restart_apache()
61 | except subprocess.CalledProcessError as e:
62 | log('Error occurred auditing apache module compliance. '
63 | 'This may have been already reported. '
64 | 'Output is: %s' % e.output, level=ERROR)
65 |
66 | @staticmethod
67 | def _get_loaded_modules():
68 | """Returns the modules which are enabled in Apache."""
69 | output = subprocess.check_output(['apache2ctl', '-M']).decode('utf-8')
70 | modules = []
71 | for line in output.splitlines():
72 | # Each line of the enabled module output looks like:
73 | # module_name (static|shared)
74 | # Plus a header line at the top of the output which is stripped
75 | # out by the regex.
76 | matcher = re.search(r'^ (\S*)_module (\S*)', line)
77 | if matcher:
78 | modules.append(matcher.group(1))
79 | return modules
80 |
81 | @staticmethod
82 | def _disable_module(module):
83 | """Disables the specified module in Apache."""
84 | try:
85 | subprocess.check_call(['a2dismod', module])
86 | except subprocess.CalledProcessError as e:
87 | # Note: catch error here to allow the attempt of disabling
88 | # multiple modules in one go rather than failing after the
89 | # first module fails.
90 | log('Error occurred disabling module %s. '
91 | 'Output is: %s' % (module, e.output), level=ERROR)
92 |
93 | @staticmethod
94 | def _restart_apache():
95 | """Restarts the apache process"""
96 | subprocess.check_output(['service', 'apache2', 'restart'])
97 |
98 | @staticmethod
99 | def is_ssl_enabled():
100 | """Check if SSL module is enabled or not"""
101 | return 'ssl' in DisabledModuleAudit._get_loaded_modules()
102 |
--------------------------------------------------------------------------------
/charmhelpers/contrib/hardening/audits/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.fetch import (
16 | apt_cache,
17 | apt_purge
18 | )
19 | from charmhelpers.core.hookenv import (
20 | log,
21 | DEBUG,
22 | WARNING,
23 | )
24 | from charmhelpers.contrib.hardening.audits import BaseAudit
25 | from charmhelpers.fetch import ubuntu_apt_pkg as apt_pkg
26 |
27 |
28 | class AptConfig(BaseAudit):
29 |
30 | def __init__(self, config, **kwargs):
31 | self.config = config
32 |
33 | def verify_config(self):
34 | apt_pkg.init()
35 | for cfg in self.config:
36 | value = apt_pkg.config.get(cfg['key'], cfg.get('default', ''))
37 | if value and value != cfg['expected']:
38 | log("APT config '%s' has unexpected value '%s' "
39 | "(expected='%s')" %
40 | (cfg['key'], value, cfg['expected']), level=WARNING)
41 |
42 | def ensure_compliance(self):
43 | self.verify_config()
44 |
45 |
46 | class RestrictedPackages(BaseAudit):
47 | """Class used to audit restricted packages on the system."""
48 |
49 | def __init__(self, pkgs, **kwargs):
50 | super(RestrictedPackages, self).__init__(**kwargs)
51 | if isinstance(pkgs, str) or not hasattr(pkgs, '__iter__'):
52 | self.pkgs = pkgs.split()
53 | else:
54 | self.pkgs = pkgs
55 |
56 | def ensure_compliance(self):
57 | cache = apt_cache()
58 |
59 | for p in self.pkgs:
60 | if p not in cache:
61 | continue
62 |
63 | pkg = cache[p]
64 | if not self.is_virtual_package(pkg):
65 | if not pkg.current_ver:
66 | log("Package '%s' is not installed." % pkg.name,
67 | level=DEBUG)
68 | continue
69 | else:
70 | log("Restricted package '%s' is installed" % pkg.name,
71 | level=WARNING)
72 | self.delete_package(cache, pkg)
73 | else:
74 | log("Checking restricted virtual package '%s' provides" %
75 | pkg.name, level=DEBUG)
76 | self.delete_package(cache, pkg)
77 |
78 | def delete_package(self, cache, pkg):
79 | """Deletes the package from the system.
80 |
81 | Deletes the package form the system, properly handling virtual
82 | packages.
83 |
84 | :param cache: the apt cache
85 | :param pkg: the package to remove
86 | """
87 | if self.is_virtual_package(pkg):
88 | log("Package '%s' appears to be virtual - purging provides" %
89 | pkg.name, level=DEBUG)
90 | for _p in pkg.provides_list:
91 | self.delete_package(cache, _p[2].parent_pkg)
92 | elif not pkg.current_ver:
93 | log("Package '%s' not installed" % pkg.name, level=DEBUG)
94 | return
95 | else:
96 | log("Purging package '%s'" % pkg.name, level=DEBUG)
97 | apt_purge(pkg.name)
98 |
99 | def is_virtual_package(self, pkg):
100 | return (pkg.get('has_provides', False) and
101 | not pkg.get('has_versions', False))
102 |
--------------------------------------------------------------------------------
/charmhelpers/contrib/hardening/defaults/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstack/charm-swift-proxy/b4aa3c978b8be71585d43475598394451dbad11c/charmhelpers/contrib/hardening/defaults/__init__.py
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 %}
--------------------------------------------------------------------------------
/charmhelpers/contrib/hardening/host/templates/99-hardening.sh:
--------------------------------------------------------------------------------
1 | TMOUT={{ tmout }}
2 | readonly TMOUT
3 | export TMOUT
4 |
5 | readonly HISTFILE
6 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/charmhelpers/contrib/hardening/host/templates/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstack/charm-swift-proxy/b4aa3c978b8be71585d43475598394451dbad11c/charmhelpers/contrib/hardening/host/templates/__init__.py
--------------------------------------------------------------------------------
/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
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/charmhelpers/contrib/hardening/mysql/templates/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstack/charm-swift-proxy/b4aa3c978b8be71585d43475598394451dbad11c/charmhelpers/contrib/hardening/mysql/templates/__init__.py
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/charmhelpers/contrib/hardening/ssh/templates/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstack/charm-swift-proxy/b4aa3c978b8be71585d43475598394451dbad11c/charmhelpers/contrib/hardening/ssh/templates/__init__.py
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/charmhelpers/contrib/openstack/templates/section-audit-middleware-notifications:
--------------------------------------------------------------------------------
1 | {% if audit_middleware -%}
2 | [audit_middleware_notifications]
3 | driver = log
4 | {% endif -%}
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 -%}
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/charmhelpers/contrib/openstack/templates/section-oslo-middleware:
--------------------------------------------------------------------------------
1 | [oslo_middleware]
2 |
3 | # Bug #1758675
4 | enable_proxy_headers_parsing = true
5 |
6 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/charmhelpers/contrib/openstack/templates/vendor_data.json:
--------------------------------------------------------------------------------
1 | {{ vendor_data_json }}
--------------------------------------------------------------------------------
/charmhelpers/contrib/openstack/templates/wsgi-openstack-api.conf:
--------------------------------------------------------------------------------
1 | # Configuration file maintained by Juju. Local changes may be overwritten.
2 |
3 | {% if port -%}
4 | Listen {{ port }}
5 | {% endif -%}
6 |
7 | {% if admin_port -%}
8 | Listen {{ admin_port }}
9 | {% endif -%}
10 |
11 | {% if public_port -%}
12 | Listen {{ public_port }}
13 | {% endif -%}
14 |
15 | {% if wsgi_socket_rotation -%}
16 | WSGISocketRotation On
17 | {% else -%}
18 | WSGISocketRotation Off
19 | {% endif -%}
20 |
21 | {% if port -%}
22 |
23 | WSGIDaemonProcess {{ service_name }} processes={{ processes }} threads={{ threads }} user={{ user }} group={{ group }} \
24 | display-name=%{GROUP} lang=C.UTF-8 locale=C.UTF-8
25 | WSGIProcessGroup {{ service_name }}
26 | WSGIScriptAlias / {{ script }}
27 | WSGIApplicationGroup %{GLOBAL}
28 | WSGIPassAuthorization On
29 | KeepAliveTimeout 75
30 | MaxKeepAliveRequests 1000
31 | = 2.4>
32 | ErrorLogFormat "%{cu}t %M"
33 |
34 | ErrorLog /var/log/apache2/{{ service_name }}_error.log
35 | CustomLog /var/log/apache2/{{ service_name }}_access.log combined
36 |
37 |
38 | = 2.4>
39 | Require all granted
40 |
41 |
42 | Order allow,deny
43 | Allow from all
44 |
45 |
46 |
47 | {% endif -%}
48 |
49 | {% if admin_port -%}
50 |
51 | WSGIDaemonProcess {{ service_name }}-admin processes={{ admin_processes }} threads={{ threads }} user={{ user }} group={{ group }} \
52 | display-name=%{GROUP} lang=C.UTF-8 locale=C.UTF-8
53 | WSGIProcessGroup {{ service_name }}-admin
54 | WSGIScriptAlias / {{ admin_script }}
55 | WSGIApplicationGroup %{GLOBAL}
56 | WSGIPassAuthorization On
57 | KeepAliveTimeout 75
58 | MaxKeepAliveRequests 1000
59 | = 2.4>
60 | ErrorLogFormat "%{cu}t %M"
61 |
62 | ErrorLog /var/log/apache2/{{ service_name }}_error.log
63 | CustomLog /var/log/apache2/{{ service_name }}_access.log combined
64 |
65 |
66 | = 2.4>
67 | Require all granted
68 |
69 |
70 | Order allow,deny
71 | Allow from all
72 |
73 |
74 |
75 | {% endif -%}
76 |
77 | {% if public_port -%}
78 |
79 | WSGIDaemonProcess {{ service_name }}-public processes={{ public_processes }} threads={{ threads }} user={{ user }} group={{ group }} \
80 | display-name=%{GROUP} lang=C.UTF-8 locale=C.UTF-8
81 | WSGIProcessGroup {{ service_name }}-public
82 | WSGIScriptAlias / {{ public_script }}
83 | WSGIApplicationGroup %{GLOBAL}
84 | WSGIPassAuthorization On
85 | KeepAliveTimeout 75
86 | MaxKeepAliveRequests 1000
87 | = 2.4>
88 | ErrorLogFormat "%{cu}t %M"
89 |
90 | ErrorLog /var/log/apache2/{{ service_name }}_error.log
91 | CustomLog /var/log/apache2/{{ service_name }}_access.log combined
92 |
93 |
94 | = 2.4>
95 | Require all granted
96 |
97 |
98 | Order allow,deny
99 | Allow from all
100 |
101 |
102 |
103 | {% endif -%}
104 |
--------------------------------------------------------------------------------
/charmhelpers/contrib/openstack/templates/wsgi-openstack-metadata.conf:
--------------------------------------------------------------------------------
1 | # Configuration file maintained by Juju. Local changes may be overwritten.
2 |
3 | {% if port -%}
4 | Listen {{ port }}
5 | {% endif -%}
6 |
7 | {% if admin_port -%}
8 | Listen {{ admin_port }}
9 | {% endif -%}
10 |
11 | {% if public_port -%}
12 | Listen {{ public_port }}
13 | {% endif -%}
14 |
15 | {% if wsgi_socket_rotation -%}
16 | WSGISocketRotation On
17 | {% else -%}
18 | WSGISocketRotation Off
19 | {% endif -%}
20 |
21 | {% if port -%}
22 |
23 | WSGIDaemonProcess {{ service_name }} processes={{ processes }} threads={{ threads }} user={{ user }} group={{ group }} \
24 | display-name=%{GROUP} lang=C.UTF-8 locale=C.UTF-8
25 | WSGIProcessGroup {{ service_name }}
26 | WSGIScriptAlias / {{ script }}
27 | WSGIApplicationGroup %{GLOBAL}
28 | WSGIPassAuthorization On
29 | KeepAliveTimeout 75
30 | MaxKeepAliveRequests 1000
31 | = 2.4>
32 | ErrorLogFormat "%{cu}t %M"
33 |
34 | ErrorLog /var/log/apache2/{{ service_name }}_error.log
35 | CustomLog /var/log/apache2/{{ service_name }}_access.log combined
36 |
37 |
38 | = 2.4>
39 | Require all granted
40 |
41 |
42 | Order allow,deny
43 | Allow from all
44 |
45 |
46 |
47 | {% endif -%}
48 |
49 | {% if admin_port -%}
50 |
51 | WSGIDaemonProcess {{ service_name }}-admin processes={{ admin_processes }} threads={{ threads }} user={{ user }} group={{ group }} \
52 | display-name=%{GROUP} lang=C.UTF-8 locale=C.UTF-8
53 | WSGIProcessGroup {{ service_name }}-admin
54 | WSGIScriptAlias / {{ admin_script }}
55 | WSGIApplicationGroup %{GLOBAL}
56 | WSGIPassAuthorization On
57 | KeepAliveTimeout 75
58 | MaxKeepAliveRequests 1000
59 | = 2.4>
60 | ErrorLogFormat "%{cu}t %M"
61 |
62 | ErrorLog /var/log/apache2/{{ service_name }}_error.log
63 | CustomLog /var/log/apache2/{{ service_name }}_access.log combined
64 |
65 |
66 | = 2.4>
67 | Require all granted
68 |
69 |
70 | Order allow,deny
71 | Allow from all
72 |
73 |
74 |
75 | {% endif -%}
76 |
77 | {% if public_port -%}
78 |
79 | WSGIDaemonProcess {{ service_name }}-public processes={{ public_processes }} threads={{ threads }} user={{ user }} group={{ group }} \
80 | display-name=%{GROUP} lang=C.UTF-8 locale=C.UTF-8
81 | WSGIProcessGroup {{ service_name }}-public
82 | WSGIScriptAlias / {{ public_script }}
83 | WSGIApplicationGroup %{GLOBAL}
84 | WSGIPassAuthorization On
85 | KeepAliveTimeout 75
86 | MaxKeepAliveRequests 1000
87 | = 2.4>
88 | ErrorLogFormat "%{cu}t %M"
89 |
90 | ErrorLog /var/log/apache2/{{ service_name }}_error.log
91 | CustomLog /var/log/apache2/{{ service_name }}_access.log combined
92 |
93 |
94 | = 2.4>
95 | Require all granted
96 |
97 |
98 | Order allow,deny
99 | Allow from all
100 |
101 |
102 |
103 | {% endif -%}
104 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/charmhelpers/core/decorators.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 2014 Canonical Ltd.
17 | #
18 | # Authors:
19 | # Edward Hope-Morley
20 | #
21 |
22 | import time
23 |
24 | from charmhelpers.core.hookenv import (
25 | log,
26 | INFO,
27 | )
28 |
29 |
30 | def retry_on_exception(num_retries, base_delay=0, exc_type=Exception):
31 | """If the decorated function raises exception exc_type, allow num_retries
32 | retry attempts before raise the exception.
33 | """
34 | def _retry_on_exception_inner_1(f):
35 | def _retry_on_exception_inner_2(*args, **kwargs):
36 | retries = num_retries
37 | multiplier = 1
38 | while True:
39 | try:
40 | return f(*args, **kwargs)
41 | except exc_type:
42 | if not retries:
43 | raise
44 |
45 | delay = base_delay * multiplier
46 | multiplier += 1
47 | log("Retrying '%s' %d more times (delay=%s)" %
48 | (f.__name__, retries, delay), level=INFO)
49 | retries -= 1
50 | if delay:
51 | time.sleep(delay)
52 |
53 | return _retry_on_exception_inner_2
54 |
55 | return _retry_on_exception_inner_1
56 |
57 |
58 | def retry_on_predicate(num_retries, predicate_fun, base_delay=0):
59 | """Retry based on return value
60 |
61 | The return value of the decorated function is passed to the given predicate_fun. If the
62 | result of the predicate is False, retry the decorated function up to num_retries times
63 |
64 | An exponential backoff up to base_delay^num_retries seconds can be introduced by setting
65 | base_delay to a nonzero value. The default is to run with a zero (i.e. no) delay
66 |
67 | :param num_retries: Max. number of retries to perform
68 | :type num_retries: int
69 | :param predicate_fun: Predicate function to determine if a retry is necessary
70 | :type predicate_fun: callable
71 | :param base_delay: Starting value in seconds for exponential delay, defaults to 0 (no delay)
72 | :type base_delay: float
73 | """
74 | def _retry_on_pred_inner_1(f):
75 | def _retry_on_pred_inner_2(*args, **kwargs):
76 | retries = num_retries
77 | multiplier = 1
78 | delay = base_delay
79 | while True:
80 | result = f(*args, **kwargs)
81 | if predicate_fun(result) or retries <= 0:
82 | return result
83 | delay *= multiplier
84 | multiplier += 1
85 | log("Result {}, retrying '{}' {} more times (delay={})".format(
86 | result, f.__name__, retries, delay), level=INFO)
87 | retries -= 1
88 | if delay:
89 | time.sleep(delay)
90 |
91 | return _retry_on_pred_inner_2
92 |
93 | return _retry_on_pred_inner_1
94 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/charmhelpers/core/host_factory/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstack/charm-swift-proxy/b4aa3c978b8be71585d43475598394451dbad11c/charmhelpers/core/host_factory/__init__.py
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/charmhelpers/core/host_factory/ubuntu.py:
--------------------------------------------------------------------------------
1 | import subprocess
2 |
3 | from charmhelpers.core.hookenv import cached
4 | from charmhelpers.core.strutils import BasicStringComparator
5 |
6 |
7 | UBUNTU_RELEASES = (
8 | 'lucid',
9 | 'maverick',
10 | 'natty',
11 | 'oneiric',
12 | 'precise',
13 | 'quantal',
14 | 'raring',
15 | 'saucy',
16 | 'trusty',
17 | 'utopic',
18 | 'vivid',
19 | 'wily',
20 | 'xenial',
21 | 'yakkety',
22 | 'zesty',
23 | 'artful',
24 | 'bionic',
25 | 'cosmic',
26 | 'disco',
27 | 'eoan',
28 | 'focal',
29 | 'groovy',
30 | 'hirsute',
31 | 'impish',
32 | 'jammy',
33 | 'kinetic',
34 | 'lunar',
35 | 'mantic',
36 | 'noble',
37 | 'oracular',
38 | )
39 |
40 |
41 | class CompareHostReleases(BasicStringComparator):
42 | """Provide comparisons of Ubuntu releases.
43 |
44 | Use in the form of
45 |
46 | if CompareHostReleases(release) > 'trusty':
47 | # do something with mitaka
48 | """
49 | _list = UBUNTU_RELEASES
50 |
51 |
52 | def service_available(service_name):
53 | """Determine whether a system service is available"""
54 | try:
55 | subprocess.check_output(
56 | ['service', service_name, 'status'],
57 | stderr=subprocess.STDOUT).decode('UTF-8')
58 | except subprocess.CalledProcessError as e:
59 | return b'unrecognized service' not in e.output
60 | else:
61 | return True
62 |
63 |
64 | def add_new_group(group_name, system_group=False, gid=None):
65 | cmd = ['addgroup']
66 | if gid:
67 | cmd.extend(['--gid', str(gid)])
68 | if system_group:
69 | cmd.append('--system')
70 | else:
71 | cmd.extend([
72 | '--group',
73 | ])
74 | cmd.append(group_name)
75 | subprocess.check_call(cmd)
76 |
77 |
78 | def lsb_release():
79 | """Return /etc/lsb-release in a dict"""
80 | d = {}
81 | with open('/etc/lsb-release', 'r') as lsb:
82 | for l in lsb:
83 | k, v = l.split('=')
84 | d[k.strip()] = v.strip()
85 | return d
86 |
87 |
88 | def get_distrib_codename():
89 | """Return the codename of the distribution
90 | :returns: The codename
91 | :rtype: str
92 | """
93 | return lsb_release()['DISTRIB_CODENAME'].lower()
94 |
95 |
96 | def cmp_pkgrevno(package, revno, pkgcache=None):
97 | """Compare supplied revno with the revno of the installed package.
98 |
99 | * 1 => Installed revno is greater than supplied arg
100 | * 0 => Installed revno is the same as supplied arg
101 | * -1 => Installed revno is less than supplied arg
102 |
103 | This function imports apt_cache function from charmhelpers.fetch if
104 | the pkgcache argument is None. Be sure to add charmhelpers.fetch if
105 | you call this function, or pass an apt_pkg.Cache() instance.
106 | """
107 | from charmhelpers.fetch import apt_pkg, get_installed_version
108 | if not pkgcache:
109 | current_ver = get_installed_version(package)
110 | else:
111 | pkg = pkgcache[package]
112 | current_ver = pkg.current_ver
113 |
114 | return apt_pkg.version_compare(current_ver.ver_str, revno)
115 |
116 |
117 | @cached
118 | def arch():
119 | """Return the package architecture as a string.
120 |
121 | :returns: the architecture
122 | :rtype: str
123 | :raises: subprocess.CalledProcessError if dpkg command fails
124 | """
125 | return subprocess.check_output(
126 | ['dpkg', '--print-architecture']
127 | ).rstrip().decode('UTF-8')
128 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/charmhelpers/core/kernel_factory/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstack/charm-swift-proxy/b4aa3c978b8be71585d43475598394451dbad11c/charmhelpers/core/kernel_factory/__init__.py
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/charmhelpers/core/templating.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 |
17 | from charmhelpers.core import host
18 | from charmhelpers.core import hookenv
19 |
20 |
21 | def render(source, target, context, owner='root', group='root',
22 | perms=0o444, templates_dir=None, encoding='UTF-8',
23 | template_loader=None, config_template=None):
24 | """
25 | Render a template.
26 |
27 | The `source` path, if not absolute, is relative to the `templates_dir`.
28 |
29 | The `target` path should be absolute. It can also be `None`, in which
30 | case no file will be written.
31 |
32 | The context should be a dict containing the values to be replaced in the
33 | template.
34 |
35 | config_template may be provided to render from a provided template instead
36 | of loading from a file.
37 |
38 | The `owner`, `group`, and `perms` options will be passed to `write_file`.
39 |
40 | If omitted, `templates_dir` defaults to the `templates` folder in the charm.
41 |
42 | The rendered template will be written to the file as well as being returned
43 | as a string.
44 |
45 | Note: Using this requires python3-jinja2; if it is not installed, calling
46 | this will attempt to use charmhelpers.fetch.apt_install to install it.
47 | """
48 | try:
49 | from jinja2 import FileSystemLoader, Environment, exceptions
50 | except ImportError:
51 | try:
52 | from charmhelpers.fetch import apt_install
53 | except ImportError:
54 | hookenv.log('Could not import jinja2, and could not import '
55 | 'charmhelpers.fetch to install it',
56 | level=hookenv.ERROR)
57 | raise
58 | apt_install('python3-jinja2', fatal=True)
59 | from jinja2 import FileSystemLoader, Environment, exceptions
60 |
61 | if template_loader:
62 | template_env = Environment(loader=template_loader)
63 | else:
64 | if templates_dir is None:
65 | templates_dir = os.path.join(hookenv.charm_dir(), 'templates')
66 | template_env = Environment(loader=FileSystemLoader(templates_dir))
67 |
68 | # load from a string if provided explicitly
69 | if config_template is not None:
70 | template = template_env.from_string(config_template)
71 | else:
72 | try:
73 | source = source
74 | template = template_env.get_template(source)
75 | except exceptions.TemplateNotFound as e:
76 | hookenv.log('Could not load template %s from %s.' %
77 | (source, templates_dir),
78 | level=hookenv.ERROR)
79 | raise e
80 | content = template.render(context)
81 | if target is not None:
82 | target_dir = os.path.dirname(target)
83 | if not os.path.exists(target_dir):
84 | # This is a terrible default directory permission, as the file
85 | # or its siblings will often contain secrets.
86 | host.mkdir(os.path.dirname(target), owner, group, perms=0o755)
87 | host.write_file(target, content.encode(encoding), owner, group, perms)
88 | return content
89 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/copyright:
--------------------------------------------------------------------------------
1 | Format: http://dep.debian.net/deps/dep5/
2 |
3 | Files: *
4 | Copyright: Copyright 2012, Canonical Ltd., All Rights Reserved.
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/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstack/charm-swift-proxy/b4aa3c978b8be71585d43475598394451dbad11c/files/.gitkeep
--------------------------------------------------------------------------------
/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/__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/amqp-relation-broken:
--------------------------------------------------------------------------------
1 | swift_hooks.py
--------------------------------------------------------------------------------
/hooks/amqp-relation-changed:
--------------------------------------------------------------------------------
1 | swift_hooks.py
--------------------------------------------------------------------------------
/hooks/amqp-relation-departed:
--------------------------------------------------------------------------------
1 | swift_hooks.py
--------------------------------------------------------------------------------
/hooks/amqp-relation-joined:
--------------------------------------------------------------------------------
1 | swift_hooks.py
--------------------------------------------------------------------------------
/hooks/certificates-relation-changed:
--------------------------------------------------------------------------------
1 | swift_hooks.py
--------------------------------------------------------------------------------
/hooks/certificates-relation-departed:
--------------------------------------------------------------------------------
1 | swift_hooks.py
--------------------------------------------------------------------------------
/hooks/certificates-relation-joined:
--------------------------------------------------------------------------------
1 | swift_hooks.py
--------------------------------------------------------------------------------
/hooks/cluster-relation-changed:
--------------------------------------------------------------------------------
1 | swift_hooks.py
--------------------------------------------------------------------------------
/hooks/cluster-relation-departed:
--------------------------------------------------------------------------------
1 | swift_hooks.py
--------------------------------------------------------------------------------
/hooks/cluster-relation-joined:
--------------------------------------------------------------------------------
1 | swift_hooks.py
--------------------------------------------------------------------------------
/hooks/config-changed:
--------------------------------------------------------------------------------
1 | swift_hooks.py
--------------------------------------------------------------------------------
/hooks/ha-relation-changed:
--------------------------------------------------------------------------------
1 | swift_hooks.py
--------------------------------------------------------------------------------
/hooks/ha-relation-joined:
--------------------------------------------------------------------------------
1 | swift_hooks.py
--------------------------------------------------------------------------------
/hooks/identity-service-relation-changed:
--------------------------------------------------------------------------------
1 | swift_hooks.py
--------------------------------------------------------------------------------
/hooks/identity-service-relation-joined:
--------------------------------------------------------------------------------
1 | swift_hooks.py
--------------------------------------------------------------------------------
/hooks/install:
--------------------------------------------------------------------------------
1 | #!/bin/bash -e
2 | # Wrapper to deal with newer Ubuntu versions that don't have py2 installed
3 | # by default.
4 |
5 | declare -a DEPS=('apt' 'netaddr' 'netifaces' 'pip' 'yaml' 'dnspython')
6 |
7 | check_and_install() {
8 | pkg="${1}-${2}"
9 | if ! dpkg -s ${pkg} 2>&1 > /dev/null; then
10 | apt-get -y install ${pkg}
11 | fi
12 | }
13 |
14 | PYTHON="python3"
15 |
16 | for dep in ${DEPS[@]}; do
17 | check_and_install ${PYTHON} ${dep}
18 | done
19 |
20 | exec ./hooks/install.real
21 |
--------------------------------------------------------------------------------
/hooks/install.real:
--------------------------------------------------------------------------------
1 | swift_hooks.py
--------------------------------------------------------------------------------
/hooks/leader-deposed:
--------------------------------------------------------------------------------
1 | swift_hooks.py
--------------------------------------------------------------------------------
/hooks/leader-elected:
--------------------------------------------------------------------------------
1 | swift_hooks.py
--------------------------------------------------------------------------------
/hooks/leader-settings-changed:
--------------------------------------------------------------------------------
1 | swift_hooks.py
--------------------------------------------------------------------------------
/hooks/nrpe-external-master-relation-changed:
--------------------------------------------------------------------------------
1 | swift_hooks.py
--------------------------------------------------------------------------------
/hooks/nrpe-external-master-relation-joined:
--------------------------------------------------------------------------------
1 | swift_hooks.py
--------------------------------------------------------------------------------
/hooks/object-store-relation-joined:
--------------------------------------------------------------------------------
1 | swift_hooks.py
--------------------------------------------------------------------------------
/hooks/post-series-upgrade:
--------------------------------------------------------------------------------
1 | swift_hooks.py
--------------------------------------------------------------------------------
/hooks/pre-series-upgrade:
--------------------------------------------------------------------------------
1 | swift_hooks.py
--------------------------------------------------------------------------------
/hooks/rings-consumer-relation-changed:
--------------------------------------------------------------------------------
1 | swift_hooks.py
--------------------------------------------------------------------------------
/hooks/rings-consumer-relation-departed:
--------------------------------------------------------------------------------
1 | swift_hooks.py
--------------------------------------------------------------------------------
/hooks/rings-consumer-relation-joined:
--------------------------------------------------------------------------------
1 | swift_hooks.py
--------------------------------------------------------------------------------
/hooks/rings-distributor-relation-changed:
--------------------------------------------------------------------------------
1 | swift_hooks.py
--------------------------------------------------------------------------------
/hooks/rings-distributor-relation-departed:
--------------------------------------------------------------------------------
1 | swift_hooks.py
--------------------------------------------------------------------------------
/hooks/rings-distributor-relation-joined:
--------------------------------------------------------------------------------
1 | swift_hooks.py
--------------------------------------------------------------------------------
/hooks/start:
--------------------------------------------------------------------------------
1 | swift_hooks.py
--------------------------------------------------------------------------------
/hooks/stop:
--------------------------------------------------------------------------------
1 | swift_hooks.py
--------------------------------------------------------------------------------
/hooks/swift-storage-relation-broken:
--------------------------------------------------------------------------------
1 | swift_hooks.py
--------------------------------------------------------------------------------
/hooks/swift-storage-relation-changed:
--------------------------------------------------------------------------------
1 | swift_hooks.py
--------------------------------------------------------------------------------
/hooks/swift-storage-relation-joined:
--------------------------------------------------------------------------------
1 | swift_hooks.py
--------------------------------------------------------------------------------
/hooks/update-status:
--------------------------------------------------------------------------------
1 | swift_hooks.py
--------------------------------------------------------------------------------
/hooks/upgrade-charm:
--------------------------------------------------------------------------------
1 | swift_hooks.py
--------------------------------------------------------------------------------
/lib/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openstack/charm-swift-proxy/b4aa3c978b8be71585d43475598394451dbad11c/lib/__init__.py
--------------------------------------------------------------------------------
/metadata.yaml:
--------------------------------------------------------------------------------
1 | name: swift-proxy
2 | summary: OpenStack Object Storage - Swift proxy service
3 | maintainer: OpenStack Charmers
4 | description: |
5 | OpenStack Object Storage (code-named Swift) is open source software for
6 | creating redundant, scalable object storage using clusters of standardized
7 | servers to store petabytes of accessible data. It is not a file system or
8 | real-time data storage system, but rather a long-term storage system for a
9 | more permanent type of static data that can be retrieved, leveraged, and
10 | then updated if necessary. Primary examples of data that best fit this
11 | type of storage model are virtual machine images, photo storage, email
12 | storage and backup archiving. Having no central "brain" or master point of
13 | control provides greater scalability, redundancy and permanence.
14 | .
15 | This charm deploys the Swift proxy service, providing HTTP based access
16 | onto underlying Swift storage services.
17 | tags:
18 | - openstack
19 | - cache-proxy
20 | series:
21 | - jammy
22 | extra-bindings:
23 | public:
24 | admin:
25 | internal:
26 | provides:
27 | nrpe-external-master:
28 | interface: nrpe-external-master
29 | scope: container
30 | object-store:
31 | interface: swift-proxy
32 | rings-distributor:
33 | interface: swift-global-cluster
34 | requires:
35 | swift-storage:
36 | interface: swift
37 | identity-service:
38 | interface: keystone
39 | ha:
40 | interface: hacluster
41 | scope: container
42 | amqp:
43 | interface: rabbitmq
44 | certificates:
45 | interface: tls-certificates
46 | rings-consumer:
47 | interface: swift-global-cluster
48 | peers:
49 | cluster:
50 | interface: swift-ha
51 | resources:
52 | policyd-override:
53 | type: file
54 | filename: policyd-override.zip
55 | description: The policy.d overrides file
56 |
--------------------------------------------------------------------------------
/osci.yaml:
--------------------------------------------------------------------------------
1 | - project:
2 | templates:
3 | - charm-unit-jobs-py310
4 | check:
5 | jobs:
6 | - test-s3api-noble-caracal
7 | vars:
8 | needs_charm_build: true
9 | charm_build_name: swift-proxy
10 | build_type: charmcraft
11 | charmcraft_channel: 3.x/beta
12 |
13 | - job:
14 | name: test-s3api-noble-caracal
15 | parent: func-target
16 | dependencies:
17 | - charm-build
18 | - osci-lint
19 | - name: tox-py310
20 | soft: true
21 | vars:
22 | tox_extra_args: '-- test-s3api:noble-caracal'
23 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/revision:
--------------------------------------------------------------------------------
1 | 147
2 |
--------------------------------------------------------------------------------
/scripts/add_to_cluster:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | service corosync start || /bin/true
3 | sleep 2
4 | while ! service pacemaker start; do
5 | echo "Attempting to start pacemaker"
6 | sleep 1;
7 | done;
8 | crm node online
9 | sleep 2
10 | while crm status | egrep -q 'Stopped$'; do
11 | echo "Waiting for nodes to come online"
12 | sleep 1
13 | done
14 |
--------------------------------------------------------------------------------
/scripts/remove_from_cluster:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | crm node standby
3 | service pacemaker stop
4 | service corosync stop
5 |
--------------------------------------------------------------------------------
/setup.cfg:
--------------------------------------------------------------------------------
1 | [metadata]
2 | name = charm-swift-proxy
3 | summary = Charm module for OpenStack Swift Proxy
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=lib,swift_hooks
25 |
--------------------------------------------------------------------------------
/swift_manager/.stestr.conf:
--------------------------------------------------------------------------------
1 | [DEFAULT]
2 | test_path=./
3 | top_dir=./
4 |
--------------------------------------------------------------------------------
/templates/memcached.conf:
--------------------------------------------------------------------------------
1 | # memcached default config file
2 | # 2003 - Jay Bonci
3 | # This configuration file is read by the start-memcached script provided as
4 | # part of the Debian GNU/Linux distribution.
5 |
6 | # Run memcached as a daemon. This command is implied, and is not needed for the
7 | # daemon to run. See the README.Debian that comes with this package for more
8 | # information.
9 | -d
10 |
11 | # Log memcached's output to /var/log/memcached
12 | logfile /var/log/memcached.log
13 |
14 | # Be verbose
15 | # -v
16 |
17 | # Be even more verbose (print client commands as well)
18 | # -vv
19 |
20 | # Start with a cap of 64 megs of memory. It's reasonable, and the daemon default
21 | # Note that the daemon will grow to this size, but does not start out holding this much
22 | # memory
23 | -m 64
24 |
25 | # Default connection port is 11211
26 | -p 11211
27 |
28 | # Run the daemon as root. The start-memcached will default to running as root if no
29 | # -u command is present in this config file
30 | -u memcache
31 |
32 | # Specify which IP address to listen on. The default is to listen on all IP addresses
33 | # This parameter is one of the only security measures that memcached has, so make sure
34 | # it's listening on a firewalled interface.
35 | -l {{ memcached_ip }}
36 |
37 | # Limit the number of simultaneous incoming connections. The daemon default is 1024
38 | # -c 1024
39 |
40 | # Lock down all paged memory. Consult with the README and homepage before you do this
41 | # -k
42 |
43 | # Return error when memory is exhausted (rather than removing items)
44 | # -M
45 |
46 | # Maximize core file limit
47 | # -r
48 |
--------------------------------------------------------------------------------
/templates/mitaka/dispersion.conf:
--------------------------------------------------------------------------------
1 | [dispersion]
2 | auth_url = {{ auth_protocol }}://{{ keystone_host }}:{{ service_port }}/v2.0
3 | auth_user = {{ service_tenant }}:{{ service_user }}
4 | auth_key = {{ service_password }}
5 | endpoint_type = internalURL
6 | auth_version = 2
7 |
--------------------------------------------------------------------------------
/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/dispersion.conf:
--------------------------------------------------------------------------------
1 | [dispersion]
2 | auth_url = {{ auth_protocol }}://{{ keystone_host }}:{{ auth_port }}
3 | auth_user = {{ service_user }}
4 | auth_key = {{ service_password }}
5 | endpoint_type = internalURL
6 | auth_version = 3
7 | project_domain_name = {{ admin_domain_name }}
8 | user_domain_name = {{ admin_domain_name }}
9 | project_name = {{ admin_tenant_name }}
10 |
--------------------------------------------------------------------------------
/templates/swift-rings:
--------------------------------------------------------------------------------
1 |
2 | Order deny,allow
3 | {% for host in allowed_hosts %}
4 | Allow from {{ host }}
5 | {% endfor %}
6 | Deny from all
7 |
8 |
--------------------------------------------------------------------------------
/templates/swift-rings.conf:
--------------------------------------------------------------------------------
1 | swift-rings
--------------------------------------------------------------------------------
/templates/swift.conf:
--------------------------------------------------------------------------------
1 | [swift-hash]
2 | # random unique string that can never change (DO NOT LOSE)
3 | swift_hash_path_suffix = {{ swift_hash }}
4 |
5 |
--------------------------------------------------------------------------------
/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: noble
5 |
6 | comment:
7 | - 'machines section to decide order of deployment. database sooner = faster'
8 | machines:
9 | '0':
10 | constraints: mem=3072M
11 | '1':
12 | constraints: mem=3072M
13 | '2':
14 | constraints: mem=3072M
15 | '3':
16 | '4':
17 | '5':
18 | '6':
19 |
20 | applications:
21 |
22 | keystone-mysql-router:
23 | charm: ch:mysql-router
24 | channel: latest/edge
25 | glance-mysql-router:
26 | charm: ch:mysql-router
27 | channel: latest/edge
28 |
29 | mysql-innodb-cluster:
30 | charm: ch:mysql-innodb-cluster
31 | num_units: 3
32 | options:
33 | source: *openstack-origin
34 | to:
35 | - '0'
36 | - '1'
37 | - '2'
38 | channel: latest/edge
39 |
40 | keystone:
41 | expose: True
42 | charm: ch:keystone
43 | num_units: 1
44 | options:
45 | openstack-origin: *openstack-origin
46 | to:
47 | - '3'
48 | channel: latest/edge
49 |
50 | swift-proxy:
51 | charm: ../../swift-proxy.charm
52 | num_units: 1
53 | options:
54 | zone-assignment: manual
55 | replicas: 1
56 | swift-hash: fdfef9d4-8b06-11e2-8ac0-531c923c8fae
57 | openstack-origin: *openstack-origin
58 | to:
59 | - '4'
60 |
61 | glance:
62 | expose: True
63 | charm: ch:glance
64 | num_units: 1
65 | options:
66 | openstack-origin: *openstack-origin
67 | to:
68 | - '5'
69 | channel: latest/edge
70 |
71 | swift-storage:
72 | charm: ch:swift-storage
73 | num_units: 1
74 | storage:
75 | block-devices: 'cinder,2G,2'
76 | options:
77 | zone: 1
78 | openstack-origin: *openstack-origin
79 | to:
80 | - '6'
81 | channel: latest/edge
82 |
83 | relations:
84 |
85 | - - 'keystone:shared-db'
86 | - 'keystone-mysql-router:shared-db'
87 | - - 'keystone-mysql-router:db-router'
88 | - 'mysql-innodb-cluster:db-router'
89 |
90 | - - 'glance:shared-db'
91 | - 'glance-mysql-router:shared-db'
92 | - - 'glance-mysql-router:db-router'
93 | - 'mysql-innodb-cluster:db-router'
94 |
95 | - - 'glance:identity-service'
96 | - 'keystone:identity-service'
97 |
98 | - - 'swift-proxy:identity-service'
99 | - 'keystone:identity-service'
100 |
101 | - - 'swift-storage:swift-storage'
102 | - 'swift-proxy:swift-storage'
103 |
104 | - - 'glance:object-store'
105 | - 'swift-proxy:object-store'
106 |
--------------------------------------------------------------------------------
/tests/bundles/overlays/noble-caracal-gr-r1.yaml.j2:
--------------------------------------------------------------------------------
1 | applications:
2 | keystone:
3 | offers:
4 | keystone:
5 | endpoints:
6 | - identity-service
7 | swift-proxy-region1:
8 | charm: {{ charm_location }}
9 | offers:
10 | swift-proxy-region1:
11 | endpoints:
12 | - swift-storage
13 | - rings-distributor
14 | swift-storage-region1-zone1:
15 | offers:
16 | swift-storage-region1-zone1:
17 | endpoints:
18 | - swift-storage
19 | swift-storage-region1-zone2:
20 | offers:
21 | swift-storage-region1-zone2:
22 | endpoints:
23 | - swift-storage
24 | swift-storage-region1-zone3:
25 | offers:
26 | swift-storage-region1-zone3:
27 | endpoints:
28 | - swift-storage
29 |
--------------------------------------------------------------------------------
/tests/bundles/overlays/noble-caracal-gr-r2.yaml.j2:
--------------------------------------------------------------------------------
1 | applications:
2 | swift-proxy-region2:
3 | charm: {{ charm_location }}
4 | relations:
5 | - - swift-proxy-region2:identity-service
6 | - keystone:identity-service
7 | - - swift-proxy-region2:swift-storage
8 | - swift-storage-region1-zone1:swift-storage
9 | - - swift-proxy-region2:swift-storage
10 | - swift-storage-region1-zone2:swift-storage
11 | - - swift-proxy-region2:swift-storage
12 | - swift-storage-region1-zone3:swift-storage
13 | - - swift-storage-region2-zone1:swift-storage
14 | - swift-proxy-region1:swift-storage
15 | - - swift-storage-region2-zone2:swift-storage
16 | - swift-proxy-region1:swift-storage
17 | - - swift-storage-region2-zone3:swift-storage
18 | - swift-proxy-region1:swift-storage
19 | - - swift-proxy-region2:rings-consumer
20 | - swift-proxy-region1:rings-distributor
21 | saas:
22 | keystone:
23 | url: admin/{{ swift_gr_region1 }}.keystone
24 | swift-proxy-region1:
25 | url: admin/{{ swift_gr_region1 }}.swift-proxy-region1
26 | swift-storage-region1-zone1:
27 | url: admin/{{ swift_gr_region1 }}.swift-storage-region1-zone1
28 | swift-storage-region1-zone2:
29 | url: admin/{{ swift_gr_region1 }}.swift-storage-region1-zone2
30 | swift-storage-region1-zone3:
31 | url: admin/{{ swift_gr_region1 }}.swift-storage-region1-zone3
32 |
--------------------------------------------------------------------------------
/tests/tests.yaml:
--------------------------------------------------------------------------------
1 | charm_name: swift-proxy
2 |
3 | gate_bundles:
4 | - noble-caracal
5 | dev_bundles:
6 | - noble-caracal
7 | smoke_bundles:
8 | # Use no s3api test for smoke
9 | - noble-caracal
10 | configure:
11 | - swift_gr_region1:
12 | - zaza.openstack.charm_tests.swift.setup.wait_for_region2
13 |
14 | tests:
15 | - zaza.openstack.charm_tests.swift.tests.SwiftImageCreateTest
16 | - zaza.openstack.charm_tests.swift.tests.SwiftProxyTests
17 | - test-s3api:
18 | - zaza.openstack.charm_tests.swift.tests.SwiftImageCreateTest
19 | - zaza.openstack.charm_tests.swift.tests.SwiftProxyTests
20 | - zaza.openstack.charm_tests.swift.tests.S3APITest
21 | - swift_gr_region1:
22 | - zaza.openstack.charm_tests.swift.tests.SwiftGlobalReplicationTests
23 | - zaza.openstack.charm_tests.swift.tests.SwiftProxyMultiZoneTests
24 |
25 | tests_options:
26 | policyd:
27 | - service: swift
28 |
--------------------------------------------------------------------------------
/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 os
16 | import sys
17 |
18 | from unittest.mock import patch
19 |
20 |
21 | _path = os.path.dirname(os.path.realpath(__file__))
22 | _parent = os.path.abspath(os.path.join(_path, '..'))
23 |
24 |
25 | def _add_path(path):
26 | if path not in sys.path:
27 | sys.path.insert(1, path)
28 |
29 |
30 | _add_path(_parent)
31 |
32 | # Patch out lsb_release() and get_platform() as unit tests should be fully
33 | # insulated from the underlying platform. Unit tests assume that the system is
34 | # ubuntu jammy.
35 | patch(
36 | 'charmhelpers.osplatform.get_platform', return_value='ubuntu'
37 | ).start()
38 | patch(
39 | 'charmhelpers.core.host.lsb_release',
40 | return_value={
41 | 'DISTRIB_CODENAME': 'jammy'
42 | }).start()
43 |
--------------------------------------------------------------------------------
/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 | import sys
17 |
18 | import unittest
19 |
20 | from unittest.mock import patch, MagicMock
21 |
22 | os.environ['JUJU_UNIT_NAME'] = 'swift-proxy'
23 |
24 | # python-apt is not installed as part of test-requirements but is imported by
25 | # some charmhelpers modules so create a fake import.
26 | sys.modules['apt'] = MagicMock()
27 | sys.modules['apt_pkg'] = MagicMock()
28 |
29 | with patch('charmhelpers.contrib.hardening.harden.harden') as mock_dec, \
30 | patch('lib.swift_utils.register_configs') as configs:
31 | mock_dec.side_effect = (lambda *dargs, **dkwargs: lambda f:
32 | lambda *args, **kwargs: f(*args, **kwargs))
33 | import actions.openstack_upgrade as openstack_upgrade
34 |
35 |
36 | TO_PATCH = [
37 | 'config_changed',
38 | 'do_openstack_upgrade',
39 | ]
40 |
41 |
42 | class CharmTestCase(unittest.TestCase):
43 |
44 | def setUp(self, obj, patches):
45 | super(CharmTestCase, self).setUp()
46 | self.patches = patches
47 | self.obj = obj
48 | self.patch_all()
49 |
50 | def patch(self, method):
51 | _m = patch.object(self.obj, method)
52 | mocked = _m.start()
53 | self.addCleanup(_m.stop)
54 | return mocked
55 |
56 | def patch_all(self):
57 | for method in self.patches:
58 | setattr(self, method, self.patch(method))
59 |
60 |
61 | class TestSwiftUpgradeActions(CharmTestCase):
62 |
63 | def setUp(self):
64 | super(TestSwiftUpgradeActions, self).setUp(openstack_upgrade,
65 | TO_PATCH)
66 |
67 | @patch('charmhelpers.contrib.openstack.utils.config')
68 | @patch('charmhelpers.contrib.openstack.utils.action_set')
69 | @patch('charmhelpers.contrib.openstack.utils.openstack_upgrade_available')
70 | def test_openstack_upgrade_true(self, upgrade_avail,
71 | action_set, config):
72 | upgrade_avail.return_value = True
73 | config.return_value = True
74 |
75 | openstack_upgrade.openstack_upgrade()
76 |
77 | self.assertTrue(self.do_openstack_upgrade.called)
78 | self.assertTrue(self.config_changed.called)
79 |
80 | @patch('charmhelpers.contrib.openstack.utils.config')
81 | @patch('charmhelpers.contrib.openstack.utils.action_set')
82 | @patch('charmhelpers.contrib.openstack.utils.openstack_upgrade_available')
83 | def test_openstack_upgrade_false(self, upgrade_avail,
84 | action_set, config):
85 | upgrade_avail.return_value = True
86 | config.return_value = False
87 |
88 | openstack_upgrade.openstack_upgrade()
89 |
90 | self.assertFalse(self.do_openstack_upgrade.called)
91 | self.assertFalse(self.config_changed.called)
92 |
--------------------------------------------------------------------------------
/unit_tests/test_templates.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 | import unittest
17 |
18 | from jinja2 import Environment
19 |
20 | from charmhelpers.contrib.openstack.templating import get_loader
21 |
22 |
23 | class ProxyServerTemplateTestCase(unittest.TestCase):
24 |
25 | @mock.patch('charmhelpers.contrib.openstack.templating.log')
26 | def get_template_for_release(self, os_release, mock_log):
27 | loader = get_loader('./templates', os_release)
28 | env = Environment(loader=loader)
29 |
30 | return env.get_template('proxy-server.conf')
31 |
32 | def test_statsd_config_for_all_releases(self):
33 | """The configs contain statsd settings if statsd-host is set."""
34 | for release in ('mitaka'):
35 | template = self.get_template_for_release(release)
36 |
37 | result = template.render(statsd_host='127.0.0.1')
38 |
39 | self.assertTrue("log_statsd_host" in result)
40 | self.assertTrue("log_statsd_port" in result)
41 | self.assertTrue("log_statsd_default_sample_rate" in result)
42 |
43 | result = template.render()
44 |
45 | self.assertFalse("log_statsd_host" in result)
46 | self.assertFalse("log_statsd_port" in result)
47 | self.assertFalse("log_statsd_default_sample_rate" in result)
48 |
49 | def test_keystonemiddleware_config_for_newer_release(self):
50 | """Test template should follow newer keystone middleware config."""
51 | release = 'yoga'
52 | template = self.get_template_for_release(release)
53 | result = template.render(auth_type='keystone')
54 | self.assertFalse('signing_dir' in result)
55 | self.assertFalse('hash_algorithms' in result)
56 |
57 | self.assertTrue('filter:authtoken' in result)
58 | self.assertTrue('www_authenticate_uri' in result)
59 | self.assertTrue('auth_url' in result)
60 |
--------------------------------------------------------------------------------