diff --git a/CHANGELOG.md b/CHANGELOG.md index cb10188963..136570dbf7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,26 +2,25 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. -## [3.1.0](https://github.com/nguyen102/service-workbench-on-aws/compare/v3.0.0...v3.1.0) (2021-05-10) - +## [3.1.0](https://github.com/awslabs/service-workbench-on-aws/compare/v3.0.0...v3.1.0) (2021-05-10) ### Features -* Allow uploading a folder to My Studies ([#475](https://github.com/awslabs/service-workbench-on-aws/issues/475)) ([cb17d4b](https://github.com/awslabs/service-workbench-on-aws/commit/cb17d4be8c0fdaaee7384229629e4bc7ec7d95a1)) -* Run coverage for merge commit ([#458](https://github.com/awslabs/service-workbench-on-aws/issues/458)) ([03afe0e](https://github.com/awslabs/service-workbench-on-aws/commit/03afe0e1387b30dfc50ffab48b9982103048c585)) -* Test coverage ([#456](https://github.com/awslabs/service-workbench-on-aws/issues/456)) ([252b504](https://github.com/awslabs/service-workbench-on-aws/commit/252b5049400c1d3fcb2ceb4720f64210bf0d5359)) - +- Allow uploading a folder to My Studies ([#475](https://github.com/awslabs/service-workbench-on-aws/issues/475)) ([cb17d4b](https://github.com/awslabs/service-workbench-on-aws/commit/cb17d4be8c0fdaaee7384229629e4bc7ec7d95a1)) +- Run coverage for merge commit ([#458](https://github.com/awslabs/service-workbench-on-aws/issues/458)) ([03afe0e](https://github.com/awslabs/service-workbench-on-aws/commit/03afe0e1387b30dfc50ffab48b9982103048c585)) +- Test coverage ([#456](https://github.com/awslabs/service-workbench-on-aws/issues/456)) ([252b504](https://github.com/awslabs/service-workbench-on-aws/commit/252b5049400c1d3fcb2ceb4720f64210bf0d5359)) ### Bug Fixes -* Fix BYOB app role to only modify FS roles ([#454](https://github.com/awslabs/service-workbench-on-aws/issues/454)) ([35f6cce](https://github.com/awslabs/service-workbench-on-aws/commit/35f6cce3ccc301921ead742240c15c1a7e332f0c)) -* free-form strings for workspace configs ([#479](https://github.com/awslabs/service-workbench-on-aws/issues/479)) ([fca73f4](https://github.com/awslabs/service-workbench-on-aws/commit/fca73f4dbaf509f06ce55b6b0c87c66e31ed8a88)) -* properly handle SC products with no active versions ([#468](https://github.com/awslabs/service-workbench-on-aws/issues/468)) ([3c561f4](https://github.com/awslabs/service-workbench-on-aws/commit/3c561f4850faffe3ccc6fd0ffcc5b7065f53f3c6)) -* Update workspace name reg exp and workspace config tags reg exp ([#452](https://github.com/awslabs/service-workbench-on-aws/issues/452)) ([f9b7d62](https://github.com/awslabs/service-workbench-on-aws/commit/f9b7d628a08b337eaa0a9c8b71bb6226ff0f7b34)) +- Fix BYOB app role to only modify FS roles ([#454](https://github.com/awslabs/service-workbench-on-aws/issues/454)) ([35f6cce](https://github.com/awslabs/service-workbench-on-aws/commit/35f6cce3ccc301921ead742240c15c1a7e332f0c)) +- free-form strings for workspace configs ([#479](https://github.com/awslabs/service-workbench-on-aws/issues/479)) ([fca73f4](https://github.com/awslabs/service-workbench-on-aws/commit/fca73f4dbaf509f06ce55b6b0c87c66e31ed8a88)) +- properly handle SC products with no active versions ([#468](https://github.com/awslabs/service-workbench-on-aws/issues/468)) ([3c561f4](https://github.com/awslabs/service-workbench-on-aws/commit/3c561f4850faffe3ccc6fd0ffcc5b7065f53f3c6)) +- Update workspace name reg exp and workspace config tags reg exp ([#452](https://github.com/awslabs/service-workbench-on-aws/issues/452)) ([f9b7d62](https://github.com/awslabs/service-workbench-on-aws/commit/f9b7d628a08b337eaa0a9c8b71bb6226ff0f7b34)) ## [3.0.0] - 2021-04-19 ### Added + - refactor: restricting AppDeployer permissions - refactor: Remove permission boundary condition on launch constraint role - refactor: restrict sc roles @@ -31,22 +30,24 @@ All notable changes to this project will be documented in this file. See [standa **Customer Impact:** Below outlines the actions required for you to successfully adopt this security enhancement. The first two items are applicable to all customers. If you have created custom workspace types, then all three items below are applicable. 1. After running the update, onboard all hosting accounts once again to benefit from the enhanced security, and test the application. -**Note:** The attached pdf contains steps for onboarding hosting accounts, contact your Service Workbench Administrator if you have not performed these steps before. + **Note:** The attached pdf contains steps for onboarding hosting accounts, contact your Service Workbench Administrator if you have not performed these steps before. 2. After running the update, import and use the newly available Service Catalog product versions for workspace types (latest version numbers) to benefit from the enhanced security. 3. **ONLY Customers that have created custom workspace types:** It is possible that the permissions boundaries would prevent actions that were formerly allowed. You should plan to validate your custom workspace types after the update. Issues should be addressed by modifying the custom workspaces to work within the permissions granted, or modify the permissions boundary for your installation (this would require a change to Service Workbench code (specifically the IAM policies that are attached as the permissions boundary) for your install). -Note: Any existing custom or non-custom workspaces types (for example, EC2 Linux/Windows, EMR, SageMaker, R Studio) are not impacted by this upgrade. + Note: Any existing custom or non-custom workspaces types (for example, EC2 Linux/Windows, EMR, SageMaker, R Studio) are not impacted by this upgrade. ## [2.2.0] - 2021-04-12 ### Added + - feat: Display SWB Version in UI's Top Bar - fix: Fix cost dashboard bugs ## [2.1.5] - 2021-04-08 ### Added + - fix: Ensure sdk retry logic is enabled in prod - docs: Readme updated - fix: assume role on added member account @@ -54,20 +55,23 @@ Note: Any existing custom or non-custom workspaces types (for example, EC2 Linux ## [2.1.4] - 2021-04-06 ### Added + - fix: managing pnpm version for nodejs compatibility ## [2.1.3] - 2021-04-06 ### Added + - fix: adding required AppDeployer permissions - chore: package dependency updates - fix: added X-ray support and fix CWL IAM permissions - + If you have been using CI/CD pipeline, please redeploy the pipeline stack to incorporate this fix by following the steps listed on the `main/cicd/README.md` file. ## [2.1.2] - 2021-04-01 ### Added + - fix: managing AppDeployer role permission boundary - fix: CW log resources corrected in backend CFN template - refactor: restrict ApiHandler role permissions @@ -81,6 +85,7 @@ If you have been using CI/CD pipeline, please redeploy the pipeline stack to inc ## [2.1.1] - 2021-03-19 ### Added + - chore: Enable SSE-S3 when registering buckets in BYOB - refactor: restrict data source reachability Lambda role - fix: Add 'reachable' and 'error' status to reachability check schema @@ -89,6 +94,7 @@ If you have been using CI/CD pipeline, please redeploy the pipeline stack to inc ## [2.1.0] - 2021-03-12 ### Added + - fix: Upgraded react-dev-utils yarn dependency version - feat: Added Bring Your Own Bucket(BYOB) functionality - feat: Added integration testing for all APIs @@ -97,7 +103,8 @@ If you have been using CI/CD pipeline, please redeploy the pipeline stack to inc ## [2.0.3] - 2021-03-12 -### Added +### Added + - chore(deps): bump websocket-extensions from 0.1.3 to 0.1.4 - test: fix flaky integ tests - fix: emr workspace image. Lock jupyterlab to version 2.2.6 @@ -106,7 +113,8 @@ If you have been using CI/CD pipeline, please redeploy the pipeline stack to inc ## [2.0.2] - 2021-03-03 -### Added +### Added + - fix: SageMaker environment status update - fix: Validate Open Data ARNs - test: Integration test components and framework @@ -114,7 +122,8 @@ If you have been using CI/CD pipeline, please redeploy the pipeline stack to inc ## [2.0.1] - 2021-02-08 -### Added +### Added + - fix: Added usernameInIdp property to update user schema - fix: Made external researcher used UserOnboarding template less permissive - fix: labeler yml syntax @@ -124,10 +133,12 @@ We recommend to apply this patch as soon as possible ## [2.0.0] - 2021-01-29 -### Added +### Added + - feat: Adding ability to manage CIDR blocks of workspace's configured security group Note: + 1. This feature has added permissions to the onboard-account template and requires re-onboarding existing member accounts. Please contact your system administrator for the same. 2. For RStudio instances, please allow 2-5 minutes for CIDR changes to take effect. 3. For SageMaker instances, currently application admins and workspace owners have ability to access the SageMaker platform directly, irrespective of CIDR inclusion. @@ -136,21 +147,24 @@ Note: ## [1.4.7] - 2021-01-28 -### Added +### Added + - fix: Fix a bug on the update user API We recommend to apply this patch as soon as possible ## [1.4.6] - 2021-01-15 -### Added +### Added + - fix: Add tables back to cloudformation and don't authorize API Keys We recommend to apply this patch as soon as possible ## [1.4.5] - 2021-01-14 -### Added +### Added + - fix: remove API Keys functionality We recommend to apply this patch as soon as possible @@ -158,6 +172,7 @@ We recommend to apply this patch as soon as possible ## [1.4.4] - 2021-01-13 ### Added + - fix: open data scraper bugfix - docs: improvements to deployment documentation - fix: Upload Files button disappears for R/W users @@ -171,18 +186,21 @@ We recommend to apply this patch as soon as possible ## [1.4.3] - 2020-11-24 ### Added + - feat: Support Read/Write Study mounts for EC2 Windows ## [1.4.2] - 2020-11-23 -### Added +### Added + - fix: Fix a bug on the update study API We recommend to apply this patch as soon as possible ## [1.4.1] - 2020-11-18 -### Added +### Added + - fix: Handling policy names for windows envs - fix: Fix a bug on the create study API @@ -190,13 +208,14 @@ We recommend to apply this patch as soon as possible ## [1.4.0] - 2020-11-13 -### Added +### Added + - feat: Study Read/Write and Permission propagation (Goofys) - feat: Read/Only study mounts on AWS Service Catalog based EC2 Windows workspaces ## [1.3.2] - 2020-10-23 -### Added +### Added - fix: Adding dependencies for Dynamo table creation to prevent install crash - fix: Query string parameters were getting duplicated in the url diff --git a/addons/addon-base-raas/packages/base-raas-services/lib/environment/service-catalog/__tests__/environment-sc-service.test.js b/addons/addon-base-raas/packages/base-raas-services/lib/environment/service-catalog/__tests__/environment-sc-service.test.js index b2fb9e35f0..b0347a2b58 100644 --- a/addons/addon-base-raas/packages/base-raas-services/lib/environment/service-catalog/__tests__/environment-sc-service.test.js +++ b/addons/addon-base-raas/packages/base-raas-services/lib/environment/service-catalog/__tests__/environment-sc-service.test.js @@ -725,6 +725,53 @@ describe('EnvironmentSCService', () => { AWSMock.restore(); }); + it('Should sync EC2 status to FAILED when stale status is COMPLETED and we cannot retrieve current status', async () => { + // BUILD + indexesService.list = jest + .fn() + .mockResolvedValue([{ id: 'some-index-id', awsAccountId: 'some-aws-account-uuid' }]); + awsAccountsService.list = jest.fn().mockResolvedValue([ + { + roleArn: 'some-role-arn', + externalId: 'some-external-id', + id: 'some-aws-account-uuid', + accountId: 'some-aws-account-id', + }, + ]); + dbService.table.scan.mockResolvedValueOnce([ + { + id: 'some-environment-id', + indexId: 'some-index-id', + status: 'COMPLETED', + outputs: [{ OutputKey: 'Ec2WorkspaceInstanceId', OutputValue: 'ec2-instance-id' }], + }, + ]); + service.update = jest.fn(); + AWSMock.setSDKInstance(aws.sdk); + AWSMock.mock('STS', 'assumeRole', { Credentials: stsResponse }); + AWSMock.mock('EC2', 'describeInstances', { + Reservations: [ + { + Instances: [], + }, + ], + }); + + // OPERATE + const result = await service.pollAndSyncWsStatus(requestContext); + expect(result).toMatchObject([ + { + accountId: 'some-aws-account-id', + ec2Updated: { + 'ec2-instance-id': { currentStatus: 'FAILED', ddbID: 'some-environment-id', staleStatus: 'COMPLETED' }, + }, + sagemakerUpdated: {}, + }, + ]); + // CHECK + AWSMock.restore(); + }); + it('Should not sync EC2 status when stale status is STARTING and inWorkflow is true', async () => { // BUILD indexesService.list = jest @@ -866,6 +913,54 @@ describe('EnvironmentSCService', () => { AWSMock.restore(); }); + it('Should sync SageMaker status to FAILED when stale status is COMPLETED and we cannot find it', async () => { + // BUILD + indexesService.list = jest + .fn() + .mockResolvedValue([{ id: 'some-index-id', awsAccountId: 'some-aws-account-uuid' }]); + awsAccountsService.list = jest.fn().mockResolvedValue([ + { + roleArn: 'some-role-arn', + externalId: 'some-external-id', + id: 'some-aws-account-uuid', + accountId: 'some-aws-account-id', + }, + ]); + dbService.table.scan.mockResolvedValueOnce([ + { + id: 'some-environment-id', + indexId: 'some-index-id', + status: 'COMPLETED', + outputs: [{ OutputKey: 'NotebookInstanceName', OutputValue: 'notebook-instance-name' }], + }, + ]); + service.update = jest.fn(); + + AWSMock.setSDKInstance(aws.sdk); + AWSMock.mock('STS', 'assumeRole', { Credentials: stsResponse }); + AWSMock.mock('SageMaker', 'listNotebookInstances', { + NotebookInstances: [], + }); + + // OPERATE + const result = await service.pollAndSyncWsStatus(requestContext); + // CHECK + expect(result).toMatchObject([ + { + accountId: 'some-aws-account-id', + ec2Updated: {}, + sagemakerUpdated: { + 'notebook-instance-name': { + currentStatus: 'FAILED', + ddbID: 'some-environment-id', + staleStatus: 'COMPLETED', + }, + }, + }, + ]); + AWSMock.restore(); + }); + it('Should call listNotebookInstances with NextToken if NextToken is returned', async () => { // BUILD indexesService.list = jest diff --git a/addons/addon-base-raas/packages/base-raas-services/lib/environment/service-catalog/environment-sc-service.js b/addons/addon-base-raas/packages/base-raas-services/lib/environment/service-catalog/environment-sc-service.js index 8dbe0f3e8d..21ea7b1388 100644 --- a/addons/addon-base-raas/packages/base-raas-services/lib/environment/service-catalog/environment-sc-service.js +++ b/addons/addon-base-raas/packages/base-raas-services/lib/environment/service-catalog/environment-sc-service.js @@ -109,7 +109,7 @@ class EnvironmentScService extends Service { envs, // Status polling is created to account for instance auto stop functionality // COMPLETED is included since the corresponding instance could be stopped - // Other 'unstalbe' statuses are included as they could be result of a previous poll and sync + // Other 'unstable' statuses are included as they could be result of a previous poll and sync env => _.includes(['COMPLETED', 'STARTING', 'STOPPING', 'TERMINATING'], env.status) && env.inWorkflow !== 'true', ); const indexes = await indexesService.list(requestContext, { fields: ['id', 'awsAccountId'] }); @@ -138,6 +138,41 @@ class EnvironmentScService extends Service { return { accountId, ec2Updated, sagemakerUpdated }; } + async updateStatus(requestContext, existingEnvRecord, expectedDDBStatus) { + if (expectedDDBStatus && existingEnvRecord.status !== expectedDDBStatus) { + return this.updateDDBStatus(requestContext, existingEnvRecord, expectedDDBStatus); + } + if (!expectedDDBStatus) { + // If workspace is not found assume it was FAILED + this.log.warn(`Error getting record status for: ${existingEnvRecord.id}; Defaulting the status to 'FAILED'`); + return this.updateDDBStatus(requestContext, existingEnvRecord, 'FAILED'); + } + return undefined; + } + + async updateDDBStatus(requestContext, existingEnvRecord, expectedDDBStatus) { + const newEnvironment = { + id: existingEnvRecord.id, + rev: existingEnvRecord.rev || 0, + status: expectedDDBStatus.toUpperCase(), + }; + try { + // Might run into situation where the environment was just updated and rev number does not match + // Log the error and skip the update for now + // The next invocation of poll and sync will do the sync if it's still needed + await this.update(requestContext, newEnvironment); + return { + ddbID: existingEnvRecord.id, + currentStatus: expectedDDBStatus, + staleStatus: existingEnvRecord.status, + }; + } catch (e) { + this.log.error(`Error updating record ${existingEnvRecord.id}`); + this.log.error(e); + } + return undefined; + } + async pollAndSyncEc2Status(roleArn, externalId, ec2Instances, requestContext) { const EC2StatusMap = { 'running': 'COMPLETED', @@ -151,26 +186,9 @@ class EnvironmentScService extends Service { const ec2Updated = {}; _.forEach(ec2Instances, async (existingEnvRecord, ec2InstanceId) => { const expectedDDBStatus = EC2StatusMap[ec2RealtimeStatus[ec2InstanceId]]; - if (expectedDDBStatus && existingEnvRecord.status !== expectedDDBStatus) { - const newEnvironment = { - id: existingEnvRecord.id, - rev: existingEnvRecord.rev || 0, - status: expectedDDBStatus.toUpperCase(), - }; - try { - // Might run into situation where the environment was just updated and rev number does not match - // Log the error and skip the update for now - // The next invocation of poll and sync will do the sync if it's still needed - await this.update(requestContext, newEnvironment); - ec2Updated[ec2InstanceId] = { - ddbID: existingEnvRecord.id, - currentStatus: expectedDDBStatus, - staleStatus: existingEnvRecord.status, - }; - } catch (e) { - this.log.error(`Error updating record ${existingEnvRecord.id}`); - this.log.error(e); - } + const updateStatusResult = await this.updateStatus(requestContext, existingEnvRecord, expectedDDBStatus); + if (updateStatusResult) { + ec2Updated[ec2InstanceId] = updateStatusResult; } }); return ec2Updated; @@ -210,26 +228,9 @@ class EnvironmentScService extends Service { const sagemakerUpdated = {}; _.forEach(sagemakerInstances, async (existingEnvRecord, key) => { const expectedDDBStatus = SageMakerStatusMap[sagemakerRealtimeStatus[key]]; - if (expectedDDBStatus && existingEnvRecord.status !== expectedDDBStatus) { - const newEnvironment = { - id: existingEnvRecord.id, - rev: existingEnvRecord.rev || 0, - status: SageMakerStatusMap[sagemakerRealtimeStatus[key]].toUpperCase(), - }; - try { - // Might run into situation where the environment was just updated and rev number does not match - // Log the error and skip the update for now - // The next invocation of poll and sync will do the sync if it's still needed - await this.update(requestContext, newEnvironment); - sagemakerUpdated[key] = { - ddbID: existingEnvRecord.id, - currentStatus: expectedDDBStatus, - staleStatus: existingEnvRecord.status, - }; - } catch (e) { - this.log.error(`Error updating record ${existingEnvRecord.id}`); - this.log.error(e); - } + const updateStatusResult = await this.updateStatus(requestContext, existingEnvRecord, expectedDDBStatus); + if (updateStatusResult) { + sagemakerUpdated[key] = updateStatusResult; } }); return sagemakerUpdated;