Skip to content

Commit d07e69f

Browse files
authored
Merge branch 'master' into ensure_s3_bucket_pr495
2 parents 574a692 + 3c5f462 commit d07e69f

File tree

15 files changed

+513
-62
lines changed

15 files changed

+513
-62
lines changed

CHANGELOG.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,14 @@
1+
## 1.1.2 (2017-11-01)
2+
3+
This is a minor update to help deal with some of the issues between `stacker`
4+
and `stacker_blueprints` both having dependencies on `troposphere`. It loosens
5+
the dependencies, allowing stacker to work with any reasonably new version
6+
of troposphere (anything greater than `1.9.0`). `stacker_blueprints` will
7+
likely require newer versions of troposphere, as new types are introduced to
8+
the blueprints, but it's unlikely we'll change the `troposphere` version string
9+
for stacker, since it relies on only the most basic parts of the `troposphere`
10+
API.
11+
112
## 1.1.1 (2017-10-11)
213

314
This release is mostly about updating the dependencies for stacker to newer

RELEASE.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Steps to release a new version
2+
3+
## Preparing for the release
4+
5+
- Check out a branch named for the version: `git checkout -b release-1.1.1`
6+
- Change version in setup.py and stacker/\_\_init\_\_.py
7+
- Update CHANGELOG.md with changes made since last release (see below for helpful
8+
command)
9+
- add changed files: `git add setup.py stacker/\_\_init\_\_.py CHANGELOG.md`
10+
- Commit changes: `git commit -m "Release 1.1.1"`
11+
- Create a signed tag: `git tag --sign -m "Release 1.1.1" 1.1.1`
12+
- Push branch up to git: `git push -u origin release-1.1.1`
13+
- Open a PR for the release, ensure that tests pass
14+
15+
## Releasing
16+
17+
- Push tag: `git push --tags`
18+
- Merge PR into master, checkout master locally: `git checkout master; git pull`
19+
- Create PyPI release: `python setup.py sdist upload --sign`
20+
- Update github release page: https://github.com/remind101/stacker/releases
21+
- use the contents of the latest CHANGELOG entry for the body.
22+
23+
# Helper to create CHANGELOG entries
24+
git log --reverse --pretty=format:"%s" | tail -100 | sed 's/^/- /'

docs/config.rst

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ See the AWS documentation for `AWS CloudFormation Service Roles`_.
143143

144144
Remote Packages
145145
---------------
146-
The **package_sources** top level keyword can be used to define remote git
146+
The **package_sources** top level keyword can be used to define remote
147147
sources for blueprints (e.g., retrieving ``stacker_blueprints`` on github at
148148
tag ``v1.0.2``).
149149

@@ -162,13 +162,30 @@ The only required key for a git repository config is ``uri``, but ``branch``,
162162
- uri: git@github.com:contoso/foo.git
163163
commit: 12345678
164164

165-
Use the ``paths`` option when subdirectories of the repo should be added to
166-
Stacker's ``sys.path``.
167-
168165
If no specific commit or tag is specified for a repo, the remote repository
169166
will be checked for newer commits on every execution of Stacker.
170167

171-
Cloned repositories will be cached between builds; the cache location defaults
168+
For ``.tar.gz`` & ``zip`` archives on s3, specify a ``bucket`` & ``key``::
169+
170+
package_sources:
171+
s3:
172+
- bucket: mystackers3bucket
173+
key: archives/blueprints-v1.zip
174+
paths:
175+
- stacker_blueprints
176+
- bucket: anothers3bucket
177+
key: public/public-blueprints-v2.tar.gz
178+
requester_pays: true
179+
- bucket: yetanothers3bucket
180+
key: sallys-blueprints-v1.tar.gz
181+
# use_latest defaults to true - will update local copy if the
182+
# last modified date on S3 changes
183+
use_latest: false
184+
185+
Use the ``paths`` option when subdirectories of the repo/archive should be
186+
added to Stacker's ``sys.path``.
187+
188+
Cloned repos/archives will be cached between builds; the cache location defaults
172189
to ~/.stacker but can be manually specified via the **stacker_cache_dir** top
173190
level keyword.
174191

setup.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,25 @@
11
import os
22
from setuptools import setup, find_packages
33

4-
VERSION = "1.1.1"
4+
VERSION = "1.1.2"
55

66
src_dir = os.path.dirname(__file__)
77

88
install_requires = [
9-
"troposphere~=2.0.0",
9+
"troposphere>=1.9.0",
1010
"boto3>=1.3.1,<1.5.0",
1111
"PyYAML~=3.12",
12-
"awacs~=0.7.1",
12+
"awacs>=0.6.0",
1313
"colorama~=0.3.7",
1414
"formic~=0.9b",
1515
"gitpython~=2.0",
16-
"schematics~=2.0.1"
16+
"schematics~=2.0.1",
17+
"python-dateutil~=2.0"
1718
]
1819

1920
tests_require = [
2021
"mock~=2.0.0",
21-
"moto~=0.4.30",
22+
"moto~=1.1.24",
2223
"testfixtures~=4.10.0",
2324
"coverage~=4.3.4"
2425
]
@@ -48,7 +49,7 @@ def read(filename):
4849
author_email="loki77@gmail.com",
4950
license="New BSD license",
5051
url="https://github.com/remind101/stacker",
51-
description="Opinionated AWS CloudFormation Stack manager",
52+
description="AWS CloudFormation Stack manager",
5253
long_description=read("README.rst"),
5354
packages=find_packages(),
5455
scripts=scripts,

stacker/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = "1.1.1"
1+
__version__ = "1.1.2"

stacker/config/__init__.py

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -242,9 +242,21 @@ class GitPackageSource(Model):
242242
configs = ListType(StringType, serialize_when_none=False)
243243

244244

245+
class S3PackageSource(Model):
246+
bucket = StringType(required=True)
247+
248+
key = StringType(required=True)
249+
250+
use_latest = BooleanType(serialize_when_none=False)
251+
252+
requester_pays = BooleanType(serialize_when_none=False)
253+
254+
245255
class PackageSources(Model):
246256
git = ListType(ModelType(GitPackageSource))
247257

258+
s3 = ListType(ModelType(S3PackageSource))
259+
248260

249261
class Hook(Model):
250262
path = StringType(required=True)
@@ -357,10 +369,11 @@ def validate(self):
357369

358370
def validate_stacks(self, data, value):
359371
if value:
360-
names = set()
361-
for i, stack in enumerate(value):
362-
if stack.name in names:
363-
raise ValidationError(
364-
"Duplicate stack %s found at index %d."
365-
% (stack.name, i))
366-
names.add(stack.name)
372+
stack_names = [stack.name for stack in value]
373+
if len(set(stack_names)) != len(stack_names):
374+
# only loop / enumerate if there is an issue.
375+
for i, stack_name in enumerate(stack_names):
376+
if stack_names.count(stack_name) != 1:
377+
raise ValidationError(
378+
"Duplicate stack %s found at index %d."
379+
% (stack_name, i))

stacker/lookups/handlers/envvar.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,5 +30,5 @@ def handler(value, **kwargs):
3030

3131
try:
3232
return os.environ[value]
33-
except:
33+
except KeyError:
3434
raise ValueError('EnvVar "{}" does not exist'.format(value))

stacker/plan.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,11 @@ def dump(self, directory, context, provider=None):
355355
blueprint = step.stack.blueprint
356356
filename = stack_template_key_name(blueprint)
357357
path = os.path.join(directory, filename)
358+
359+
blueprint_dir = os.path.dirname(path)
360+
if not os.path.exists(blueprint_dir):
361+
os.makedirs(blueprint_dir)
362+
358363
logger.info("Writing stack \"%s\" -> %s", step_name, path)
359364
with open(path, "w") as f:
360365
f.write(blueprint.rendered)

stacker/tests/test_config.py

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
from stacker import exceptions
1515
from stacker.lookups.registry import LOOKUP_HANDLERS
1616

17+
from yaml.constructor import ConstructorError
18+
1719
config = """a: $a
1820
b: $b
1921
c: $c"""
@@ -97,7 +99,7 @@ def test_config_validate_duplicate_stack_names(self):
9799
error = ex.exception.errors['stacks'][0]
98100
self.assertEquals(
99101
error.__str__(),
100-
"Duplicate stack bastion found at index 1.")
102+
"Duplicate stack bastion found at index 0.")
101103

102104
def test_dump_unicode(self):
103105
config = Config()
@@ -196,6 +198,15 @@ def test_parse(self):
196198
args:
197199
domain: mydomain.com
198200
package_sources:
201+
s3:
202+
- bucket: acmecorpbucket
203+
key: public/acmecorp-blueprints-v1.zip
204+
- bucket: examplecorpbucket
205+
key: public/examplecorp-blueprints-v2.tar.gz
206+
requester_pays: true
207+
- bucket: anotherexamplebucket
208+
key: example-blueprints-v3.tar.gz
209+
use_latest: false
199210
git:
200211
- uri: git@github.com:acmecorp/stacker_blueprints.git
201212
- uri: git@github.com:remind101/stacker_blueprints.git
@@ -248,6 +259,15 @@ def test_parse(self):
248259
args:
249260
domain: mydomain.com
250261
package_sources:
262+
s3:
263+
- bucket: acmecorpbucket
264+
key: public/acmecorp-blueprints-v1.zip
265+
- bucket: examplecorpbucket
266+
key: public/examplecorp-blueprints-v2.tar.gz
267+
requester_pays: true
268+
- bucket: anotherexamplebucket
269+
key: example-blueprints-v3.tar.gz
270+
use_latest: false
251271
git:
252272
- uri: git@github.com:acmecorp/stacker_blueprints.git
253273
- uri: git@github.com:remind101/stacker_blueprints.git
@@ -290,6 +310,25 @@ def test_parse(self):
290310
self.assertEqual(
291311
hooks[0].args, {"domain": "mydomain.com"})
292312

313+
self.assertEqual(
314+
config.package_sources.s3[0].bucket,
315+
"acmecorpbucket")
316+
self.assertEqual(
317+
config.package_sources.s3[0].key,
318+
"public/acmecorp-blueprints-v1.zip")
319+
self.assertEqual(
320+
config.package_sources.s3[1].bucket,
321+
"examplecorpbucket")
322+
self.assertEqual(
323+
config.package_sources.s3[1].key,
324+
"public/examplecorp-blueprints-v2.tar.gz")
325+
self.assertEqual(
326+
config.package_sources.s3[1].requester_pays,
327+
True)
328+
self.assertEqual(
329+
config.package_sources.s3[2].use_latest,
330+
False)
331+
293332
self.assertEqual(
294333
config.package_sources.git[0].uri,
295334
"git@github.com:acmecorp/stacker_blueprints.git")
@@ -398,6 +437,29 @@ def test_render_parse_load_namespace_fallback(self):
398437
config.validate()
399438
self.assertEquals(config.namespace, "prod")
400439

440+
def test_raise_constructor_error_on_duplicate_key(self):
441+
yaml_config = """
442+
namespace: prod
443+
stacks:
444+
- name: vpc
445+
class_path: blueprints.VPC
446+
class_path: blueprints.Fake
447+
"""
448+
with self.assertRaises(ConstructorError):
449+
parse(yaml_config)
450+
451+
def test_raise_construct_error_on_duplicate_stack_name(self):
452+
yaml_config = """
453+
namespace: prod
454+
stacks:
455+
my_vpc:
456+
class_path: blueprints.VPC1
457+
my_vpc:
458+
class_path: blueprints.VPC2
459+
"""
460+
with self.assertRaises(ConstructorError):
461+
parse(yaml_config)
462+
401463

402464
if __name__ == '__main__':
403465
unittest.main()

stacker/tests/test_lookups.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ def test_valid_extract_lookups_from_string(self):
8989
_input = "vpc::PublicSubnets"
9090
value = "${%s %s}" % (_type, _input)
9191
lookups = extract_lookups_from_string(value)
92-
l = lookups.pop()
93-
assert l.type == _type
94-
assert l.input == _input
95-
assert l.raw == "%s %s" % (_type, _input)
92+
lookup = lookups.pop()
93+
assert lookup.type == _type
94+
assert lookup.input == _input
95+
assert lookup.raw == "%s %s" % (_type, _input)

0 commit comments

Comments
 (0)