/packages/@aws-cdk/aws-ssm/test/test.parameter.ts

https://github.com/awslabs/aws-cdk · TypeScript · 710 lines · 546 code · 89 blank · 75 comment · 10 complexity · cebaec68cd4f25288102c089c10b0dcf MD5 · raw file

  1. /* eslint-disable max-len */
  2. import { expect, haveResource } from '@aws-cdk/assert';
  3. import * as iam from '@aws-cdk/aws-iam';
  4. import * as kms from '@aws-cdk/aws-kms';
  5. import * as cdk from '@aws-cdk/core';
  6. import { Test } from 'nodeunit';
  7. import * as ssm from '../lib';
  8. export = {
  9. 'creating a String SSM Parameter'(test: Test) {
  10. // GIVEN
  11. const stack = new cdk.Stack();
  12. // WHEN
  13. new ssm.StringParameter(stack, 'Parameter', {
  14. allowedPattern: '.*',
  15. description: 'The value Foo',
  16. parameterName: 'FooParameter',
  17. stringValue: 'Foo',
  18. });
  19. // THEN
  20. expect(stack).to(haveResource('AWS::SSM::Parameter', {
  21. AllowedPattern: '.*',
  22. Description: 'The value Foo',
  23. Name: 'FooParameter',
  24. Type: 'String',
  25. Value: 'Foo',
  26. }));
  27. test.done();
  28. },
  29. 'expect String SSM Parameter to have tier properly set'(test: Test) {
  30. // GIVEN
  31. const stack = new cdk.Stack();
  32. // WHEN
  33. new ssm.StringParameter(stack, 'Parameter', {
  34. allowedPattern: '.*',
  35. description: 'The value Foo',
  36. parameterName: 'FooParameter',
  37. stringValue: 'Foo',
  38. tier: ssm.ParameterTier.ADVANCED,
  39. });
  40. // THEN
  41. expect(stack).to(haveResource('AWS::SSM::Parameter', {
  42. Tier: 'Advanced',
  43. }));
  44. test.done();
  45. },
  46. 'String SSM Parameter rejects invalid values'(test: Test) {
  47. // GIVEN
  48. const stack = new cdk.Stack();
  49. // THEN
  50. test.throws(() => new ssm.StringParameter(stack, 'Parameter', { allowedPattern: '^Bar$', stringValue: 'FooBar' }),
  51. /does not match the specified allowedPattern/);
  52. test.done();
  53. },
  54. 'String SSM Parameter allows unresolved tokens'(test: Test) {
  55. // GIVEN
  56. const stack = new cdk.Stack();
  57. // THEN
  58. test.doesNotThrow(() => {
  59. new ssm.StringParameter(stack, 'Parameter', {
  60. allowedPattern: '^Bar$',
  61. stringValue: cdk.Lazy.stringValue({ produce: () => 'Foo!' }),
  62. });
  63. });
  64. test.done();
  65. },
  66. 'creating a StringList SSM Parameter'(test: Test) {
  67. // GIVEN
  68. const stack = new cdk.Stack();
  69. // WHEN
  70. new ssm.StringListParameter(stack, 'Parameter', {
  71. allowedPattern: '(Foo|Bar)',
  72. description: 'The values Foo and Bar',
  73. parameterName: 'FooParameter',
  74. stringListValue: ['Foo', 'Bar'],
  75. });
  76. // THEN
  77. expect(stack).to(haveResource('AWS::SSM::Parameter', {
  78. AllowedPattern: '(Foo|Bar)',
  79. Description: 'The values Foo and Bar',
  80. Name: 'FooParameter',
  81. Type: 'StringList',
  82. Value: 'Foo,Bar',
  83. }));
  84. test.done();
  85. },
  86. 'String SSM Parameter throws on long descriptions'(test: Test) {
  87. // GIVEN
  88. const stack = new cdk.Stack();
  89. // THEN
  90. test.throws(() => {
  91. new ssm.StringParameter(stack, 'Parameter', {
  92. stringValue: 'Foo',
  93. description: '1024+ character long description: Lorem ipsum dolor sit amet, consectetuer adipiscing elit. \
  94. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, \
  95. nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat \
  96. massa quis enim. Donec pede justo, fringilla vel, aliquet nec, vulputate eget, arcu. In enim justo, rhoncus ut, \
  97. imperdiet a, venenatis vitae, justo. Nullam dictum felis eu pede mollis pretium. Integer tincidunt. Cras dapibus. \
  98. Vivamus elementum semper nisi. Aenean vulputate eleifend tellus. Aenean leo ligula, porttitor eu, consequat vitae, \
  99. eleifend ac, enim. Aliquam lorem ante, dapibus in, viverra quis, feugiat a, tellus. Phasellus viverra nulla ut metus \
  100. varius laoreet. Quisque rutrum. Aenean imperdiet. Etiam ultricies nisi vel augue. Curabitur ullamcorper ultricies nisi. \
  101. Nam eget dui. Etiam rhoncus. Maecenas tempus, tellus eget condimentum rhoncus, sem quam semper libero, sit amet adipiscing \
  102. sem neque sed ipsum.',
  103. });
  104. }, /Description cannot be longer than 1024 characters./);
  105. test.done();
  106. },
  107. 'String SSM Parameter throws on long names'(test: Test) {
  108. // GIVEN
  109. const stack = new cdk.Stack();
  110. // THEN
  111. test.throws(() => {
  112. new ssm.StringParameter(stack, 'Parameter', {
  113. stringValue: 'Foo',
  114. parameterName: '2048+ character long name: Lorem ipsum dolor sit amet, consectetuer adipiscing elit. \
  115. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, \
  116. nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat \
  117. massa quis enim. Donec pede justo, fringilla vel, aliquet nec, vulputate eget, arcu. In enim justo, rhoncus ut, \
  118. imperdiet a, venenatis vitae, justo. Nullam dictum felis eu pede mollis pretium. Integer tincidunt. Cras dapibus. \
  119. Vivamus elementum semper nisi. Aenean vulputate eleifend tellus. Aenean leo ligula, porttitor eu, consequat vitae, \
  120. eleifend ac, enim. Aliquam lorem ante, dapibus in, viverra quis, feugiat a, tellus. Phasellus viverra nulla ut metus \
  121. varius laoreet. Quisque rutrum. Aenean imperdiet. Etiam ultricies nisi vel augue. Curabitur ullamcorper ultricies nisi. \
  122. Nam eget dui. Etiam rhoncus. Maecenas tempus, tellus eget condimentum rhoncus, sem quam semper libero, sit amet adipiscing \
  123. sem neque sed ipsum. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. \
  124. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, \
  125. nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat \
  126. massa quis enim. Donec pede justo, fringilla vel, aliquet nec, vulputate eget, arcu. In enim justo, rhoncus ut, \
  127. imperdiet a, venenatis vitae, justo. Nullam dictum felis eu pede mollis pretium. Integer tincidunt. Cras dapibus. \
  128. Vivamus elementum semper nisi. Aenean vulputate eleifend tellus. Aenean leo ligula, porttitor eu, consequat vitae, \
  129. eleifend ac, enim. Aliquam lorem ante, dapibus in, viverra quis, feugiat a, tellus. Phasellus viverra nulla ut metus \
  130. varius laoreet. Quisque rutrum. Aenean imperdiet. Etiam ultricies nisi vel augue. Curabitur ullamcorper ultricies nisi. \
  131. Nam eget dui. Etiam rhoncus. Maecenas tempus, tellus eget condimentum rhoncus, sem quam semper libero, sit amet adipiscing \
  132. sem neque sed ipsum.',
  133. });
  134. }, /Name cannot be longer than 2048 characters./);
  135. test.done();
  136. },
  137. 'StringList SSM Parameter throws on long descriptions'(test: Test) {
  138. // GIVEN
  139. const stack = new cdk.Stack();
  140. // THEN
  141. test.throws(() => {
  142. new ssm.StringListParameter(stack, 'Parameter', {
  143. stringListValue: ['Foo', 'Bar'],
  144. description: '1024+ character long description: Lorem ipsum dolor sit amet, consectetuer adipiscing elit. \
  145. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, \
  146. nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat \
  147. massa quis enim. Donec pede justo, fringilla vel, aliquet nec, vulputate eget, arcu. In enim justo, rhoncus ut, \
  148. imperdiet a, venenatis vitae, justo. Nullam dictum felis eu pede mollis pretium. Integer tincidunt. Cras dapibus. \
  149. Vivamus elementum semper nisi. Aenean vulputate eleifend tellus. Aenean leo ligula, porttitor eu, consequat vitae, \
  150. eleifend ac, enim. Aliquam lorem ante, dapibus in, viverra quis, feugiat a, tellus. Phasellus viverra nulla ut metus \
  151. varius laoreet. Quisque rutrum. Aenean imperdiet. Etiam ultricies nisi vel augue. Curabitur ullamcorper ultricies nisi. \
  152. Nam eget dui. Etiam rhoncus. Maecenas tempus, tellus eget condimentum rhoncus, sem quam semper libero, sit amet adipiscing \
  153. sem neque sed ipsum.',
  154. });
  155. }, /Description cannot be longer than 1024 characters./);
  156. test.done();
  157. },
  158. 'StringList SSM Parameter throws on long names'(test: Test) {
  159. // GIVEN
  160. const stack = new cdk.Stack();
  161. // THEN
  162. test.throws(() => {
  163. new ssm.StringListParameter(stack, 'Parameter', {
  164. stringListValue: ['Foo', 'Bar'],
  165. parameterName: '2048+ character long name: Lorem ipsum dolor sit amet, consectetuer adipiscing elit. \
  166. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, \
  167. nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat \
  168. massa quis enim. Donec pede justo, fringilla vel, aliquet nec, vulputate eget, arcu. In enim justo, rhoncus ut, \
  169. imperdiet a, venenatis vitae, justo. Nullam dictum felis eu pede mollis pretium. Integer tincidunt. Cras dapibus. \
  170. Vivamus elementum semper nisi. Aenean vulputate eleifend tellus. Aenean leo ligula, porttitor eu, consequat vitae, \
  171. eleifend ac, enim. Aliquam lorem ante, dapibus in, viverra quis, feugiat a, tellus. Phasellus viverra nulla ut metus \
  172. varius laoreet. Quisque rutrum. Aenean imperdiet. Etiam ultricies nisi vel augue. Curabitur ullamcorper ultricies nisi. \
  173. Nam eget dui. Etiam rhoncus. Maecenas tempus, tellus eget condimentum rhoncus, sem quam semper libero, sit amet adipiscing \
  174. sem neque sed ipsum. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. \
  175. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, \
  176. nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat \
  177. massa quis enim. Donec pede justo, fringilla vel, aliquet nec, vulputate eget, arcu. In enim justo, rhoncus ut, \
  178. imperdiet a, venenatis vitae, justo. Nullam dictum felis eu pede mollis pretium. Integer tincidunt. Cras dapibus. \
  179. Vivamus elementum semper nisi. Aenean vulputate eleifend tellus. Aenean leo ligula, porttitor eu, consequat vitae, \
  180. eleifend ac, enim. Aliquam lorem ante, dapibus in, viverra quis, feugiat a, tellus. Phasellus viverra nulla ut metus \
  181. varius laoreet. Quisque rutrum. Aenean imperdiet. Etiam ultricies nisi vel augue. Curabitur ullamcorper ultricies nisi. \
  182. Nam eget dui. Etiam rhoncus. Maecenas tempus, tellus eget condimentum rhoncus, sem quam semper libero, sit amet adipiscing \
  183. sem neque sed ipsum.',
  184. });
  185. }, /Name cannot be longer than 2048 characters./);
  186. test.done();
  187. },
  188. 'StringList SSM Parameter values cannot contain commas'(test: Test) {
  189. // GIVEN
  190. const stack = new cdk.Stack();
  191. // THEN
  192. test.throws(() => new ssm.StringListParameter(stack, 'Parameter', { stringListValue: ['Foo,Bar'] }),
  193. /cannot contain the ',' character/);
  194. test.done();
  195. },
  196. 'StringList SSM Parameter rejects invalid values'(test: Test) {
  197. // GIVEN
  198. const stack = new cdk.Stack();
  199. // THEN
  200. test.throws(() => new ssm.StringListParameter(stack, 'Parameter', { allowedPattern: '^(Foo|Bar)$', stringListValue: ['Foo', 'FooBar'] }),
  201. /does not match the specified allowedPattern/);
  202. test.done();
  203. },
  204. 'StringList SSM Parameter allows unresolved tokens'(test: Test) {
  205. // GIVEN
  206. const stack = new cdk.Stack();
  207. // THEN
  208. test.doesNotThrow(() => new ssm.StringListParameter(stack, 'Parameter', {
  209. allowedPattern: '^(Foo|Bar)$',
  210. stringListValue: ['Foo', cdk.Lazy.stringValue({ produce: () => 'Baz!' })],
  211. }));
  212. test.done();
  213. },
  214. 'parameterArn is crafted correctly'(test: Test) {
  215. // GIVEN
  216. const stack = new cdk.Stack();
  217. const param = new ssm.StringParameter(stack, 'Parameter', { stringValue: 'Foo' });
  218. // THEN
  219. test.deepEqual(stack.resolve(param.parameterArn), {
  220. 'Fn::Join': ['', [
  221. 'arn:',
  222. { Ref: 'AWS::Partition' },
  223. ':ssm:',
  224. { Ref: 'AWS::Region' },
  225. ':',
  226. { Ref: 'AWS::AccountId' },
  227. ':parameter/',
  228. { Ref: 'Parameter9E1B4FBA' },
  229. ]],
  230. });
  231. test.done();
  232. },
  233. 'parameterName that includes a "/" must be fully qualified (i.e. begin with "/") as well'(test: Test) {
  234. // GIVEN
  235. const stack = new cdk.Stack();
  236. // THEN
  237. test.throws(() => new ssm.StringParameter(stack, 'myParam', {
  238. stringValue: 'myValue',
  239. parameterName: 'path/to/parameter',
  240. }), /Parameter names must be fully qualified/);
  241. test.throws(() => new ssm.StringListParameter(stack, 'myParam2', {
  242. stringListValue: ['foo', 'bar'],
  243. parameterName: 'path/to/parameter2',
  244. }), /Parameter names must be fully qualified \(if they include \"\/\" they must also begin with a \"\/\"\)\: path\/to\/parameter2/);
  245. test.done();
  246. },
  247. 'StringParameter.fromStringParameterName'(test: Test) {
  248. // GIVEN
  249. const stack = new cdk.Stack();
  250. // WHEN
  251. const param = ssm.StringParameter.fromStringParameterName(stack, 'MyParamName', 'MyParamName');
  252. // THEN
  253. test.deepEqual(stack.resolve(param.parameterArn), {
  254. 'Fn::Join': ['', [
  255. 'arn:',
  256. { Ref: 'AWS::Partition' },
  257. ':ssm:',
  258. { Ref: 'AWS::Region' },
  259. ':',
  260. { Ref: 'AWS::AccountId' },
  261. ':parameter/MyParamName',
  262. ]],
  263. });
  264. test.deepEqual(stack.resolve(param.parameterName), 'MyParamName');
  265. test.deepEqual(stack.resolve(param.parameterType), 'String');
  266. test.deepEqual(stack.resolve(param.stringValue), { Ref: 'MyParamNameParameter' });
  267. expect(stack).toMatch({
  268. Parameters: {
  269. MyParamNameParameter: {
  270. Type: 'AWS::SSM::Parameter::Value<String>',
  271. Default: 'MyParamName',
  272. },
  273. },
  274. });
  275. test.done();
  276. },
  277. 'StringParameter.fromStringParameterAttributes'(test: Test) {
  278. // GIVEN
  279. const stack = new cdk.Stack();
  280. // WHEN
  281. const param = ssm.StringParameter.fromStringParameterAttributes(stack, 'MyParamName', {
  282. parameterName: 'MyParamName',
  283. version: 2,
  284. });
  285. // THEN
  286. test.deepEqual(stack.resolve(param.parameterArn), {
  287. 'Fn::Join': ['', [
  288. 'arn:',
  289. { Ref: 'AWS::Partition' },
  290. ':ssm:',
  291. { Ref: 'AWS::Region' },
  292. ':',
  293. { Ref: 'AWS::AccountId' },
  294. ':parameter/MyParamName',
  295. ]],
  296. });
  297. test.deepEqual(stack.resolve(param.parameterName), 'MyParamName');
  298. test.deepEqual(stack.resolve(param.parameterType), 'String');
  299. test.deepEqual(stack.resolve(param.stringValue), '{{resolve:ssm:MyParamName:2}}');
  300. test.done();
  301. },
  302. 'StringParameter.fromSecureStringParameterAttributes'(test: Test) {
  303. // GIVEN
  304. const stack = new cdk.Stack();
  305. // WHEN
  306. const param = ssm.StringParameter.fromSecureStringParameterAttributes(stack, 'MyParamName', {
  307. parameterName: 'MyParamName',
  308. version: 2,
  309. });
  310. // THEN
  311. test.deepEqual(stack.resolve(param.parameterArn), {
  312. 'Fn::Join': ['', [
  313. 'arn:',
  314. { Ref: 'AWS::Partition' },
  315. ':ssm:',
  316. { Ref: 'AWS::Region' },
  317. ':',
  318. { Ref: 'AWS::AccountId' },
  319. ':parameter/MyParamName',
  320. ]],
  321. });
  322. test.deepEqual(stack.resolve(param.parameterName), 'MyParamName');
  323. test.deepEqual(stack.resolve(param.parameterType), 'SecureString');
  324. test.deepEqual(stack.resolve(param.stringValue), '{{resolve:ssm-secure:MyParamName:2}}');
  325. test.done();
  326. },
  327. 'StringParameter.fromSecureStringParameterAttributes with encryption key creates the correct policy for grantRead'(test: Test) {
  328. // GIVEN
  329. const stack = new cdk.Stack();
  330. const key = kms.Key.fromKeyArn(stack, 'CustomKey', 'arn:aws:kms:us-east-1:123456789012:key/xyz');
  331. const role = new iam.Role(stack, 'Role', {
  332. assumedBy: new iam.AccountRootPrincipal(),
  333. });
  334. // WHEN
  335. const param = ssm.StringParameter.fromSecureStringParameterAttributes(stack, 'MyParamName', {
  336. parameterName: 'MyParamName',
  337. version: 2,
  338. encryptionKey: key,
  339. });
  340. param.grantRead(role);
  341. // THEN
  342. expect(stack).to(haveResource('AWS::IAM::Policy', {
  343. PolicyDocument: {
  344. Statement: [
  345. {
  346. Action: 'kms:Decrypt',
  347. Effect: 'Allow',
  348. Resource: 'arn:aws:kms:us-east-1:123456789012:key/xyz',
  349. },
  350. {
  351. Action: [
  352. 'ssm:DescribeParameters',
  353. 'ssm:GetParameters',
  354. 'ssm:GetParameter',
  355. 'ssm:GetParameterHistory',
  356. ],
  357. Effect: 'Allow',
  358. Resource: {
  359. 'Fn::Join': [
  360. '',
  361. [
  362. 'arn:',
  363. {
  364. Ref: 'AWS::Partition',
  365. },
  366. ':ssm:',
  367. {
  368. Ref: 'AWS::Region',
  369. },
  370. ':',
  371. {
  372. Ref: 'AWS::AccountId',
  373. },
  374. ':parameter/MyParamName',
  375. ],
  376. ],
  377. },
  378. },
  379. ],
  380. Version: '2012-10-17',
  381. },
  382. }));
  383. test.done();
  384. },
  385. 'StringParameter.fromSecureStringParameterAttributes with encryption key creates the correct policy for grantWrite'(test: Test) {
  386. // GIVEN
  387. const stack = new cdk.Stack();
  388. const key = kms.Key.fromKeyArn(stack, 'CustomKey', 'arn:aws:kms:us-east-1:123456789012:key/xyz');
  389. const role = new iam.Role(stack, 'Role', {
  390. assumedBy: new iam.AccountRootPrincipal(),
  391. });
  392. // WHEN
  393. const param = ssm.StringParameter.fromSecureStringParameterAttributes(stack, 'MyParamName', {
  394. parameterName: 'MyParamName',
  395. version: 2,
  396. encryptionKey: key,
  397. });
  398. param.grantWrite(role);
  399. // THEN
  400. expect(stack).to(haveResource('AWS::IAM::Policy', {
  401. PolicyDocument: {
  402. Statement: [
  403. {
  404. Action: [
  405. 'kms:Encrypt',
  406. 'kms:ReEncrypt*',
  407. 'kms:GenerateDataKey*',
  408. ],
  409. Effect: 'Allow',
  410. Resource: 'arn:aws:kms:us-east-1:123456789012:key/xyz',
  411. },
  412. {
  413. Action: 'ssm:PutParameter',
  414. Effect: 'Allow',
  415. Resource: {
  416. 'Fn::Join': [
  417. '',
  418. [
  419. 'arn:',
  420. {
  421. Ref: 'AWS::Partition',
  422. },
  423. ':ssm:',
  424. {
  425. Ref: 'AWS::Region',
  426. },
  427. ':',
  428. {
  429. Ref: 'AWS::AccountId',
  430. },
  431. ':parameter/MyParamName',
  432. ],
  433. ],
  434. },
  435. },
  436. ],
  437. Version: '2012-10-17',
  438. },
  439. }));
  440. test.done();
  441. },
  442. 'StringListParameter.fromName'(test: Test) {
  443. // GIVEN
  444. const stack = new cdk.Stack();
  445. // WHEN
  446. const param = ssm.StringListParameter.fromStringListParameterName(stack, 'MyParamName', 'MyParamName');
  447. // THEN
  448. test.deepEqual(stack.resolve(param.parameterArn), {
  449. 'Fn::Join': ['', [
  450. 'arn:',
  451. { Ref: 'AWS::Partition' },
  452. ':ssm:',
  453. { Ref: 'AWS::Region' },
  454. ':',
  455. { Ref: 'AWS::AccountId' },
  456. ':parameter/MyParamName',
  457. ]],
  458. });
  459. test.deepEqual(stack.resolve(param.parameterName), 'MyParamName');
  460. test.deepEqual(stack.resolve(param.parameterType), 'StringList');
  461. test.deepEqual(stack.resolve(param.stringListValue), { 'Fn::Split': [',', '{{resolve:ssm:MyParamName}}'] });
  462. test.done();
  463. },
  464. 'fromLookup will use the SSM context provider to read value during synthesis'(test: Test) {
  465. // GIVEN
  466. const app = new cdk.App();
  467. const stack = new cdk.Stack(app, 'my-staq', { env: { region: 'us-east-1', account: '12344' } });
  468. // WHEN
  469. const value = ssm.StringParameter.valueFromLookup(stack, 'my-param-name');
  470. // THEN
  471. test.deepEqual(value, 'dummy-value-for-my-param-name');
  472. test.deepEqual(app.synth().manifest.missing, [
  473. {
  474. key: 'ssm:account=12344:parameterName=my-param-name:region=us-east-1',
  475. props: {
  476. account: '12344',
  477. region: 'us-east-1',
  478. parameterName: 'my-param-name',
  479. },
  480. provider: 'ssm',
  481. },
  482. ]);
  483. test.done();
  484. },
  485. valueForStringParameter: {
  486. 'returns a token that represents the SSM parameter value'(test: Test) {
  487. // GIVEN
  488. const stack = new cdk.Stack();
  489. // WHEN
  490. const value = ssm.StringParameter.valueForStringParameter(stack, 'my-param-name');
  491. // THEN
  492. expect(stack).toMatch({
  493. Parameters: {
  494. SsmParameterValuemyparamnameC96584B6F00A464EAD1953AFF4B05118Parameter: {
  495. Type: 'AWS::SSM::Parameter::Value<String>',
  496. Default: 'my-param-name',
  497. },
  498. },
  499. });
  500. test.deepEqual(stack.resolve(value), { Ref: 'SsmParameterValuemyparamnameC96584B6F00A464EAD1953AFF4B05118Parameter' });
  501. test.done();
  502. },
  503. 'de-dup based on parameter name'(test: Test) {
  504. // GIVEN
  505. const stack = new cdk.Stack();
  506. // WHEN
  507. ssm.StringParameter.valueForStringParameter(stack, 'my-param-name');
  508. ssm.StringParameter.valueForStringParameter(stack, 'my-param-name');
  509. ssm.StringParameter.valueForStringParameter(stack, 'my-param-name-2');
  510. ssm.StringParameter.valueForStringParameter(stack, 'my-param-name');
  511. // THEN
  512. expect(stack).toMatch({
  513. Parameters: {
  514. SsmParameterValuemyparamnameC96584B6F00A464EAD1953AFF4B05118Parameter: {
  515. Type: 'AWS::SSM::Parameter::Value<String>',
  516. Default: 'my-param-name',
  517. },
  518. SsmParameterValuemyparamname2C96584B6F00A464EAD1953AFF4B05118Parameter: {
  519. Type: 'AWS::SSM::Parameter::Value<String>',
  520. Default: 'my-param-name-2',
  521. },
  522. },
  523. });
  524. test.done();
  525. },
  526. 'can query actual SSM Parameter Names, multiple times'(test: Test) {
  527. // GIVEN
  528. const stack = new cdk.Stack();
  529. // WHEN
  530. ssm.StringParameter.valueForStringParameter(stack, '/my/param/name');
  531. ssm.StringParameter.valueForStringParameter(stack, '/my/param/name');
  532. test.done();
  533. },
  534. },
  535. 'rendering of parameter arns'(test: Test) {
  536. const stack = new cdk.Stack();
  537. const param = new cdk.CfnParameter(stack, 'param');
  538. const expectedA = { 'Fn::Join': ['', ['arn:', { Ref: 'AWS::Partition' }, ':ssm:', { Ref: 'AWS::Region' }, ':', { Ref: 'AWS::AccountId' }, ':parameter/bam']] };
  539. const expectedB = { 'Fn::Join': ['', ['arn:', { Ref: 'AWS::Partition' }, ':ssm:', { Ref: 'AWS::Region' }, ':', { Ref: 'AWS::AccountId' }, ':parameter/', { Ref: 'param' }]] };
  540. const expectedC = { 'Fn::Join': ['', ['arn:', { Ref: 'AWS::Partition' }, ':ssm:', { Ref: 'AWS::Region' }, ':', { Ref: 'AWS::AccountId' }, ':parameter', { Ref: 'param' }]] };
  541. let i = 0;
  542. // WHEN
  543. const case1 = ssm.StringParameter.fromStringParameterName(stack, `p${i++}`, 'bam');
  544. const case2 = ssm.StringParameter.fromStringParameterName(stack, `p${i++}`, '/bam');
  545. const case4 = ssm.StringParameter.fromStringParameterAttributes(stack, `p${i++}`, { parameterName: 'bam' });
  546. const case5 = ssm.StringParameter.fromStringParameterAttributes(stack, `p${i++}`, { parameterName: '/bam' });
  547. const case6 = ssm.StringParameter.fromStringParameterAttributes(stack, `p${i++}`, { parameterName: param.valueAsString, simpleName: true });
  548. const case7 = ssm.StringParameter.fromSecureStringParameterAttributes(stack, `p${i++}`, { parameterName: 'bam', version: 10 });
  549. const case8 = ssm.StringParameter.fromSecureStringParameterAttributes(stack, `p${i++}`, { parameterName: '/bam', version: 10 });
  550. const case9 = ssm.StringParameter.fromSecureStringParameterAttributes(stack, `p${i++}`, { parameterName: param.valueAsString, version: 10, simpleName: false });
  551. // auto-generated name is always generated as a "simple name" (not/a/path)
  552. const case10 = new ssm.StringParameter(stack, `p${i++}`, { stringValue: 'value' });
  553. // explicitly named physical name gives us a hint on how to render the ARN
  554. const case11 = new ssm.StringParameter(stack, `p${i++}`, { parameterName: '/foo/bar', stringValue: 'hello' });
  555. const case12 = new ssm.StringParameter(stack, `p${i++}`, { parameterName: 'simple-name', stringValue: 'hello' });
  556. const case13 = new ssm.StringListParameter(stack, `p${i++}`, { stringListValue: ['hello', 'world'] });
  557. const case14 = new ssm.StringListParameter(stack, `p${i++}`, { parameterName: '/not/simple', stringListValue: ['hello', 'world'] });
  558. const case15 = new ssm.StringListParameter(stack, `p${i++}`, { parameterName: 'simple', stringListValue: ['hello', 'world'] });
  559. // THEN
  560. test.deepEqual(stack.resolve(case1.parameterArn), expectedA);
  561. test.deepEqual(stack.resolve(case2.parameterArn), expectedA);
  562. test.deepEqual(stack.resolve(case4.parameterArn), expectedA);
  563. test.deepEqual(stack.resolve(case5.parameterArn), expectedA);
  564. test.deepEqual(stack.resolve(case6.parameterArn), expectedB);
  565. test.deepEqual(stack.resolve(case7.parameterArn), expectedA);
  566. test.deepEqual(stack.resolve(case8.parameterArn), expectedA);
  567. test.deepEqual(stack.resolve(case9.parameterArn), expectedC);
  568. // new ssm.Parameters determine if "/" is needed based on the posture of `parameterName`.
  569. test.deepEqual(stack.resolve(case10.parameterArn), { 'Fn::Join': ['', ['arn:', { Ref: 'AWS::Partition' }, ':ssm:', { Ref: 'AWS::Region' }, ':', { Ref: 'AWS::AccountId' }, ':parameter/', { Ref: 'p81BB0F6FE' }]] });
  570. test.deepEqual(stack.resolve(case11.parameterArn), { 'Fn::Join': ['', ['arn:', { Ref: 'AWS::Partition' }, ':ssm:', { Ref: 'AWS::Region' }, ':', { Ref: 'AWS::AccountId' }, ':parameter', { Ref: 'p97A508212' }]] });
  571. test.deepEqual(stack.resolve(case12.parameterArn), { 'Fn::Join': ['', ['arn:', { Ref: 'AWS::Partition' }, ':ssm:', { Ref: 'AWS::Region' }, ':', { Ref: 'AWS::AccountId' }, ':parameter/', { Ref: 'p107D6B8AB0' }]] });
  572. test.deepEqual(stack.resolve(case13.parameterArn), { 'Fn::Join': ['', ['arn:', { Ref: 'AWS::Partition' }, ':ssm:', { Ref: 'AWS::Region' }, ':', { Ref: 'AWS::AccountId' }, ':parameter/', { Ref: 'p118A9CB02C' }]] });
  573. test.deepEqual(stack.resolve(case14.parameterArn), { 'Fn::Join': ['', ['arn:', { Ref: 'AWS::Partition' }, ':ssm:', { Ref: 'AWS::Region' }, ':', { Ref: 'AWS::AccountId' }, ':parameter', { Ref: 'p129BE4CE91' }]] });
  574. test.deepEqual(stack.resolve(case15.parameterArn), { 'Fn::Join': ['', ['arn:', { Ref: 'AWS::Partition' }, ':ssm:', { Ref: 'AWS::Region' }, ':', { Ref: 'AWS::AccountId' }, ':parameter/', { Ref: 'p1326A2AEC4' }]] });
  575. test.done();
  576. },
  577. 'if parameterName is a token separator must be specified'(test: Test) {
  578. // GIVEN
  579. const stack = new cdk.Stack();
  580. const param = new cdk.CfnParameter(stack, 'param');
  581. let i = 0;
  582. // WHEN
  583. const p1 = new ssm.StringParameter(stack, `p${i++}`, { parameterName: param.valueAsString, stringValue: 'foo', simpleName: true });
  584. const p2 = new ssm.StringParameter(stack, `p${i++}`, { parameterName: param.valueAsString, stringValue: 'foo', simpleName: false });
  585. const p3 = new ssm.StringListParameter(stack, `p${i++}`, { parameterName: param.valueAsString, stringListValue: ['foo'], simpleName: false });
  586. // THEN
  587. test.deepEqual(stack.resolve(p1.parameterArn), { 'Fn::Join': ['', ['arn:', { Ref: 'AWS::Partition' }, ':ssm:', { Ref: 'AWS::Region' }, ':', { Ref: 'AWS::AccountId' }, ':parameter/', { Ref: 'p0B02A8F65' }]] });
  588. test.deepEqual(stack.resolve(p2.parameterArn), { 'Fn::Join': ['', ['arn:', { Ref: 'AWS::Partition' }, ':ssm:', { Ref: 'AWS::Region' }, ':', { Ref: 'AWS::AccountId' }, ':parameter', { Ref: 'p1E43AD5AC' }]] });
  589. test.deepEqual(stack.resolve(p3.parameterArn), { 'Fn::Join': ['', ['arn:', { Ref: 'AWS::Partition' }, ':ssm:', { Ref: 'AWS::Region' }, ':', { Ref: 'AWS::AccountId' }, ':parameter', { Ref: 'p2C1903AEB' }]] });
  590. test.done();
  591. },
  592. 'fails if name is a token and no explicit separator'(test: Test) {
  593. // GIVEN
  594. const stack = new cdk.Stack();
  595. const param = new cdk.CfnParameter(stack, 'param');
  596. let i = 0;
  597. // THEN
  598. const expected = /Unable to determine ARN separator for SSM parameter since the parameter name is an unresolved token. Use "fromAttributes" and specify "simpleName" explicitly/;
  599. test.throws(() => ssm.StringParameter.fromStringParameterName(stack, `p${i++}`, param.valueAsString), expected);
  600. test.throws(() => ssm.StringParameter.fromSecureStringParameterAttributes(stack, `p${i++}`, { parameterName: param.valueAsString, version: 1 }), expected);
  601. test.throws(() => new ssm.StringParameter(stack, `p${i++}`, { parameterName: param.valueAsString, stringValue: 'foo' }), expected);
  602. test.throws(() => new ssm.StringParameter(stack, `p${i++}`, { parameterName: param.valueAsString, stringValue: 'foo' }), expected);
  603. test.done();
  604. },
  605. 'fails if simpleName is wrong based on a concrete physical name'(test: Test) {
  606. // GIVEN
  607. const stack = new cdk.Stack();
  608. let i = 0;
  609. // THEN
  610. test.throws(() => ssm.StringParameter.fromStringParameterAttributes(stack, `p${i++}`, { parameterName: 'simple', simpleName: false }), /Parameter name "simple" is a simple name, but "simpleName" was explicitly set to false. Either omit it or set it to true/);
  611. test.throws(() => ssm.StringParameter.fromStringParameterAttributes(stack, `p${i++}`, { parameterName: '/foo/bar', simpleName: true }), /Parameter name "\/foo\/bar" is not a simple name, but "simpleName" was explicitly set to true. Either omit it or set it to false/);
  612. test.done();
  613. },
  614. 'fails if parameterName is undefined and simpleName is "false"'(test: Test) {
  615. // GIVEN
  616. const stack = new cdk.Stack();
  617. // THEN
  618. test.throws(() => new ssm.StringParameter(stack, 'p', { simpleName: false, stringValue: 'foo' }), /If "parameterName" is not explicitly defined, "simpleName" must be "true" or undefined since auto-generated parameter names always have simple names/);
  619. test.done();
  620. },
  621. };