Merge lp:~cprov/uci-engine/1335753-glance-creds into lp:uci-engine

Proposed by Celso Providelo
Status: Needs review
Proposed branch: lp:~cprov/uci-engine/1335753-glance-creds
Merge into: lp:uci-engine
Diff against target: 332 lines (+203/-32)
5 files modified
ci-utils/ci_utils/tests/test_unit_config.py (+125/-0)
ci-utils/ci_utils/unit_config.py (+57/-16)
juju-deployer/configs/unit_config.yaml.tmpl (+13/-5)
juju-deployer/deploy.py (+6/-6)
juju-deployer/test_deploy.py (+2/-5)
To merge this branch: bzr merge lp:~cprov/uci-engine/1335753-glance-creds
Reviewer Review Type Date Requested Status
PS Jenkins bot (community) continuous-integration Needs Fixing
Andy Doan (community) Approve
Vincent Ladeuil (community) Needs Fixing
Review via email: mp+225248@code.launchpad.net

Commit message

Independent set of credentials for ImageBuilder and TestRunner in unit_config.

Description of the change

Resuming Vincent's work for creating an independent set of credentials for using in ImageBuilder and TestRunner, since they may operate in an different environment (cloud) than they are deployed.

Original MP -> https://code.launchpad.net/~vila/uci-engine/1335753-glance-creds/+merge/225191

To post a comment you must log in.
634. By Celso Providelo

adding missing test.

635. By Celso Providelo

Adding missing docstring.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :

FAILED: Continuous integration, rev:635
http://s-jenkins.ubuntu-ci:8080/job/uci-engine-ci/990/
Executed test runs:

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/uci-engine-ci/990/rebuild

review: Needs Fixing (continuous-integration)
636. By Celso Providelo

Fixing test failures.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :

PASSED: Continuous integration, rev:636
http://s-jenkins.ubuntu-ci:8080/job/uci-engine-ci/992/
Executed test runs:

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/uci-engine-ci/992/rebuild

review: Approve (continuous-integration)
Revision history for this message
Vincent Ladeuil (vila) wrote :
Download full text (9.5 KiB)

Typos aside, there is an issue with tests creating and removing unit_config at the root of the branch.

With a full deployment available on hp and GLANCE_* vars defined, I get:

$ ./run-tests
<...>

======================================================================
ERROR: tests.test_test_runner.TestTestRunner.test_process_ticket
----------------------------------------------------------------------
Traceback (most recent call last):
  File "tests/test_test_runner.py", line 90, in test_process_ticket
    raise_errors=True)
  File "/home/vila/ci/uci-engine/reviews/1335753-glance-creds/ci-utils/ci_utils/amqp_utils.py", line 99, in send
    conn, channel = declare_queue(queue_name, config)
  File "/home/vila/ci/uci-engine/reviews/1335753-glance-creds/ci-utils/ci_utils/amqp_utils.py", line 83, in declare_queue
    raise e
error: [Errno 110] Connection timed out
======================================================================
FAIL: juju-deployer.test_deploy.TestCheckEnvironment.test_check_environment_defaults
----------------------------------------------------------------------
Traceback (most recent call last):
  File "build/bdist.linux-x86_64/egg/mock.py", line 1201, in patched
    return func(*args, **keywargs)
  File "juju-deployer/test_deploy.py", line 77, in test_check_environment_defaults
    self.assertEqual('', os.environ['GLANCE_OS_USERNAME'])
  File "/usr/lib/python2.7/unittest/case.py", line 515, in assertEqual
    assertion_func(first, second, msg=msg)
  File "/usr/lib/python2.7/unittest/case.py", line 508, in _baseAssertEqual
    raise self.failureException(msg)
AssertionError: '' != '<email address hidden>'

Ran 594 tests in 501.909s
FAILED (failures=2)

test_process_tickey is now understood as missing an exposed rabbit.

But re-running:
$ ./run-tests
<...>
======================================================================
ERROR: test_runner.tstrun.tests.test_data_store.TestDataStore.test_put_file_stores_content
----------------------------------------------------------------------
Traceback (most recent call last):
  File "test_runner/tstrun/tests/test_data_store.py", line 62, in setUp
    tstrun.get_auth_config(), public=True)
  File "test_runner/tstrun/__init__.py", line 28, in get_auth_config
    with open(path) as f:
IOError: [Errno 2] No such file or directory: '/home/vila/ci/uci-engine/reviews/1335753-glance-creds/unit_config'
======================================================================
ERROR: test_runner.tstrun.tests.test_data_store.TestDataStore.test_store_created_empty
----------------------------------------------------------------------
Traceback (most recent call last):
  File "test_runner/tstrun/tests/test_data_store.py", line 62, in setUp
    tstrun.get_auth_config(), public=True)
  File "test_runner/tstrun/__init__.py", line 28, in get_auth_config
    with open(path) as f:
IOError: [Errno 2] No such file or directory: '/home/vila/ci/uci-engine/reviews/1335753-glance-creds/unit_config'
======================================================================
ERROR: test_runner.tstrun.tests.test_testbed.TestTestbed.test_create_new_ssh_key
-----------------------------------------------------...

Read more...

review: Needs Fixing
Revision history for this message
Vincent Ladeuil (vila) wrote :

I'll dig further and try to fix those.

637. By Celso Providelo

merge trunk

638. By Celso Providelo

FIxing typos and test env var isolation.

Revision history for this message
Celso Providelo (cprov) wrote :

The fact that we have tests that depend on 'unit_config' on the project root is wrong, in fact. If it's not committed in the VCS it should be handled ad-hoc by a testing fixture.

Also, the only test that needs to exercise disk operations with 'unit_config' is the one I've added in this branch, all the rest of the system should mock get_auth_config() and use whatever result they expect.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :

PASSED: Continuous integration, rev:638
http://s-jenkins.ubuntu-ci:8080/job/uci-engine-ci/996/
Executed test runs:

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/uci-engine-ci/996/rebuild

review: Approve (continuous-integration)
Revision history for this message
Vincent Ladeuil (vila) wrote :

> The fact that we have tests that depend on 'unit_config' on the project root
> is wrong, in fact.
> If it's not committed in the VCS it should be handled ad-
> hoc by a testing fixture.

There is more than one way to do it :)

The tests that rely on unit_config do use fixtures but still let the user decide whether or not he want to run those tests by creating that file or not.

If you have a better way that doesn't break the existing tests, I'm fine with that.

>
> Also, the only test that needs to exercise disk operations with 'unit_config'
> is the one I've added in this branch, all the rest of the system should mock
> get_auth_config() and use whatever result they expect.

Yes, that's the point I raised when you introduced deploy.install_unit_config()... I don't know which tests required that.

Revision history for this message
Andy Doan (doanac) wrote :

I mostly like it. I noticed a bug a though. I think any test failing because it assumes the location of the unit-config should be considered broken. I've got MP's on the way:

 https://code.launchpad.net/~doanac/uci-engine/lander-code-layout/+merge/225046

that are placing unit_config *outside* our code directory, so moving forward this assumption will definitely not work.

Revision history for this message
Celso Providelo (cprov) wrote :

Thanks for the review Andy, comments addressed inline.

639. By Celso Providelo

Re-implement unit_config module get() for not breaking possibly untested code.

Revision history for this message
Andy Doan (doanac) :
review: Approve
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :

PASSED: Continuous integration, rev:639
http://s-jenkins.ubuntu-ci:8080/job/uci-engine-ci/1001/
Executed test runs:

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/uci-engine-ci/1001/rebuild

review: Approve (continuous-integration)
640. By Celso Providelo

unit_config.get() not deprecated anymore, it's useful.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :

PASSED: Continuous integration, rev:640
http://s-jenkins.ubuntu-ci:8080/job/uci-engine-ci/1006/
Executed test runs:

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/uci-engine-ci/1006/rebuild

review: Approve (continuous-integration)
641. By Celso Providelo

merge trunk

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :

FAILED: Continuous integration, rev:641
http://s-jenkins.ubuntu-ci:8080/job/uci-engine-ci/1017/
Executed test runs:

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/uci-engine-ci/1017/rebuild

review: Needs Fixing (continuous-integration)

Unmerged revisions

641. By Celso Providelo

merge trunk

640. By Celso Providelo

unit_config.get() not deprecated anymore, it's useful.

639. By Celso Providelo

Re-implement unit_config module get() for not breaking possibly untested code.

638. By Celso Providelo

FIxing typos and test env var isolation.

637. By Celso Providelo

merge trunk

636. By Celso Providelo

Fixing test failures.

635. By Celso Providelo

Adding missing docstring.

634. By Celso Providelo

adding missing test.

633. By Celso Providelo

Making GLANCE_* variables optional and adding tests for ci_utils.unit_config.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== added file 'ci-utils/ci_utils/tests/test_unit_config.py'
--- ci-utils/ci_utils/tests/test_unit_config.py 1970-01-01 00:00:00 +0000
+++ ci-utils/ci_utils/tests/test_unit_config.py 2014-07-04 21:48:29 +0000
@@ -0,0 +1,125 @@
1#!/usr/bin/env python
2# Ubuntu CI Engine
3# Copyright 2014 Canonical Ltd.
4
5# This program is free software: you can redistribute it and/or modify it
6# under the terms of the GNU Affero General Public License version 3, as
7# published by the Free Software Foundation.
8
9# This program is distributed in the hope that it will be useful, but
10# WITHOUT ANY WARRANTY; without even the implied warranties of
11# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
12# PURPOSE. See the GNU Affero General Public License for more details.
13
14# You should have received a copy of the GNU Affero General Public License
15# along with this program. If not, see <http://www.gnu.org/licenses/>.
16"""Tests for the 'unit_config' loader."""
17import os
18import unittest
19
20from ci_utils import unit_config
21
22
23class TestUnitConfig(unittest.TestCase):
24
25 sample_content = {
26 'auth_user': 'a_user',
27 }
28
29 def setUp(self):
30 """Reset configuration cache."""
31 unit_config._reset_config()
32 self.config_path = unit_config._get_config_path()
33
34 def test_asserts_exists(self):
35 # `get_auth_config` asserts the 'unit_config' path exists.
36 with self.assertRaises(AssertionError) as cm:
37 unit_config.get_auth_config()
38 msg = 'unit_config does not exist! ({})'.format(self.config_path)
39 self.assertEqual(msg, cm.exception.message)
40
41 def test_asserts_not_empty(self):
42 # `get_auth_config` asserts the 'unit_config' is not an empty file.
43 with open(self.config_path, 'w') as fd:
44 fd.write('')
45 with self.assertRaises(AssertionError) as cm:
46 unit_config.get_auth_config()
47 msg = 'unit_config is empty! ({})'.format(self.config_path)
48 self.assertEqual(msg, cm.exception.message)
49
50 def create_config(self, content=None):
51 """Creates a 'unit_config' pseudo-YAML for tests."""
52 options = self.sample_content.copy()
53 if content is not None:
54 options.update(content)
55 with open(self.config_path, 'w') as fd:
56 for k, v in options.iteritems():
57 fd.write('{}: {}\n'.format(k, v))
58
59 def drop_if_exists():
60 if os.path.exists(self.config_path):
61 os.remove(self.config_path)
62 # Delete testing config if it exists.
63 self.addCleanup(drop_if_exists)
64
65 def test_loading(self):
66 # `get_auth_config` returns a dictionary corresponding to the
67 # YAML content. 'auth_*' attributes are mirrored to 'glance_auth_*'
68 self.create_config()
69 config = unit_config.get_auth_config()
70 self.assertEqual(
71 {'auth_user': 'a_user', 'glance_auth_user': 'a_user'}, config)
72
73 def test_get(self):
74 # `get` returns specific configuration options/attributes.
75 self.create_config()
76 self.assertEqual('a_user', unit_config.get('auth_user'))
77 self.assertEqual('a_user', unit_config.get('glance_auth_user'))
78
79 def test_loading_glance(self):
80 # `get_auth_config` preserves original 'glance_auth_*'
81 # attributes if 'glance_auth_user' is not empty.
82 glance_spec = {
83 'auth_url': 'a_url',
84 'glance_auth_user': 'another_user',
85 'glance_auth_url': 'another_url',
86 }
87 self.create_config(content=glance_spec)
88 config = unit_config.get_auth_config()
89 self.assertEqual(
90 {'auth_url': 'a_url',
91 'auth_user': 'a_user',
92 'glance_auth_url': 'another_url',
93 'glance_auth_user': 'another_user'},
94 config)
95
96 def test_cache(self):
97 # `get_auth_config` loads configuration file contents only once
98 # and caches it's (parsed) results. `_reset_config` is a testing
99 # artifact for cleaning its cache (use with care!).
100 self.create_config()
101 config = unit_config.get_auth_config()
102 self.create_config(content={'auth_user': 'fresh'})
103 cached = unit_config.get_auth_config()
104 self.assertEqual(cached, config)
105 unit_config._reset_config()
106 fresh = unit_config.get_auth_config()
107 self.assertEqual(
108 {'auth_user': 'fresh', 'glance_auth_user': 'fresh'},
109 fresh)
110
111 def test_no_cache_poisoning(self):
112 # `get_auth_config` returns a copy of the configuration cache,
113 # so its cache cannot be *poisoned*.
114 self.create_config()
115 config = unit_config.get_auth_config()
116 config['auth_user'] = 'someone-else'
117 config['auth_poison'] = 'bad-data'
118 new_config = unit_config.get_auth_config()
119 self.assertEqual(
120 {'auth_user': 'a_user', 'glance_auth_user': 'a_user'},
121 new_config)
122
123
124if __name__ == "__main__":
125 unittest.main()
0126
=== modified file 'ci-utils/ci_utils/unit_config.py'
--- ci-utils/ci_utils/unit_config.py 2014-05-14 09:11:00 +0000
+++ ci-utils/ci_utils/unit_config.py 2014-07-04 21:48:29 +0000
@@ -12,35 +12,76 @@
1212
13# You should have received a copy of the GNU Affero General Public License13# You should have received a copy of the GNU Affero General Public License
14# along with this program. If not, see <http://www.gnu.org/licenses/>.14# along with this program. If not, see <http://www.gnu.org/licenses/>.
1515"""Application 'unit_config' loader."""
16import os16import os
17
18import yaml17import yaml
1918
2019
21HERE = os.path.abspath(os.path.dirname(__file__))20HERE = os.path.abspath(os.path.dirname(__file__))
22
23
24_unit_config = None21_unit_config = None
2522
2623
27def _load():24def _reset_config():
28 path = os.path.join(HERE, '../../unit_config')25 """Testing utility for reseting unit_config cache."""
26 global _unit_config
27 _unit_config = None
28
29
30def _get_config_path():
31 """Testing utility for retrieving the configuration path."""
32 return os.path.join(HERE, '../../unit_config')
33
34
35def _load_config():
36 """Load the configuration file as YAML and cache it.
37
38 Asserts the expected 'unit_config' exists and contains valid YAML.
39 """
40 global _unit_config
41 path = _get_config_path()
42 assert os.path.exists(path), (
43 'unit_config does not exist! ({})'.format(path))
29 with open(path) as f:44 with open(path) as f:
30 global _unit_config
31 _unit_config = yaml.safe_load(f)45 _unit_config = yaml.safe_load(f)
46 assert _unit_config is not None, (
47 'unit_config is empty! ({})'.format(path))
48
49
50def get_auth_config():
51 """Return a configuration dictionary for applications.
52
53 Loads the deployment 'unit_config' YAML file, if it wasn't loaded
54 before, and return the corresponding python dictionary.
55
56 If 'glance_auth_user' is undefined (empty), 'glance_*' parameters
57 are filled with the corresponding 'auth_*' values, i.e., GLANCE_*
58 variables only have to be defined when the ci-airline 'testbed'
59 environment is different than where the system is deployed e.g.:
60 - stagingstack + scalingstack
61 - stagingstack + hpcloud
62 """
63 global _unit_config
64 if _unit_config is None:
65 _load_config()
66
67 # Apply configuration defaults/overrides in a copy of the cached
68 # configuration dictionary. This way applications will not be able
69 # to poisoning the cached value.
70 cfg = _unit_config.copy()
71
72 # 'glance_*' defaults.
73 if cfg.get('glance_auth_user') is None:
74 auth_keys = [k for k in cfg.keys() if k.startswith('auth_')]
75 for auth_key in auth_keys:
76 glance_key = 'glance_' + auth_key
77 cfg[glance_key] = cfg[auth_key]
78
79 return cfg
3280
3381
34def get(key):82def get(key):
35 if not _unit_config:83 """Get specific 'unit_config' options."""
36 _load()84 return get_auth_config()[key]
37 return _unit_config[key]
38
39
40def get_auth_config():
41 if not _unit_config:
42 _load()
43 return _unit_config
4485
4586
46def is_hpcloud(string=None):87def is_hpcloud(string=None):
4788
=== modified file 'juju-deployer/configs/unit_config.yaml.tmpl'
--- juju-deployer/configs/unit_config.yaml.tmpl 2014-07-01 15:58:10 +0000
+++ juju-deployer/configs/unit_config.yaml.tmpl 2014-07-04 21:48:29 +0000
@@ -1,26 +1,34 @@
1# for nova direct access (swift, image builder, test runner among others)1#--------------------------------------------------------------
2# This file is managed by Juju; ANY CHANGES WILL BE OVERWRITTEN
3#--------------------------------------------------------------
4# CI-Airline unit configuration file.
5
6# Options for system deployment and common Swift access.
2auth_url: $OS_AUTH_URL7auth_url: $OS_AUTH_URL
3auth_user: $OS_USERNAME8auth_user: $OS_USERNAME
4auth_password: $OS_PASSWORD9auth_password: $OS_PASSWORD
5auth_tenant_name: $OS_TENANT_NAME10auth_tenant_name: $OS_TENANT_NAME
6auth_region: $OS_REGION_NAME11auth_region: $OS_REGION_NAME
712
13# Options for Gatekeeper Swift tempurl generation and upload
14# signature validation.
8auth_access_key_id: $HP_ACCESS_KEY_ID15auth_access_key_id: $HP_ACCESS_KEY_ID
9auth_tenant_id: $HP_TENANT_ID16auth_tenant_id: $HP_TENANT_ID
10tempurl_signing_key: $CI_TEMPURL_SIGNING_KEY17tempurl_signing_key: $CI_TEMPURL_SIGNING_KEY
11tempurl_expires: $CI_TEMPURL_EXPIRES18tempurl_expires: $CI_TEMPURL_EXPIRES
12tempurl_public_host: $CI_TEMPURL_PUBLIC_HOST19tempurl_public_host: $CI_TEMPURL_PUBLIC_HOST
20keyring_uri: $CI_KEYRING_URI
21keyserver_url: $CI_KEYSERVER_URL
1322
23# Options for acessing a isolated environment for
24# Image-builder (Glance) and Test-runner (Nova).
25# If not provided (empty), the system environment is used.
14glance_auth_url: $GLANCE_OS_AUTH_URL26glance_auth_url: $GLANCE_OS_AUTH_URL
15glance_auth_user: $GLANCE_OS_USERNAME27glance_auth_user: $GLANCE_OS_USERNAME
16glance_auth_password: $GLANCE_OS_PASSWORD28glance_auth_password: $GLANCE_OS_PASSWORD
17glance_auth_tenant_name: $GLANCE_OS_TENANT_NAME29glance_auth_tenant_name: $GLANCE_OS_TENANT_NAME
18glance_auth_region: $GLANCE_OS_REGION_NAME30glance_auth_region: $GLANCE_OS_REGION_NAME
1931
20
21keyring_uri: $CI_KEYRING_URI
22keyserver_url: $CI_KEYSERVER_URL
23
24# for launchpad apis32# for launchpad apis
25# and see: https://help.launchpad.net/API/SigningRequests33# and see: https://help.launchpad.net/API/SigningRequests
26# and see ../../create_lp_creds.py34# and see ../../create_lp_creds.py
2735
=== modified file 'juju-deployer/deploy.py'
--- juju-deployer/deploy.py 2014-07-03 17:25:58 +0000
+++ juju-deployer/deploy.py 2014-07-04 21:48:29 +0000
@@ -94,11 +94,11 @@
94 '''94 '''
95 cheetah_vars = {95 cheetah_vars = {
96 'OS_USERNAME': None,96 'OS_USERNAME': None,
97 'GLANCE_OS_USERNAME': None,97 'GLANCE_OS_USERNAME': '',
98 'GLANCE_OS_AUTH_URL': None,98 'GLANCE_OS_AUTH_URL': '',
99 'GLANCE_OS_PASSWORD': None,99 'GLANCE_OS_PASSWORD': '',
100 'GLANCE_OS_TENANT_NAME': None,100 'GLANCE_OS_TENANT_NAME': '',
101 'GLANCE_OS_REGION_NAME': None,101 'GLANCE_OS_REGION_NAME': '',
102 'CI_CODE_SOURCE': 'branch',102 'CI_CODE_SOURCE': 'branch',
103 'CI_BRANCH': 'lp:uci-engine',103 'CI_BRANCH': 'lp:uci-engine',
104 'CI_PAYLOAD_URL': 'n/a',104 'CI_PAYLOAD_URL': 'n/a',
@@ -154,7 +154,7 @@
154 ERROR: Missing required environment variables:154 ERROR: Missing required environment variables:
155 {}155 {}
156 Please ensure the novarc file has been sourced.''')156 Please ensure the novarc file has been sourced.''')
157 sys.exit(template.format('\n '.join(missing_required)))157 sys.exit(template.format('\n '.join(sorted(missing_required))))
158158
159159
160def bootstrap():160def bootstrap():
161161
=== modified file 'juju-deployer/test_deploy.py'
--- juju-deployer/test_deploy.py 2014-07-03 17:25:58 +0000
+++ juju-deployer/test_deploy.py 2014-07-04 21:48:29 +0000
@@ -36,11 +36,6 @@
3636
37 DEFAULT_ENV = {37 DEFAULT_ENV = {
38 'OS_USERNAME': 'os-user',38 'OS_USERNAME': 'os-user',
39 'GLANCE_OS_USERNAME': 'glance-os-user',
40 'GLANCE_OS_AUTH_URL': 'glance-url',
41 'GLANCE_OS_REGION_NAME': 'glance-region',
42 'GLANCE_OS_TENANT_NAME': 'glance-tenant',
43 'GLANCE_OS_PASSWORD': 'glance-password',
44 'OS_AUTH_URL': 'something.stack',39 'OS_AUTH_URL': 'something.stack',
45 'CI_OAUTH_CONSUMER_KEY': 'key',40 'CI_OAUTH_CONSUMER_KEY': 'key',
46 'CI_OAUTH_TOKEN': 'token',41 'CI_OAUTH_TOKEN': 'token',
@@ -61,6 +56,7 @@
61 'CI_TEMPURL_SIGNING_KEY': None,56 'CI_TEMPURL_SIGNING_KEY': None,
62 'CI_KEYRING_URI': None,57 'CI_KEYRING_URI': None,
63 'CI_KEYSERVER_URL': None,58 'CI_KEYSERVER_URL': None,
59 'GLANCE_OS_USERNAME': None,
64 'HP_ACCESS_KEY_ID': None,60 'HP_ACCESS_KEY_ID': None,
65 'HP_TENANT_ID': None,61 'HP_TENANT_ID': None,
66 }62 }
@@ -79,6 +75,7 @@
79 self.assertEqual(os.environ['CI_KEYRING_URI'], '')75 self.assertEqual(os.environ['CI_KEYRING_URI'], '')
80 self.assertEqual(76 self.assertEqual(
81 os.environ['CI_KEYSERVER_URL'], 'keyserver.ubuntu.com')77 os.environ['CI_KEYSERVER_URL'], 'keyserver.ubuntu.com')
78 self.assertEqual('', os.environ['GLANCE_OS_USERNAME'])
82 # CI_TEMPURL_SIGNING_KEY used for canonistack/prodstack TempURL79 # CI_TEMPURL_SIGNING_KEY used for canonistack/prodstack TempURL
83 # generation and `deploy.py` generated a new random HMAC-SHA180 # generation and `deploy.py` generated a new random HMAC-SHA1
84 # (40 chars) key for each deployment.81 # (40 chars) key for each deployment.

Subscribers

People subscribed via source and target branches