From c118d12e6fa5e8791133c8135c73906e1164a8b4 Mon Sep 17 00:00:00 2001 From: Declan Shanaghy Date: Mon, 19 Jun 2017 18:22:33 -0700 Subject: [PATCH 1/8] Add describe_parameters support --- moto/ssm/models.py | 6 ++++++ moto/ssm/responses.py | 14 ++++++++++++++ setup.py | 2 +- 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/moto/ssm/models.py b/moto/ssm/models.py index 3344623dd..cb4d5946e 100644 --- a/moto/ssm/models.py +++ b/moto/ssm/models.py @@ -46,6 +46,12 @@ class SimpleSystemManagerBackend(BaseBackend): except KeyError: pass + def get_all_parameters(self): + result = [] + for k, _ in self._parameters.iteritems(): + result.append(self._parameters[k]) + return result + def get_parameters(self, names, with_decryption): result = [] for name in names: diff --git a/moto/ssm/responses.py b/moto/ssm/responses.py index ee21d7380..6c53bf039 100644 --- a/moto/ssm/responses.py +++ b/moto/ssm/responses.py @@ -43,6 +43,20 @@ class SimpleSystemManagerResponse(BaseResponse): return json.dumps(response) + def describe_parameters(self): + # filters = self._get_param('Filters') + result = self.ssm_backend.get_all_parameters() + + response = { + 'Parameters': [], + } + + for parameter in result: + param_data = parameter.response_object(False) + response['Parameters'].append(param_data) + + return json.dumps(response) + def put_parameter(self): name = self._get_param('Name') description = self._get_param('Description') diff --git a/setup.py b/setup.py index 289c1684c..2da16557c 100644 --- a/setup.py +++ b/setup.py @@ -24,7 +24,7 @@ extras_require = { setup( name='moto', - version='1.0.1', + version='1.0.1.1', description='A library that allows your python tests to easily' ' mock out the boto library', author='Steve Pulec', From db20dfcd82034ca49d98ed3d112bc454bbacf1d4 Mon Sep 17 00:00:00 2001 From: Declan Shanaghy Date: Tue, 20 Jun 2017 11:47:53 -0700 Subject: [PATCH 2/8] Added filtering --- moto/ssm/models.py | 5 +- moto/ssm/responses.py | 51 +++++++++++- setup.py | 2 +- tests/test_ssm/test_ssm_boto3.py | 137 +++++++++++++++++++++++++++++++ 4 files changed, 190 insertions(+), 5 deletions(-) diff --git a/moto/ssm/models.py b/moto/ssm/models.py index cb4d5946e..4efa22817 100644 --- a/moto/ssm/models.py +++ b/moto/ssm/models.py @@ -28,11 +28,14 @@ class Parameter(BaseModel): return value[len(prefix):] def response_object(self, decrypt=False): - return { + r = { 'Name': self.name, 'Type': self.type, 'Value': self.decrypt(self.value) if decrypt else self.value } + if self.keyid: + r['KeyId'] = self.keyid + return r class SimpleSystemManagerBackend(BaseBackend): diff --git a/moto/ssm/responses.py b/moto/ssm/responses.py index 6c53bf039..f4ed9561d 100644 --- a/moto/ssm/responses.py +++ b/moto/ssm/responses.py @@ -44,16 +44,61 @@ class SimpleSystemManagerResponse(BaseResponse): return json.dumps(response) def describe_parameters(self): - # filters = self._get_param('Filters') + page_size = 10 + filters = self._get_param('Filters') + token = self._get_param('NextToken') + if hasattr(token, 'strip'): + token = token.strip() + if not token: + token = '0' + + token = int(token) + + result = self.ssm_backend.get_all_parameters() response = { 'Parameters': [], } - for parameter in result: + end = token + page_size + for parameter in result[token:]: param_data = parameter.response_object(False) - response['Parameters'].append(param_data) + add = False + + if filters: + for filter in filters: + if filter['Key'] == 'Name': + k = param_data['Name'] + for v in filter['Values']: + if k.startswith(v): + add = True + break + elif filter['Key'] == 'Type': + k = param_data['Type'] + for v in filter['Values']: + if k == v: + add = True + break + elif filter['Key'] == 'KeyId': + k = param_data.get('KeyId') + if k: + for v in filter['Values']: + if k == v: + add = True + break + else: + add = True + + if add: + response['Parameters'].append(param_data) + + token = token + 1 + if len(response['Parameters']) == page_size: + response['NextToken'] = str(end) + break + + return json.dumps(response) diff --git a/setup.py b/setup.py index 2da16557c..b00567895 100644 --- a/setup.py +++ b/setup.py @@ -24,7 +24,7 @@ extras_require = { setup( name='moto', - version='1.0.1.1', + version='1.0.1.2', description='A library that allows your python tests to easily' ' mock out the boto library', author='Steve Pulec', diff --git a/tests/test_ssm/test_ssm_boto3.py b/tests/test_ssm/test_ssm_boto3.py index 6b8a1a369..8b5d1f200 100644 --- a/tests/test_ssm/test_ssm_boto3.py +++ b/tests/test_ssm/test_ssm_boto3.py @@ -47,6 +47,143 @@ def test_put_parameter(): response['Parameters'][0]['Type'].should.equal('String') +@mock_ssm +def test_describe_parameters(): + client = boto3.client('ssm', region_name='us-east-1') + + client.put_parameter( + Name='test', + Description='A test parameter', + Value='value', + Type='String') + + response = client.describe_parameters() + + len(response['Parameters']).should.equal(1) + response['Parameters'][0]['Name'].should.equal('test') + response['Parameters'][0]['Type'].should.equal('String') + + +@mock_ssm +def test_describe_parameters_paging(): + client = boto3.client('ssm', region_name='us-east-1') + + for i in range(50): + client.put_parameter( + Name="param-%d" % i, + Value="value-%d" % i, + Type="String" + ) + + response = client.describe_parameters() + len(response['Parameters']).should.equal(10) + response['NextToken'].should.equal('10') + + response = client.describe_parameters(NextToken=response['NextToken']) + len(response['Parameters']).should.equal(10) + response['NextToken'].should.equal('20') + + response = client.describe_parameters(NextToken=response['NextToken']) + len(response['Parameters']).should.equal(10) + response['NextToken'].should.equal('30') + + response = client.describe_parameters(NextToken=response['NextToken']) + len(response['Parameters']).should.equal(10) + response['NextToken'].should.equal('40') + + response = client.describe_parameters(NextToken=response['NextToken']) + len(response['Parameters']).should.equal(10) + response['NextToken'].should.equal('50') + + response = client.describe_parameters(NextToken=response['NextToken']) + len(response['Parameters']).should.equal(0) + ''.should.equal(response.get('NextToken', '')) + +@mock_ssm +def test_describe_parameters_filter_names(): + client = boto3.client('ssm', region_name='us-east-1') + + for i in range(50): + p = { + 'Name': "param-%d" % i, + 'Value': "value-%d" % i, + 'Type': "String" + } + if i % 5 == 0: + p['Type'] = 'SecureString' + p['KeyId'] = 'a key' + client.put_parameter(**p) + + + response = client.describe_parameters(Filters=[ + { + 'Key': 'Name', + 'Values': ['param-45', 'param-22'] + }, + ]) + len(response['Parameters']).should.equal(2) + response['Parameters'][0]['Name'].should.equal('param-22') + response['Parameters'][0]['Type'].should.equal('String') + response['Parameters'][1]['Name'].should.equal('param-45') + response['Parameters'][1]['Type'].should.equal('SecureString') + ''.should.equal(response.get('NextToken', '')) + +@mock_ssm +def test_describe_parameters_filter_type(): + client = boto3.client('ssm', region_name='us-east-1') + + for i in range(50): + p = { + 'Name': "param-%d" % i, + 'Value': "value-%d" % i, + 'Type': "String" + } + if i % 5 == 0: + p['Type'] = 'SecureString' + p['KeyId'] = 'a key' + client.put_parameter(**p) + + + response = client.describe_parameters(Filters=[ + { + 'Key': 'Type', + 'Values': ['SecureString'] + }, + ]) + len(response['Parameters']).should.equal(10) + response['Parameters'][0]['Name'].should.equal('param-35') + response['Parameters'][0]['Type'].should.equal('SecureString') + '10'.should.equal(response.get('NextToken', '')) + +@mock_ssm +def test_describe_parameters_filter_keyid(): + client = boto3.client('ssm', region_name='us-east-1') + + for i in range(50): + p = { + 'Name': "param-%d" % i, + 'Value': "value-%d" % i, + 'Type': "String" + } + if i % 5 == 0: + p['Type'] = 'SecureString' + p['KeyId'] = "key:%d" % i + client.put_parameter(**p) + + + response = client.describe_parameters(Filters=[ + { + 'Key': 'KeyId', + 'Values': ['key:5','key:10'] + }, + ]) + len(response['Parameters']).should.equal(2) + response['Parameters'][0]['Name'].should.equal('param-10') + response['Parameters'][0]['Type'].should.equal('SecureString') + response['Parameters'][1]['Name'].should.equal('param-5') + response['Parameters'][1]['Type'].should.equal('SecureString') + ''.should.equal(response.get('NextToken', '')) + @mock_ssm def test_put_parameter_secure_default_kms(): client = boto3.client('ssm', region_name='us-east-1') From f2d64e86395864a355d660ba023a1a7f27916d00 Mon Sep 17 00:00:00 2001 From: Declan Shanaghy Date: Tue, 20 Jun 2017 12:03:50 -0700 Subject: [PATCH 3/8] Revert version bump --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index b00567895..289c1684c 100644 --- a/setup.py +++ b/setup.py @@ -24,7 +24,7 @@ extras_require = { setup( name='moto', - version='1.0.1.2', + version='1.0.1', description='A library that allows your python tests to easily' ' mock out the boto library', author='Steve Pulec', From 5a4b2139501b1ec695afac6970615efd61686010 Mon Sep 17 00:00:00 2001 From: Declan Shanaghy Date: Tue, 20 Jun 2017 12:38:52 -0700 Subject: [PATCH 4/8] Remove blank lines --- moto/ssm/responses.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/moto/ssm/responses.py b/moto/ssm/responses.py index f4ed9561d..09fe6d0c2 100644 --- a/moto/ssm/responses.py +++ b/moto/ssm/responses.py @@ -51,12 +51,9 @@ class SimpleSystemManagerResponse(BaseResponse): token = token.strip() if not token: token = '0' - token = int(token) - result = self.ssm_backend.get_all_parameters() - response = { 'Parameters': [], } @@ -98,8 +95,6 @@ class SimpleSystemManagerResponse(BaseResponse): response['NextToken'] = str(end) break - - return json.dumps(response) def put_parameter(self): From f0fae81af1f522e7344708e5117b70d2ae7957c1 Mon Sep 17 00:00:00 2001 From: Declan Shanaghy Date: Tue, 20 Jun 2017 12:55:01 -0700 Subject: [PATCH 5/8] Fix iteritems --- moto/ssm/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/moto/ssm/models.py b/moto/ssm/models.py index 4efa22817..f1aac336b 100644 --- a/moto/ssm/models.py +++ b/moto/ssm/models.py @@ -51,7 +51,7 @@ class SimpleSystemManagerBackend(BaseBackend): def get_all_parameters(self): result = [] - for k, _ in self._parameters.iteritems(): + for k, _ in self._parameters.items(): result.append(self._parameters[k]) return result From 8ca27e184aa98b62fd6841862499f66084b71bf1 Mon Sep 17 00:00:00 2001 From: Declan Shanaghy Date: Mon, 26 Jun 2017 11:17:36 -0700 Subject: [PATCH 6/8] Simplify tests --- tests/test_ssm/test_ssm_boto3.py | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/tests/test_ssm/test_ssm_boto3.py b/tests/test_ssm/test_ssm_boto3.py index 8b5d1f200..a62536a23 100644 --- a/tests/test_ssm/test_ssm_boto3.py +++ b/tests/test_ssm/test_ssm_boto3.py @@ -118,14 +118,12 @@ def test_describe_parameters_filter_names(): response = client.describe_parameters(Filters=[ { 'Key': 'Name', - 'Values': ['param-45', 'param-22'] + 'Values': ['param-22'] }, ]) - len(response['Parameters']).should.equal(2) + len(response['Parameters']).should.equal(1) response['Parameters'][0]['Name'].should.equal('param-22') response['Parameters'][0]['Type'].should.equal('String') - response['Parameters'][1]['Name'].should.equal('param-45') - response['Parameters'][1]['Type'].should.equal('SecureString') ''.should.equal(response.get('NextToken', '')) @mock_ssm @@ -174,14 +172,12 @@ def test_describe_parameters_filter_keyid(): response = client.describe_parameters(Filters=[ { 'Key': 'KeyId', - 'Values': ['key:5','key:10'] + 'Values': ['key:10'] }, ]) - len(response['Parameters']).should.equal(2) + len(response['Parameters']).should.equal(1) response['Parameters'][0]['Name'].should.equal('param-10') response['Parameters'][0]['Type'].should.equal('SecureString') - response['Parameters'][1]['Name'].should.equal('param-5') - response['Parameters'][1]['Type'].should.equal('SecureString') ''.should.equal(response.get('NextToken', '')) @mock_ssm From 27f1248788b71943e3c04c9b7e173ac70e22dd81 Mon Sep 17 00:00:00 2001 From: Declan Shanaghy Date: Mon, 26 Jun 2017 11:20:56 -0700 Subject: [PATCH 7/8] Fix spacing --- tests/test_ssm/test_ssm_boto3.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/test_ssm/test_ssm_boto3.py b/tests/test_ssm/test_ssm_boto3.py index a62536a23..de0793e82 100644 --- a/tests/test_ssm/test_ssm_boto3.py +++ b/tests/test_ssm/test_ssm_boto3.py @@ -99,6 +99,7 @@ def test_describe_parameters_paging(): len(response['Parameters']).should.equal(0) ''.should.equal(response.get('NextToken', '')) + @mock_ssm def test_describe_parameters_filter_names(): client = boto3.client('ssm', region_name='us-east-1') @@ -114,7 +115,6 @@ def test_describe_parameters_filter_names(): p['KeyId'] = 'a key' client.put_parameter(**p) - response = client.describe_parameters(Filters=[ { 'Key': 'Name', @@ -126,6 +126,7 @@ def test_describe_parameters_filter_names(): response['Parameters'][0]['Type'].should.equal('String') ''.should.equal(response.get('NextToken', '')) + @mock_ssm def test_describe_parameters_filter_type(): client = boto3.client('ssm', region_name='us-east-1') @@ -153,6 +154,7 @@ def test_describe_parameters_filter_type(): response['Parameters'][0]['Type'].should.equal('SecureString') '10'.should.equal(response.get('NextToken', '')) + @mock_ssm def test_describe_parameters_filter_keyid(): client = boto3.client('ssm', region_name='us-east-1') @@ -180,6 +182,7 @@ def test_describe_parameters_filter_keyid(): response['Parameters'][0]['Type'].should.equal('SecureString') ''.should.equal(response.get('NextToken', '')) + @mock_ssm def test_put_parameter_secure_default_kms(): client = boto3.client('ssm', region_name='us-east-1') From 7bf5211bef53c3b821bb60435ddab9db9f96da9e Mon Sep 17 00:00:00 2001 From: Declan Shanaghy Date: Mon, 26 Jun 2017 12:07:44 -0700 Subject: [PATCH 8/8] Simplify test 2 --- tests/test_ssm/test_ssm_boto3.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/test_ssm/test_ssm_boto3.py b/tests/test_ssm/test_ssm_boto3.py index de0793e82..60a027933 100644 --- a/tests/test_ssm/test_ssm_boto3.py +++ b/tests/test_ssm/test_ssm_boto3.py @@ -150,7 +150,6 @@ def test_describe_parameters_filter_type(): }, ]) len(response['Parameters']).should.equal(10) - response['Parameters'][0]['Name'].should.equal('param-35') response['Parameters'][0]['Type'].should.equal('SecureString') '10'.should.equal(response.get('NextToken', ''))