Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Serverless framework- Await on an asynchronous action in a hook #700

Open
s1mrankaur opened this issue Dec 21, 2022 · 14 comments
Open

Serverless framework- Await on an asynchronous action in a hook #700

s1mrankaur opened this issue Dec 21, 2022 · 14 comments
Labels
question Further information is requested

Comments

@s1mrankaur
Copy link

s1mrankaur commented Dec 21, 2022

We are using the serverless framework in the application for our backend microservices and I am looking to update the microservice version number in SSM from a serverless lifecycle hook mentioned below

after:deploy:deploy
After it gets updated, I'd like to see those versions in Serverless dashboard outputs

https://www.serverless.com/framework/docs/guides/output-variables#:~:text=The%20Serverless%20Framework%20Dashboard%20helps,key%2Fvalues%20in%20other%20serverless.

Based on the info I have, the outputs dashboard gets updated in serverless at "after:was:info:disolayServiceInfo" hook".

So I'd like to ensure that SSM update action is waited upon in the hook before the framework proceeds to the next step as recommended here serverless/serverless#4557 (comment)

Here's what the plugin looks like:

    'use strict';
    
    // const { exec } = require('child_process');
    const AWS = require('aws-sdk');
    const BbPromise = require('bluebird');
    
    
    class ServerlessPlugin {
      constructor(serverless, options) {
        this.serverless = serverless;
        this.options = options;
        this.log = this.serverless.cli.log.bind(this);
    
        this.commands = {};
    
        this.hooks = {
          //'after:aws:deploy:deploy:updateStack': this.updateVersionToSsm.bind(this)
          'before:package:cleanup': () => BbPromise.bind(this)
                    .then(this.updateVersionToSsm)
        };
      }
    
      updateVersionToSsm() {
        this.serverless.cli.log('SSM API version: Acquiring info...');
        const { stage, region } = this.options;
        const provider = this.serverless.getProvider('aws');
        const awsCredentials = provider.getCredentials();
        const SSM = new AWS.SSM({
          region,
          credentials: awsCredentials.credentials
        });
    
        const getSsmParameter = (name) => new Promise((resolve, reject) => {
          var params = {
            Name: name
          };
          SSM.getParameter(params, (err, data) => {
            if (err) {
              this.serverless.cli.log(`get Parameter err is '${err}'`);
              resolve("");
            }
            else {
              this.serverless.cli.log(`get Parameter res is`, JSON.stringify(data));
              resolve(data.Parameter.Value);
            }
          });
        });
    
        const incrementVersion = (version) => {
          this.serverless.cli.log(`Current version is '${version}'`);
          let currentDate = new Date();
          const year = currentDate.getUTCFullYear()
          const month = currentDate.getUTCMonth()
          const date = currentDate.getUTCDate()
          var newVersion = "".concat(year, ".", month, ".", date, ".", "0")
          this.serverless.cli.log(`Default new version is '${newVersion}'`);
          if (version && (typeof version === 'string' || version instanceof String) && version.includes('.')) {
            let currentVersionArr = version.split('.')
            if (year == currentVersionArr[0] && month == currentVersionArr[1] && date == currentVersionArr[2]) {
              let dayIncrement = parseInt(currentVersionArr[3]) + 1
              newVersion = "".concat(year, ".", month, ".", date, ".", dayIncrement)
              this.serverless.cli.log(`Incremented new version is '${newVersion}'`);
            }
          }
          return newVersion
        }
    
        const putSsmParameter = (name, value) => new Promise((resolve, reject) => {
          var params = {
            Name: name,
            Type: 'String',
            Value: value,
            Overwrite: true
          };
          this.serverless.cli.log(`Incrementing SSM version`, name, value);
          SSM.putParameter(params, (err, data) => {
            if (err) { reject(err); }
            else { 
              resolve(data);
             }
          });
        });
    
        const ssmPrefix = (this.serverless.service.custom
          && this.serverless.service.custom.ssmApiVersion
          && this.serverless.service.custom.ssmApiVersion.ssmPrefix)
          ? this.serverless.service.custom.ssmApiVersion.ssmPrefix.replace(/<stage>/g, stage)
          : `/app/${stage}/versions/`;
        const ssmParameterName = ssmPrefix + this.serverless.service.service;
    
        let promise = BbPromise.fromCallback(cb => {
          getSsmParameter(ssmParameterName)
          .then(value => {
            this.serverless.cli.log(`SSM API version: current version`, value);
            const incrementedVersion = incrementVersion(value.toString())
            this.serverless.cli.log(`SSM API version: Updating new version '${incrementedVersion}' to SSM with key '${ssmParameterName}' at region ${region}`);
            putSsmParameter(ssmParameterName, incrementedVersion);
            cb();
          });
        });
        
        return promise;
    
      }
    }
    
    module.exports = ServerlessPlugin;
 

The version updated in the Outputs dashboard picks the last version, not the updated version after deployment.
What am I missing?

@medikoo
Copy link
Contributor

medikoo commented Dec 21, 2022

@s1mrankaur Dashboard outputs are read from Service configuration, and this configuration cannot change after plugin initialization. It means that you cannot modify dashboard outputs after deployment.

Conceptually Dashboard outputs are prerequisites for deployment and not its outcome.

@medikoo medikoo added the question Further information is requested label Dec 21, 2022
@s1mrankaur
Copy link
Author

s1mrankaur commented Dec 21, 2022

@medikoo Thanks for your response. After reading your comment, I modified the plugin to use

  this.hooks = {
      //'after:aws:deploy:deploy:updateStack': this.updateVersionToSsm.bind(this)
      'before:package:cleanup': () => BbPromise.bind(this)
                .then(this.updateVersionToSsm)
    };

and the dashboard still doesn't get the updated value. Since it returns a promise, I suppose it will await on the package:initialize hook for the ssm update to complete. Why does it still not sync the updated value to the dashboard?

Here's what the deployment logs look like:

email-service: Serverless: Invoke deploy
--
email-service: Serverless: Invoke package
email-service: Serverless: SSM API version: Acquiring info...
email-service: Serverless: [AWS ssm 200 0.028s 0 retries] getParameter({ Name: '/app/dev/versions/email-service' })
email-service: {     "Parameter": {         "Name": "/app/dev/versions/email-service",         "Type": "String",         "Value": "2022.11.21.6",         "Version": 176,         "LastModifiedDate": "2022-12-21T21:38:47.319Z",         "ARN": "arn:aws:ssm:us-west-2:accnumber:parameter/app/dev/versions/email-service",         "DataType": "text"     } }: get Parameter res is
email-service: 2022.11.21.6: SSM API version: current version
email-service: Serverless: Current version is '2022.11.21.6'
email-service: Serverless: Default new version is '2022.11.21.0'
email-service: Serverless: Incremented new version is '2022.11.21.7'
email-service: Serverless: SSM API version: Updating new version '2022.11.21.7' to SSM with key '/app/dev/versions/email-service' at region undefined
email-service: /app/dev/versions/email-service: Incrementing SSM version
email-service: Serverless: [AWS ssm 200 0.09s 0 retries] putParameter({
email-service:   Name: '/app/dev/versions/email-service',
email-service:   Type: 'String',
email-service:   Value: '***SensitiveInformation***',
email-service:   Overwrite: true
email-service: })
email-service:  IN: before:package:cleanup
email-service: Serverless: Invoke aws:common:validate
email-service:  IN: before:aws:common:validate:validate
email-service:  IN: after:aws:common:validate:validate
email-service: Serverless: Invoke aws:common:cleanupTempDir
email-service:  IN: before:aws:common:cleanupTempDir:cleanup
email-service:  IN: after:aws:common:cleanupTempDir:cleanup
email-service:  IN: after:package:cleanup
email-service:  IN: before:package:initialize
email-service:  IN: after:package:initialize
email-service:  IN: before:package:setupProviderConfiguration
email-service:  IN: after:package:setupProviderConfiguration
email-service: Serverless: Invoke webpack:validate
email-service:  IN: before:webpack:validate:validate
email-service: Serverless: Using configuration:
email-service: {
email-service:   "packager": "npm",
email-service:   "concurrency": 4,
email-service:   "packagerOptions": {},
email-service:   "webpackConfig": "../../node_modules/serverless-bundle/src/webpack.config.js",
email-service:   "includeModules": {
email-service:     "forceExclude": [
email-service:       "aws-sdk"
email-service:     ],
email-service:     "forceInclude": null,
email-service:     "packagePath": "package.json"
email-service:   },
email-service:   "excludeRegex": {},
email-service:   "keepOutputDirectory": false
email-service: }
email-service: Serverless: Removing /codebuild/output/src317508916/src/services/email-service/.webpack
email-service:  IN: after:webpack:validate:validate
email-service: Serverless: Invoke webpack:compile
email-service:  IN: before:webpack:compile:compile
email-service: Serverless: Bundling with Webpack...
email-service: Serverless: [AWS sts 200 1.928s 0 retries] getCallerIdentity({})
email-service:  IN: after:webpack:compile:compile
email-service: Serverless: Invoke webpack:package
email-service:  IN: before:webpack:package:packExternalModules
email-service: Serverless: Fetch dependency graph from /codebuild/output/src317508916/src/services/email-service/package.json
email-service: Serverless: WARNING: Could not determine version of module aws-sdk
email-service: Serverless: Excluding external modules: aws-sdk
email-service: Serverless: No external modules needed
email-service:  IN: after:webpack:package:packExternalModules
email-service:  IN: before:webpack:package:packageModules
email-service: Serverless: Excluded 0 file(s) based on excludeRegex
email-service: Serverless: Zip service: /codebuild/output/src317508916/src/services/email-service/.webpack/service [69 ms]
email-service:  IN: after:webpack:package:packageModules
email-service:  IN: before:webpack:package:copyExistingArtifacts
email-service: Serverless: Copying existing artifacts...
email-service: Serverless: Setting artifact for function 'EmailsSender' to '.serverless/email-service.zip'
email-service:  IN: after:webpack:package:copyExistingArtifacts
email-service:  IN: before:package:createDeploymentArtifacts
email-service: Serverless: Packaging service...
email-service: Serverless: Remove /codebuild/output/src317508916/src/services/email-service/.webpack
email-service:  IN: after:package:createDeploymentArtifacts
email-service:  IN: before:package:compileLayers
email-service:  IN: after:package:compileLayers
email-service:  IN: before:package:compileFunctions
email-service:  IN: after:package:compileFunctions
email-service:  IN: before:package:compileEvents
email-service:  IN: after:package:compileEvents
email-service:  IN: before:package:finalize
email-service: Serverless: Invoke aws:package:finalize
email-service:  IN: before:aws:package:finalize:addExportNameForOutputs
email-service:  IN: after:aws:package:finalize:addExportNameForOutputs
email-service:  IN: before:aws:package:finalize:mergeCustomProviderResources
email-service:  IN: after:aws:package:finalize:mergeCustomProviderResources
email-service:  IN: before:aws:package:finalize:stripNullPropsFromTemplateResources
email-service:  IN: after:aws:package:finalize:stripNullPropsFromTemplateResources
email-service:  IN: before:aws:package:finalize:saveServiceState
email-service: Serverless: Info: Log ingestion is configured to pull-based ingestion.
email-service: Serverless: Invoke aws:common:moveArtifactsToPackage
email-service:  IN: before:aws:common:moveArtifactsToPackage:move
email-service:  IN: after:aws:common:moveArtifactsToPackage:move
email-service:  IN: after:aws:package:finalize:saveServiceState
email-service:  IN: after:package:finalize
email-service: Serverless: Invoke aws:common:validate
email-service:  IN: before:aws:common:validate:validate
email-service:  IN: after:aws:common:validate:validate
email-service: Serverless: Safeguards Processing...
email-service:  IN: before:deploy:deploy
email-service: Serverless: Invoke aws:deploy:deploy
email-service:  IN: before:aws:deploy:deploy:createStack
email-service: Serverless: Safeguards Results:
email-service:    Summary --------------------------------------------------
email-service:   running - require description
email-service:    passed  - require description
email-service: Serverless: Safeguards Summary: 1 passed, 0 warnings, 0 errors, 0 skipped
email-service: Serverless: Removing /codebuild/output/src317508916/src/services/email-service/.webpack done
email-service: Serverless: [AWS cloudformation 200 0.05s 0 retries] describeStacks({ StackName: 'email-service-dev' })
email-service:  IN: after:aws:deploy:deploy:createStack
email-service:  IN: before:aws:deploy:deploy:checkForChanges
email-service: Serverless: Ensuring that deployment bucket exists
email-service: Serverless: [AWS cloudformation 200 0.052s 0 retries] describeStackResource({
email-service:   StackName: 'email-service-dev',
email-service:   LogicalResourceId: 'ServerlessDeploymentBucket'
email-service: })
email-service: Serverless: [AWS s3 200 0.106s 0 retries] headBucket({
email-service:   Bucket: 'email-service-dev-serverlessdeploymentbucket-19wnsq4799l09'
email-service: })
email-service: Serverless: [AWS s3 200 0.053s 0 retries] listObjectsV2({
email-service:   Bucket: 'email-service-dev-serverlessdeploymentbucket-19wnsq4799l09',
email-service:   Prefix: 'serverless/email-service/dev'
email-service: })
email-service: Serverless: [AWS s3 200 0.067s 0 retries] headObject({
email-service:   Bucket: 'email-service-dev-serverlessdeploymentbucket-19wnsq4799l09',
email-service:   Key: 'serverless/email-service/dev/1671658751801-2022-12-21T21:39:11.801Z/compiled-cloudformation-template.json'
email-service: })
email-service: Serverless: [AWS s3 200 0.075s 0 retries] headObject({
email-service:   Bucket: 'email-service-dev-serverlessdeploymentbucket-19wnsq4799l09',
email-service:   Key: 'serverless/email-service/dev/1671658751801-2022-12-21T21:39:11.801Z/email-service.zip'
email-service: })
email-service: Serverless: [AWS lambda 200 0.045s 0 retries] getFunction({ FunctionName: 'email-service-dev-EmailsSender' })
email-service:  IN: after:aws:deploy:deploy:checkForChanges
email-service:  IN: before:aws:deploy:deploy:uploadArtifacts
email-service: Serverless: Uploading CloudFormation file to S3...
email-service: Serverless: [AWS s3 200 0.065s 0 retries] putObject({
email-service:   Body: <Buffer 7b 22 41 57 53 54 65 6d 70 6c 61 74 65 46 6f 72 6d 61 74 56 65 72 73 69 6f 6e 22 3a 22 32 30 31 30 2d 30 39 2d 30 39 22 2c 22 44 65 73 63 72 69 70 74 ... 10287 more bytes>,
email-service:   Bucket: 'email-service-dev-serverlessdeploymentbucket-19wnsq4799l09',
email-service:   Key: 'serverless/email-service/dev/1671665906844-2022-12-21T23:38:26.844Z/compiled-cloudformation-template.json',
email-service:   ContentType: 'application/json',
email-service:   Metadata: { filesha256: 'tL3zv0TIO7aptkgFn6QVov5sAryRyXIuY4rypVBLAmg=' }
email-service: })
email-service: Serverless: Uploading artifacts...
email-service: Serverless: Uploading service email-service.zip file to S3 (1.11 MB)...
email-service: Serverless: [AWS s3 200 0.166s 0 retries] putObject({
email-service:   Body: <Buffer 50 4b 03 04 0a 00 00 00 08 00 00 00 21 00 d5 a3 fc 17 9b a5 02 00 8d ca 08 00 17 00 00 00 73 72 63 2f 68 61 6e 64 6c 65 72 73 2f 68 61 6e 64 6c 65 72 ... 1108646 more bytes>,
email-service:   Bucket: 'email-service-dev-serverlessdeploymentbucket-19wnsq4799l09',
email-service:   Key: 'serverless/email-service/dev/1671665906844-2022-12-21T23:38:26.844Z/email-service.zip',
email-service:   ContentType: 'application/zip',
email-service:   Metadata: { filesha256: 'DTI37gkV4lfIKVlbtAvUXiXfgGIqZctomT5zmcznmZI=' }
email-service: })
email-service:  IN: after:aws:deploy:deploy:uploadArtifacts
email-service:  IN: before:aws:deploy:deploy:validateTemplate
email-service: Serverless: Validating template...
email-service: Serverless: [AWS cloudformation 200 0.159s 0 retries] validateTemplate({
email-service:   TemplateURL: 'https://s3.amazonaws.com/email-service-dev-serverlessdeploymentbucket-19wnsq4799l09/serverless/email-service/dev/1671665906844-2022-12-21T23:38:26.844Z/compiled-cloudformation-template.json'
email-service: })
email-service:  IN: after:aws:deploy:deploy:validateTemplate
email-service:  IN: before:aws:deploy:deploy:updateStack
email-service: Serverless: Updating Stack...
email-service: Serverless: [AWS cloudformation 200 0.423s 0 retries] updateStack({
email-service:   StackName: 'email-service-dev',
email-service:   Capabilities: [ 'CAPABILITY_IAM', 'CAPABILITY_NAMED_IAM', [length]: 2 ],
email-service:   Parameters: [ [length]: 0 ],
email-service:   TemplateURL: 'https://s3.amazonaws.com/email-service-dev-serverlessdeploymentbucket-19wnsq4799l09/serverless/email-service/dev/1671665906844-2022-12-21T23:38:26.844Z/compiled-cloudformation-template.json',
email-service:   Tags: [
email-service:     { Key: 'STAGE', Value: 'dev' },
email-service:     { Key: 'MicroService', Value: 'email-service-dev' },
email-service:     [length]: 2
email-service:   ]
email-service: })
email-service: Serverless: Checking Stack update progress...
email-service: Serverless: [AWS cloudformation 200 0.13s 0 retries] describeStackEvents({
email-service:   StackName: 'arn:aws:cloudformation:us-west-2:accnumber:stack/email-service-dev/37b12610-ac5b-11eb-baa0-027e849bc751'
email-service: })
email-service: CloudFormation - UPDATE_IN_PROGRESS - AWS::CloudFormation::Stack - email-service-dev
email-service: Serverless: [AWS cloudformation 200 0.074s 0 retries] describeStackEvents({
email-service:   StackName: 'arn:aws:cloudformation:us-west-2:accnumber:stack/email-service-dev/37b12610-ac5b-11eb-baa0-027e849bc751'
email-service: })
email-service: CloudFormation - UPDATE_IN_PROGRESS - AWS::Lambda::Function - EmailsSenderLambdaFunction
email-service: Serverless: [AWS cloudformation 200 0.07s 0 retries] describeStackEvents({
email-service:   StackName: 'arn:aws:cloudformation:us-west-2:accnumber:stack/email-service-dev/37b12610-ac5b-11eb-baa0-027e849bc751'
email-service: })
email-service: Serverless: [AWS cloudformation 200 0.15s 0 retries] describeStackEvents({
email-service:   StackName: 'arn:aws:cloudformation:us-west-2:accnumber:stack/email-service-dev/37b12610-ac5b-11eb-baa0-027e849bc751'
email-service: })
email-service: CloudFormation - UPDATE_COMPLETE - AWS::Lambda::Function - EmailsSenderLambdaFunction
email-service: Serverless: [AWS cloudformation 200 0.534s 0 retries] describeStackEvents({
email-service:   StackName: 'arn:aws:cloudformation:us-west-2:accnumber:stack/email-service-dev/37b12610-ac5b-11eb-baa0-027e849bc751'
email-service: })
email-service: CloudFormation - UPDATE_COMPLETE_CLEANUP_IN_PROGRESS - AWS::CloudFormation::Stack - email-service-dev
email-service: CloudFormation - UPDATE_COMPLETE - AWS::CloudFormation::Stack - email-service-dev
email-service: Serverless: Stack update finished...
email-service:  IN: after:aws:deploy:deploy:updateStack
email-service: Serverless: Invoke aws:info
email-service:  IN: before:aws:info:validate
email-service:  IN: after:aws:info:validate
email-service:  IN: before:aws:info:gatherData
email-service: Serverless: [AWS cloudformation 200 0.109s 0 retries] describeStacks({ StackName: 'email-service-dev' })
email-service: Serverless: [AWS cloudformation 200 0.097s 0 retries] listStackResources({ StackName: 'email-service-dev', NextToken: undefined })
email-service:  IN: after:aws:info:gatherData
email-service:  IN: before:aws:info:displayServiceInfo
email-service: Service Information
email-service: service: email-service
email-service: stage: dev
email-service: region: us-west-2
email-service: stack: email-service-dev
email-service: resources: 19
email-service:  IN: after:aws:info:displayServiceInfo
email-service:  IN: before:aws:info:displayApiKeys
email-service: api keys:
email-service:   None
email-service:  IN: after:aws:info:displayApiKeys
email-service:  IN: before:aws:info:displayEndpoints
email-service: endpoints:
email-service:  IN: after:aws:info:displayEndpoints
email-service:  IN: before:aws:info:displayFunctions
email-service: functions:
email-service:   EmailsSender: email-service-dev-EmailsSender
email-service:  IN: after:aws:info:displayFunctions
email-service:  IN: before:aws:info:displayLayers
email-service: layers:
email-service:   None
email-service:  IN: after:aws:info:displayLayers
email-service:  IN: before:aws:info:displayStackOutputs
email-service: Stack Outputs
email-service: EnterpriseLogAccessIamRole: arn:aws:iam::accnumber:role/email-service-dev-EnterpriseLogAccessIamRole-1A8XOM4DTCOAI
email-service: ServerlessDeploymentBucketName: email-service-dev-serverlessdeploymentbucket-19wnsq4799l09
email-service:  IN: after:aws:info:displayStackOutputs
email-service: Serverless: [AWS cloudformation 200 0.112s 0 retries] updateTerminationProtection({ EnableTerminationProtection: true, StackName: 'email-service-dev' })
email-service: Serverless: Enabled termination protection
email-service:  IN: after:deploy:deploy
email-service:  IN: before:deploy:finalize
email-service: Serverless: Invoke aws:deploy:finalize
email-service:  IN: before:aws:deploy:finalize:cleanup
email-service: Serverless: [AWS s3 200 0.07s 0 retries] listObjectsV2({
email-service:   Bucket: 'email-service-dev-serverlessdeploymentbucket-19wnsq4799l09',
email-service:   Prefix: 'serverless/email-service/dev'
email-service: })
email-service: Serverless: Removing old service artifacts from S3...
email-service: Serverless: [AWS s3 200 0.105s 0 retries] deleteObjects({
email-service:   Bucket: 'email-service-dev-serverlessdeploymentbucket-19wnsq4799l09',
email-service:   Delete: {
email-service:     Objects: [
email-service:       {
email-service:         Key: 'serverless/email-service/dev/1671611211736-2022-12-21T08:26:51.736Z/compiled-cloudformation-template.json'
email-service:       },
email-service:       {
email-service:         Key: 'serverless/email-service/dev/1671611211736-2022-12-21T08:26:51.736Z/email-service.zip'
email-service:       },
email-service:       [length]: 2
email-service:     ]
email-service:   }
email-service: })
email-service:  IN: after:aws:deploy:finalize:cleanup
email-service: Serverless: Publishing service to the Serverless Dashboard...
email-service: Serverless: [AWS cloudformation 200 0.093s 0 retries] describeStacks({ StackName: 'email-service-dev' })
email-service: Serverless: Successfully published your service to the Serverless Dashboard: https://app.serverless.com/sikau/apps/viewlinc-cloud/email-service/dev/us-west-2
email-service:  IN: after:deploy:finalize
email-service: Serverless: Deprecation warnings:
email-service: Variables resolver reports following resolution errors:
email-service:   - Cannot resolve variable at "provider.environment.VIEWLINC_BASE_URL": Cannot resolve "baseUrlMapping" out of "constants.js": Approached a JS function resolver, confirm it's updated to work with a new parser by setting "variablesResolutionMode: 20210326" in service config. Falling back to old resolver,
email-service:   - Cannot resolve variable at "custom.ses.domain": Cannot resolve "SESSenderDomain" out of "constants.js": Approached a JS function resolver, confirm it's updated to work with a new parser by setting "variablesResolutionMode: 20210326" in service config. Falling back to old resolver,
email-service:   - Cannot resolve variable at "custom.sharedService.stage": Cannot parse "shared-service-stage.js": Approached a JS function resolver, confirm it's updated to work with a new parser by setting "variablesResolutionMode: 20210326" in service config. Falling back to old resolver,
email-service:   - Cannot resolve variable at "resources.Resources.s3EmailPublicResourcesBucket.DeletionPolicy": Cannot resolve "deletionPolicy" out of "resources-deletions-and-updates.js": Approached a JS function resolver, confirm it's updated to work with a new parser by setting "variablesResolutionMode: 20210326" in service config. Falling back to old resolver,
email-service:   - Cannot resolve variable at "resources.Resources.s3EmailPublicResourcesBucket.UpdateReplacePolicy": Cannot resolve "updateReplacePolicy" out of "resources-deletions-and-updates.js



Going by " this configuration cannot change after plugin initialization" and looking at the sequence of events at the top, I expected it to read the updated value from SSM but it still is reading the old value. Thoughts?

@s1mrankaur s1mrankaur removed their assignment Dec 21, 2022
@medikoo
Copy link
Contributor

medikoo commented Dec 22, 2022

@s1mrankaur in my understanding this feature doesn't have public facing API. Best if you contact Dashboard support about that

@s1mrankaur
Copy link
Author

@medikoo Thanks. I did but they wouldn't respond :( I tried to go through the dashboard-plugin code though and it seems to create artifacts in before:package:createDeploymentArtifacts

case 'before:package:createDeploymentArtifacts': {
and posts them after deployment to dashboard.

If the artifacts are being created after the hook that I am updating SSM in, what might be the reason for it to leave out the updated values?

@garethmcc
Copy link

@s1mrankaur the issue at hand here is that SSM is read at the start when variables are initialized and not updated from source later. If you pass a value to SSM why not just pass the same value you sent to SSM to the outputs as well to save the new value. In fact, why send to SSM at all as you can both save and read from outputs like SSM but its cheaper and easier.

@s1mrankaur
Copy link
Author

s1mrankaur commented Dec 22, 2022

@garethmcc Thanks for your response. Ah, I didn't know I can read the value from outputs, I am happy to increment it just there and skip the SSM bit altogether. This may actually work :) I'll keep you posted

@s1mrankaur
Copy link
Author

s1mrankaur commented Dec 24, 2022

@garethmcc I tried to go with the suggested approach but it doesn't seem to work yet.

Added the following function:


module.exports.getIncrementedVersion = (serverless) => {
    let currentDate = new Date();
    const year = currentDate.getUTCFullYear();
    const month = currentDate.getUTCMonth();
    const date = currentDate.getUTCDate();
    var newVersion = "".concat(year, ".", month, ".", date, ".", "0");
    console.log(`Default new version is '${newVersion}'`);
    try{
    const {  "VERSION_NUMBER": version  } = serverless.service.provider.environment;
    console.log(`Existing version from SLS dashboard outputs  ${version} `);
    console.log(`Process env VERSION FROM SLS DASHBOARD ${process.env.VERSION_NUMBER}`)
    console.log(`SLS service provider ${ JSON.stringify(serverless.service.provider) }`)
    console.log(`SLS service provider environment ${  JSON.stringify(serverless.service.provider.environment) }`)

      if (version && (typeof version === 'string' || version instanceof String) && /^\d{4}.\d{2}.\d{2}.\d{1,2}$/.test(version)) {
          let currentVersionArr = version.split('.');
          if (year == currentVersionArr[0] && month == currentVersionArr[1] && date == currentVersionArr[2]) {
          let dayIncrement = parseInt(currentVersionArr[3]) + 1;
          newVersion = "".concat(year, ".", month, ".", date, ".", dayIncrement);
          console.log(`Incremented new version is '${newVersion}'`);
        }else{
          console.log(`version '${version}' from SLS dashboard outputs doesn't contain the current UTC date, revision increment not needed`)
        }
      }else{
        console.log(`Invalid version '${version}' from SLS dashboard outputs, defaulting to revision 0 of the current UTC date`)
      }
    }catch(err){
      console.log(`Error in getIncrementedVersion '${err}'`)
    }

    console.log(`Final version being updated in the SLS dashboard outputs '${newVersion}'`)
    return newVersion
  };


In the serverless.yml file, I added

outputs:
  app-version: ${file(../../shared/const/app-version.js):getIncrementedVersion}

provider:
 environment:
     # Existing version number
    VERSION_NUMBER: ${output:${self:service}.app-version}

My console log statements give

"VERSION_NUMBER": "${output:${self:service}.app-version}"
Instead of getting the existing version number from the output, it gets the expression string instead i.e "${output:${self:service}.app-version}"

Am I not reading the output correctly? I tried passing "${output:${self:service}.app-version}" both to an environment variable and tried using

const { "VERSION_NUMBER": version } = serverless.service.provider.environment;
directly in the function as well. The result is the expression string instead of the evaluated expression. Thoughts?

The requirement is basically:

  1. Read the existing version number from serverless dashboard outputs
  2. increment the version number
  3. update the incremented version number in serverless dashboard outputs

I'd appreciate some clarity here, Thanks

@medikoo
Copy link
Contributor

medikoo commented Dec 27, 2022

@s1mrankaur I'm a bit confused here. Can you in one sentence, clarify what you're trying to achieve?
Are you trying to update the SSM secret with a value that's presented in Dashboard Outputs. Or are you trying to update the value of one of the Dashboard Outputs?

The relation of SSM and Dashboard Outputs is not clear to me here

@s1mrankaur
Copy link
Author

@medikoo Thanks for your response. Here it goes:

My end goal is to show the version number of each serverless microservice on the "Serverless Dashboard". I am using "Serverless Dashboard Outputs" for the same. We have been incrementing and maintaining our version numbers on each deployment in SSM thus the first attempt was to fetch the updated deployment number from SSM and send it to Serverless Dashboard Outputs. I gave that a go and realized it is not feasible no matter how early on I update the version in SSM during the deployment process, the dashboard always picked the last version number and not the most recent one.

In response to @garethmcc's suggestion, I then tried to read the version directly from Serverless Outputs Dashboard and skip SSM altogether. The issue with the approach is that instead of getting the version number in my app-version.js file, I get the expression i.e "${output:${self:service}.app-version}" thus I still am not able to get the version in my js file to read it, increment it and send it back to the SLS dashboard outputs on every new deployment.

Please let me know if I can clarify this further.

@medikoo
Copy link
Contributor

medikoo commented Dec 28, 2022

@s1mrankaur so to summarize, I believe you're doing following:

  1. Setup outputs section in serverless.yml with values to be resolved from SSM (relying on ssm variables)
  2. After deployment you automatically create a new deployment version and set SSM secret with it
  3. You expect that dashboard output which refers to SSM value as configured in serverless.yml will show the updated value.

Is that correct?

@s1mrankaur
Copy link
Author

s1mrankaur commented Dec 30, 2022

@medikoo That's absolutely correct.

Continuing the suggestion from @garethmcc, Based on what I've read, something like the following should be possible i.e resolving the variables in app-version.js based on the unevaluated expressions that I see at the stage when app-version.js is triggered.

  let version = await serverless.resolveVariable('output:${self:service}.app-version, self:provider.environment.VERSION_SSM');

Is resolveVariable supposed to be the fix here? I haven't tried it yet though.

@medikoo
Copy link
Contributor

medikoo commented Jan 5, 2023

@s1mrankaur, thanks for the clarification.

Outputs are sent to the Dashboard with after:aws:deploy:finalize:cleanup hook.

If you want to adjust Outputs after deployment but before they're sent to the Serverless Dashboard, I think it's fine if in your plugin you attach to the very same hook and over there do the job of (1) storing new version in SSM (2) updating serverless.service.output with the updated values.

Having that done it's the updated values that should be sent to the Serverless Dashboard

@s1mrankaur
Copy link
Author

Hi @medikoo Thanks for your response. I thought so and did the ssm update in after:aws:deploy but it hasn't been using the updated value so far.

Can you elaborate on how I could possibly update serverless.service.output in the same hook?

@medikoo
Copy link
Contributor

medikoo commented Jan 9, 2023

Can you elaborate on how I could possibly update serverless.service.output in the same hook?

Simply alter serverless.service.output content, and again hook you should attach to is after:aws:deploy:finalize:cleanup (it may not work with after:aws:deploy)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

3 participants