From b2f02ebfe3b9eef79b8e80ea12e2184c82a96cf5 Mon Sep 17 00:00:00 2001 From: Ethiraj Krishnamanaidu <EKrishnamanaidu@slb.com> Date: Sat, 18 Apr 2020 15:34:18 -0500 Subject: [PATCH] ado-code merge and removed SLB reference --- .gitignore | 6 + .gitlab-ci.yml | 4 +- .../opengroup/osdu/legal/api/LegalTagApi.java | 4 + provider/legal-aws/.env.template | 63 +++ .../Automated/config-bucket.yml | 6 +- .../CloudFormation/Automated/ecs-cluster.yml | 212 ++++++- .../CloudFormation/Automated/ecs-network.yml | 98 ++-- .../CloudFormation/Automated/sns-topic.yml | 22 +- .../JarDeploy/CodePipeline-JarDeploy.yml | 252 +++++++++ .../Manual/01-CreateCodePipeline.yml | 363 +----------- .../CloudFormation/Master/os-legal-master.yml | 85 ++- .../Params/dev.template_configuration.json | 10 +- .../Params/prod.template_configuration.json | 10 +- .../Params/uat.template_configuration.json | 10 +- provider/legal-aws/Dockerfile | 11 +- provider/legal-aws/buildspec-jar-deploy.yml | 64 +++ provider/legal-aws/buildspec-post-deploy.yml | 20 +- provider/legal-aws/buildspec-pre-deploy.yml | 7 +- provider/legal-aws/pom.xml | 70 ++- .../dataaccess/LegalTagRepositoryImpl.java | 2 +- .../src/main/resources/application.properties | 8 +- .../aws/api/LegalTagRepositoryImplTest.java | 2 +- provider/legal-ibm/README.md | 43 ++ provider/legal-ibm/pom.xml | 107 ++++ .../osdu/legal/ibm/LegalApplication.java | 29 + .../countries/StorageReaderFactoryImpl.java | 110 ++++ .../ibm/countries/StorageReaderImpl.java | 111 ++++ .../osdu/legal/ibm/di/DevNullPublisher.java | 46 ++ .../osdu/legal/ibm/di/DpsLogFactory.java | 41 ++ .../legal/ibm/jobs/LegalTagPublisherImpl.java | 65 +++ .../legal/ibm/security/SecurityConfig.java | 24 + .../legal/ibm/security/WhoamiController.java | 25 + .../ibm/tags/CloudantBackedLegalTag.java | 100 ++++ .../ibm/tags/CloudantLegalTagRepository.java | 350 ++++++++++++ .../src/main/resources/application.yml | 35 ++ .../src/main/resources/logback.groovy | 43 ++ .../ibm/api/EntitlementsFactoryByoc.java | 31 ++ .../ibm/api/EntitlementsServiceByoc.java | 93 ++++ .../osdu/legal/ibm/api/LegalTagApiTest.java | 85 +++ .../osdu/legal/ibm/tags/LegalTagTests.java | 519 ++++++++++++++++++ .../src/test/resources/logback.groovy | 40 ++ testing/legal-test-aws/pom.xml | 10 +- .../osdu/legal/util/AwsLegalTagUtils.java | 2 +- .../osdu/legal/util/LegalTagUtils.java | 2 +- .../opengroup/osdu/legal/util/TestUtils.java | 3 - testing/legal-test-ibm/pom.xml | 93 ++++ testing/legal-test-ibm/run_service.sh | 53 ++ testing/legal-test-ibm/run_tests.sh | 20 + testing/legal-test-ibm/setup_acceptance.sh | 52 ++ .../TestCreateLegalTagApiAcceptance.java | 124 +++++ .../TestDeleteLegalTagApiAcceptance.java | 46 ++ .../TestGetLegalTagApiAcceptance.java | 40 ++ ...estGetLegalTagPropertiesApiAcceptance.java | 40 ++ .../TestGetLegalTagsApiAcceptance.java | 43 ++ .../TestListLegalTagsApiAcceptance.java | 43 ++ .../TestUpdateLegalTagApiAcceptance.java | 43 ++ .../TestValidateLegalTagsApiAcceptance.java | 42 ++ .../util/IBMLegalTagUtils.java | 21 + .../src/test/resources/InitialTags.json | 76 +++ .../src/test/resources/Tenant.json | 17 + testing/legal-test-ibm/teardown_acceptance.sh | 10 + 61 files changed, 3537 insertions(+), 469 deletions(-) create mode 100644 provider/legal-aws/.env.template create mode 100644 provider/legal-aws/CloudFormation/JarDeploy/CodePipeline-JarDeploy.yml create mode 100644 provider/legal-aws/buildspec-jar-deploy.yml create mode 100644 provider/legal-ibm/README.md create mode 100644 provider/legal-ibm/pom.xml create mode 100644 provider/legal-ibm/src/main/java/org/opengroup/osdu/legal/ibm/LegalApplication.java create mode 100644 provider/legal-ibm/src/main/java/org/opengroup/osdu/legal/ibm/countries/StorageReaderFactoryImpl.java create mode 100644 provider/legal-ibm/src/main/java/org/opengroup/osdu/legal/ibm/countries/StorageReaderImpl.java create mode 100644 provider/legal-ibm/src/main/java/org/opengroup/osdu/legal/ibm/di/DevNullPublisher.java create mode 100644 provider/legal-ibm/src/main/java/org/opengroup/osdu/legal/ibm/di/DpsLogFactory.java create mode 100644 provider/legal-ibm/src/main/java/org/opengroup/osdu/legal/ibm/jobs/LegalTagPublisherImpl.java create mode 100644 provider/legal-ibm/src/main/java/org/opengroup/osdu/legal/ibm/security/SecurityConfig.java create mode 100644 provider/legal-ibm/src/main/java/org/opengroup/osdu/legal/ibm/security/WhoamiController.java create mode 100644 provider/legal-ibm/src/main/java/org/opengroup/osdu/legal/ibm/tags/CloudantBackedLegalTag.java create mode 100644 provider/legal-ibm/src/main/java/org/opengroup/osdu/legal/ibm/tags/CloudantLegalTagRepository.java create mode 100644 provider/legal-ibm/src/main/resources/application.yml create mode 100644 provider/legal-ibm/src/main/resources/logback.groovy create mode 100644 provider/legal-ibm/src/test/java/org/opengroup/osdu/legal/ibm/api/EntitlementsFactoryByoc.java create mode 100644 provider/legal-ibm/src/test/java/org/opengroup/osdu/legal/ibm/api/EntitlementsServiceByoc.java create mode 100644 provider/legal-ibm/src/test/java/org/opengroup/osdu/legal/ibm/api/LegalTagApiTest.java create mode 100644 provider/legal-ibm/src/test/java/org/opengroup/osdu/legal/ibm/tags/LegalTagTests.java create mode 100644 provider/legal-ibm/src/test/resources/logback.groovy create mode 100644 testing/legal-test-ibm/pom.xml create mode 100644 testing/legal-test-ibm/run_service.sh create mode 100644 testing/legal-test-ibm/run_tests.sh create mode 100644 testing/legal-test-ibm/setup_acceptance.sh create mode 100644 testing/legal-test-ibm/src/test/java/org/opengroup/osdu/legal/ibm/acceptanceTests/TestCreateLegalTagApiAcceptance.java create mode 100644 testing/legal-test-ibm/src/test/java/org/opengroup/osdu/legal/ibm/acceptanceTests/TestDeleteLegalTagApiAcceptance.java create mode 100644 testing/legal-test-ibm/src/test/java/org/opengroup/osdu/legal/ibm/acceptanceTests/TestGetLegalTagApiAcceptance.java create mode 100644 testing/legal-test-ibm/src/test/java/org/opengroup/osdu/legal/ibm/acceptanceTests/TestGetLegalTagPropertiesApiAcceptance.java create mode 100644 testing/legal-test-ibm/src/test/java/org/opengroup/osdu/legal/ibm/acceptanceTests/TestGetLegalTagsApiAcceptance.java create mode 100644 testing/legal-test-ibm/src/test/java/org/opengroup/osdu/legal/ibm/acceptanceTests/TestListLegalTagsApiAcceptance.java create mode 100644 testing/legal-test-ibm/src/test/java/org/opengroup/osdu/legal/ibm/acceptanceTests/TestUpdateLegalTagApiAcceptance.java create mode 100644 testing/legal-test-ibm/src/test/java/org/opengroup/osdu/legal/ibm/acceptanceTests/TestValidateLegalTagsApiAcceptance.java create mode 100644 testing/legal-test-ibm/src/test/java/org/opengroup/osdu/legal/ibm/acceptanceTests/util/IBMLegalTagUtils.java create mode 100644 testing/legal-test-ibm/src/test/resources/InitialTags.json create mode 100644 testing/legal-test-ibm/src/test/resources/Tenant.json create mode 100644 testing/legal-test-ibm/teardown_acceptance.sh diff --git a/.gitignore b/.gitignore index 8ea620568..b7efba2c0 100644 --- a/.gitignore +++ b/.gitignore @@ -27,8 +27,14 @@ target/ /.nb-gradle/ build/ +/provider/*/bin +/legal-core/bin + ### VS Code ### .vscode/ ### macOS ### *.DS_Store + +# Environment configuration +*.env diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index c8e06e7e9..12a86fc19 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -4,13 +4,13 @@ variables: AWS_ENVIRONMENT: dev GCP_BUILD_SUBDIR: provider/legal-gcp GCP_INT_TEST_SUBDIR: testing/legal-test-gcp - GCP_APPLICATION_NAME: os-legal + GCP_APPLICATION_NAME: osdu-legal GCP_ENVIRONMENT: dev GCP_PROJECT: opendes GCP_TENANT_NAME: opendes GCP_DEPLOY_ENV: p4d GCP_DOMAIN: cloud.slb-ds.com - GCP_STORAGE_URL: https://os-legal-dot-opendes.appspot.com/api/legal/v2/ + GCP_STORAGE_URL: https://osdu-legal-dot-opendes.appspot.com/api/legal/v2/ include: - project: 'osdu/platform/ci-cd-pipelines' diff --git a/legal-core/src/main/java/org/opengroup/osdu/legal/api/LegalTagApi.java b/legal-core/src/main/java/org/opengroup/osdu/legal/api/LegalTagApi.java index 21db1b3f6..af147a96c 100644 --- a/legal-core/src/main/java/org/opengroup/osdu/legal/api/LegalTagApi.java +++ b/legal-core/src/main/java/org/opengroup/osdu/legal/api/LegalTagApi.java @@ -10,6 +10,7 @@ import org.opengroup.osdu.core.common.model.http.RequestInfo; import org.opengroup.osdu.core.common.model.legal.ServiceConfig; import javax.validation.Valid; +import javax.validation.ValidationException; import javax.validation.constraints.NotNull; import javax.inject.Inject; @@ -86,6 +87,9 @@ public class LegalTagApi { @PreAuthorize("@authorizationFilter.hasPermission('" + ServiceConfig.LEGAL_USER + "', '" + ServiceConfig.LEGAL_EDITOR + "', '" + ServiceConfig.LEGAL_ADMIN + "')") @GetMapping("/legaltags") public ResponseEntity<LegalTagDtos> listLegalTags(@RequestParam(name = "valid", required = false, defaultValue = "true") boolean valid) { + if (requestInfo.getTenantInfo() == null) { + throw new ValidationException("No tenant supplied"); + } LegalTagDtos output = legalTagService.list(valid, requestInfo.getTenantInfo().getName()); return new ResponseEntity<LegalTagDtos>(output, HttpStatus.OK); } diff --git a/provider/legal-aws/.env.template b/provider/legal-aws/.env.template new file mode 100644 index 000000000..380262362 --- /dev/null +++ b/provider/legal-aws/.env.template @@ -0,0 +1,63 @@ +# Copyright © Amazon Web Services +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +##### Sample os-legal .env file ########################################################### +# +# Basic use: duplicate this file, and make sure the new copy is also in the root of the AWS +# 'provider' folder, and name it `.env`. Note that on macOS, by default, files starting with +# are considered hidden system files, and are not displayed by default in Finder or the file +# selector (which you will need to use when adding the environment file(s) to the run +# configuration(s). While you can change a setting to show hidden files and folders by +# default, there is also a keyboard shortcut to quickly toggle between hide/show. With either +# Finder as the active application ("Finder" appears next to the Apple logo in the Menu Bar), +# press: command + shift + . (period). You can store configurations for multiple environments +# by adding more duplicates following a naming scheme of your choosing, for example: +# `staging.env`, `uat.env`, or `local.env`. +# +# This requires installing a plugin to your IDE that allows you to use a .env +# file in your repository folder (does NOT get checked into source control; +# only the sample environment configuration (sample.env) should be committed. +# +# Download links for .env file plugins: +# IntelliJ - https://github.com/Ashald/EnvFile + +##### Authentication / Secrets ##### +# Replace placeholder text with your own AWS secret access keys +# and rename to `.env` - do NOT check-in .env with your credentials! Leave it in .gitignore +AWS_ACCESS_KEY_ID= +AWS_SECRET_KEY= +AWS_ACCOUNT_ID= + +##### URLs/Ports - these values are most likely to change between environments ############# +APPLICATION_PORT= +DOMAIN= + + +##### Other environment variables ########################################################## +JAVA_HEAP_MEMORY= +SNS_TOPIC_NAME= +S3_LEGAL_CONFIG_BUCKET= +ENVIRONMENT= +AWS_REGION= + +##### Integration test-specific - these are only used for integration tests, not the app ### +AWS_COGNITO_AUTH_FLOW= +AWS_COGNITO_AUTH_PARAMS_PASSWORD= +AWS_COGNITO_AUTH_PARAMS_USER= +AWS_COGNITO_AUTH_PARAMS_USER_NO_ACCESS= +AWS_COGNITO_CLIENT_ID= +HOST_URL= +MY_TENANT= +AWS_S3_ENDPOINT= +AWS_S3_REGION= \ No newline at end of file diff --git a/provider/legal-aws/CloudFormation/Automated/config-bucket.yml b/provider/legal-aws/CloudFormation/Automated/config-bucket.yml index 8f1bfd9e2..442fc4c53 100644 --- a/provider/legal-aws/CloudFormation/Automated/config-bucket.yml +++ b/provider/legal-aws/CloudFormation/Automated/config-bucket.yml @@ -34,7 +34,7 @@ Parameters: Default: us-east-1 LegalConfigBucketName: - Description: The name of the legal service config S3 bucket. Defaults to osdu-legal-config. + Description: The base name of the legal service config S3 bucket. Will be prefixed by the environment and account ID. AllowedPattern: "^[a-zA-Z]+[0-9a-zA-Z_-]*$" ConstraintDescription: Must start with a letter. Only numbers, letters, -, and _ accepted. Max. length 64 characters. Default: osdu-legal-config @@ -47,7 +47,7 @@ Resources: Type: 'AWS::S3::Bucket' DeletionPolicy: Delete Properties: - BucketName: !Sub ${Environment}-${LegalConfigBucketName} + BucketName: !Sub ${Environment}-${AWS::AccountId}-${LegalConfigBucketName} LegalConfigS3BucketPolicy: Type: AWS::S3::BucketPolicy @@ -70,6 +70,6 @@ Resources: Outputs: LegalConfigS3BucketName: Description: The name of the OSDU legal config S3 bucket. - Value: !Ref LegalConfigBucketName + Value: !Ref S3BucketLegalConfig Export: Name: !Sub ${Environment}-S3BucketLegalConfig \ No newline at end of file diff --git a/provider/legal-aws/CloudFormation/Automated/ecs-cluster.yml b/provider/legal-aws/CloudFormation/Automated/ecs-cluster.yml index 1c97b95cd..5cd3513ee 100644 --- a/provider/legal-aws/CloudFormation/Automated/ecs-cluster.yml +++ b/provider/legal-aws/CloudFormation/Automated/ecs-cluster.yml @@ -1,3 +1,17 @@ +# Copyright © Amazon Web Services +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + AWSTemplateFormatVersion: 2010-09-09 Description: >- CloudFormation template for creating the resources used for the ECS cluster the application will @@ -152,6 +166,32 @@ Parameters: MinValue: 256 MaxValue: 131072 + DomainName: + Description: >- + The optional custom DNS name for the ECS service's load balancer. If omitted, the site will only be accessible + via the ECS service's Application Load Balancer DNS name. This value is used in the creation and signing of + the service's SSL certificate. Leave blank is not using a custom domain for this deployment. + Type: String + Default: '' + + HostedZoneName: + Description: >- + The name of the hosted zone (ex: for legal.osdu.slb.com, this would likely be osdu.slb.com). + Leave blank is not using a custom domain for this deployment. + Type: String + Default: '' + + VersionNumber: + Description: The version number for the service jar being produced + Type: String + Default: '0.0.1' + + ServiceName: + Description: >- + The service name associated with the jar package for the Dockerfile. + Type: String + Default: 'legal' + Mappings: # This mapping is for the ECS-optimized edition of the November 13-14, 2019 release of the Amazon Linux 2 AMI # It will need to be periodically updated as new versions are released by Amazon. @@ -191,7 +231,45 @@ Mappings: sa-east-1: AMIID: ami-0c947c117562538ee +Conditions: + IncludeCustomDomain: !Not [!Equals [ !Ref DomainName, '' ]] + IsPortStandardSSL: + !Or [!Equals [ !Ref ECSPort, '443' ], !Equals [ !Ref ECSPort, '8443' ]] + IsLoadBalancerHTTPS: !And # HTTPS for ECS requires a custom domain, but CloudFront will still have HTTPS/SSL + - !Condition IncludeCustomDomain + - !Condition IsPortStandardSSL + Resources: + # This sets up a Route 53 record for CloudFront if a custom domain is being used, + # otherwise a default cloudfront.net value will be used instead + CloudFrontDNSName: + Type: AWS::Route53::RecordSetGroup + Condition: IncludeCustomDomain + Properties: + HostedZoneName: !Join ['', [!Ref HostedZoneName, .]] # Route 53 requires a trailing period + RecordSets: + - Name: !Ref DomainName + Type: A + AliasTarget: + # This hosted zone ID is for ALL CloudFront distributions, always, and should be hard-coded + HostedZoneId: Z2FDTNDATAQYW2 + DNSName: !GetAtt ECSCloudFrontDistribution.DomainName + + # This sets up a Route 53 record for the ECS ALB origin if a custom domain is being used + ECSDNSName: + Type: AWS::Route53::RecordSetGroup + Condition: IncludeCustomDomain + Properties: + HostedZoneName: !Join ['', [!Ref HostedZoneName, .]] # Route 53 requires a trailing period + RecordSets: + - Name: !Join ['.', ['origin', !Ref DomainName]] # prefix the ECS origin record with 'origin.' + Type: A + AliasTarget: + HostedZoneId: !GetAtt ECSALB.CanonicalHostedZoneID # this value comes from the ALB attributes + DNSName: !GetAtt ECSALB.DNSName + EvaluateTargetHealth: true # Route 53 routes traffic to ECS targets based on their health checks + DependsOn: ECSALB + CodeDeployApplication: Type: AWS::CodeDeploy::Application Properties: @@ -211,11 +289,11 @@ Resources: AWS: - !Sub arn:aws:iam::${AWS::AccountId}:root - Fn::ImportValue: - !Sub "${Environment}-${ApplicationName}-CodeBuildRoleArn" + !Sub "${Environment}-CodeBuildRoleArn" - Fn::ImportValue: - !Sub "${Environment}-${ApplicationName}-CFNRoleArn" + !Sub "${Environment}-CFNRoleArn" - Fn::ImportValue: - !Sub "${Environment}-${ApplicationName}-PipelineRoleArn" + !Sub "${Environment}-PipelineRoleArn" Service: - codebuild.amazonaws.com Action: @@ -282,7 +360,9 @@ Resources: - Name: SNS_TOPIC_NAME Value: !Ref SNSTopicName - Name: S3_LEGAL_CONFIG_BUCKET - Value: !Ref LegalConfigS3BucketName + Value: + Fn::ImportValue: + !Sub "${Environment}-S3BucketLegalConfig" - Name: JAVA_HEAP_MEMORY Value: !Ref ECSMemoryAllocation Volumes: @@ -314,7 +394,16 @@ Resources: TargetGroupArn: !Ref 'ECSTargetGroup' LoadBalancerArn: !Ref 'ECSALB' Port: !Ref ECSPort - Protocol: HTTP + Protocol: !If [IsLoadBalancerHTTPS, HTTPS, HTTP] + + LoadBalancerALBListenerCertificate: + Type: AWS::ElasticLoadBalancingV2::ListenerCertificate + Condition: IncludeCustomDomain + Properties: + Certificates: + - Fn::ImportValue: + !Sub "${Environment}-${ApplicationName}-LoadBalancerSSLCertificateArn" + ListenerArn: !Ref 'ALBListener' ECSALBPrimaryListenerRule: Type: AWS::ElasticLoadBalancingV2::ListenerRule @@ -335,17 +424,92 @@ Resources: Properties: HealthCheckIntervalSeconds: 120 HealthCheckPath: /api/legal/v1/_ah/liveness_check - HealthCheckProtocol: HTTP + HealthCheckProtocol: !If [IsLoadBalancerHTTPS, HTTPS, HTTP] HealthCheckTimeoutSeconds: 5 HealthyThresholdCount: 2 - Name: !Sub ECSTargetGroup-${ApplicationName} + Name: !Sub ECSTargetGroup-New-${ApplicationName} Port: !Ref ECSPort - Protocol: HTTP + Protocol: !If [IsLoadBalancerHTTPS, HTTPS, HTTP] UnhealthyThresholdCount: 2 VpcId: Fn::ImportValue: !Sub "${Environment}-OSDU-VPC" + ECSCloudFrontDistribution: + Type: AWS::CloudFront::Distribution + DependsOn: ECSALB + Properties: + DistributionConfig: + Comment: 'Cloudfront Distribution pointing ALB Origin' + Origins: + - DomainName: !GetAtt 'ECSALB.DNSName' + Id: !Ref 'ECSALB' + CustomOriginConfig: + HTTPPort: !Ref ECSPort # The ports are the same because we'll only ever be accessing the ECS cluster over one protocol, as set in OriginProtocolPolicy below + HTTPSPort: !Ref ECSPort # The ports are the same because we'll only ever be accessing the ECS cluster over one protocol, as set in OriginProtocolPolicy below + OriginProtocolPolicy: !If [IsLoadBalancerHTTPS, https-only, http-only] # this only affects the origin, not CloudFront / the user's request + OriginKeepaliveTimeout: '60' + OriginReadTimeout: '60' + OriginSSLProtocols: + - TLSv1 + - TLSv1.1 + - TLSv1.2 + - SSLv3 + Enabled: true + HttpVersion: 'http2' + Aliases: + - Fn::If: + - IncludeCustomDomain + - !Ref DomainName + - !Ref AWS::NoValue + DefaultCacheBehavior: + AllowedMethods: + - GET + - HEAD + - OPTIONS + - PUT + - POST + - PATCH + - DELETE + Compress: true + TargetOriginId: !Ref 'ECSALB' + DefaultTTL: 5 + MaxTTL: 30 + ForwardedValues: + QueryString: true + Cookies: + Forward: all + Headers: + - Authorization + - Data-Partition-Id + - Content-Type + - Kind + - Limit + - Cursor + ViewerProtocolPolicy: redirect-to-https # CloudFront requests will always be HTTPS, regardless of the origin or the request + ViewerCertificate: + AcmCertificateArn: + Fn::If: + - IncludeCustomDomain + - Fn::ImportValue: + !Sub "${Environment}-${ApplicationName}-LoadBalancerSSLCertificateArn" + - Ref: AWS::NoValue + CloudFrontDefaultCertificate: + Fn::If: + - IncludeCustomDomain + - Ref: AWS::NoValue + - true + SslSupportMethod: + Fn::If: + - IncludeCustomDomain + - sni-only # sni-only is free; 'vip' is the only other option, which allows viewers without Server Name Indication (SNI) support by using dedicated IP addresses, but it costs $600/mo per SSL certificate + - Ref: AWS::NoValue + MinimumProtocolVersion: + Fn::If: + - IncludeCustomDomain + - TLSv1 + - Ref: AWS::NoValue # this is not used when using the default CloudFront certificate (which is always TLSv1) + ECSAutoScalingGroup: Type: AWS::AutoScaling::AutoScalingGroup Properties: @@ -534,8 +698,40 @@ Outputs: Export: Name: !Sub ${Environment}-${ApplicationName}-EcsAlbUrl + ECSALBCustomDNSName: + Description: The custom DNS name of the ECS service's ALB origin. + Condition: IncludeCustomDomain + Value: !Join ['.', ['origin', !Ref DomainName]] + Export: + Name: !Sub ${Environment}-${ApplicationName}-EcsAlbCustomDnsName + + ECSCloudFrontCustomDNSName: + Description: The custom DNS name of the ECS service's CloudFront Distribution. + Condition: IncludeCustomDomain + Value: !Ref DomainName + Export: + Name: !Sub ${Environment}-${ApplicationName}-EcsCloudFrontCustomDnsName + + ECSCloudFrontDomainName: + Description: The custom DNS name of the ECS service's CloudFront Distribution. + Value: !GetAtt ECSCloudFrontDistribution.DomainName + Export: + Name: !Sub ${Environment}-${ApplicationName}-EcsCloudFrontDomainName + TaskDefinitionArn: Description: The ARN of the Search Service ECS task definition. Value: !Ref 'TaskDefinition' Export: Name: !Sub ${Environment}-${ApplicationName}-EcsTaskDefinitionArn + + JarVersionNumber: + Description: The service name associated with the JAR package for the Dockerfile. + Value: !Ref 'VersionNumber' + Export: + Name: !Sub ${Environment}-${ApplicationName}-JarVersionNumber + + JarServiceName: + Description: The service name associated with the JAR package for the Dockerfile. + Value: !Ref 'ServiceName' + Export: + Name: !Sub ${Environment}-${ApplicationName}-JarServiceName \ No newline at end of file diff --git a/provider/legal-aws/CloudFormation/Automated/ecs-network.yml b/provider/legal-aws/CloudFormation/Automated/ecs-network.yml index 1b7037389..1d8c2fa23 100644 --- a/provider/legal-aws/CloudFormation/Automated/ecs-network.yml +++ b/provider/legal-aws/CloudFormation/Automated/ecs-network.yml @@ -1,3 +1,17 @@ +# Copyright © Amazon Web Services +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + AWSTemplateFormatVersion: 2010-09-09 Description: >- CloudFormation template for creating the network resources used for the ECS cluster the application will @@ -38,11 +52,49 @@ Parameters: ECSPort: Description: The port that the ECS Service will listen on. Type: Number - Default: 80 + Default: 443 MinValue: 1 MaxValue: 65535 + DomainName: + Description: >- + The optional custom DNS name for the service's load balancer. If omitted, the site will only be accessible + via the ECS service's Application Load Balancer DNS name. This value is used in the creation and signing of + the service's SSL certificate. Leave blank for none. + Type: String + Default: '' + + AcmCertificateArn: + Description: >- + The Amazon Resource Name (ARN) of an existing AWS Certificate Manager (ACM) certificate. + If omitted, a new SSL certified will be requested/generated (only if the custom domain name + parameter is provided, otherwise the ECS service's ALB will not use SSL/HTTPS). + Type: String + AllowedPattern: "^(|arn:aws:acm:.*)$" + Default: '' + +Conditions: + IncludeCustomDomain: !Not [!Equals [ !Ref DomainName, '' ]] + UseExistingACMSSLCertificate: !And + - !Not [!Equals [ !Ref AcmCertificateArn, '' ]] + - !Condition IncludeCustomDomain + ShouldRequestNewSSLCertificate: !And + - !Not [!Condition UseExistingACMSSLCertificate] + - !Condition IncludeCustomDomain + ShouldExportSSLCertificate: !Or + - !Condition IncludeCustomDomain + - !Condition UseExistingACMSSLCertificate + Resources: + # If an existing SSL certificate is not provided, but a custom domain is, request one + LoadBalancerSSLCertificate: + Type: 'AWS::CertificateManager::Certificate' + Condition: ShouldRequestNewSSLCertificate + Properties: + DomainName: !Ref DomainName + SubjectAlternativeNames: + - !Join ['.', ['origin', !Ref DomainName]] # + ECSSecurityGroup: Type: AWS::EC2::SecurityGroup Properties: @@ -52,7 +104,7 @@ Resources: Fn::ImportValue: !Sub "${Environment}-OSDU-VPC" - # Public access to ECS Listening Port + # Public access to the specified ECS Listening Port ECSSecurityGroupECSListenerInbound: Type: AWS::EC2::SecurityGroupIngress Properties: @@ -62,37 +114,8 @@ Resources: ToPort: !Ref ECSPort CidrIp: 0.0.0.0/0 - # Public access to port 443 - ECSSecurityGroupHTTPSInbound: - Type: AWS::EC2::SecurityGroupIngress - Properties: - GroupId: !Ref 'ECSSecurityGroup' - IpProtocol: tcp - FromPort: '443' - ToPort: '443' - CidrIp: 0.0.0.0/0 - - # Public access to port 8080 - ECSSecurityGroupHTTPAltInbound: - Type: AWS::EC2::SecurityGroupIngress - Properties: - GroupId: !Ref 'ECSSecurityGroup' - IpProtocol: tcp - FromPort: '8080' - ToPort: '8080' - CidrIp: 0.0.0.0/0 - - # Public access to port 8443 - ECSSecurityGroupHTTPSAltInbound: - Type: AWS::EC2::SecurityGroupIngress - Properties: - GroupId: !Ref 'ECSSecurityGroup' - IpProtocol: tcp - FromPort: '8443' - ToPort: '8443' - CidrIp: 0.0.0.0/0 - - # SSH access for instances in our VPC's jump box subnet group (coming soon – will be part of the Util CFN) + # SSH access for instances in our VPC's jump box subnet group + # TODO: Update when the jump box is created as a part of the Util CFN, for now it is public ECSSecurityGroupSSHInbound: Type: AWS::EC2::SecurityGroupIngress Properties: @@ -102,7 +125,7 @@ Resources: ToPort: '22' CidrIp: 0.0.0.0/0 - # Open Application Load Balancer port range to itself + # Open Application Load Balancer port range to self-access ECSSecurityGroupALBports: Type: AWS::EC2::SecurityGroupIngress Properties: @@ -118,3 +141,10 @@ Outputs: Value: !Ref 'ECSSecurityGroup' Export: Name: !Sub ${Environment}-${ApplicationName}-EcsNetworkSecurityGroupId + + LoadBalancerSSLCertificateArn: + Condition: ShouldExportSSLCertificate + Description: The ARN of the SSL certificate to be used for both ECS and CloudFront (includes both DNS names). + Value: !If [UseExistingACMSSLCertificate, !Ref AcmCertificateArn, !Ref 'LoadBalancerSSLCertificate'] + Export: + Name: !Sub ${Environment}-${ApplicationName}-LoadBalancerSSLCertificateArn diff --git a/provider/legal-aws/CloudFormation/Automated/sns-topic.yml b/provider/legal-aws/CloudFormation/Automated/sns-topic.yml index d2bcc0042..20893e56f 100644 --- a/provider/legal-aws/CloudFormation/Automated/sns-topic.yml +++ b/provider/legal-aws/CloudFormation/Automated/sns-topic.yml @@ -78,11 +78,11 @@ Resources: - OSDULegalSQSQueue - Arn Protocol: sqs - - Endpoint: - Fn::GetAtt: - - OSDUComplianceTrigger - - Arn - Protocol: lambda +# - Endpoint: +# Fn::GetAtt: +# - OSDUComplianceTrigger +# - Arn +# Protocol: lambda OSDULegalSQSQueue: @@ -90,18 +90,6 @@ Resources: Properties: QueueName: !Sub ${Environment}-${SQSQueueName} - OSDUComplianceTrigger: - Type: AWS::Lambda::Function - Properties: - FunctionName: !Sub ${Environment}-${ComplianceTriggerName} - Handler: compliance.ComplianceTriggerFunction::handleRequest - Runtime: java8 - MemorySize: 512 - Role: arn:aws:iam::888733619319:role/dev-os-legal-lambda-ComplianceTriggerFunctionRole-1RGCZVRE1V91S - Code: - S3Bucket: dev-os-legal-lambda-cloudformation - S3Key: 89ed4d883fb1fb7f6da4a507e607390d - OSDUQueuePolicy: Type: AWS::SQS::QueuePolicy Properties: diff --git a/provider/legal-aws/CloudFormation/JarDeploy/CodePipeline-JarDeploy.yml b/provider/legal-aws/CloudFormation/JarDeploy/CodePipeline-JarDeploy.yml new file mode 100644 index 000000000..a09e0b76e --- /dev/null +++ b/provider/legal-aws/CloudFormation/JarDeploy/CodePipeline-JarDeploy.yml @@ -0,0 +1,252 @@ +# Copyright © Amazon Web Services +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +AWSTemplateFormatVersion: 2010-09-09 + +Description: > + This CloudFormation script creates the deployment pipeline for OSDU's legal service. The CodePipeline + should automatically trigger whenever commits are made on the tracked branch. The start and end + of the CodePipeline should trigger a SNS alert to keep track of when the deployment has started + and when it finishes. + +Parameters: + Environment: + Description: Environment Name. Defaults to 'dev'. Can only be dev/uat/prod. + Type: String + AllowedValues: + - dev + - uat + - prod + Default: dev + + DeploymentRegion: + Description: The AWS region to deploy the application to. The default is us-east-1. + Type: String + Default: us-east-1 + + SNSNotificationEmail: + Description: The email address to send SNS notifications about the build to. + Type: String + Default: barclay.walsh@parivedasolutions.com + + CodeCommitRepositoryName: + Description: The name of the Code Commit Repository that the CodePipeline source is connected to. + Type: String + Default: os-legal + + JarServiceBase: + Description: The name of the service base path for the JAR files (e.g. 'legal'). + Type: String + Default: legal + + CodeCommitBranchName: + Description: The name of the Code Commit branch that the CodePipeline source is connected to. + Type: String + Default: dev + +Resources: + ArtifactStoreBucket: + Type: AWS::S3::Bucket + DeletionPolicy: Delete + Properties: + VersioningConfiguration: + Status: Enabled + + ArtifactStoreBucketPolicy: + Type: AWS::S3::BucketPolicy + Properties: + Bucket: !Ref ArtifactStoreBucket + PolicyDocument: + Statement: + - Action: + - s3:* + Effect: Allow + Resource: + - !Sub arn:aws:s3:::${ArtifactStoreBucket} + - !Sub arn:aws:s3:::${ArtifactStoreBucket}/* + Principal: + AWS: + - !Sub arn:aws:iam::${AWS::AccountId}:root + - !ImportValue + 'Fn::Sub': '${Environment}-CodeBuildRoleArn' + - !ImportValue + 'Fn::Sub': '${Environment}-PipelineRoleArn' + - !ImportValue + 'Fn::Sub': '${Environment}-CFNRoleArn' + + CachingBucket: + Type: AWS::S3::Bucket + DeletionPolicy: Delete + Properties: + VersioningConfiguration: + Status: Enabled + + CachingBucketPolicy: + Type: AWS::S3::BucketPolicy + Properties: + Bucket: !Ref CachingBucket + PolicyDocument: + Statement: + - Action: + - s3:* + Effect: Allow + Resource: + - !Sub arn:aws:s3:::${CachingBucket} + - !Sub arn:aws:s3:::${CachingBucket}/* + Principal: + AWS: + - !Sub arn:aws:iam::${AWS::AccountId}:root + - !ImportValue + 'Fn::Sub': '${Environment}-CodeBuildRoleArn' + - !ImportValue + 'Fn::Sub': '${Environment}-PipelineRoleArn' + - !ImportValue + 'Fn::Sub': '${Environment}-CFNRoleArn' + + SNSCodePipelineDeploymentFailed: + Type: AWS::SNS::Topic + Properties: + Subscription: + - Endpoint: !Ref SNSNotificationEmail + Protocol: email + TopicName: !Sub '${Environment}-OS-Legal-Deployment-CodePipeline-JarDeploy-Failed' + + EventRuleCodePipelineFailed: + Type: AWS::Events::Rule + Properties: + Description: Triggered whenever the CodePipeline deployment stage has failed. + EventPattern: + source: + - "aws.codepipeline" + detail-type: + - "CodePipeline Stage Execution State Change" + detail: + state: + - "FAILED" + pipeline: + - !Sub '${Environment}-OSDU-OS-Legal-CodePipeline-JarDeploy' + + Name: !Sub ${Environment}-CodePipelineEventRule-${CodeCommitRepositoryName}-JarDeploy + Targets: + - + Arn: + !Ref SNSCodePipelineDeploymentFailed + Id: "Deployment-CodePipeline-JarDeploy-Failed" + InputTransformer: + InputPathsMap: + pipeline : "$.detail.pipeline" + InputTemplate: '"The Pipeline <pipeline> has failed."' + + Pipeline: + Type: AWS::CodePipeline::Pipeline + Properties: + ArtifactStore: + Location: !Ref ArtifactStoreBucket + Type: S3 + Name: !Sub '${Environment}-OSDU-OS-Legal-CodePipeline-JarDeploy' + RoleArn: !ImportValue + 'Fn::Sub': '${Environment}-PipelineRoleArn' + Stages: + - Name: Source + Actions: + - Name: Source + ActionTypeId: + Category: Source + Owner: AWS + Provider: CodeCommit + Version: '1' + Configuration: + BranchName: !Ref CodeCommitBranchName + RepositoryName: !Ref CodeCommitRepositoryName + OutputArtifacts: + - Name: Source + RunOrder: '1' + + - Name: CodeBuild + Actions: + - Name: Jar-CodeBuild + ActionTypeId: + Category: Build + Owner: AWS + Provider: CodeBuild + Version: '1' + InputArtifacts: + - Name: Source + OutputArtifacts: + - Name: Jar-CodeBuild + Configuration: + ProjectName: !Ref JarCodeBuild + RunOrder: '2' + + JarCodeBuild: + Type: AWS::CodeBuild::Project + Properties: + Name: !Sub ${Environment}-jar-codebuild-${CodeCommitRepositoryName} + Description: > + CodeBuild commands which handle setting environment variables, along with the + build, test, and packaging of the .jar file. It then uses the AWS CLI to copy + the versioned JAR and associated build files to the shared jar-deploy S3 bucket. + ServiceRole: !ImportValue + 'Fn::Sub': '${Environment}-CodeBuildRoleArn' + Artifacts: + Type: S3 + Location: !Ref ArtifactStoreBucket + Name: !Sub ${Environment}-jar-codebuild + Environment: + Type: LINUX_CONTAINER + ComputeType: BUILD_GENERAL1_SMALL + Image: aws/codebuild/standard:2.0 + EnvironmentVariables: + - Name: ENVIRONMENT + Type: PLAINTEXT + Value: !Ref Environment + - Name: AWS_ACCOUNT_ID + Type: PLAINTEXT + Value: !Ref AWS::AccountId + - Name: AWS_REGION + Type: PLAINTEXT + Value: !Ref DeploymentRegion + - Name: APPLICATION_NAME + Type: PLAINTEXT + Value: !Ref CodeCommitRepositoryName + - Name: JAR_SERVICE_BASE + Type: PLAINTEXT + Value: !Ref JarServiceBase + - Name: M2_REPO_S3_BUCKET + Type: PLAINTEXT + Value: !Sub "${Environment}-${AWS::AccountId}-persistent-maven-m2-bucket" + - Name: JAR_DEPLOY_S3_BUCKET + Type: PLAINTEXT + Value: !Sub ${Environment}-${AWS::AccountId}-osdu-jar-deploy + PrivilegedMode: true + Source: + BuildSpec: ./provider/legal-aws/buildspec-jar-deploy.yml + Location: !Sub https://git-codecommit.${AWS::Region}.amazonaws.com/v1/repos/${CodeCommitRepositoryName} + Type: CODECOMMIT + Cache: + Type: S3 + Location: !Sub ${CachingBucket}/${Environment} + TimeoutInMinutes: 15 + VpcConfig: + SecurityGroupIds: + - Fn::ImportValue: + !Sub "${Environment}-OSDU-CodeBuildSecurityGroup" + Subnets: + - Fn::ImportValue: + !Sub "${Environment}-OSDU-PrivateSubnet-AZ1" + - Fn::ImportValue: + !Sub "${Environment}-OSDU-PrivateSubnet-AZ2" + VpcId: + Fn::ImportValue: + !Sub "${Environment}-OSDU-VPC" diff --git a/provider/legal-aws/CloudFormation/Manual/01-CreateCodePipeline.yml b/provider/legal-aws/CloudFormation/Manual/01-CreateCodePipeline.yml index c4ff88bd7..b22b0d04a 100644 --- a/provider/legal-aws/CloudFormation/Manual/01-CreateCodePipeline.yml +++ b/provider/legal-aws/CloudFormation/Manual/01-CreateCodePipeline.yml @@ -61,31 +61,6 @@ Parameters: Default: provider/legal-aws/CloudFormation/Master/os-legal-master.yml Resources: - S3BucketCloudFormation: - Type: 'AWS::S3::Bucket' - DeletionPolicy: Delete - Properties: - BucketName: !Sub ${Environment}-os-legal-cloudformation-scripts - - CloudFormationS3BucketPolicy: - Type: AWS::S3::BucketPolicy - Properties: - Bucket: !Ref S3BucketCloudFormation - PolicyDocument: - Statement: - - Action: - - s3:* - Effect: Allow - Resource: - - !Sub arn:aws:s3:::${S3BucketCloudFormation} - - !Sub arn:aws:s3:::${S3BucketCloudFormation}/* - Principal: - AWS: - - !Sub arn:aws:iam::${AWS::AccountId}:root - - !GetAtt [CodeBuildRole,Arn] - - !GetAtt [PipelineRole,Arn] - - !GetAtt [CFNRole,Arn] - ArtifactStoreBucket: Type: AWS::S3::Bucket DeletionPolicy: Delete @@ -108,9 +83,12 @@ Resources: Principal: AWS: - !Sub arn:aws:iam::${AWS::AccountId}:root - - !GetAtt [CodeBuildRole,Arn] - - !GetAtt [PipelineRole,Arn] - - !GetAtt [CFNRole,Arn] + - !ImportValue + 'Fn::Sub': '${Environment}-CodeBuildRoleArn' + - !ImportValue + 'Fn::Sub': '${Environment}-PipelineRoleArn' + - !ImportValue + 'Fn::Sub': '${Environment}-CFNRoleArn' CachingBucket: Type: AWS::S3::Bucket @@ -134,9 +112,12 @@ Resources: Principal: AWS: - !Sub arn:aws:iam::${AWS::AccountId}:root - - !GetAtt [CodeBuildRole,Arn] - - !GetAtt [PipelineRole,Arn] - - !GetAtt [CFNRole,Arn] + - !ImportValue + 'Fn::Sub': '${Environment}-CodeBuildRoleArn' + - !ImportValue + 'Fn::Sub': '${Environment}-PipelineRoleArn' + - !ImportValue + 'Fn::Sub': '${Environment}-CFNRoleArn' SNSCodePipelineDeploymentFailed: Type: AWS::SNS::Topic @@ -179,7 +160,8 @@ Resources: Location: !Ref ArtifactStoreBucket Type: S3 Name: !Sub '${Environment}-OSDU-OS-Legal-CodePipeline' - RoleArn: !GetAtt [PipelineRole, Arn] + RoleArn: !ImportValue + 'Fn::Sub': '${Environment}-PipelineRoleArn' Stages: - Name: Source Actions: @@ -225,7 +207,8 @@ Resources: Configuration: ActionMode: CREATE_UPDATE Capabilities: CAPABILITY_NAMED_IAM - RoleArn: !GetAtt [ CFNRole, Arn ] + RoleArn: !ImportValue + 'Fn::Sub': '${Environment}-CFNRoleArn' StackName: !Sub ${Environment}-${MasterStackName} TemplatePath: !Sub "Source::${MasterTemplateName}" TemplateConfiguration: !Sub "Source::provider/legal-aws/CloudFormation/Params/${Environment}.template_configuration.json" @@ -252,8 +235,8 @@ Resources: Properties: Name: !Sub ${Environment}-pre-deployment-codebuild-${CodeCommitRepositoryName} Description: CodeBuild commands which run prior to the CloudFormation deployment. - ServiceRole: - Fn::GetAtt: [ CodeBuildRole, Arn ] + ServiceRole: !ImportValue + 'Fn::Sub': '${Environment}-CodeBuildRoleArn' Artifacts: Type: S3 Location: !Ref ArtifactStoreBucket @@ -274,7 +257,11 @@ Resources: Value: !Ref DeploymentRegion - Name: CFN_S3_BUCKET Type: PLAINTEXT - Value: !Sub ${Environment}-os-legal-cloudformation-scripts + Value: !ImportValue + 'Fn::Sub': '${Environment}-S3BucketCloudFormation' + - Name: APPLICATION_NAME + Type: PLAINTEXT + Value: !Ref CodeCommitRepositoryName PrivilegedMode: false Source: BuildSpec: ./provider/legal-aws/buildspec-pre-deploy.yml @@ -287,8 +274,8 @@ Resources: Properties: Name: !Sub ${Environment}-post-deployment-codebuild-${CodeCommitRepositoryName} Description: CodeBuild commands which run after the CloudFormation deployment. - ServiceRole: - Fn::GetAtt: [ CodeBuildRole, Arn ] + ServiceRole: !ImportValue + 'Fn::Sub': '${Environment}-CodeBuildRoleArn' Artifacts: Type: S3 Location: !Ref ArtifactStoreBucket @@ -307,9 +294,6 @@ Resources: - Name: AWS_REGION Type: PLAINTEXT Value: !Ref DeploymentRegion - - Name: VSTS_FEED_USER - Type: PLAINTEXT - Value: '{{resolve:secretsmanager:dev-VSTSFeedToken:SecretString:vsts_feed_user}}' - Name: VSTS_FEED_TOKEN Type: PLAINTEXT Value: '{{resolve:secretsmanager:dev-VSTSFeedToken:SecretString:vsts_feed_token}}' @@ -322,6 +306,9 @@ Resources: - Name: APPLICATION_NAME Type: PLAINTEXT Value: !Ref CodeCommitRepositoryName + - Name: M2_REPO_S3_BUCKET + Type: PLAINTEXT + Value: !Sub "${Environment}-${AWS::AccountId}-persistent-maven-m2-bucket" PrivilegedMode: true Source: BuildSpec: ./provider/legal-aws/buildspec-post-deploy.yml @@ -343,297 +330,3 @@ Resources: VpcId: Fn::ImportValue: !Sub "${Environment}-OSDU-VPC" - - CFNRole: - Type: AWS::IAM::Role - Properties: - AssumeRolePolicyDocument: - Statement: - - Action: ['sts:AssumeRole'] - Effect: Allow - Principal: - Service: [cloudformation.amazonaws.com] - Version: '2012-10-17' - Path: / - Policies: - - PolicyName: !Sub CloudFormationRole-${CodeCommitRepositoryName} - PolicyDocument: - Version: '2012-10-17' - Statement: - - - Action: - - 's3:*' - - 'ec2:*' - - 'apigateway:*' - - 'cloudwatch:*' - - 'events:*' - - 'logs:*' - - 'xray:*' - - 'lambda:*' - - 'rds:*' - - 'codepipeline:*' - - 'codecommit:*' - - 'cloudformation:*' - - 'dynamodb:*' - - 'application-autoscaling:*' - - 'autoscaling:*' - - 'states:*' - - 'iam:CreateUser' - - 'iam:UpdateUser' - - 'iam:DeleteUser' - - 'iam:CreateAccessKey' - - 'iam:UpdateAccessKey' - - 'iam:DeleteAccessKey' - - 'iam:Delete*' - - "iam:List*" - - "iam:Get*" - - "iam:CreateServiceSpecificCredential" - - "iam:DeactivateMFADevice" - - "iam:GenerateServiceLastAccessedDetails" - - "iam:UpdateOpenIDConnectProviderThumbprint" - - "iam:PutRolePolicy" - - "iam:AddRoleToInstanceProfile" - - "iam:SimulateCustomPolicy" - - "iam:UploadSSHPublicKey" - - "iam:UpdateServiceSpecificCredential" - - "iam:RemoveClientIDFromOpenIDConnectProvider" - - "iam:UpdateRoleDescription" - - "iam:UpdateServerCertificate" - - "iam:CreateInstanceProfile" - - "iam:GenerateCredentialReport" - - "iam:UntagRole" - - "iam:PutRolePermissionsBoundary" - - "iam:TagRole" - - "iam:ResetServiceSpecificCredential" - - "iam:PassRole" - - "iam:EnableMFADevice" - - "iam:ResyncMFADevice" - - "iam:UpdateSAMLProvider" - - "iam:CreatePolicy" - - "iam:CreateServiceLinkedRole" - - "iam:UpdateRole" - - "iam:AddClientIDToOpenIDConnectProvider" - - "iam:SetDefaultPolicyVersion" - - "iam:UpdateAssumeRolePolicy" - - "iam:RemoveRoleFromInstanceProfile" - - "iam:CreateRole" - - "iam:AttachRolePolicy" - - "iam:CreateLoginProfile" - - "iam:DetachRolePolicy" - - "iam:AttachUserPolicy" - - "iam:DetachUserPolicy" - - "iam:PutUserPolicy" - - "iam:*UserPolicy" - - "iam:SimulatePrincipalPolicy" - - "iam:CreateAccountAlias" - - "iam:ChangePassword" - - "iam:UpdateLoginProfile" - - "iam:UpdateAccessKey" - - "iam:UpdateSSHPublicKey" - - "iam:UpdateAccountPasswordPolicy" - - "iam:CreateSAMLProvider" - - "iam:CreateVirtualMFADevice" - - "iam:CreateAccessKey" - - "iam:AddUserToGroup" - - "iam:RemoveUserFromGroup" - - "iam:CreatePolicyVersion" - - "iam:UploadSigningCertificate" - - "iam:TagUser" - - "iam:CreateOpenIDConnectProvider" - - "iam:UploadServerCertificate" - - "iam:UntagUser" - - "iam:UpdateSigningCertificate" - - 'sns:*' - - 'sqs:*' - - 'secretsmanager:*' - - 'acm:*' - - 'kms:*' - - 'cloudfront:*' - - 'route53:*' - - 'route53domains:*' - - 'elasticache:*' - - 'ecr:*' - - 'codedeploy:*' - - 'elasticloadbalancing:*' - - 'ecs:*' - - 'servicediscovery:CreatePrivateDnsNamespace' - - 'servicediscovery:CreateService' - - 'servicediscovery:GetNamespace' - - 'servicediscovery:GetOperation' - - 'servicediscovery:GetService' - - 'servicediscovery:ListNamespaces' - - 'servicediscovery:ListServices' - - 'servicediscovery:UpdateService' - - 'servicediscovery:DeleteService' - Effect: Allow - Resource: '*' - - CodeBuildRole: - Type: "AWS::IAM::Role" - Properties: - RoleName: !Sub CodeBuildRole-${CodeCommitRepositoryName} - AssumeRolePolicyDocument: - Version: "2012-10-17" - Statement: - - - Effect: "Allow" - Principal: - Service: - - "codebuild.amazonaws.com" - Action: - - "sts:AssumeRole" - Path: /service-role/ - Policies: - - - PolicyName: !Sub CodeBuildNestedCFNAccessPolicy-${CodeCommitRepositoryName} - PolicyDocument: - Version: "2012-10-17" - Statement: - - - Effect: "Allow" - Action: - - "cloudformation:Get*" - - "cloudformation:Describe*" - - "cloudformation:List*" - Resource: - - '*' - - - Effect: "Allow" - Action: - - "codebuild:StartBuild" - Resource: - - Fn::Sub: arn:aws:codebuild:${AWS::Region}:${AWS::AccountId}:project/* - - - Effect: "Allow" - Action: - - "codecommit:ListBranches" - - "codecommit:ListRepositories" - - "codecommit:BatchGetRepositories" - - "codecommit:Get*" - - "codecommit:GitPull" - Resource: - - !Sub arn:aws:codecommit:${AWS::Region}:${AWS::AccountId}:${CodeCommitRepositoryName} - - - Effect: "Allow" - Action: - - "ec2:*" - - "cloudformation:ValidateTemplate" - - "elasticloadbalancing:Describe*" - - "autoscaling:Describe*" - - "iam:Get*" - - "iam:List*" - - "logs:Describe*" - - "logs:Get*" - - "tag:Get*" - - "ecr:*" - - "codedeploy:*" - - "ecs:*" - Resource: - - "*" - - - Effect: "Allow" - Action: - - "logs:CreateLogGroup" - - "logs:CreateLogStream" - - "logs:PutLogEvents" - Resource: - - Fn::Sub: arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/codebuild/* - - - Effect: "Allow" - Action: - - "s3:*" - Resource: '*' - - - Effect: "Allow" - Action: - - "lambda:UpdateFunctionCode" - - "lambda:UpdateFunctionConfiguration" - - "lambda:PublishLayerVersion" - - "lambda:GetLayerVersion" - Resource: '*' - - - Effect: "Allow" - Action: - - "apigateway:GET" - - "apigateway:POST" - Resource: '*' - - PipelineRole: - Type: AWS::IAM::Role - Properties: - AssumeRolePolicyDocument: - Statement: - - Action: ['sts:AssumeRole'] - Effect: Allow - Principal: - Service: [codepipeline.amazonaws.com] - Version: '2012-10-17' - Path: / - Policies: - - PolicyName: !Sub CodePipelineAccess-${CodeCommitRepositoryName} - PolicyDocument: - Version: '2012-10-17' - Statement: - - Action: - - 's3:*' - - 'cloudformation:CreateStack' - - 'cloudformation:DescribeStacks' - - 'cloudformation:DeleteStack' - - 'cloudformation:UpdateStack' - - 'cloudformation:CreateChangeSet' - - 'cloudformation:ExecuteChangeSet' - - 'cloudformation:DeleteChangeSet' - - 'cloudformation:DescribeChangeSet' - - 'cloudformation:SetStackPolicy' - - 'cloudformation:ValidateTemplate' - - 'iam:PassRole' - - 'sns:Publish' - - 'lambda:ListFunctions' - - 'lambda:InvokeFunction' - - 'ec2:Describe*' - - 'ec2:Get*' - - 'ec2:Search*' - - 'ec2:*Vpc*' - - 'ec2:*Gateway' - - 'ec2:*Tags' - - 'ec2:*Subnet*' - - 'ec2:*Route*' - - 'ec2:*SecurityGroup' - - 'ec2:allocate*' - - 'ec2:release*' - Effect: Allow - Resource: '*' - - Action: - - 'codecommit:GetUploadArchiveStatus' - - 'codecommit:CancelUploadArchive' - - 'codecommit:GetBranch' - - 'codecommit:GetCommit' - - 'codecommit:GetUploadStatus' - - 'codecommit:UploadArchive' - Effect: Allow - Resource: '*' - - - Effect: "Allow" - Action: - - "codebuild:*" - Resource: - - Fn::Sub: arn:aws:codebuild:${AWS::Region}:${AWS::AccountId}:project/* - -Outputs: - CodeBuildRoleArn: - Description: The ARN of the role used by the CodeBuild projects. - Value: !GetAtt CodeBuildRole.Arn - Export: - Name: !Sub ${Environment}-${CodeCommitRepositoryName}-CodeBuildRoleArn - - CFNRoleArn: - Description: The ARN of the role used by CloudFormation templates run from the automated pipeline. - Value: !GetAtt CFNRole.Arn - Export: - Name: !Sub ${Environment}-${CodeCommitRepositoryName}-CFNRoleArn - - PipelineRoleArn: - Description: The ARN of the role used by the application's CodePipeline. - Value: !GetAtt PipelineRole.Arn - Export: - Name: !Sub ${Environment}-${CodeCommitRepositoryName}-PipelineRoleArn diff --git a/provider/legal-aws/CloudFormation/Master/os-legal-master.yml b/provider/legal-aws/CloudFormation/Master/os-legal-master.yml index 6ac45aa6a..e335f660c 100644 --- a/provider/legal-aws/CloudFormation/Master/os-legal-master.yml +++ b/provider/legal-aws/CloudFormation/Master/os-legal-master.yml @@ -32,14 +32,6 @@ Parameters: Type: String Default: us-east-1 - ChildTemplateBasePath: - Description: >- - The base path for where child CloudFormation templates are located – can be relative or absolute, e.g. - https://s3.amazonaws.com/dev-os-legal-cloudformation-scripts/Automated/ - Type: String - AllowedPattern: '^https:\/\/s3.amazonaws.com\/.*\/$' - Default: https://s3.amazonaws.com/dev-os-legal-cloudformation-scripts/Automated/ - LegalConfigS3BucketName: Description: The name of the legal service config S3 bucket. Defaults to osdu-legal-config. AllowedPattern: "^[a-zA-Z]+[0-9a-zA-Z_-]*$" @@ -205,6 +197,41 @@ Parameters: MinValue: 256 MaxValue: 131072 + DomainName: + Description: >- + The optional custom DNS name for the ECS service's load balancer. If omitted, the site will only be accessible + via the ECS service's Application Load Balancer DNS name. This value is used in the creation and signing of + the service's SSL certificate. Leave blank is not using a custom domain for this deployment. + Type: String + Default: '' + + HostedZoneName: + Description: >- + The name of the hosted zone (ex: for storage.osdu.slb.com, this would likely be osdu.slb.com). + Leave blank is not using a custom domain for this deployment. + Type: String + Default: '' + + AcmCertificateArn: + Description: >- + The Amazon Resource Name (ARN) of an existing AWS Certificate Manager (ACM) certificate. + If omitted, a new SSL certified will be requested/generated (only if the custom domain name + parameter is provided, otherwise the ECS service's ALB will not use SSL/HTTPS). + Type: String + AllowedPattern: "^(|arn:aws:acm:.*)$" + Default: '' + + VersionNumber: + Description: The version number for the service jar being produced + Type: String + Default: '0.0.1' + + ServiceName: + Description: >- + The service name associated with the jar package for the Dockerfile. + Type: String + Default: 'legal' + Resources: #### Shared Resources ################################################################ @@ -212,7 +239,11 @@ Resources: IAMCredentialsStack: Type: 'AWS::CloudFormation::Stack' Properties: - TemplateURL: !Join [ '', [ !Ref ChildTemplateBasePath, iam-credentials.yml ] ] + TemplateURL: !Sub + - https://s3.amazonaws.com/${CloudFormationS3Bucket}/${ApplicationName}/Automated/${CFNTemplateFilename} + - CloudFormationS3Bucket: !ImportValue + 'Fn::Sub': '${Environment}-S3BucketCloudFormation' + CFNTemplateFilename: iam-credentials.yml Parameters: Environment: !Ref Environment Region: !Ref DeploymentRegion @@ -222,7 +253,11 @@ Resources: MessageBusSNSStack: Type: 'AWS::CloudFormation::Stack' Properties: - TemplateURL: !Join [ '', [ !Ref ChildTemplateBasePath, sns-topic.yml ] ] + TemplateURL: !Sub + - https://s3.amazonaws.com/${CloudFormationS3Bucket}/${ApplicationName}/Automated/${CFNTemplateFilename} + - CloudFormationS3Bucket: !ImportValue + 'Fn::Sub': '${Environment}-S3BucketCloudFormation' + CFNTemplateFilename: sns-topic.yml Parameters: Environment: !Ref Environment Region: !Ref DeploymentRegion @@ -235,18 +270,28 @@ Resources: Type: 'AWS::CloudFormation::Stack' DependsOn: IAMCredentialsStack Properties: - TemplateURL: !Join [ '', [ !Ref ChildTemplateBasePath, ecs-network.yml ] ] + TemplateURL: !Sub + - https://s3.amazonaws.com/${CloudFormationS3Bucket}/${ApplicationName}/Automated/${CFNTemplateFilename} + - CloudFormationS3Bucket: !ImportValue + 'Fn::Sub': '${Environment}-S3BucketCloudFormation' + CFNTemplateFilename: ecs-network.yml Parameters: Environment: !Ref Environment Region: !Ref DeploymentRegion ApplicationName: !Ref ApplicationName ECSPort: !Ref ECSPort + DomainName: !Ref DomainName + AcmCertificateArn: !Ref AcmCertificateArn ECSClusterStack: Type: 'AWS::CloudFormation::Stack' DependsOn: ECSNetworkStack Properties: - TemplateURL: !Join [ '', [ !Ref ChildTemplateBasePath, ecs-cluster.yml ] ] + TemplateURL: !Sub + - https://s3.amazonaws.com/${CloudFormationS3Bucket}/${ApplicationName}/Automated/${CFNTemplateFilename} + - CloudFormationS3Bucket: !ImportValue + 'Fn::Sub': '${Environment}-S3BucketCloudFormation' + CFNTemplateFilename: ecs-cluster.yml Parameters: Environment: !Ref Environment Region: !Ref DeploymentRegion @@ -259,13 +304,21 @@ Resources: SNSTopicName: !Ref LegalServiceSNSTopicName LegalConfigS3BucketName: !Ref LegalConfigS3BucketName ECSMemoryAllocation: !Ref ECSMemoryAllocation + DomainName: !Ref DomainName + HostedZoneName: !Ref HostedZoneName + VersionNumber: !Ref VersionNumber + ServiceName: !Ref ServiceName #### Legal Repository DB ############################################################# LegalRepositoryStack: Type: 'AWS::CloudFormation::Stack' Properties: - TemplateURL: !Join [ '', [ !Ref ChildTemplateBasePath, legal-repository.yml ] ] + TemplateURL: !Sub + - https://s3.amazonaws.com/${CloudFormationS3Bucket}/${ApplicationName}/Automated/${CFNTemplateFilename} + - CloudFormationS3Bucket: !ImportValue + 'Fn::Sub': '${Environment}-S3BucketCloudFormation' + CFNTemplateFilename: legal-repository.yml Parameters: Environment: !Ref Environment Region: !Ref DeploymentRegion @@ -277,7 +330,11 @@ Resources: Type: 'AWS::CloudFormation::Stack' DependsOn: IAMCredentialsStack Properties: - TemplateURL: !Join [ '', [ !Ref ChildTemplateBasePath, config-bucket.yml ] ] + TemplateURL: !Sub + - https://s3.amazonaws.com/${CloudFormationS3Bucket}/${ApplicationName}/Automated/${CFNTemplateFilename} + - CloudFormationS3Bucket: !ImportValue + 'Fn::Sub': '${Environment}-S3BucketCloudFormation' + CFNTemplateFilename: config-bucket.yml Parameters: Environment: !Ref Environment Region: !Ref DeploymentRegion diff --git a/provider/legal-aws/CloudFormation/Params/dev.template_configuration.json b/provider/legal-aws/CloudFormation/Params/dev.template_configuration.json index a417686f5..d580c998f 100644 --- a/provider/legal-aws/CloudFormation/Params/dev.template_configuration.json +++ b/provider/legal-aws/CloudFormation/Params/dev.template_configuration.json @@ -2,7 +2,6 @@ "Parameters" : { "Environment" : "dev", "DeploymentRegion" : "us-east-1", - "ChildTemplateBasePath" : "https://s3.amazonaws.com/dev-os-legal-cloudformation-scripts/Automated/", "ApplicationName" : "os-legal", "KeyName": "legal-ecs-keypair", "DesiredCapacity": "1", @@ -15,9 +14,14 @@ "LegalServiceIamKeyRotationSerial": "1", "LegalServiceSNSTopicName": "osdu-legal-messages", "LegalServiceSQSQueueName": "osdu-legal-queue", - "ECSPort": "80", + "ECSPort": "443", "ECSCPUAllocation": "1024", - "ECSMemoryAllocation": "3072" + "ECSMemoryAllocation": "3072", + "DomainName": "", + "HostedZoneName": "", + "AcmCertificateArn": "", + "ServiceName": "legal", + "VersionNumber": "0.0.5-SNAPSHOT" }, "Tags" : { "Environment" : "dev" diff --git a/provider/legal-aws/CloudFormation/Params/prod.template_configuration.json b/provider/legal-aws/CloudFormation/Params/prod.template_configuration.json index c7a512be4..81c36ab18 100644 --- a/provider/legal-aws/CloudFormation/Params/prod.template_configuration.json +++ b/provider/legal-aws/CloudFormation/Params/prod.template_configuration.json @@ -2,7 +2,6 @@ "Parameters" : { "Environment" : "prod", "DeploymentRegion" : "us-east-1", - "ChildTemplateBasePath" : "https://s3.amazonaws.com/prod-os-legal-cloudformation-scripts/Automated/", "ApplicationName" : "os-legal", "KeyName": "legal-ecs-keypair", "DesiredCapacity": "1", @@ -13,9 +12,14 @@ "DataStorageS3BucketName": "osdu-legal-config", "LegalServiceIamUsername": "service-user-os-legal", "LegalServiceIamKeyRotationSerial": "1", - "ECSPort": "80", + "ECSPort": "443", "ECSCPUAllocation": "1024", - "ECSMemoryAllocation": "3072" + "ECSMemoryAllocation": "3072", + "DomainName": "", + "HostedZoneName": "", + "AcmCertificateArn": "", + "ServiceName": "legal", + "VersionNumber": "0.0.5-SNAPSHOT" }, "Tags" : { "Environment" : "prod" diff --git a/provider/legal-aws/CloudFormation/Params/uat.template_configuration.json b/provider/legal-aws/CloudFormation/Params/uat.template_configuration.json index afd6e8fb1..6d83e64ed 100644 --- a/provider/legal-aws/CloudFormation/Params/uat.template_configuration.json +++ b/provider/legal-aws/CloudFormation/Params/uat.template_configuration.json @@ -2,7 +2,6 @@ "Parameters" : { "Environment" : "uat", "DeploymentRegion" : "us-east-1", - "ChildTemplateBasePath" : "https://s3.amazonaws.com/uat-os-legal-cloudformation-scripts/Automated/", "ApplicationName" : "os-legal", "KeyName": "legal-ecs-keypair", "DesiredCapacity": "1", @@ -13,9 +12,14 @@ "DataStorageS3BucketName": "osdu-legal-config", "LegalServiceIamUsername": "service-user-os-legal", "LegalServiceIamKeyRotationSerial": "1", - "ECSPort": "80", + "ECSPort": "443", "ECSCPUAllocation": "1024", - "ECSMemoryAllocation": "3072" + "ECSMemoryAllocation": "3072", + "DomainName": "", + "HostedZoneName": "", + "AcmCertificateArn": "", + "ServiceName": "legal", + "VersionNumber": "0.0.5-SNAPSHOT" }, "Tags" : { "Environment" : "uat" diff --git a/provider/legal-aws/Dockerfile b/provider/legal-aws/Dockerfile index 6e108d41e..97892b25c 100644 --- a/provider/legal-aws/Dockerfile +++ b/provider/legal-aws/Dockerfile @@ -13,11 +13,14 @@ # limitations under the License. FROM amazoncorretto:8 -ARG JAR_VERSION -ENV JAR_FILE=legal-aws-${JAR_VERSION}-spring-boot.jar +ARG versionNumber + +ARG service +ENV serviceName=${service}-aws +ENV awsJar=${serviceName}-${versionNumber}-spring-boot.jar WORKDIR / -COPY provider/legal-aws/target/$JAR_FILE $JAR_FILE +COPY provider/${serviceName}/target/${awsJar} ${awsJar} EXPOSE 8080 -CMD java -jar $JAR_FILE +CMD ["sh","-c", " java -jar ${awsJar}"] \ No newline at end of file diff --git a/provider/legal-aws/buildspec-jar-deploy.yml b/provider/legal-aws/buildspec-jar-deploy.yml new file mode 100644 index 000000000..df2329eca --- /dev/null +++ b/provider/legal-aws/buildspec-jar-deploy.yml @@ -0,0 +1,64 @@ +# Copyright © Amazon Web Services +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +version: 0.2 + +phases: + install: + runtime-versions: + java: openjdk8 + commands: + - echo Entered the install phase... + - apt-get update -y + - apt-get install -y maven + - java -version + - mvn clean # .m2 is not created until the first Maven command + - cp ./provider/legal-aws/maven/settings.xml /root/.m2/settings.xml # copy the AWS-specific settings.xml to the CodeBuild instance's .m2 folder + - cat /root/.m2/settings.xml + - java -version + - export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64 + - echo $JAVA_HOME + - mvn -version + - echo "Look below for M2 bucket name:" + - echo $M2_REPO_S3_BUCKET + - aws s3 sync s3://$M2_REPO_S3_BUCKET /root/.m2 # copy previous state of the shared libraries' .m2 folder from S3 to local + - nohup /usr/local/bin/dockerd --host=unix:///var/run/docker.sock --host=tcp://127.0.0.1:2375 --storage-driver=overlay2& # start the Docker Daemon + - timeout 15 sh -c "until docker info; do echo .; sleep 1; done" # wait for Docker to be ready before proceeding to the build steps + build: + commands: + - echo os-legal Java build started on `date`... + - java -version + - export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64 + - mvn -version + - echo All environment variables + - printenv + - mvn clean test -e -pl legal-core,provider/legal-aws + - echo ...os-legal Java build completed on `date`. + - echo os-legal beginning packaging to jar... + # NOTE: we have to be extremely specific in this command, both with the profiles AND the modules to do two things: + # (1) ensure that the core is explicitly built first, so that it doesn't look for artifacts that may not exist yet on + # ADO in order to build the AWS provider module, and (2) exclude GCP so that it doesn't fail due to errors that the + # GCP resources don't exist (we aren't building them on AWS, so they definitely are 'missing', and are missing + # dependencies for the GCP tests to pass, anyway). + - mvn clean install '-Plegal-aws,!legal-gcp' -pl legal-core,provider/legal-aws -Ddeployment.environment=$ENVIRONMENT + - echo Uploading os-legal JAR to S3... + - aws s3 cp provider/$JAR_SERVICE_BASE-aws/target s3://$JAR_DEPLOY_S3_BUCKET/$JAR_SERVICE_BASE-aws --recursive --exclude "*" --include "*.jar" # build and push the JAR(s) to S3 + +cache: + paths: + - '/root/.m2/**/*' + +artifacts: + files: + - '**/*' diff --git a/provider/legal-aws/buildspec-post-deploy.yml b/provider/legal-aws/buildspec-post-deploy.yml index a137cc3ad..7a8c6b68e 100644 --- a/provider/legal-aws/buildspec-post-deploy.yml +++ b/provider/legal-aws/buildspec-post-deploy.yml @@ -30,6 +30,9 @@ phases: - export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64 - echo $JAVA_HOME - mvn -version + - echo "Look below for M2 bucket name:" + - echo $M2_REPO_S3_BUCKET + - aws s3 sync s3://$M2_REPO_S3_BUCKET /root/.m2 # copy previous state of the shared libraries' .m2 folder from S3 to local - nohup /usr/local/bin/dockerd --host=unix:///var/run/docker.sock --host=tcp://127.0.0.1:2375 --storage-driver=overlay2& # start the Docker Daemon - timeout 15 sh -c "until docker info; do echo .; sleep 1; done" # wait for Docker to be ready before proceeding to the build steps pre_build: @@ -45,21 +48,26 @@ phases: - java -version - export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64 - mvn -version - - echo Setting environment variables from CloudFormation Exports... # use the AWS CLI commands to query for the CloudFormation export values created in the previous step and set the required environment variables + - echo Setting variables from CloudFormation Exports... # use the AWS CLI commands to query for the CloudFormation export values created in the previous step and set the required environment variables - echo Environment - $ENVIRONMENT - echo AWSRegion - $AWS_REGION - echo AWSAccountID - $AWS_ACCOUNT_ID - - export SNS_TOPIC_NAME=$(aws cloudformation list-exports --query "Exports[?Name=='$ENVIRONMENT-OSDUStorageSNSTopic'].[Value]" --output text --region $AWS_REGION) - - export S3_LEGAL_CONFIG_BUCKET=$(aws cloudformation list-exports --query "Exports[?Name=='$ENVIRONMENT-S3BucketLegalConfig'].[Value]" --output text --region $AWS_REGION) + - export VERSIONNUMBER=$(aws cloudformation list-exports --query "Exports[?Name=='$ENVIRONMENT-$APPLICATION_NAME-JarVersionNumber'].[Value]" --output text --region $AWS_REGION) + - export SERVICE=$(aws cloudformation list-exports --query "Exports[?Name=='$ENVIRONMENT-$APPLICATION_NAME-JarServiceName'].[Value]" --output text --region $AWS_REGION) - echo ...finished setting environment variables! - echo All environment variables - printenv - - mvn clean test -e -pl legal-core,provider/legal-aws -Ddeployment.environment=$ENVIRONMENT -Daws.accessKeyId=$AWS_SECRET_KEY -Daws.secretKey=$AWS_ACCESS_KEY_ID -Dazure.devops.token=$VSTS_FEED_TOKEN -Dazure.devops.username=$VSTS_FEED_USER -DSNS_TOPIC_NAME=$SNS_TOPIC_NAME -DS3_LEGAL_CONFIG_BUCKET=$S3_LEGAL_CONFIG_BUCKET -DAWS_ACCOUNT_ID=$AWS_ACCOUNT_ID -DAWS_REGION=$AWS_REGION -DaltSnapshotDeploymentRepository=snapshot::default::file:../../local-snapshots-dir -DaltReleaseDeploymentRepository=release::default::file:../../local-release-dir -DaltDeploymentRepository=release::default::file:../../local-release-dir + - mvn clean test -pl legal-core,provider/legal-aws - echo ...os-legal Java build completed on `date`. - echo os-legal beginning packaging to jar... - - mvn clean deploy -e -pl legal-core,provider/legal-aws -Ddeployment.environment=$ENVIRONMENT -Dazure.devops.token=$VSTS_FEED_TOKEN -Dazure.devops.username=$VSTS_FEED_USER -DaltSnapshotDeploymentRepository=snapshot::default::file:../../local-snapshots-dir -DaltReleaseDeploymentRepository=release::default::file:../../local-release-dir -DaltDeploymentRepository=release::default::file:../../local-release-dir + # NOTE: we have to be extremely specific in this command, both with the profiles AND the modules to do two things: + # (1) ensure that the core is explicitly built first, so that it doesn't look for artifacts that may not exist yet on + # ADO in order to build the AWS provider module, and (2) exclude GCP so that it doesn't fail due to errors that the + # GCP resources don't exist (we aren't building them on AWS, so they definitely are 'missing', and are missing + # dependencies for the GCP tests to pass, anyway). + - mvn clean install '-Plegal-aws,!legal-gcp' -pl legal-core,provider/legal-aws -Dversion.number=$VERSIONNUMBER -Ddeployment.environment=$ENVIRONMENT - echo os-legal Docker image build started on `date`... - - docker build -f provider/legal-aws/Dockerfile -t $REPOSITORY_URI:latest . + - docker build -f provider/legal-aws/Dockerfile -t $REPOSITORY_URI:latest --build-arg versionNumber=$VERSIONNUMBER --build-arg service=$SERVICE . - docker tag $REPOSITORY_URI:latest $REPOSITORY_URI:$IMAGE_TAG - echo ...os-legal Docker image build completed on `date`. - echo Pushing the Docker image to ECR... diff --git a/provider/legal-aws/buildspec-pre-deploy.yml b/provider/legal-aws/buildspec-pre-deploy.yml index 5fd7313b1..2e9b33ffe 100644 --- a/provider/legal-aws/buildspec-pre-deploy.yml +++ b/provider/legal-aws/buildspec-pre-deploy.yml @@ -17,12 +17,11 @@ version: 0.1 phases: build: commands: - - echo Starting 'Copying CloudFormation scripts to S3://$CFN_S3_BUCKET' -# - cd provider/legal-aws + - echo Starting 'Copying CloudFormation scripts to S3://$CFN_S3_BUCKET/$APPLICATION_NAME' - pwd - ls - - aws s3 cp ./provider/legal-aws/CloudFormation "s3://$CFN_S3_BUCKET" --exclude "*" --include "*.yml" --recursive --debug - - echo Ending 'Ending CloudFormation scripts to S3://$CFN_S3_BUCKET' + - aws s3 cp ./provider/legal-aws/CloudFormation "s3://$CFN_S3_BUCKET/$APPLICATION_NAME" --exclude "*" --include "*.yml" --recursive --debug + - echo Ending 'Ending CloudFormation scripts to S3://$CFN_S3_BUCKET/$APPLICATION_NAME' artifacts: files: diff --git a/provider/legal-aws/pom.xml b/provider/legal-aws/pom.xml index 1ac763823..97bac0d43 100644 --- a/provider/legal-aws/pom.xml +++ b/provider/legal-aws/pom.xml @@ -27,19 +27,19 @@ <artifactId>legal-aws</artifactId> <packaging>jar</packaging> - <version>0.0.5-SNAPSHOT</version> <properties> - <aws.version>1.11.637</aws.version> + <aws.version>1.11.651</aws.version> <deployment.environment>dev</deployment.environment> + <version.number>0.0.5-SNAPSHOT</version.number> </properties> <dependencies> <!-- Internal packages --> <dependency> <groupId>org.opengroup.osdu.core.aws</groupId> - <artifactId>aws-osdu-util</artifactId> - <version>0.0.9</version> + <artifactId>os-core-lib-aws</artifactId> + <version>0.0.10</version> </dependency> <dependency> <groupId>org.opengroup.osdu</groupId> @@ -49,30 +49,30 @@ <dependency> <groupId>org.opengroup.osdu.legal</groupId> <artifactId>legal-core</artifactId> - <version>0.0.5-SNAPSHOT</version> + <version>${version.number}</version> </dependency> <!-- AWS-managed packages --> <dependency> <groupId>com.amazonaws</groupId> <artifactId>aws-java-sdk-bom</artifactId> - <version>1.11.651</version> + <version>${aws.version}</version> <type>pom</type> </dependency> <dependency> <groupId>com.amazonaws</groupId> <artifactId>aws-java-sdk</artifactId> - <version>1.11.651</version> + <version>${aws.version}</version> </dependency> <dependency> <groupId>com.amazonaws</groupId> <artifactId>aws-java-sdk-core</artifactId> - <version>1.11.651</version> + <version>${aws.version}</version> </dependency> <dependency> <groupId>com.amazonaws</groupId> <artifactId>aws-java-sdk-dynamodb</artifactId> - <version>1.11.651</version> + <version>${aws.version}</version> </dependency> <!-- Third party Apache 2.0 license packages --> @@ -116,15 +116,22 @@ <scope>test</scope> </dependency> <dependency> - <groupId>org.mockito</groupId> - <artifactId>mockito-all</artifactId> - <version>1.10.19</version> + <groupId>org.powermock</groupId> + <artifactId>powermock-api-mockito2</artifactId> + <version>2.0.2</version> <scope>test</scope> </dependency> <dependency> <groupId>org.powermock</groupId> <artifactId>powermock-module-junit4</artifactId> <version>2.0.2</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.mockito</groupId> + <artifactId>mockito-core</artifactId> + <version>3.0.0</version> + <scope>test</scope> </dependency> </dependencies> @@ -177,4 +184,43 @@ </plugins> </build> + <profiles> + <profile> + <id>aws-dev</id> + <activation> + <property> + <name>deployment.environment</name> + <value>dev</value> + </property> + </activation> + <properties> + <aws.version>1.11.651</aws.version> + </properties> + </profile> + <profile> + <id>aws-uat</id> + <activation> + <property> + <name>deployment.environment</name> + <value>uat</value> + </property> + </activation> + <properties> + <aws.version>1.11.632</aws.version> + </properties> + </profile> + <profile> + <id>aws-prod</id> + <activation> + <property> + <name>deployment.environment</name> + <value>prod</value> + </property> + </activation> + <properties> + <aws.version>1.11.632</aws.version> + </properties> + </profile> + </profiles> + </project> \ No newline at end of file diff --git a/provider/legal-aws/src/main/java/org/opengroup/osdu/legal/aws/tags/dataaccess/LegalTagRepositoryImpl.java b/provider/legal-aws/src/main/java/org/opengroup/osdu/legal/aws/tags/dataaccess/LegalTagRepositoryImpl.java index 468275f44..bc5d06522 100644 --- a/provider/legal-aws/src/main/java/org/opengroup/osdu/legal/aws/tags/dataaccess/LegalTagRepositoryImpl.java +++ b/provider/legal-aws/src/main/java/org/opengroup/osdu/legal/aws/tags/dataaccess/LegalTagRepositoryImpl.java @@ -19,9 +19,9 @@ import org.opengroup.osdu.core.aws.dynamodb.DynamoDBQueryHelper; import org.opengroup.osdu.core.aws.dynamodb.QueryPageResult; import org.opengroup.osdu.core.common.model.legal.ListLegalTagArgs; import org.opengroup.osdu.core.common.model.legal.LegalTag; -import org.opengroup.osdu.legal.provider.interfaces.ILegalTagRepository; import org.opengroup.osdu.core.common.model.http.AppException; +import org.opengroup.osdu.legal.provider.interfaces.ILegalTagRepository; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Repository; diff --git a/provider/legal-aws/src/main/resources/application.properties b/provider/legal-aws/src/main/resources/application.properties index 37fafb4a3..62ec9ab34 100644 --- a/provider/legal-aws/src/main/resources/application.properties +++ b/provider/legal-aws/src/main/resources/application.properties @@ -6,13 +6,9 @@ server.port=${APPLICATION_PORT} JAVA_HEAP_OPTS=-Xms${JAVA_HEAP_MEMORY}M -Xmx${JAVA_HEAP_MEMORY}M JAVA_GC_OPTS=-XX:+UseG1GC -XX:+UseStringDeduplication -XX:InitiatingHeapOccupancyPercent=45 -## Spring Configuration -spring.security.user.name=opendes@byoc.local -spring.security.user.password=123 -spring.security.user.roles=service.legal.admin ## AWS Lambda configuration -aws.lambda.get-groups-function-name=dev-os-entitlements-GroupsFunction-1DTM5841SUIFO +aws.lambda.get-groups-function-name=${ENVIRONMENT}-os-entitlements-GroupsFunction REGION=${AWS_REGION} AUTHORIZE_API=notused @@ -28,7 +24,7 @@ aws.dynamodb.endpoint=dynamodb.${AWS_REGION}.amazonaws.com ## AWS S3 configuration aws.s3.region=${AWS_REGION} aws.s3.endpoint=s3.${AWS_REGION}.amazonaws.com -aws.s3.legal.config.bucket-name=${ENVIRONMENT}-${S3_LEGAL_CONFIG_BUCKET} +aws.s3.legal.config.bucket-name=${S3_LEGAL_CONFIG_BUCKET} aws.s3.legal.config.file-name=Legal_COO.json ## AWS SNS configuration diff --git a/provider/legal-aws/src/test/java/org/opengroup/osdu/legal/aws/api/LegalTagRepositoryImplTest.java b/provider/legal-aws/src/test/java/org/opengroup/osdu/legal/aws/api/LegalTagRepositoryImplTest.java index d6e4ca7f8..6b59e01e8 100644 --- a/provider/legal-aws/src/test/java/org/opengroup/osdu/legal/aws/api/LegalTagRepositoryImplTest.java +++ b/provider/legal-aws/src/test/java/org/opengroup/osdu/legal/aws/api/LegalTagRepositoryImplTest.java @@ -20,6 +20,7 @@ import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.*; +import org.mockito.runners.MockitoJUnitRunner; import org.opengroup.osdu.core.aws.dynamodb.DynamoDBQueryHelper; import org.opengroup.osdu.core.aws.dynamodb.QueryPageResult; import org.opengroup.osdu.legal.aws.tags.dataaccess.LegalDoc; @@ -27,7 +28,6 @@ import org.opengroup.osdu.legal.aws.tags.dataaccess.LegalTagRepositoryImpl; import org.opengroup.osdu.core.common.model.legal.ListLegalTagArgs; import org.opengroup.osdu.core.common.model.legal.LegalTag; import org.springframework.boot.test.context.SpringBootTest; -import org.mockito.junit.MockitoJUnitRunner; import java.io.UnsupportedEncodingException; import java.util.*; diff --git a/provider/legal-ibm/README.md b/provider/legal-ibm/README.md new file mode 100644 index 000000000..2fba562be --- /dev/null +++ b/provider/legal-ibm/README.md @@ -0,0 +1,43 @@ +# IBM's backend for legal + +## A note about authentication and entitlements + +OAuth2 JWT token authentication is now enforced + +## A note about publishing legal tag changes + +This is not implemented yet, the Bean that takes the pubsub requests is a Mock. +However, since we are using cloudant, we could keep it that way and leverage +cloudant's change stream + +## Testing + +For testing a Cloudant instance is needed. Once you have a cloudant instance +in IBMCloud, download the credentials JSON somewhere, and point the IBM_CREDENTIALS_FILE +environment variable to it: + + $> export IBM_CREDENTIALS_FILE=/path/to/credentials.json + + +### Running the unit tests + +To run the unit tests, go to `provider/legal-ibm` and run: + + $> mvn test + +### Running the acceptance tests + +For this it ideal to open another terminal with the IBM_CREDENTIALS_FILE variable set also. + +In one terminal go to `testing/legal-test-ibm` and run: + + $> setup_acceptance.sh + $> run_service.sh + +In the other, also go to `testing/legal-test-ibm` and run: + + $> run_tests.sh + +To delete the test databases, just run: + + $> teardown_acceptance.sh diff --git a/provider/legal-ibm/pom.xml b/provider/legal-ibm/pom.xml new file mode 100644 index 000000000..83b71cf9f --- /dev/null +++ b/provider/legal-ibm/pom.xml @@ -0,0 +1,107 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <parent> + <artifactId>legal-service</artifactId> + <groupId>org.opengroup.osdu.legal</groupId> + <version>0.0.5-SNAPSHOT</version> + <relativePath>../../pom.xml</relativePath> + </parent> + <modelVersion>4.0.0</modelVersion> + + <artifactId>legal-ibm</artifactId> + <packaging>jar</packaging> + <properties> + <osdu.ibmcore.version>0.0.13-SNAPSHOT</osdu.ibmcore.version> + </properties> + + <dependencies> + <dependency> + <groupId>org.opengroup.osdu.legal</groupId> + <artifactId>legal-core</artifactId> + <version>0.0.5-SNAPSHOT</version> + </dependency> + <dependency> + <groupId>org.opengroup.osdu</groupId> + <artifactId>os-core-lib-ibm</artifactId> + <version>${osdu.ibmcore.version}</version> + </dependency> + + <dependency> + <groupId>org.projectlombok</groupId> + <artifactId>lombok</artifactId> + </dependency> + + <!-- Test Dependencies --> + <!-- https://mvnrepository.com/artifact/org.powermock/powermock-api-mockito2 --> + <dependency> + <groupId>org.powermock</groupId> + <artifactId>powermock-api-mockito2</artifactId> + <version>2.0.2</version> + <scope>test</scope> + </dependency> + <!-- https://mvnrepository.com/artifact/org.powermock/powermock-module-junit4 --> + <dependency> + <groupId>org.powermock</groupId> + <artifactId>powermock-module-junit4</artifactId> + <version>2.0.2</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.mockito</groupId> + <artifactId>mockito-core</artifactId> + <version>3.0.0</version> + <scope>test</scope> + </dependency> + + <!-- To configure logback with groovy --> + <dependency> + <groupId>org.codehaus.groovy</groupId> + <artifactId>groovy</artifactId> + <version>2.5.8</version> + <type>pom</type> + </dependency> + + <dependency> + <groupId>org.codehaus.groovy</groupId> + <artifactId>groovy-jsr223</artifactId> + <version>2.5.8</version> + <type>pom</type> + </dependency> + + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-test</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.springframework.security</groupId> + <artifactId>spring-security-test</artifactId> + <scope>test</scope> + </dependency> + + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-maven-plugin</artifactId> + <executions> + <execution> + <goals> + <goal>repackage</goal> + </goals> + <configuration> + <classifier>spring-boot</classifier> + <mainClass> + org.opengroup.osdu.legal.ibm.LegalApplication + </mainClass> + </configuration> + </execution> + </executions> + </plugin> + </plugins> + </build> +</project> diff --git a/provider/legal-ibm/src/main/java/org/opengroup/osdu/legal/ibm/LegalApplication.java b/provider/legal-ibm/src/main/java/org/opengroup/osdu/legal/ibm/LegalApplication.java new file mode 100644 index 000000000..65edb1f99 --- /dev/null +++ b/provider/legal-ibm/src/main/java/org/opengroup/osdu/legal/ibm/LegalApplication.java @@ -0,0 +1,29 @@ +// (C) Copyright IBM Corporation 2019 +// U.S. Government Users Restricted Rights: Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package org.opengroup.osdu.legal.ibm; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.ComponentScan; + +@ComponentScan("org.opengroup.osdu") +@SpringBootApplication +public class LegalApplication { + + public static void main(String[] args) { + SpringApplication.run(LegalApplication.class, args); + } +} diff --git a/provider/legal-ibm/src/main/java/org/opengroup/osdu/legal/ibm/countries/StorageReaderFactoryImpl.java b/provider/legal-ibm/src/main/java/org/opengroup/osdu/legal/ibm/countries/StorageReaderFactoryImpl.java new file mode 100644 index 000000000..4780610af --- /dev/null +++ b/provider/legal-ibm/src/main/java/org/opengroup/osdu/legal/ibm/countries/StorageReaderFactoryImpl.java @@ -0,0 +1,110 @@ +// (C) Copyright IBM Corporation 2019 +// U.S. Government Users Restricted Rights: Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package org.opengroup.osdu.legal.ibm.countries; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.MalformedURLException; +import java.util.concurrent.ConcurrentHashMap; + +import javax.inject.Inject; + +import org.opengroup.osdu.core.common.logging.JaxRsDpsLog; +import org.opengroup.osdu.core.common.model.http.AppException; +import org.opengroup.osdu.core.common.model.tenant.TenantInfo; +import org.opengroup.osdu.core.ibm.auth.ServiceCredentials; +import org.opengroup.osdu.core.ibm.cloudant.IBMCloudantClientFactory; +import org.opengroup.osdu.legal.provider.interfaces.IStorageReader; +import org.opengroup.osdu.legal.provider.interfaces.IStorageReaderFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.core.io.ResourceLoader; +import org.springframework.stereotype.Component; + +/** + * @author mbayser + * + */ +@Component +public class StorageReaderFactoryImpl implements IStorageReaderFactory { + + private ConcurrentHashMap<String, IStorageReader> readers = new ConcurrentHashMap<>(); + + @Value("${ibm.legal.db.url}") + private String dbUrl; + @Value("${ibm.legal.db.apikey:#{null}}") + private String apiKey; + @Value("${ibm.legal.db.user:#{null}}") + private String dbUser; + @Value("${ibm.legal.db.password:#{null}}") + private String dbPassword; + @Value("${ibm.env.prefix:local-dev}") + private String dbNamePrefix; + + @Value("${ibm.legal.db.credentials:#{null}}") + private String credentialsJSON; + + @Value("${ibm.countries.db.name:countries}") + private String dbName; + + @Inject + private ResourceLoader resourceLoader; + + @Inject + private JaxRsDpsLog logger; + + + /* (non-Javadoc) + * @see org.opengroup.osdu.legal.countries.StorageReaderFactory#getReader(org.opengroup.osdu.core.multitenancy.TenantInfo, java.lang.String) + */ + @Override + + public IStorageReader getReader(TenantInfo tenant, String projectRegion) { + + ServiceCredentials creds = null; + + if (dbUrl != null && apiKey != null) { + creds = new ServiceCredentials(dbUrl, apiKey); + } else if (dbUrl != null && dbUser != null) { + creds = new ServiceCredentials(dbUrl, dbUser, dbPassword); + } else { + try { + creds = new ServiceCredentials(new InputStreamReader(resourceLoader.getResource(credentialsJSON).getInputStream())); + } catch (IOException e) { + logger.error(" 500, Malformed URL Invalid cloudant URL", e); + throw new AppException(500, "Malformed URL", "Invalid cloudant URL", e); + } + } + + IBMCloudantClientFactory cloudantFactory = new IBMCloudantClientFactory(creds); + + return getReader(cloudantFactory, tenant, projectRegion, dbNamePrefix, dbName); + } + + public IStorageReader getReader(IBMCloudantClientFactory cloudantFactory, TenantInfo tenant, String projectRegion, String dbNamePrefix, String dbName) { + + final String key = tenant+":"+projectRegion; + readers.computeIfAbsent(key, s -> { + try { + return new StorageReaderImpl(tenant, projectRegion, cloudantFactory, dbNamePrefix, dbName); + } catch (MalformedURLException | FileNotFoundException e) { + logger.error("Error creating a Storage Reader", e); + return null; + } + }); + return readers.get(key); + } +} \ No newline at end of file diff --git a/provider/legal-ibm/src/main/java/org/opengroup/osdu/legal/ibm/countries/StorageReaderImpl.java b/provider/legal-ibm/src/main/java/org/opengroup/osdu/legal/ibm/countries/StorageReaderImpl.java new file mode 100644 index 000000000..e85b1cee8 --- /dev/null +++ b/provider/legal-ibm/src/main/java/org/opengroup/osdu/legal/ibm/countries/StorageReaderImpl.java @@ -0,0 +1,111 @@ +// (C) Copyright IBM Corporation 2019 +// U.S. Government Users Restricted Rights: Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package org.opengroup.osdu.legal.ibm.countries; + +import static com.cloudant.client.api.query.Expression.eq; +import static com.cloudant.client.api.query.Operation.and; + +import java.io.FileNotFoundException; +import java.lang.ref.WeakReference; +import java.net.MalformedURLException; +import java.util.concurrent.atomic.AtomicLong; + +import javax.inject.Inject; + +import org.opengroup.osdu.core.common.logging.JaxRsDpsLog; +import org.opengroup.osdu.core.common.model.http.AppException; +import org.opengroup.osdu.core.common.model.tenant.TenantInfo; +import org.opengroup.osdu.core.ibm.cloudant.IBMCloudantClientFactory; +import org.opengroup.osdu.legal.provider.interfaces.IStorageReader; + +import com.cloudant.client.api.CloudantClient; +import com.cloudant.client.api.Database; +import com.cloudant.client.api.query.QueryBuilder; +import com.cloudant.client.api.query.QueryResult; +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; + + +/** + * @author mbayser + * + */ +public class StorageReaderImpl implements IStorageReader { + + private final TenantInfo tenantInfo; + private final String cloudRegion; + private final String dbNamePrefix; + private final String dbName; + private final IBMCloudantClientFactory cloudantFactory; + private final CloudantClient cloudant; + private static final long CACHE_EXPIRATION_MS = 60000; + private AtomicLong lastUpdate = new AtomicLong(0); + private WeakReference<byte[]> cache = new WeakReference<byte[]>(null); + + + public StorageReaderImpl(TenantInfo tenantInfo, String projectRegion, IBMCloudantClientFactory cloudantFactory, String dbNamePrefix, String dbName) throws MalformedURLException, FileNotFoundException { + this.tenantInfo = tenantInfo; + this.cloudRegion = projectRegion; + this.dbNamePrefix = dbNamePrefix; + this.dbName = dbName; + this.cloudantFactory = cloudantFactory; + this.cloudant = cloudantFactory.getClient(); + } + + @Inject + private JaxRsDpsLog logger; + + /* (non-Javadoc) + * @see org.opengroup.osdu.legal.countries.StorageReader#readAllBytes() + */ + @Override + public byte[] readAllBytes() { + //There is a race condition here, but other than a few wasteful HTTP requests it does no harm. + // A mutex here on the other hand could lead to increased latency. + if ((lastUpdate.get() + CACHE_EXPIRATION_MS) > System.currentTimeMillis()) { + byte[] c = cache.get(); + if (c != null) { + return c; + } + } + + try { + + Database db = cloudantFactory.getDatabase(cloudant, dbNamePrefix, dbName); + + QueryResult<JsonObject> result = db.query(new QueryBuilder(and(eq("tenant", tenantInfo.getName()), eq("region", cloudRegion))) + .fields("name", "alpha2", "numeric", "residencyRisk", "typesNotApplyDataResidency").build(), JsonObject.class); + + // The encapsulation of the Database class sucks in this case. If we could grab its internal + // import com.cloudant.client.org.lightcouch.CouchDbClient we could avoid de-serializing the + // response just to serialize it again. + JsonArray array = new JsonArray(); + for (JsonObject s: result.getDocs()) { + array.add(s); + } + byte[] blob = cloudant.getGson().toJson(array).getBytes(); + + cache = new WeakReference<byte[]>(blob); + lastUpdate.set(System.currentTimeMillis()); + + return blob; + } catch (MalformedURLException e) { + logger.error(" 500, Malformed URL Invalid cloudant URL", e); + throw new AppException(500, "Malformed URL", "Invalid cloudant URL", e); + } + } + +} diff --git a/provider/legal-ibm/src/main/java/org/opengroup/osdu/legal/ibm/di/DevNullPublisher.java b/provider/legal-ibm/src/main/java/org/opengroup/osdu/legal/ibm/di/DevNullPublisher.java new file mode 100644 index 000000000..ab4ca44b3 --- /dev/null +++ b/provider/legal-ibm/src/main/java/org/opengroup/osdu/legal/ibm/di/DevNullPublisher.java @@ -0,0 +1,46 @@ +// (C) Copyright IBM Corporation 2019 +// U.S. Government Users Restricted Rights: Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package org.opengroup.osdu.legal.ibm.di; + + +import org.opengroup.osdu.core.common.model.http.DpsHeaders; +import org.opengroup.osdu.core.common.model.legal.StatusChangedTags; +import org.opengroup.osdu.legal.provider.interfaces.ILegalTagPublisher; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.stereotype.Service; + +/** + * @author mbayser + * + */ +@ConditionalOnProperty( + value="ibm.legal.publisher.devnull", + havingValue = "true", + matchIfMissing = false) +@Service +public class DevNullPublisher implements ILegalTagPublisher { + + + /* (non-Javadoc) + * @see org.opengroup.osdu.legal.provider.interfaces.LegalTagPublisher#publish(java.lang.String, org.opengroup.osdu.core.api.DpsHeaders, org.opengroup.osdu.legal.jobs.StatusChangedTags) + */ + @Override + public void publish(String projectId, DpsHeaders headers, StatusChangedTags tags) throws Exception { + // TODO Auto-generated method stub + + } + +} diff --git a/provider/legal-ibm/src/main/java/org/opengroup/osdu/legal/ibm/di/DpsLogFactory.java b/provider/legal-ibm/src/main/java/org/opengroup/osdu/legal/ibm/di/DpsLogFactory.java new file mode 100644 index 000000000..8123e25d8 --- /dev/null +++ b/provider/legal-ibm/src/main/java/org/opengroup/osdu/legal/ibm/di/DpsLogFactory.java @@ -0,0 +1,41 @@ +// (C) Copyright IBM Corporation 2019 +// U.S. Government Users Restricted Rights: Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package org.opengroup.osdu.legal.ibm.di; + +import org.opengroup.osdu.core.common.logging.ILogger; +import org.opengroup.osdu.core.ibm.logging.logger.IBMLoggingProvider; +import org.springframework.beans.factory.config.AbstractFactoryBean; +import org.springframework.stereotype.Component; + +/** + * @author mbayser + * + */ +//@Component +public class DpsLogFactory extends AbstractFactoryBean<ILogger> { + + private IBMLoggingProvider ibmLoggingProvider = new IBMLoggingProvider(); + + @Override + protected ILogger createInstance() throws Exception { + return ibmLoggingProvider.getLogger(); + } + + @Override + public Class<?> getObjectType() { + return ILogger.class; + } +} \ No newline at end of file diff --git a/provider/legal-ibm/src/main/java/org/opengroup/osdu/legal/ibm/jobs/LegalTagPublisherImpl.java b/provider/legal-ibm/src/main/java/org/opengroup/osdu/legal/ibm/jobs/LegalTagPublisherImpl.java new file mode 100644 index 000000000..a9e143e73 --- /dev/null +++ b/provider/legal-ibm/src/main/java/org/opengroup/osdu/legal/ibm/jobs/LegalTagPublisherImpl.java @@ -0,0 +1,65 @@ +// Copyright 2020 IBM Corp. All Rights Reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package org.opengroup.osdu.legal.ibm.jobs; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.inject.Inject; + +import org.opengroup.osdu.core.common.model.http.DpsHeaders; +import org.opengroup.osdu.core.common.model.legal.StatusChangedTag; +import org.opengroup.osdu.core.common.model.legal.StatusChangedTags; +import org.opengroup.osdu.core.ibm.messagebus.IMessageFactory; +import org.opengroup.osdu.legal.provider.interfaces.ILegalTagPublisher; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.stereotype.Component; + +import com.google.gson.Gson; + +@ConditionalOnProperty( + value="ibm.legal.publisher.devnull", + havingValue = "false", + matchIfMissing = true) +@Component +public class LegalTagPublisherImpl implements ILegalTagPublisher { + + @Inject + IMessageFactory mq; + + @Override + public void publish(String projectId, DpsHeaders headers, StatusChangedTags tags) throws Exception { + + final int BATCH_SIZE = 50; + Gson gson = new Gson(); + Map<String, String> message = new HashMap<>(); + + for (int i = 0; i < tags.getStatusChangedTags().size(); i += BATCH_SIZE) { + + List<StatusChangedTag> batch = tags.getStatusChangedTags().subList(i, + Math.min(tags.getStatusChangedTags().size(), i + BATCH_SIZE)); + String json = gson.toJson(batch); + message.put("data", json); + message.put(DpsHeaders.ACCOUNT_ID, headers.getPartitionIdWithFallbackToAccountId()); + message.put(DpsHeaders.DATA_PARTITION_ID, headers.getPartitionIdWithFallbackToAccountId()); + headers.addCorrelationIdIfMissing(); + message.put(DpsHeaders.CORRELATION_ID, headers.getCorrelationId()); + mq.sendMessage(IMessageFactory.LEGAL_QUEUE_NAME, gson.toJson(message)); + + } + + } +} diff --git a/provider/legal-ibm/src/main/java/org/opengroup/osdu/legal/ibm/security/SecurityConfig.java b/provider/legal-ibm/src/main/java/org/opengroup/osdu/legal/ibm/security/SecurityConfig.java new file mode 100644 index 000000000..8fcf9df53 --- /dev/null +++ b/provider/legal-ibm/src/main/java/org/opengroup/osdu/legal/ibm/security/SecurityConfig.java @@ -0,0 +1,24 @@ +package org.opengroup.osdu.legal.ibm.security; + +import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; + +@EnableWebSecurity +@EnableGlobalMethodSecurity(prePostEnabled = true) +public class SecurityConfig extends WebSecurityConfigurerAdapter { + @Override + protected void configure(HttpSecurity http) throws Exception { + http + .csrf().disable() + .authorizeRequests() + .antMatchers("/v2/api-docs", + "/configuration/ui", + "/swagger-resources/**", + "/configuration/security", + "/swagger-ui.html", + "/webjars/**").permitAll() + .anyRequest().authenticated().and().oauth2ResourceServer().jwt(); + } +} diff --git a/provider/legal-ibm/src/main/java/org/opengroup/osdu/legal/ibm/security/WhoamiController.java b/provider/legal-ibm/src/main/java/org/opengroup/osdu/legal/ibm/security/WhoamiController.java new file mode 100644 index 000000000..a76c8ace7 --- /dev/null +++ b/provider/legal-ibm/src/main/java/org/opengroup/osdu/legal/ibm/security/WhoamiController.java @@ -0,0 +1,25 @@ +package org.opengroup.osdu.legal.ibm.security; + +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseBody; + +@Controller +public class WhoamiController { + @RequestMapping(value = {"/", "/whoami"}) + @ResponseBody + public String whoami() { + final Authentication auth = SecurityContextHolder.getContext().getAuthentication(); + + String userName = auth.getName(); + String roles = String.valueOf(auth.getAuthorities()); + String details = String.valueOf(auth.getPrincipal()); + + return "user: " + userName + "<BR>" + + "roles: " + roles + "<BR>" + + "details: " + details; + } +} + diff --git a/provider/legal-ibm/src/main/java/org/opengroup/osdu/legal/ibm/tags/CloudantBackedLegalTag.java b/provider/legal-ibm/src/main/java/org/opengroup/osdu/legal/ibm/tags/CloudantBackedLegalTag.java new file mode 100644 index 000000000..cadec423d --- /dev/null +++ b/provider/legal-ibm/src/main/java/org/opengroup/osdu/legal/ibm/tags/CloudantBackedLegalTag.java @@ -0,0 +1,100 @@ +package org.opengroup.osdu.legal.ibm.tags; +import java.lang.reflect.Type; +import java.sql.Date; +import java.util.Optional; + +import javax.inject.Inject; + +import org.opengroup.osdu.core.common.model.legal.LegalTag; +import org.opengroup.osdu.core.common.model.legal.Properties; +import org.opengroup.osdu.core.common.logging.JaxRsDpsLog; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; +import com.google.gson.JsonPrimitive; +import com.google.gson.JsonSerializationContext; +import com.google.gson.JsonSerializer; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; + +@Getter +@Setter +@ToString(callSuper=true) + +public class CloudantBackedLegalTag extends LegalTag { + + @EqualsAndHashCode.Exclude + private String _rev = null; + @Inject + private static JaxRsDpsLog logger; + + public static final JsonSerializer<LegalTag> serializer = new JsonSerializer<LegalTag>() { + @Override + public JsonElement serialize(LegalTag src, Type typeOfSrc, JsonSerializationContext context) { + JsonObject json = new JsonObject(); + + if (src instanceof CloudantBackedLegalTag) { + json.addProperty("_rev", ((CloudantBackedLegalTag)src).get_rev()); + } + + json.addProperty("_id", src.getId().toString()); + json.addProperty("name", src.getName()); + json.addProperty("description", src.getDescription()); + json.addProperty("is_valid", src.getIsValid()); + + json.add("properties", context.serialize(src.getProperties(), Properties.class)); + + return json; + } + }; + + public static final JsonSerializer<Date> sqlDateSerializer = new JsonSerializer<Date>() { + @Override + public JsonElement serialize(Date src, Type typeOfSrc, JsonSerializationContext context) { + return new JsonPrimitive(src.getTime()); + } + }; + + public static final JsonDeserializer<CloudantBackedLegalTag> deserializer = new JsonDeserializer<CloudantBackedLegalTag>() { + + @Override + public CloudantBackedLegalTag deserialize(JsonElement json, Type arg1, JsonDeserializationContext context) + throws JsonParseException { + + final CloudantBackedLegalTag result = new CloudantBackedLegalTag(); + JsonObject src = json.getAsJsonObject(); + + try { + // Only the _rev object may be null + result.set_rev(Optional.ofNullable(src.get("_rev")).map(JsonElement::getAsString).orElse(null)); + + result.setId(src.get("_id").getAsLong()); + result.setName(src.get("name").getAsString()); + result.setDescription(src.get("description").getAsString()); + result.setIsValid(src.get("is_valid").getAsBoolean()); + result.setProperties(context.deserialize(src.get("properties"), Properties.class)); + + } catch (NullPointerException ex) { + logger.error("Serialized Legal Tag is missing one or more required fields"); + throw new IllegalStateException("Serialized Legal Tag is missing one or more required fields"); + } + return result; + } + + }; + + public static final JsonDeserializer<Date> sqlDateDeserializer = new JsonDeserializer<Date>() { + + @Override + public Date deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) + throws JsonParseException { + return new Date(json.getAsLong()); + } + + }; + +} diff --git a/provider/legal-ibm/src/main/java/org/opengroup/osdu/legal/ibm/tags/CloudantLegalTagRepository.java b/provider/legal-ibm/src/main/java/org/opengroup/osdu/legal/ibm/tags/CloudantLegalTagRepository.java new file mode 100644 index 000000000..55368b99e --- /dev/null +++ b/provider/legal-ibm/src/main/java/org/opengroup/osdu/legal/ibm/tags/CloudantLegalTagRepository.java @@ -0,0 +1,350 @@ +// (C) Copyright IBM Corporation 2019 +// U.S. Government Users Restricted Rights: Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package org.opengroup.osdu.legal.ibm.tags; + +import static com.cloudant.client.api.query.Expression.eq; +import static com.cloudant.client.api.query.Expression.in; + +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.MalformedURLException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; + +import javax.annotation.PostConstruct; +import javax.inject.Inject; + +import org.opengroup.osdu.core.common.model.http.AppException; +import org.opengroup.osdu.core.common.model.legal.LegalTag; +import org.opengroup.osdu.core.common.model.legal.ListLegalTagArgs; +import org.opengroup.osdu.core.ibm.auth.ServiceCredentials; +import org.opengroup.osdu.core.ibm.cloudant.IBMCloudantClientFactory; +import org.opengroup.osdu.legal.provider.interfaces.ILegalTagRepository; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.core.io.ResourceLoader; +import org.springframework.stereotype.Repository; + +import com.cloudant.client.api.CloudantClient; +import com.cloudant.client.api.Database; +import com.cloudant.client.api.model.Response; +import com.cloudant.client.api.query.EmptyExpression; +import com.cloudant.client.api.query.ExecutionStats; +import com.cloudant.client.api.query.QueryBuilder; +import com.cloudant.client.api.query.QueryResult; +import com.cloudant.client.api.query.Selector; +import com.cloudant.client.org.lightcouch.DocumentConflictException; +/** + * @author mbayser + * + */ +@Repository +public class CloudantLegalTagRepository implements ILegalTagRepository { + + @Value("${ibm.legal.db.url}") + private String dbUrl; + @Value("${ibm.legal.db.apikey:#{null}}") + private String apiKey; + @Value("${ibm.legal.db.user:#{null}}") + private String dbUser; + @Value("${ibm.legal.db.password:#{null}}") + private String dbPassword; + @Value("${ibm.env.prefix:local-dev}") + private String dbNamePrefix; + + @Value("${ibm.legal.db.credentials:#{null}}") + private String credentialsJSON; + + @Value("${ibm.legal.db.name:legal-tags}") + private String dbName; + + @Inject + private ResourceLoader resourceLoader; + + private static final Logger logger = LoggerFactory.getLogger(CloudantLegalTagRepository.class); + + private IBMCloudantClientFactory cloudantFactory; + private CloudantClient cloudant; + private Database db = null; + private static final int CLOUDANT_CONFLICT_RETRIES = 10; + + // When using this class as a Bean, there must be a default constructor + // to create the object before the parameters can be injected. Only then + // can the initialization happen + public CloudantLegalTagRepository () { + } + + // This constructor is meant to facilitate testing + public CloudantLegalTagRepository(ServiceCredentials creds, String dbNamePrefix, String dataBaseName) throws MalformedURLException { + doInit(creds, dbNamePrefix, dataBaseName); + } + + @PostConstruct + public void init() throws IOException { + + ServiceCredentials creds = null; + if (dbUrl != null && apiKey != null) { + creds = new ServiceCredentials(dbUrl, apiKey); + } else if (dbUrl != null && dbUser != null) { + creds = new ServiceCredentials(dbUrl, dbUser, dbPassword); + } else { + creds = new ServiceCredentials(new InputStreamReader(resourceLoader.getResource(credentialsJSON).getInputStream())); + } + + doInit(creds, dbNamePrefix, dbName); + + } + + private void doInit(ServiceCredentials creds, String dbNamePrefix, String dataBaseName) throws MalformedURLException { + cloudantFactory = new IBMCloudantClientFactory(creds); + cloudantFactory.getGsonBuilder() + .registerTypeAdapter(java.sql.Date.class, CloudantBackedLegalTag.sqlDateSerializer) + .registerTypeAdapter(java.sql.Date.class, CloudantBackedLegalTag.sqlDateDeserializer) + .registerTypeAdapter(LegalTag.class, CloudantBackedLegalTag.serializer) + .registerTypeAdapter(CloudantBackedLegalTag.class, CloudantBackedLegalTag.serializer) + .registerTypeAdapter(CloudantBackedLegalTag.class, CloudantBackedLegalTag.deserializer); + this.cloudant = cloudantFactory.getClient(); + this.db = cloudantFactory.getDatabase(cloudant, dbNamePrefix, dataBaseName); + } + + @Override + public Long create(LegalTag legalTag) { + Long id = legalTag.getId(); + + if (id == null) { + throw new NullPointerException("Legal tag with null ID cannot be save to cloudant"); + } + try { + Response resp = db.save(legalTag); + db.ensureFullCommit(); + + if (200 <= resp.getStatusCode() && resp.getStatusCode() < 300) { + + if (resp.getStatusCode() == 202) { + int retries = 3; + // This test is crude and I think it can fail in two ways: + // 1) Race condition with an update + // 2) Sufficient quorum was still not achieved. + // But it allows us to give a little more certainty + while(retries-- > 0) { + try { + CloudantBackedLegalTag verify = retrieveExactlyOne(id); + + if (!verify.get_rev().equals(resp.getRev())) { + throw new AppException(409, "Cloudant sent a 202", "A LegalTag already exists for the given name"); + } + break; + } catch (IllegalArgumentException ex) {} + } + } + + return id; + } else { + logger.error("Failed to save legal tag in cloudant. Status code: {}, Reason: {}", resp.getStatusCode(), resp.getReason()); + return null; + } + } catch(DocumentConflictException ex) { + throw new AppException(409, ex.getReason(), "A LegalTag already exists for the given name"); + } + } + + @Override + public Collection<LegalTag> get(long[] ids) { + // Would an "eq" be faster than an "in" if there was only one id? + + QueryBuilder builder = new QueryBuilder(in("_id", Arrays.stream(ids).mapToObj(l -> Long.toString(l)).toArray())); + + if (logger.isDebugEnabled()) { + builder.executionStats(true); + } + + QueryResult<CloudantBackedLegalTag> result = db.query( + builder.build() + , CloudantBackedLegalTag.class); + + logExecutionStat(db, result); + + if (result.getDocs().isEmpty()) { + return new ArrayList<LegalTag>(); + } else { + if (result.getDocs().size() > ids.length) { + throw new IllegalStateException("Cardinality of Legal Tag result set is larger that the cardinality of IDs"); + } + return Collections.unmodifiableList(result.getDocs()); + } + } + + @Override + public Boolean delete(LegalTag legalTag) { + + CloudantBackedLegalTag toDelete = null; + + if (legalTag instanceof CloudantBackedLegalTag && ((CloudantBackedLegalTag)legalTag).get_rev() != null) { + //if (legalTag instanceof CloudantBackedLegalTag) { + toDelete = (CloudantBackedLegalTag)legalTag; + } else { + try { + toDelete = retrieveExactlyOne(legalTag.getId()); + copyNewValuesToOldVersion(legalTag, toDelete); + } catch (IllegalArgumentException ex) { + return false; + } + } + + int countDown = CLOUDANT_CONFLICT_RETRIES; + + while (countDown-- > 0) { + try { + Response resp = db.remove(toDelete.getId().toString(), toDelete.get_rev()); + if (200 <= resp.getStatusCode() && resp.getStatusCode() < 300) { + return true; + } else { + logger.error("Failed to delete legal tag in cloudant. Status code: {}, Reason: {}", resp.getStatusCode(), resp.getReason()); + return false; + } + } catch(DocumentConflictException ex) { + toDelete = retrieveExactlyOne(legalTag.getId()); + copyNewValuesToOldVersion(legalTag, toDelete); + } + } + + throw new IllegalStateException("Cloudant delete had to be retried too many times due to update conflict"); + } + + private CloudantBackedLegalTag retrieveExactlyOne(Long id) { + + QueryBuilder builder = new QueryBuilder(eq("_id", id.toString())); + + if (logger.isDebugEnabled()) { + builder.executionStats(true); + } + + QueryResult<CloudantBackedLegalTag> result = db.query(builder.build() + , CloudantBackedLegalTag.class); + + logExecutionStat(db, result); + + long numResults = result.getDocs().size(); + + if (numResults != 1) { + if (numResults == 0) { + throw new IllegalArgumentException("Legal tag does not exist in the database"); + } else { + throw new IllegalStateException("Legal tag is not unique"); + } + } + return result.getDocs().get(0); + } + + /* (non-Javadoc) + * @see org.opengroup.osdu.legal.provider.interfaces.LegalTagRepository#update(org.opengroup.osdu.legal.tags.model.LegalTag) + */ + @Override + public LegalTag update(LegalTag newLegalTag) { + + CloudantBackedLegalTag toUpdate = null; + + if (newLegalTag instanceof CloudantBackedLegalTag) { + toUpdate = (CloudantBackedLegalTag)newLegalTag; + } else { + toUpdate = retrieveExactlyOne(newLegalTag.getId()); + copyNewValuesToOldVersion(newLegalTag, toUpdate); + } + + int countDown = CLOUDANT_CONFLICT_RETRIES; + + while (countDown-- > 0) { + try { + Response resp = db.update(toUpdate); + if (200 <= resp.getStatusCode() && resp.getStatusCode() < 300) { + return newLegalTag; + } else { + logger.error("Failed to save legal tag in cloudant. Status code: {}, Reason: {}", resp.getStatusCode(), resp.getReason()); + return null; + } + } catch(DocumentConflictException ex) { + toUpdate = retrieveExactlyOne(newLegalTag.getId()); + copyNewValuesToOldVersion(newLegalTag, toUpdate); + } + } + + throw new IllegalStateException("Cloudant update had to be retried too many times due to update conflict"); + + } + + private void copyNewValuesToOldVersion(LegalTag old, LegalTag _new) { + assert(old.getId().equals(_new.getId())); + old.setName(_new.getName()); + old.setDescription(_new.getDescription()); + old.setIsValid(_new.getIsValid()); + old.setProperties(_new.getProperties()); + } + + /* (non-Javadoc) + * @see org.opengroup.osdu.legal.provider.interfaces.LegalTagRepository#list(org.opengroup.osdu.legal.tags.dataaccess.ListLegalTagArgs) + */ + @Override + public Collection<LegalTag> list(ListLegalTagArgs args) { + + Selector query = EmptyExpression.empty(); + // Since the isValid attribute is a Boolean rather than a bool + // we will interpret this a three state flag + // The byoc doesn't help to clarify that because it hits a + // NullPointerException when comparing a bool this a null Boolean, + // But at least the behavior is consistent when the limit is not + // null + // Both the commented code and the code below pass all acceptance tests + // query = eq("is_valid", Optional.ofNullable(args.getIsValid()).orElse(true).booleanValue()); + if (args.getIsValid() != null) { + query = eq("is_valid", args.getIsValid().booleanValue()); + } + + + QueryBuilder builder = new QueryBuilder(query); + + builder.bookmark(args.getCursor()); + + if (logger.isDebugEnabled()) { + builder.executionStats(true); + } + + if (args.getLimit() > 0) { + builder.limit(args.getLimit()); + } + + QueryResult<CloudantBackedLegalTag> result = db.query(builder.build() + , CloudantBackedLegalTag.class); + + logExecutionStat(db, result); + + if (args.getLimit() > 0) { + args.setCursor(result.getBookmark()); + } + return Collections.unmodifiableCollection(result.getDocs()); + } + + private void logExecutionStat(Database db, QueryResult<?> result) { + final ExecutionStats stats = result.getExecutionStats(); + if (stats != null) { + logger.debug("Query on {} returned {} results in {} ms. Total docs examined: {}. TotalKeys examined: {}. Warning message: {}", db.info().getDbName(), stats.getResultsReturned(), stats.getExecutionTimeMs(), stats.getTotalDocsExamined(), stats.getTotalKeysExamined(), result.getWarning()); + } + } + + +} diff --git a/provider/legal-ibm/src/main/resources/application.yml b/provider/legal-ibm/src/main/resources/application.yml new file mode 100644 index 000000000..9e7072815 --- /dev/null +++ b/provider/legal-ibm/src/main/resources/application.yml @@ -0,0 +1,35 @@ +server: + servlet: + contextPath: /api/legal/v1/ + port: 8080 + +spring: + security: + oauth2: + resourceserver: + jwt: + jwk-set-uri: https://some.keycloak.com/auth/realms/OSDU/protocol/openid-connect/certs + +REGION: us-central +AUTHORIZE_API: http://entitlements:8080/api/entitlements/v1 +LEGAL_HOSTNAME: notused +CRON_JOB_IP: 10.0.0.1 +LOG_PREFIX: legal + +ibm: + env: + prefix: acceptance-test + legal: + publisher: + devnull: true + db: + name: legal-tags + credentials: file:/somepath + user: change + password: change + tenant: + db: + name: tenant-info + url: ${ibm.legal.db.url} + user: ${ibm.legal.db.user} + password: ${ibm.legal.db.password} diff --git a/provider/legal-ibm/src/main/resources/logback.groovy b/provider/legal-ibm/src/main/resources/logback.groovy new file mode 100644 index 000000000..287380cc6 --- /dev/null +++ b/provider/legal-ibm/src/main/resources/logback.groovy @@ -0,0 +1,43 @@ +import org.slf4j.bridge.SLF4JBridgeHandler +import ch.qos.logback.classic.jul.LevelChangePropagator + +// see also: http://logback.qos.ch/manual/configuration.html#LevelChangePropagator +// performance speedup for redirected JUL loggers +def lcp = new LevelChangePropagator() +lcp.context = context +lcp.resetJUL = true +context.addListener(lcp) + +// needed only for the JUL bridge: http://stackoverflow.com/a/9117188/1915920 +java.util.logging.LogManager.getLogManager().reset() +SLF4JBridgeHandler.removeHandlersForRootLogger() +SLF4JBridgeHandler.install() +java.util.logging.Logger.getLogger( "" ).setLevel( java.util.logging.Level.FINEST ) + +def logPattern = "|%.-1level| [%thread] %20.30logger{30}| %msg%n" +appender("STDOUT", ConsoleAppender) { + encoder(PatternLayoutEncoder) { + pattern = logPattern + } +} +root(TRACE, ["STDOUT"]) + +def rootLvl = INFO +logger( "antlr", rootLvl ) +logger( "de", rootLvl ) +logger( "ch", rootLvl ) +logger( "com", rootLvl ) +logger( "java", rootLvl ) +logger( "javassist", rootLvl ) +logger( "javax", rootLvl ) +logger( "junit", rootLvl ) +logger( "groovy", rootLvl ) +logger( "net", rootLvl ) +logger( "org", rootLvl ) +logger( "sun", rootLvl ) +logger( "org.opengroup.osdu", DEBUG ) +logger( "org.springframework.web.servlet", INFO ) +logger( "org.springframework.security", INFO ) +logger( "org.apache.http", INFO ) + +scan("30 seconds") // reload/apply-on-change config every x sec \ No newline at end of file diff --git a/provider/legal-ibm/src/test/java/org/opengroup/osdu/legal/ibm/api/EntitlementsFactoryByoc.java b/provider/legal-ibm/src/test/java/org/opengroup/osdu/legal/ibm/api/EntitlementsFactoryByoc.java new file mode 100644 index 000000000..79936ac56 --- /dev/null +++ b/provider/legal-ibm/src/test/java/org/opengroup/osdu/legal/ibm/api/EntitlementsFactoryByoc.java @@ -0,0 +1,31 @@ +// Copyright © Microsoft Corporation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package org.opengroup.osdu.legal.ibm.api; + +import org.opengroup.osdu.core.common.model.http.DpsHeaders; +import org.opengroup.osdu.core.common.entitlements.IEntitlementsFactory; +import org.opengroup.osdu.core.common.entitlements.IEntitlementsService; +import org.springframework.context.annotation.Primary; +import org.springframework.stereotype.Component; + +@Component +@Primary +public class EntitlementsFactoryByoc implements IEntitlementsFactory { + @Override + public IEntitlementsService create(DpsHeaders headers) { + return new EntitlementsServiceByoc(headers); + } +} + diff --git a/provider/legal-ibm/src/test/java/org/opengroup/osdu/legal/ibm/api/EntitlementsServiceByoc.java b/provider/legal-ibm/src/test/java/org/opengroup/osdu/legal/ibm/api/EntitlementsServiceByoc.java new file mode 100644 index 000000000..10566a30f --- /dev/null +++ b/provider/legal-ibm/src/test/java/org/opengroup/osdu/legal/ibm/api/EntitlementsServiceByoc.java @@ -0,0 +1,93 @@ +// Copyright © Microsoft Corporation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package org.opengroup.osdu.legal.ibm.api; + +import org.apache.http.HttpStatus; +import org.opengroup.osdu.core.common.model.entitlements.*; +import org.opengroup.osdu.core.common.model.http.DpsHeaders; +import org.opengroup.osdu.core.common.entitlements.IEntitlementsService; +import org.opengroup.osdu.core.common.model.legal.ServiceConfig; +import org.opengroup.osdu.core.common.http.HttpResponse; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.context.SecurityContextHolder; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +public class EntitlementsServiceByoc implements IEntitlementsService { + DpsHeaders headers; + + public EntitlementsServiceByoc(DpsHeaders headers) { + this.headers = headers; + } + + @Override + public MemberInfo addMember(GroupEmail groupEmail, MemberInfo memberInfo) throws EntitlementsException { + return null; + } + + @Override + public Members getMembers(GroupEmail groupEmail, GetMembers getMembers) throws EntitlementsException { + return null; + } + + @Override + public Groups getGroups() throws EntitlementsException { + Authentication auth = SecurityContextHolder.getContext().getAuthentication(); + String email = auth.getName(); + List<GroupInfo> giList = new ArrayList(); + Collection<? extends GrantedAuthority> authorities = auth.getAuthorities(); + for (GrantedAuthority authority : authorities) { + GroupInfo gi = new GroupInfo(); + String role = authority.getAuthority(); + if (role.startsWith(ServiceConfig.PREFIX)) { + role = role.substring(ServiceConfig.PREFIX.length()); + } + gi.setName(role); + gi.setEmail(email); + giList.add(gi); + } + if (giList.size() > 0) { + Groups groups = new Groups(); + groups.setGroups(giList); + groups.setDesId(email); + return groups; + } + + HttpResponse response = new HttpResponse(); + response.setResponseCode(HttpStatus.SC_INTERNAL_SERVER_ERROR); + throw new EntitlementsException("no authorities found", response); + } + + @Override + public GroupInfo createGroup(CreateGroup createGroup) throws EntitlementsException { + return null; + } + + @Override + public void deleteMember(String s, String s1) throws EntitlementsException { + } + + @Override + public Groups authorizeAny(String... strings) throws EntitlementsException { + return null; + } + + @Override + public void authenticate() throws EntitlementsException { + } +} diff --git a/provider/legal-ibm/src/test/java/org/opengroup/osdu/legal/ibm/api/LegalTagApiTest.java b/provider/legal-ibm/src/test/java/org/opengroup/osdu/legal/ibm/api/LegalTagApiTest.java new file mode 100644 index 000000000..c65d6b8a2 --- /dev/null +++ b/provider/legal-ibm/src/test/java/org/opengroup/osdu/legal/ibm/api/LegalTagApiTest.java @@ -0,0 +1,85 @@ +package org.opengroup.osdu.legal.ibm.api; + +import static org.mockito.Mockito.when; +import static org.mockito.MockitoAnnotations.initMocks; + +import javax.inject.Inject; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.FixMethodOrder; +import org.junit.Ignore; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.MethodSorters; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.opengroup.osdu.core.common.model.http.AppException; +import org.opengroup.osdu.core.common.model.http.RequestInfo; +import org.opengroup.osdu.core.common.model.legal.ServiceConfig; +import org.opengroup.osdu.core.common.model.tenant.TenantInfo; +import org.opengroup.osdu.legal.api.LegalTagApi; +import org.opengroup.osdu.legal.ibm.LegalApplication; +import org.opengroup.osdu.legal.tags.LegalTagService; +import org.opengroup.osdu.legal.tags.dto.LegalTagDto; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.HttpStatus; +import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException; +import org.springframework.security.test.context.support.WithMockUser; +import org.springframework.test.context.junit4.SpringRunner; + +@Ignore +@RunWith(SpringRunner.class) +@SpringBootTest(classes={LegalApplication.class}) +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +public class LegalTagApiTest { + + @Mock + TenantInfo tenantInfo; + + @Mock + LegalTagService legalTagService; + + @Mock + RequestInfo requestInfo; + + @InjectMocks + @Inject + private LegalTagApi sut; + + @Before + public void Setup() { + initMocks(this); + when(requestInfo.getTenantInfo()).thenReturn(tenantInfo); + } + + @Test(expected = AuthenticationCredentialsNotFoundException.class) + public void givenUnauthenticated_whenCallCreateLegalTag_thenThrowsException(){ + LegalTagDto legalTag = new LegalTagDto(); + this.sut.createLegalTag(legalTag); + } + + @WithMockUser(username="admin", roles={ServiceConfig.LEGAL_ADMIN}) + @Test + public void given1AuthenticatedAdmin_whenCallCreateLegalTag_thenOk() { + LegalTagDto legalTag = new LegalTagDto(); + Assert.assertEquals(HttpStatus.CREATED, this.sut.createLegalTag(legalTag).getStatusCode()); + } + + @WithMockUser(username="viewer", roles={ServiceConfig.LEGAL_USER}) + @Test + public void givenAuthenticatedViewer_whenCallCreateLegalTag_thenForbidden() { + try { + LegalTagDto legalTag = new LegalTagDto(); + this.sut.createLegalTag(legalTag); + } catch (AppException e) { + Assert.assertEquals(HttpStatus.UNAUTHORIZED.value(), e.getError().getCode()); + } + } + + @WithMockUser(username="viewer", roles={ServiceConfig.LEGAL_USER}) + @Test + public void given2AuthenticatedViewer_whenCallGetLegalTag_thenOK() { + Assert.assertEquals(HttpStatus.OK, this.sut.listLegalTags(true).getStatusCode()); + } +} diff --git a/provider/legal-ibm/src/test/java/org/opengroup/osdu/legal/ibm/tags/LegalTagTests.java b/provider/legal-ibm/src/test/java/org/opengroup/osdu/legal/ibm/tags/LegalTagTests.java new file mode 100644 index 000000000..1b3c29669 --- /dev/null +++ b/provider/legal-ibm/src/test/java/org/opengroup/osdu/legal/ibm/tags/LegalTagTests.java @@ -0,0 +1,519 @@ +// (C) Copyright IBM Corporation 2019 +// U.S. Government Users Restricted Rights: Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package org.opengroup.osdu.legal.ibm.tags; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import java.sql.Date; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +import org.junit.After; +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.junit.MockitoJUnitRunner; +import org.opengroup.osdu.core.common.model.legal.LegalTag; +import org.opengroup.osdu.core.common.model.legal.ListLegalTagArgs; +import org.opengroup.osdu.core.common.model.legal.Properties; +import org.opengroup.osdu.core.ibm.auth.ServiceCredentials; +import org.opengroup.osdu.core.ibm.cloudant.IBMCloudantClientFactory; + +import com.cloudant.client.api.CloudantClient; +import com.cloudant.client.api.Database; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonElement; + +/** + * @author mbayser + * + */ +@Ignore +@RunWith(MockitoJUnitRunner.class) +public class LegalTagTests { + + private CloudantClient cloudant; + private static final String databaseNameFormat = "legal-tag-test-%s"; + private String databaseName; + private DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyyMMdd-HHmmss"); + private Database db; + + private CloudantLegalTagRepository repo; + + + public LegalTagTests() { + } + + @Before + public void setup() throws Exception { + + databaseName = String.format(databaseNameFormat, dtf.format(LocalDateTime.now())); + + IBMCloudantClientFactory fact; + ServiceCredentials creds; + try { + fact = new IBMCloudantClientFactory(); + creds = ServiceCredentials.environmentSupplied(); + } catch (Exception e) { + fact = new IBMCloudantClientFactory(System.getenv("CLOUDANT_URL"), System.getenv("CLOUDANT_KEY")); + creds = new ServiceCredentials(System.getenv("CLOUDANT_URL"), System.getenv("CLOUDANT_KEY")); + } + + fact.getGsonBuilder() + .registerTypeAdapter(java.sql.Date.class, CloudantBackedLegalTag.sqlDateSerializer) + .registerTypeAdapter(java.sql.Date.class, CloudantBackedLegalTag.sqlDateDeserializer) + .registerTypeAdapter(LegalTag.class, CloudantBackedLegalTag.serializer) + .registerTypeAdapter(CloudantBackedLegalTag.class, CloudantBackedLegalTag.serializer) + .registerTypeAdapter(CloudantBackedLegalTag.class, CloudantBackedLegalTag.deserializer); + cloudant = fact.getClient(); + + db = fact.getDatabase("test",databaseName); + db.getDBUri(); + + repo = new CloudantLegalTagRepository(creds, "test", databaseName); + + } + + @After + public void teardown() throws Exception { + cloudant.deleteDB(IBMCloudantClientFactory.dbNameRule("test", databaseName)); + } + + @Test + public void testEquals() { + + CloudantBackedLegalTag original = (CloudantBackedLegalTag)configureTag(new CloudantBackedLegalTag()); + + CloudantBackedLegalTag copy1 = (CloudantBackedLegalTag)configureTag(new CloudantBackedLegalTag()); + assertEquals(original, copy1); + + copy1.set_rev("qflkhfeiurlew"); + + assertEquals(original, copy1); + + LegalTag copy2 = configureTag(new LegalTag()); + + assertTrue(original.equals(copy2)); + assertTrue(copy2.equals(original)); + } + + @SuppressWarnings("deprecation") + @Test + public void testSerialization() { + + CloudantBackedLegalTag original = new CloudantBackedLegalTag(); + original.setId(1001L); + original.set_rev("3-rev"); + original.setName("TENANT1"); + original.setDescription("description"); + original.setIsValid(true); + + Properties props = new Properties(); + props.setCountryOfOrigin(Arrays.asList("Erebor")); + props.setDataType("gem"); + props.setSecurityClassification("bestows the right to rule"); + props.setPersonalData("Belongs to the Folk of Durin"); + props.setExportClassification("Kings Jewel"); + props.setOriginator("Thorin Oakenshield"); + props.setContractId("Burglary contract"); + props.setExpirationDate(new Date(2941, 11, 32)); + + original.setProperties(props); + + Gson gson = new GsonBuilder() + .registerTypeAdapter(CloudantBackedLegalTag.class, CloudantBackedLegalTag.serializer) + .registerTypeAdapter(LegalTag.class, CloudantBackedLegalTag.serializer) + .registerTypeAdapter(CloudantBackedLegalTag.class, CloudantBackedLegalTag.deserializer) + .create(); + + JsonElement serialized = gson.toJsonTree(original); + System.out.println(serialized); + + CloudantBackedLegalTag deserialized = gson.fromJson(serialized, CloudantBackedLegalTag.class); + + assertEquals(original.getId(), deserialized.getId()); + assertEquals(original.getName(), deserialized.getName()); + assertEquals(original.getDescription(), deserialized.getDescription()); + assertEquals(original.getIsValid(), deserialized.getIsValid()); + assertEquals(original.getProperties(), deserialized.getProperties()); + + // Just to make sure that lombok is doing its job + assertEquals(original.hashCode(), deserialized.hashCode()); + assertEquals(original, deserialized); + } + + @Test + public void testCreate() throws Exception { + + LegalTag tag1 = createValidLegalTag("tag1"); + Long id1 = tag1.getId(); + + Long saved_id1 = repo.create(tag1); + + assertEquals(id1, saved_id1); + + + try { + LegalTag nullIdtag = createValidLegalTag("nulltag"); + nullIdtag.setId(null); + repo.create(nullIdtag); + fail("Expected exception"); + } catch (NullPointerException e) { } + + + LegalTag tag2 = createValidLegalTag("tag2"); + tag2.setIsValid(true); + Long id2 = tag2.getId(); + + Long saved_id2 = repo.create(tag2); + + assertEquals(id2, saved_id2); + + } + + @Test + public void testGet() throws Exception { + LegalTag tag1 = createValidLegalTag("tag1"); + Long id1 = tag1.getId(); + + Long saved_id1 = repo.create(tag1); + assertEquals(id1, saved_id1); + + LegalTag tag2 = createValidLegalTag("tag2"); + tag2.setIsValid(true); + Long id2 = tag2.getId(); + + Long saved_id2 = repo.create(tag2); + + assertEquals(id2, saved_id2); + + Collection<LegalTag> retrv1 = repo.get(new long[] { id1 }); + assertEquals(retrv1.size(), 1); + + LegalTag retrv1_tag1 = retrv1.iterator().next(); + assertEquals(tag1, retrv1_tag1); + } + + @Test + public void testNone() throws Exception { + + LegalTag tag1 = createValidLegalTag("tag1"); + Long id1 = tag1.getId(); + + Long saved_id1 = repo.create(tag1); + assertEquals(id1, saved_id1); + + LegalTag tag2 = createValidLegalTag("tag2"); + tag2.setIsValid(true); + Long id2 = tag2.getId(); + + Long saved_id2 = repo.create(tag2); + + assertEquals(id2, saved_id2); + + Collection<LegalTag> retrv1 = repo.get(new long[] { 4324L }); + assertEquals(retrv1.size(), 0); + } + + + @Test + public void testGetMultiple() throws Exception { + + LegalTag tag1 = createValidLegalTag("tag1"); + Long id1 = tag1.getId(); + + Long saved_id1 = repo.create(tag1); + assertEquals(id1, saved_id1); + + LegalTag tag2 = createValidLegalTag("tag2"); + tag2.setIsValid(true); + Long id2 = tag2.getId(); + + Long saved_id2 = repo.create(tag2); + + assertEquals(id2, saved_id2); + + Collection<LegalTag> retrv1 = repo.get(new long[] { id1, id2 }); + assertEquals(retrv1.size(), 2); + + Iterator<LegalTag> it = retrv1.iterator(); + + LegalTag retrv1_tag1 = it.next(); + assertEquals(tag1, retrv1_tag1); + LegalTag retrv1_tag2 = it.next(); + assertEquals(tag2, retrv1_tag2); + } + + @Test + public void testUpdate() throws Exception { + + LegalTag tag1 = createValidLegalTag("tag1"); + Long id1 = tag1.getId(); + tag1.setDescription("description1"); + + try { + repo.update(tag1); + fail("expected exception when updating object not present in the database"); + } catch (IllegalArgumentException ex) {} + + Long saved_id1 = repo.create(tag1); + assertEquals(id1, saved_id1); + + Collection<LegalTag> retrv1 = repo.get(new long[] { id1 }); + assertEquals(retrv1.size(), 1); + + Iterator<LegalTag> retrv1_it = retrv1.iterator(); + + LegalTag retrv1_tag1 = retrv1_it.next(); + assertEquals(tag1, retrv1_tag1); + + retrv1_tag1.setDescription("description2"); + + // This update will work without extra logic because retrv1_tag1 is + // actually a CloudantBackedLegalTag with a valid _rev + repo.update(retrv1_tag1); + + Collection<LegalTag> retrv2 = repo.get(new long[] { id1 }); + assertEquals(retrv2.size(), 1); + + Iterator<LegalTag> retrv2_it = retrv2.iterator(); + + LegalTag retrv2_tag1 = retrv2_it.next(); + + assertNotEquals(tag1, retrv2_tag1); + assertEquals(retrv1_tag1, retrv2_tag1); + + + LegalTag tag1_equivalent = createValidLegalTag("tag1"); + tag1.setDescription("description3"); + assertEquals(id1, tag1_equivalent.getId()); + + // This update would fail it the update method didn't handle the missing _rev + repo.update(tag1_equivalent); + + + // This update would fail it the update method didn't handle the outdated _rev + repo.update(retrv2_tag1); + + } + + @Test + public void testDelete () throws Exception { + + LegalTag tag1 = createValidLegalTag("tag1"); + Long id1 = tag1.getId(); + tag1.setDescription("description1"); + + assertFalse(repo.delete(tag1)); + + CloudantBackedLegalTag cloudantBacked = (CloudantBackedLegalTag)configureTag(new CloudantBackedLegalTag()); + assertFalse(repo.delete(cloudantBacked)); + + Long saved_id1 = repo.create(tag1); + assertEquals(id1, saved_id1); + + Collection<LegalTag> retrv1 = repo.get(new long[] { id1 }); + assertEquals(retrv1.size(), 1); + + assertTrue(repo.delete(tag1)); + + Collection<LegalTag> retrv2 = repo.get(new long[] { id1 }); + assertEquals(retrv2.size(), 0); + + repo.create(tag1); + + Collection<LegalTag> retrv3 = repo.get(new long[] { id1 }); + assertEquals(retrv3.size(), 1); + + Iterator<LegalTag> retrv3_it = retrv3.iterator(); + + LegalTag retrv3_tag1 = retrv3_it.next(); + assertEquals(tag1, retrv3_tag1); + + retrv3_tag1.setDescription("description2"); + assertNotEquals(tag1, retrv3_tag1); + + repo.update(retrv3_tag1); + + Collection<LegalTag> retrv4 = repo.get(new long[] { id1 }); + assertEquals(retrv4.size(), 1); + + + // This would fail without the retry on conflict logic + assertTrue(repo.delete(retrv3_tag1)); + + Collection<LegalTag> retrv5 = repo.get(new long[] { id1 }); + assertEquals(retrv5.size(), 0); + + } + + @Test + public void testList() throws Exception { + + LegalTag tag1 = createValidLegalTag("tag1"); + tag1.setIsValid(false); + repo.create(tag1); + LegalTag tag2 = createValidLegalTag("tag2"); + tag2.setIsValid(true); + repo.create(tag2); + LegalTag tag3 = createValidLegalTag("tag3"); + tag3.setIsValid(false); + repo.create(tag3); + LegalTag tag4 = createValidLegalTag("tag4"); + tag4.setIsValid(true); + repo.create(tag4); + LegalTag tag5 = createValidLegalTag("tag5"); + tag5.setIsValid(false); + repo.create(tag5); + LegalTag tag6 = createValidLegalTag("tag6"); + tag6.setIsValid(true); + repo.create(tag6); + + ListLegalTagArgs allTagsNoPaging = new ListLegalTagArgs(); + allTagsNoPaging.setIsValid(null); + allTagsNoPaging.setLimit(0); + + Set<String> allNames = repo.list(allTagsNoPaging).stream().map(t -> t.getName()).collect(Collectors.toSet()); + + assertEquals(6, allNames.size()); + assertTrue(allNames.contains("tag1")); + assertTrue(allNames.contains("tag2")); + assertTrue(allNames.contains("tag3")); + assertTrue(allNames.contains("tag4")); + assertTrue(allNames.contains("tag5")); + assertTrue(allNames.contains("tag6")); + + + ListLegalTagArgs validTagsNoPaging = new ListLegalTagArgs(); + validTagsNoPaging.setIsValid(true); + validTagsNoPaging.setLimit(0); + + Set<String> validNames = repo.list(validTagsNoPaging).stream().map(t -> t.getName()).collect(Collectors.toSet()); + + assertEquals(3, validNames.size()); + assertTrue(validNames.contains("tag2")); + assertTrue(validNames.contains("tag4")); + assertTrue(validNames.contains("tag6")); + + HashSet<String> allNamesSet = new HashSet<>(Arrays.asList( + "tag1", + "tag2", + "tag3", + "tag4", + "tag5", + "tag6" + )); + + ListLegalTagArgs allTagsWithPaging = new ListLegalTagArgs(); + allTagsWithPaging.setIsValid(null); + allTagsWithPaging.setLimit(1); + + assertEquals(6, allNamesSet.size()); + + List<String> page1 = repo.list(allTagsWithPaging).stream().map(t -> t.getName()).collect(Collectors.toList()); + assertEquals(1, page1.size()); + allNamesSet.remove(page1.get(0)); + assertEquals(5, allNamesSet.size()); + + List<String> page2 = repo.list(allTagsWithPaging).stream().map(t -> t.getName()).collect(Collectors.toList()); + assertEquals(1, page2.size()); + allNamesSet.remove(page2.get(0)); + assertEquals(4, allNamesSet.size()); + + List<String> page3 = repo.list(allTagsWithPaging).stream().map(t -> t.getName()).collect(Collectors.toList()); + assertEquals(1, page3.size()); + allNamesSet.remove(page3.get(0)); + assertEquals(3, allNamesSet.size()); + + List<String> page4 = repo.list(allTagsWithPaging).stream().map(t -> t.getName()).collect(Collectors.toList()); + assertEquals(1, page4.size()); + allNamesSet.remove(page4.get(0)); + assertEquals(2, allNamesSet.size()); + + List<String> page5 = repo.list(allTagsWithPaging).stream().map(t -> t.getName()).collect(Collectors.toList()); + assertEquals(1, page5.size()); + allNamesSet.remove(page5.get(0)); + assertEquals(1, allNamesSet.size()); + + List<String> page6 = repo.list(allTagsWithPaging).stream().map(t -> t.getName()).collect(Collectors.toList()); + assertEquals(1, page6.size()); + allNamesSet.remove(page6.get(0)); + assertEquals(0, allNamesSet.size()); + + List<String> page7 = repo.list(allTagsWithPaging).stream().map(t -> t.getName()).collect(Collectors.toList()); + assertEquals(0, page7.size()); + + List<String> page8 = repo.list(allTagsWithPaging).stream().map(t -> t.getName()).collect(Collectors.toList()); + assertEquals(0, page8.size()); + } + + @SuppressWarnings("deprecation") + public static LegalTag configureTag(LegalTag original) { + + original.setId(1001L); + original.setName("TENANT1"); + original.setDescription("description"); + original.setIsValid(true); + + Properties props = new Properties(); + props.setCountryOfOrigin(Arrays.asList("Erebor")); + props.setDataType("gem"); + props.setSecurityClassification("bestows the right to rule"); + props.setPersonalData("Belongs to the Folk of Durin"); + props.setExportClassification("King's Jewel"); + props.setOriginator("Thorin Oakenshield"); + props.setContractId("Burglary contract"); + props.setExpirationDate(new Date(2941, 11, 32)); + original.setProperties(props); + return original; + } + + public static LegalTag createValidLegalTag(String name){ + LegalTag legalTag = new LegalTag(); + legalTag.setProperties(createValidProperties()); + legalTag.setName(name); + legalTag.setIsValid(false); + legalTag.setDefaultId(); + return legalTag; + } + @SuppressWarnings("serial") + public static Properties createValidProperties(){ + Properties properties = new Properties(); + properties.setCountryOfOrigin(new ArrayList<String>(){{add("USA");}}); + properties.setExpirationDate(new Date(System.currentTimeMillis())); + properties.setOriginator("MyCompany"); + properties.setContractId("Unknown"); + properties.setDataType("Tranferred Data"); + properties.setPersonalData("Sensitive Personal Information"); + properties.setSecurityClassification("Confidential"); + properties.setExportClassification("ECCN"); + return properties; + } +} diff --git a/provider/legal-ibm/src/test/resources/logback.groovy b/provider/legal-ibm/src/test/resources/logback.groovy new file mode 100644 index 000000000..7a86fe105 --- /dev/null +++ b/provider/legal-ibm/src/test/resources/logback.groovy @@ -0,0 +1,40 @@ +import org.slf4j.bridge.SLF4JBridgeHandler +import ch.qos.logback.classic.jul.LevelChangePropagator + +// see also: http://logback.qos.ch/manual/configuration.html#LevelChangePropagator +// performance speedup for redirected JUL loggers +def lcp = new LevelChangePropagator() +lcp.context = context +lcp.resetJUL = true +context.addListener(lcp) + +// needed only for the JUL bridge: http://stackoverflow.com/a/9117188/1915920 +java.util.logging.LogManager.getLogManager().reset() +SLF4JBridgeHandler.removeHandlersForRootLogger() +SLF4JBridgeHandler.install() +java.util.logging.Logger.getLogger( "" ).setLevel( java.util.logging.Level.FINEST ) + +def logPattern = "|%.-1level| [%thread] %20.30logger{30}| %msg%n" +appender("STDOUT", ConsoleAppender) { + encoder(PatternLayoutEncoder) { + pattern = logPattern + } +} +root(TRACE, ["STDOUT"]) + +def rootLvl = INFO +logger( "antlr", rootLvl ) +logger( "de", rootLvl ) +logger( "ch", rootLvl ) +logger( "com", rootLvl ) +logger( "java", rootLvl ) +logger( "javassist", rootLvl ) +logger( "javax", rootLvl ) +logger( "junit", rootLvl ) +logger( "groovy", rootLvl ) +logger( "net", rootLvl ) +logger( "org", rootLvl ) +logger( "sun", rootLvl ) +logger( "org.opengroup.osdu", DEBUG ) + +scan("30 seconds") // reload/apply-on-change config every x sec \ No newline at end of file diff --git a/testing/legal-test-aws/pom.xml b/testing/legal-test-aws/pom.xml index c95a2c10d..f8ab425c4 100644 --- a/testing/legal-test-aws/pom.xml +++ b/testing/legal-test-aws/pom.xml @@ -29,7 +29,6 @@ <maven.compiler.source>1.8</maven.compiler.source> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.main.basedir>${project.basedir}</project.main.basedir> - <MY_TENANT>opendes</MY_TENANT> </properties> <dependencies> <!-- Internal packages --> @@ -40,8 +39,8 @@ </dependency> <dependency> <groupId>org.opengroup.osdu.core.aws</groupId> - <artifactId>aws-osdu-util</artifactId> - <version>0.0.9</version> + <artifactId>os-core-lib-aws</artifactId> + <version>0.0.10</version> </dependency> <!-- AWS managed packages --> @@ -158,12 +157,7 @@ <configuration> <trimStackTrace>false</trimStackTrace> <systemPropertyVariables> - <HOST_URL>http://localhost:8082/api/legal/v1/</HOST_URL> - <ENTITLEMENT_URL>broken</ENTITLEMENT_URL> - <AWS_S3_ENDPOINT>s3.us-east-1.amazonaws.com</AWS_S3_ENDPOINT> - <AWS_S3_REGION>us-east-1</AWS_S3_REGION> <buildDirectory>${project.build.directory}</buildDirectory> - <MY_TENANT>opendes</MY_TENANT> </systemPropertyVariables> </configuration> </plugin> diff --git a/testing/legal-test-aws/src/test/java/org/opengroup/osdu/legal/util/AwsLegalTagUtils.java b/testing/legal-test-aws/src/test/java/org/opengroup/osdu/legal/util/AwsLegalTagUtils.java index fe80fe77a..223331e0b 100644 --- a/testing/legal-test-aws/src/test/java/org/opengroup/osdu/legal/util/AwsLegalTagUtils.java +++ b/testing/legal-test-aws/src/test/java/org/opengroup/osdu/legal/util/AwsLegalTagUtils.java @@ -21,7 +21,7 @@ import org.opengroup.osdu.core.aws.s3.S3Config; public class AwsLegalTagUtils extends LegalTagUtils { private static final String FILE_NAME = "Legal_COO.json"; - private static final String BUCKET_NAME_AWS = "dev-osdu-legal-config"; + private static final String BUCKET_NAME_AWS = System.getProperty("S3_LEGAL_CONFIG_BUCKET", System.getenv("S3_LEGAL_CONFIG_BUCKET")); private final static String COGNITO_CLIENT_ID_PROPERTY = "AWS_COGNITO_CLIENT_ID"; private final static String COGNITO_AUTH_FLOW_PROPERTY = "AWS_COGNITO_AUTH_FLOW"; diff --git a/testing/legal-test-core/src/main/java/org/opengroup/osdu/legal/util/LegalTagUtils.java b/testing/legal-test-core/src/main/java/org/opengroup/osdu/legal/util/LegalTagUtils.java index 70a548dc9..dd1d238a4 100644 --- a/testing/legal-test-core/src/main/java/org/opengroup/osdu/legal/util/LegalTagUtils.java +++ b/testing/legal-test-core/src/main/java/org/opengroup/osdu/legal/util/LegalTagUtils.java @@ -22,7 +22,7 @@ public abstract class LegalTagUtils extends TestUtils { public abstract String accessToken() throws Exception; private static InputStream getTestFileInputStream(String fileName) throws IOException { - return LegalTagUtils.class.getClass().getResourceAsStream("/" + fileName); + return LegalTagUtils.class.getResourceAsStream("/" + fileName); } protected static String readTestFile(String fileName) throws IOException { diff --git a/testing/legal-test-core/src/main/java/org/opengroup/osdu/legal/util/TestUtils.java b/testing/legal-test-core/src/main/java/org/opengroup/osdu/legal/util/TestUtils.java index 5abd44182..1f026e853 100644 --- a/testing/legal-test-core/src/main/java/org/opengroup/osdu/legal/util/TestUtils.java +++ b/testing/legal-test-core/src/main/java/org/opengroup/osdu/legal/util/TestUtils.java @@ -29,7 +29,6 @@ public class TestUtils { public TestUtils(boolean enforceHttp){ baseUrl = System.getProperty("HOST_URL", System.getenv("HOST_URL")); - //baseUrl = System.getenv("HOST_URL"); if(baseUrl == null || baseUrl.contains("-null")) { baseUrl = "https://localhost:8443/api/legal/v1/"; } @@ -48,7 +47,6 @@ public class TestUtils { public static String getMyProjectAccountId(){ return System.getProperty("MY_TENANT_PROJECT", System.getenv("MY_TENANT_PROJECT")); - //return System.getenv("MY_TENANT_PROJECT"); } public String getBaseHost() {return baseUrl.substring(8,baseUrl.length()-1);} @@ -60,7 +58,6 @@ public class TestUtils { public static String getMyDataPartition(){ return System.getProperty("MY_TENANT", System.getenv("MY_TENANT")); - //return System.getenv("MY_TENANT"); } public ClientResponse send(String path, String httpMethod, String token, String requestBody, String query) diff --git a/testing/legal-test-ibm/pom.xml b/testing/legal-test-ibm/pom.xml new file mode 100644 index 000000000..a904ddc8c --- /dev/null +++ b/testing/legal-test-ibm/pom.xml @@ -0,0 +1,93 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + Copyright 2017-2019 Schlumberger + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <groupId>org.opengroup.osdu.legal</groupId> + <artifactId>legal-test-ibm</artifactId> + <version>0.0.1</version> + <packaging>jar</packaging> + + <properties> + <maven.compiler.target>1.8</maven.compiler.target> + <maven.compiler.source>1.8</maven.compiler.source> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + <project.main.basedir>${project.basedir}</project.main.basedir> + <!-- + <PROJECT_ID>${PROJECT_ID}</PROJECT_ID> + <HOST_URL>${HOST_URL}</HOST_URL> + <ENTITLEMENT_URL>${ENTITLEMENT_URL}</ENTITLEMENT_URL> + <INTEGRATION_TESTER>${INTEGRATION_TESTER}</INTEGRATION_TESTER> + <INTEGRATION_TEST_AUDIENCE>${INTEGRATION_TEST_AUDIENCE}</INTEGRATION_TEST_AUDIENCE> + <MY_TENANT>${MY_TENANT}</MY_TENANT> + <CLIENT_TENANT>${CLIENT_TENANT}</CLIENT_TENANT> + <MY_TENANT_PROJECT>${MY_TENANT_PROJECT}</MY_TENANT_PROJECT> + <CLIENT_TENANT_PROJECT>${CLIENT_TENANT_PROJECT}</CLIENT_TENANT_PROJECT> + --> + </properties> + + <dependencies> + <dependency> + <groupId>com.google.code.gson</groupId> + <artifactId>gson</artifactId> + <version>2.8.5</version> + </dependency> + <dependency> + <groupId>org.opengroup.osdu.legal</groupId> + <artifactId>legal-test-core</artifactId> + <version>0.0.2-SNAPSHOT</version> + </dependency> + + <!-- Tests --> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <version>4.12</version> + <scope>test</scope> + </dependency> + </dependencies> + + <repositories> + <repository> + <id>dev-azure-com-slb-des-ext-collaboration-os-core</id> + <url>https://pkgs.dev.azure.com/slb-des-ext-collaboration/_packaging/os-core/maven/v1</url> + <releases> + <enabled>true</enabled> + </releases> + <snapshots> + <enabled>true</enabled> + <updatePolicy>never</updatePolicy> + </snapshots> + </repository> + </repositories> + <build> + <defaultGoal>test</defaultGoal> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-surefire-plugin</artifactId> + <version>2.4.2</version> + <configuration> + <trimStackTrace>false</trimStackTrace> + </configuration> + </plugin> + </plugins> + </build> +</project> diff --git a/testing/legal-test-ibm/run_service.sh b/testing/legal-test-ibm/run_service.sh new file mode 100644 index 000000000..704f52eec --- /dev/null +++ b/testing/legal-test-ibm/run_service.sh @@ -0,0 +1,53 @@ +#!/bin/bash + +export TENANT_INFO_DATABASE=acceptance-test-tenant-info +export LEGAL_TAG_DATABASE=acceptance-test-legal-tags +export COUNTRIES_DATABASE=acceptance-test-countries + +# snagged from: https://stackoverflow.com/a/51264222/26510 +function toAbsPath { + local target + target="$1" + + if [ "$target" == "." ]; then + echo "$(pwd)" + elif [ "$target" == ".." ]; then + echo "$(dirname "$(pwd)")" + else + echo "$(cd "$(dirname "$1")"; pwd)/$(basename "$1")" + fi +} + +function getScriptDir(){ + local SOURCED + local RESULT + (return 0 2>/dev/null) && SOURCED=1 || SOURCED=0 + + if [ "$SOURCED" == "1" ] + then + RESULT=$(dirname "$1") + else + RESULT="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" + fi + toAbsPath "$RESULT" +} + +SCRIPT_DIR=$(getScriptDir "$0") + +CRED_FILE=$(basename ${IBM_CREDENTIALS_FILE}) + +mkdir config +cp ${IBM_CREDENTIALS_FILE} config/ +cat <<EOF > config/application.yml +ibm: + tenant: + cloudant: + dbName: tenant-info + credentials: file:config/${CRED_FILE} + legal: + cloudant: + dbName: legal-tags + credentials: file:config/${CRED_FILE} +EOF + +java -jar ${SCRIPT_DIR}/../../provider/legal-ibm/target/legal-ibm-0.0.4-SNAPSHOT-spring-boot.jar diff --git a/testing/legal-test-ibm/run_tests.sh b/testing/legal-test-ibm/run_tests.sh new file mode 100644 index 000000000..af90a9e52 --- /dev/null +++ b/testing/legal-test-ibm/run_tests.sh @@ -0,0 +1,20 @@ +#!/bin/bash + +if [ -z "$LEGAL_TEST_TOKEN" ] +then + echo "env var LEGAL_TEST_TOKEN not set" + exit 1 +fi + +DATABASE_PREFIX=acceptance-test +export COUNTRIES_DATABASE=$DATABASE_PREFIX-countries +export TENANT_INFO_DATABASE=$DATABASE_PREFIX-tenant-info +export LEGAL_TAG_DATABASE=$DATABASE_PREFIX-legal-tags +export DATA_PARTITION_ID=data-partition-id +export HOST_URL=http://localhost:8080/api/legal/v1/ +#export HOST_URL=http://localhost:8080/api/legal/v1/ +export HOST_URL=https://os-legal-ibm-osdu-r2.osduadev-a1c3eaf78a86806e299f5f3f207556f0-0000.us-south.containers.appdomain.cloud/api/legal/v1/ +export MY_TENANT=TENANT1 +export MY_TENANT_PROJECT=PROJECT1 + +mvn test diff --git a/testing/legal-test-ibm/setup_acceptance.sh b/testing/legal-test-ibm/setup_acceptance.sh new file mode 100644 index 000000000..18e3162e3 --- /dev/null +++ b/testing/legal-test-ibm/setup_acceptance.sh @@ -0,0 +1,52 @@ +#!/bin/bash + +BASE_URL=$(jq -r ".url" < ${IBM_CREDENTIALS_FILE}) +USERNAME=$(jq -r ".username" < ${IBM_CREDENTIALS_FILE}) +PASSWORD=$(jq -r ".password" < ${IBM_CREDENTIALS_FILE}) + +DATABASE_PREFIX=acceptance-test + +curl -XPUT -u $USERNAME:$PASSWORD $BASE_URL/$DATABASE_PREFIX-countries +curl -XPUT -u $USERNAME:$PASSWORD $BASE_URL/$DATABASE_PREFIX-legal-tags +curl -XPUT -u $USERNAME:$PASSWORD $BASE_URL/$DATABASE_PREFIX-tenant-info + +# snagged from: https://stackoverflow.com/a/51264222/26510 +function toAbsPath { + local target + target="$1" + + if [ "$target" == "." ]; then + echo "$(pwd)" + elif [ "$target" == ".." ]; then + echo "$(dirname "$(pwd)")" + else + echo "$(cd "$(dirname "$1")"; pwd)/$(basename "$1")" + fi +} + +function getScriptDir(){ + local SOURCED + local RESULT + (return 0 2>/dev/null) && SOURCED=1 || SOURCED=0 + + if [ "$SOURCED" == "1" ] + then + RESULT=$(dirname "$1") + else + RESULT="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" + fi + toAbsPath "$RESULT" +} + +SCRIPT_DIR=$(getScriptDir "$0") + + + +TEST_COUNTRIES=${SCRIPT_DIR}/../legal-test-core/src/main/resources/TenantConfigTestingPurpose.json +cat $TEST_COUNTRIES | jq -rc '{ "docs": [.[] + {"tenant": "TENANT1", "region": "us"}]}' | curl -XPOST --data-binary @- -H"Content-type: application/json" -u $USERNAME:$PASSWORD $BASE_URL/$DATABASE_PREFIX-countries/_bulk_docs + +TEST_TENANT=${SCRIPT_DIR}/src/test/resources/Tenant.json +curl -XPOST --data-binary @${TEST_TENANT} -H"Content-type: application/json" -u $USERNAME:$PASSWORD $BASE_URL/$DATABASE_PREFIX-tenant-info/_bulk_docs + +TEST_TAGS=${SCRIPT_DIR}/src/test/resources/InitialTags.json +curl -XPOST --data-binary @${TEST_TAGS} -H"Content-type: application/json" -u $USERNAME:$PASSWORD $BASE_URL/$DATABASE_PREFIX-legal-tags/_bulk_docs diff --git a/testing/legal-test-ibm/src/test/java/org/opengroup/osdu/legal/ibm/acceptanceTests/TestCreateLegalTagApiAcceptance.java b/testing/legal-test-ibm/src/test/java/org/opengroup/osdu/legal/ibm/acceptanceTests/TestCreateLegalTagApiAcceptance.java new file mode 100644 index 000000000..4825dc665 --- /dev/null +++ b/testing/legal-test-ibm/src/test/java/org/opengroup/osdu/legal/ibm/acceptanceTests/TestCreateLegalTagApiAcceptance.java @@ -0,0 +1,124 @@ +package org.opengroup.osdu.legal.ibm.acceptanceTests; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.opengroup.osdu.legal.acceptanceTests.CreateLegalTagApiAcceptanceTests; +import org.opengroup.osdu.legal.ibm.acceptanceTests.util.IBMLegalTagUtils; +import org.opengroup.osdu.legal.util.TestUtils; + +import com.sun.jersey.api.client.ClientResponse; + +public class TestCreateLegalTagApiAcceptance extends CreateLegalTagApiAcceptanceTests { + + @Before + @Override + public void setup() throws Exception { + this.legalTagUtils = new IBMLegalTagUtils(); + super.setup(); + } + + @After + @Override + public void teardown() throws Exception { + super.teardown(); + this.legalTagUtils = null; + } + + /* + * This test has to be modified slightly for cloudant. Since the exact same document is + * uploaded several times, in the case where cloudant returns 202, it doesn't make + * sense to ask if 1 out of N writes is the winner. + */ + @Override + @Test + public void should_onlyLetAMaximumOf1LegaltagBeCreated_when_tryingToCreateMultipleVersionsOfTheSameContractAtTheSameTime() throws Exception { + ExecutorService executor = Executors.newFixedThreadPool(10); + List<Callable<ClientResponse>> tasks = new ArrayList<>(); + + for (int i = 0; i < 10; i++) { + Callable<ClientResponse> task = () -> { + try { + return legalTagUtils.create(name); + } catch (Exception ex) { + return null; + } + }; + tasks.add(task); + } + + List<Future<ClientResponse>> responses = executor.invokeAll(tasks); + executor.shutdown(); + executor.awaitTermination(20, TimeUnit.SECONDS); + + int sucessResponseCount = 0; + int non409ErrorResponseCount = 0; + for (Future<ClientResponse> future : responses) { + if (future.get().getStatus() == 201) { + sucessResponseCount++; + } else if (future.get().getStatus() != 409) { + non409ErrorResponseCount++; + } + } + assertTrue("Expected at least one 1 successful response. Actual " + sucessResponseCount, sucessResponseCount >= 1); + assertEquals(0, non409ErrorResponseCount); + } + + + + /* + * Now this test is designed so that we can test if we can say who the winner is when documents + * actually conflict + */ + @Test + public void should_onlyLetAMaximumOf1LegaltagBeCreated_when_tryingToCreateMultipleDifferentVersionsOfTheSameContractAtTheSameTime() throws Exception { + ExecutorService executor = Executors.newFixedThreadPool(10); + List<Callable<ClientResponse>> tasks = new ArrayList<>(); + + for (int i = 0; i < 10; i++) { + Callable<ClientResponse> task = () -> { + try { + return legalTagUtils.create( + "US", + name, + "2099-12-25", + "Transferred Data", + TestUtils.getMyDataPartition(), + "<my description>"+Thread.currentThread().getId()); + + } catch (Exception ex) { + return null; + } + }; + tasks.add(task); + } + + List<Future<ClientResponse>> responses = executor.invokeAll(tasks); + executor.shutdown(); + executor.awaitTermination(20, TimeUnit.SECONDS); + + int sucessResponseCount = 0; + int non409ErrorResponseCount = 0; + for (Future<ClientResponse> future : responses) { + if (future.get().getStatus() == 201) { + sucessResponseCount++; + } else if (future.get().getStatus() != 409) { + non409ErrorResponseCount++; + } + } + assertTrue("Expected at most one 1 successful response. Actual " + sucessResponseCount, sucessResponseCount <= 1); + assertEquals(0, non409ErrorResponseCount); + } + +} diff --git a/testing/legal-test-ibm/src/test/java/org/opengroup/osdu/legal/ibm/acceptanceTests/TestDeleteLegalTagApiAcceptance.java b/testing/legal-test-ibm/src/test/java/org/opengroup/osdu/legal/ibm/acceptanceTests/TestDeleteLegalTagApiAcceptance.java new file mode 100644 index 000000000..5259f2b4e --- /dev/null +++ b/testing/legal-test-ibm/src/test/java/org/opengroup/osdu/legal/ibm/acceptanceTests/TestDeleteLegalTagApiAcceptance.java @@ -0,0 +1,46 @@ +// (C) Copyright IBM Corporation 2019 +// U.S. Government Users Restricted Rights: Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package org.opengroup.osdu.legal.ibm.acceptanceTests; + + +import org.junit.After; +import org.junit.Before; +import org.opengroup.osdu.legal.acceptanceTests.DeleteLegalTagApiAcceptanceTests; +import org.opengroup.osdu.legal.ibm.acceptanceTests.util.IBMLegalTagUtils; + +/** + * @author mbayser + * + */ + +public class TestDeleteLegalTagApiAcceptance extends DeleteLegalTagApiAcceptanceTests { + + @Before + @Override + public void setup() throws Exception { + this.legalTagUtils = new IBMLegalTagUtils(); + super.setup(); + } + + @After + @Override + public void teardown() throws Exception { + super.teardown(); + this.legalTagUtils = null; + } + +} + diff --git a/testing/legal-test-ibm/src/test/java/org/opengroup/osdu/legal/ibm/acceptanceTests/TestGetLegalTagApiAcceptance.java b/testing/legal-test-ibm/src/test/java/org/opengroup/osdu/legal/ibm/acceptanceTests/TestGetLegalTagApiAcceptance.java new file mode 100644 index 000000000..eb8b168de --- /dev/null +++ b/testing/legal-test-ibm/src/test/java/org/opengroup/osdu/legal/ibm/acceptanceTests/TestGetLegalTagApiAcceptance.java @@ -0,0 +1,40 @@ +// (C) Copyright IBM Corporation 2019 +// U.S. Government Users Restricted Rights: Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package org.opengroup.osdu.legal.ibm.acceptanceTests; + +import org.junit.After; +import org.junit.Before; +import org.opengroup.osdu.legal.acceptanceTests.GetLegalTagApiAcceptanceTests; +import org.opengroup.osdu.legal.ibm.acceptanceTests.util.IBMLegalTagUtils; + +public class TestGetLegalTagApiAcceptance extends GetLegalTagApiAcceptanceTests { + + @Before + @Override + public void setup() throws Exception { + this.legalTagUtils = new IBMLegalTagUtils(); + super.setup(); + } + + @After + @Override + public void teardown() throws Exception { + super.teardown(); + this.legalTagUtils = null; + } + +} + diff --git a/testing/legal-test-ibm/src/test/java/org/opengroup/osdu/legal/ibm/acceptanceTests/TestGetLegalTagPropertiesApiAcceptance.java b/testing/legal-test-ibm/src/test/java/org/opengroup/osdu/legal/ibm/acceptanceTests/TestGetLegalTagPropertiesApiAcceptance.java new file mode 100644 index 000000000..612a9be18 --- /dev/null +++ b/testing/legal-test-ibm/src/test/java/org/opengroup/osdu/legal/ibm/acceptanceTests/TestGetLegalTagPropertiesApiAcceptance.java @@ -0,0 +1,40 @@ +// (C) Copyright IBM Corporation 2019 +// U.S. Government Users Restricted Rights: Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package org.opengroup.osdu.legal.ibm.acceptanceTests; + +import org.junit.After; +import org.junit.Before; +import org.opengroup.osdu.legal.acceptanceTests.GetLegalTagPropertiesApiAcceptanceTests; +import org.opengroup.osdu.legal.ibm.acceptanceTests.util.IBMLegalTagUtils; + + +public class TestGetLegalTagPropertiesApiAcceptance extends GetLegalTagPropertiesApiAcceptanceTests { + + @Before + @Override + public void setup() throws Exception { + this.legalTagUtils = new IBMLegalTagUtils(); + super.setup(); + } + + @After + @Override + public void teardown() throws Exception { + super.teardown(); + this.legalTagUtils = null; + } + +} \ No newline at end of file diff --git a/testing/legal-test-ibm/src/test/java/org/opengroup/osdu/legal/ibm/acceptanceTests/TestGetLegalTagsApiAcceptance.java b/testing/legal-test-ibm/src/test/java/org/opengroup/osdu/legal/ibm/acceptanceTests/TestGetLegalTagsApiAcceptance.java new file mode 100644 index 000000000..2c490d638 --- /dev/null +++ b/testing/legal-test-ibm/src/test/java/org/opengroup/osdu/legal/ibm/acceptanceTests/TestGetLegalTagsApiAcceptance.java @@ -0,0 +1,43 @@ +// (C) Copyright IBM Corporation 2019 +// U.S. Government Users Restricted Rights: Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package org.opengroup.osdu.legal.ibm.acceptanceTests; + +import org.junit.After; +import org.junit.Before; +import org.opengroup.osdu.legal.acceptanceTests.GetLegalTagsApiAcceptanceTests; +import org.opengroup.osdu.legal.ibm.acceptanceTests.util.IBMLegalTagUtils; + +/** + * @author mbayser + * + */ +public class TestGetLegalTagsApiAcceptance extends GetLegalTagsApiAcceptanceTests { + + @Before + @Override + public void setup() throws Exception { + this.legalTagUtils = new IBMLegalTagUtils(); + super.setup(); + } + + @After + @Override + public void teardown() throws Exception { + super.teardown(); + this.legalTagUtils = null; + } + +} \ No newline at end of file diff --git a/testing/legal-test-ibm/src/test/java/org/opengroup/osdu/legal/ibm/acceptanceTests/TestListLegalTagsApiAcceptance.java b/testing/legal-test-ibm/src/test/java/org/opengroup/osdu/legal/ibm/acceptanceTests/TestListLegalTagsApiAcceptance.java new file mode 100644 index 000000000..4e2f5724b --- /dev/null +++ b/testing/legal-test-ibm/src/test/java/org/opengroup/osdu/legal/ibm/acceptanceTests/TestListLegalTagsApiAcceptance.java @@ -0,0 +1,43 @@ +// (C) Copyright IBM Corporation 2019 +// U.S. Government Users Restricted Rights: Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package org.opengroup.osdu.legal.ibm.acceptanceTests; + +import org.junit.After; +import org.junit.Before; +import org.opengroup.osdu.legal.acceptanceTests.ListLegalTagsApiAcceptanceTests; +import org.opengroup.osdu.legal.ibm.acceptanceTests.util.IBMLegalTagUtils; + +/** + * @author mbayser + * + */ +public class TestListLegalTagsApiAcceptance extends ListLegalTagsApiAcceptanceTests { + + @Before + @Override + public void setup() throws Exception { + this.legalTagUtils = new IBMLegalTagUtils(); + super.setup(); + } + + @After + @Override + public void teardown() throws Exception { + super.teardown(); + this.legalTagUtils = null; + } + +} \ No newline at end of file diff --git a/testing/legal-test-ibm/src/test/java/org/opengroup/osdu/legal/ibm/acceptanceTests/TestUpdateLegalTagApiAcceptance.java b/testing/legal-test-ibm/src/test/java/org/opengroup/osdu/legal/ibm/acceptanceTests/TestUpdateLegalTagApiAcceptance.java new file mode 100644 index 000000000..a053ea810 --- /dev/null +++ b/testing/legal-test-ibm/src/test/java/org/opengroup/osdu/legal/ibm/acceptanceTests/TestUpdateLegalTagApiAcceptance.java @@ -0,0 +1,43 @@ +// (C) Copyright IBM Corporation 2019 +// U.S. Government Users Restricted Rights: Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package org.opengroup.osdu.legal.ibm.acceptanceTests; + +import org.junit.After; +import org.junit.Before; +import org.opengroup.osdu.legal.acceptanceTests.UpdateLegalTagApiAcceptanceTests; +import org.opengroup.osdu.legal.ibm.acceptanceTests.util.IBMLegalTagUtils; + +/** + * @author mbayser + * + */ +public class TestUpdateLegalTagApiAcceptance extends UpdateLegalTagApiAcceptanceTests { + + @Before + @Override + public void setup() throws Exception { + this.legalTagUtils = new IBMLegalTagUtils(); + super.setup(); + } + + @After + @Override + public void teardown() throws Exception { + super.teardown(); + this.legalTagUtils = null; + } + +} diff --git a/testing/legal-test-ibm/src/test/java/org/opengroup/osdu/legal/ibm/acceptanceTests/TestValidateLegalTagsApiAcceptance.java b/testing/legal-test-ibm/src/test/java/org/opengroup/osdu/legal/ibm/acceptanceTests/TestValidateLegalTagsApiAcceptance.java new file mode 100644 index 000000000..ca3e96673 --- /dev/null +++ b/testing/legal-test-ibm/src/test/java/org/opengroup/osdu/legal/ibm/acceptanceTests/TestValidateLegalTagsApiAcceptance.java @@ -0,0 +1,42 @@ +// (C) Copyright IBM Corporation 2019 +// U.S. Government Users Restricted Rights: Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package org.opengroup.osdu.legal.ibm.acceptanceTests; + +import org.junit.After; +import org.junit.Before; +import org.opengroup.osdu.legal.acceptanceTests.ValidateLegalTagsApiAcceptanceTests; +import org.opengroup.osdu.legal.ibm.acceptanceTests.util.IBMLegalTagUtils; + +/** + * @author mbayser + * + */ +public class TestValidateLegalTagsApiAcceptance extends ValidateLegalTagsApiAcceptanceTests { + + @Before + @Override + public void setup() throws Exception { + this.legalTagUtils = new IBMLegalTagUtils(); + super.setup(); + } + + @After + @Override + public void teardown() throws Exception { + super.teardown(); + this.legalTagUtils = null; + } +} diff --git a/testing/legal-test-ibm/src/test/java/org/opengroup/osdu/legal/ibm/acceptanceTests/util/IBMLegalTagUtils.java b/testing/legal-test-ibm/src/test/java/org/opengroup/osdu/legal/ibm/acceptanceTests/util/IBMLegalTagUtils.java new file mode 100644 index 000000000..661ca0c09 --- /dev/null +++ b/testing/legal-test-ibm/src/test/java/org/opengroup/osdu/legal/ibm/acceptanceTests/util/IBMLegalTagUtils.java @@ -0,0 +1,21 @@ +package org.opengroup.osdu.legal.ibm.acceptanceTests.util; + +import org.opengroup.osdu.legal.util.LegalTagUtils; + +public class IBMLegalTagUtils extends LegalTagUtils { + + public IBMLegalTagUtils() { + // TODO Auto-generated constructor stub + } + + @Override + public void uploadTenantTestingConfigFile() { + // TODO Auto-generated method stub + + } + + @Override + public String accessToken() throws Exception { + return System.getenv("LEGAL_TEST_TOKEN"); + } +} diff --git a/testing/legal-test-ibm/src/test/resources/InitialTags.json b/testing/legal-test-ibm/src/test/resources/InitialTags.json new file mode 100644 index 000000000..34ed7cfff --- /dev/null +++ b/testing/legal-test-ibm/src/test/resources/InitialTags.json @@ -0,0 +1,76 @@ +{ + "docs": [ + { + "_id": "1001", + "name": "valid_tag1", + "description": "description", + "is_valid": true, + "properties": { + "countryOfOrigin": [ + "US" + ], + "contractId": "Contract 1", + "expirationDate": 1765464244000, + "originator": "John Smith", + "dataType": "Wellbore", + "securityClassification": "confidential", + "personalData": "none", + "exportClassification": "restricted" + } + }, + { + "_id": "1002", + "name": "valid_tag1", + "description": "description", + "is_valid": true, + "properties": { + "countryOfOrigin": [ + "US" + ], + "contractId": "Contract 1", + "expirationDate": 1765464244000, + "originator": "John Smith", + "dataType": "Wellbore", + "securityClassification": "confidential", + "personalData": "none", + "exportClassification": "restricted" + } + }, + { + "_id": "1003", + "name": "invalid_tag1", + "description": "description", + "is_valid": false, + "properties": { + "countryOfOrigin": [ + "US" + ], + "contractId": "Contract 1", + "expirationDate": 1765464244000, + "originator": "John Smith", + "dataType": "Wellbore", + "securityClassification": "confidential", + "personalData": "none", + "exportClassification": "restricted" + } + }, + { + "_id": "1291004374", + "name": "TENANT1-dps-integration-test-1566474656479", + "description": "invalid date", + "is_valid": true, + "properties": { + "countryOfOrigin": [ + "US" + ], + "contractId": "A1234", + "expirationDate": 1134312244000, + "originator": "MyCompany", + "dataType": "Transferred Data", + "securityClassification": "Public", + "personalData": "No Personal Data", + "exportClassification": "EAR99" + } + } + ] +} diff --git a/testing/legal-test-ibm/src/test/resources/Tenant.json b/testing/legal-test-ibm/src/test/resources/Tenant.json new file mode 100644 index 000000000..965fdf592 --- /dev/null +++ b/testing/legal-test-ibm/src/test/resources/Tenant.json @@ -0,0 +1,17 @@ +{ + "docs": [ + { + "_id": "1001", + "name": "TENANT1", + "projectId": "PROJECT1", + "serviceAccount": "SERVICE1", + "complianceRuleSet": "shared", + "dataPartitionId": "PARTITION1", + "crmAccountIds": [ + "CRM0001", + "CRM0002", + "TENANT1" + ] + } + ] +} diff --git a/testing/legal-test-ibm/teardown_acceptance.sh b/testing/legal-test-ibm/teardown_acceptance.sh new file mode 100644 index 000000000..6009e2c56 --- /dev/null +++ b/testing/legal-test-ibm/teardown_acceptance.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +DATABASE_PREFIX=acceptance-test +BASE_URL=$(jq -r ".url" < ${IBM_CREDENTIALS_FILE}) +USERNAME=$(jq -r ".username" < ${IBM_CREDENTIALS_FILE}) +PASSWORD=$(jq -r ".password" < ${IBM_CREDENTIALS_FILE}) + +curl -XDELETE -u $USERNAME:$PASSWORD $BASE_URL/$DATABASE_PREFIX-countries +curl -XDELETE -u $USERNAME:$PASSWORD $BASE_URL/$DATABASE_PREFIX-legal-tags +curl -XDELETE -u $USERNAME:$PASSWORD $BASE_URL/$DATABASE_PREFIX-tenant-info -- GitLab