Repository: serverless/serverless (JavaScript)
Date: 2019-01-04 12:14:53+00:00
Task type: Bug Fix

Issue:
AWS: Extend ${cf} syntax to get output from another region broken
<!--
1. If you have a question and not a bug report please ask first at http://forum.serverless.com
2. Please check if an issue already exists. This bug may have already been documented
3. Check out and follow our Guidelines: https://github.com/serverless/serverless/blob/master/CONTRIBUTING.md
4. Fill out the whole template so we have a good overview on the issue
5. Do not remove any section of the template. If something is not applicable leave it empty but leave it in the Issue
6. Please follow the template, otherwise we'll have to ask you to update it
-->

# This is a Bug Report

## Description
@dschep @horike37 @exoego 
maybe I am missing something here, but this feature doesn't seem to be working as intended.
cf cross region is just creating a stack on the referenced region, with naming from the referencing region.

* What went wrong?
  - created stack `bar` in zone **`y`** and reference existing stack `foo` in zone `y`  
* What did you expect should have happened?
  - created stack `bar` in zone **`x`** and reference existing stack `foo` in zone `y`  
* What was the config you used?
  - this two used stacks `foo` and `bar` will cause the error. `x=us-east-1;` `y=eu-central-1;`

```
service: foo

provider:
  name: aws
  region: eu-central-1
  stage: dev
  profile: cndx-dev
  runtime: nodejs8.10
  memory: 1024

functions:
  hello:
    handler: handler.hello

resources:
  Outputs:
    foo:
      Value: foo
      Export:
        Name: foo
```

```
service: bar

provider:
  name: aws
  region: us-east-1
  stage: dev
  profile: cndx-dev
  runtime: nodejs8.10
  memory: 1024

functions:
  hello:
    handler: handler.hello

resources:
  Outputs:
    foobar:
      Value: ${self:custom.foobar}
      Export:
        Name: foobar

custom:
  foobar: ${cf.eu-central-1:foo-dev.foo}bar
  # foobar: foobar
```

* What stacktrace or error message from your provider did you see?
  - none

* Steps to reproduce:
```
version 1:
  1. `sls deploy` foo
  2. `sls deploy` bar (_with_ the stack reference in this last two lines enabled)
    -> this will lead to the creation of a new stack `bar-dev` in the same region as `foo-dev`
    -> error: _no direct error_ but stack `bar-dev` should be in  `us-east-1`
```
```
version 2:
1. `sls deploy` foo
2. `sls deploy` bar (_without_ the stack reference in this last two lines enabled)
3. `sls deploy` bar (_with_ the stack reference in this last two lines enabled)
  -> this will lead to the creation of a new stack `bar-dev` in the same region as `foo-dev`
  -> error: `An error occurred: IamRoleLambdaExecution - bar-dev-us-east-1-lambdaRole already exists.`
```

Similar or dependent issues:
* none

## Additional Data

* ***Serverless Framework Version you're using***: 1.35.0
* ***Operating System***: macos 10.14.2
* ***Stack Trace***: none
* ***Provider Error messages***: none



Issue discussion:
Hey, @smartinspereira any news about it? The same thing happens to me as well.
Sorry, been overwhelmed without time to check this out. @exoego, any chance you have any input since you implemented this feature?
@efimk-lu unfortunately nothing new, but i also did not test this using 1.35.1 again.
We've been testing it with Version 1.35.1, the latest :-(
I briefly tested using serverless `1.35.1` and the described serverless YAMLs while `profile: cndx-dev` were commented out (since I do not have such profile).

As far as I tested, serverless can deploy stacks to the specified regions (`foo` to eu-central-1, `bar` to us-east-1) and `${cf.REGION}` syntax works.

So I am guessing that `profile` could be suspicious.

@smartinspereira @efimk-lu 
Can you provide AWS profile ?
Please DO NOT SHARE `aws_access_key_id`, `aws_secret_access_key` or other credential information from profile.
Also, if you run `sls deploy` command with some options such as `--region` and so on, those may help too.




@exoego I'll share it shortly. We tried with --region and hard-coding region in the yaml.
@exoego what exactly do you mean with _Can you provide AWS profile ?_.
are you sure that your stack `bar` is in us-east-1? - see `version 1`, it will deploy the stack, but in the wrong region. also you could just create a profile in `~/.aws/credentials` with the name `cndx-dev` and your own credentials.
>  are you sure that your stack bar is in us-east-1? - see version 1, 

Actually, `bar` was deployed to `eu-central-1`, not `us-east-1`.
However, serverless log says that it deployed to `us-east-1` like below:

```
Serverless: Stack update finished...
Service Information
service: bar
stage: dev
region: us-east-1
stack: bar-dev
api keys:
  None
endpoints:
  None
functions:
  hello: bar-dev-hello
layers:
  None
```
> what exactly do you mean with Can you provide AWS profile ?

I initially thought default region or such field in profile may help to reproduce issue.
However, it seems that profile is not needed to reproduce.






I think I found a root cause.
Will open a PR this weekend.


Solution patch:
diff --git a/lib/plugins/aws/provider/awsProvider.js b/lib/plugins/aws/provider/awsProvider.js
index 1b4cc8655e1..cb68ddcd898 100644
--- a/lib/plugins/aws/provider/awsProvider.js
+++ b/lib/plugins/aws/provider/awsProvider.js
@@ -226,7 +226,7 @@ class AwsProvider {
    */
   request(service, method, params, options) {
     const that = this;
-    const credentials = that.getCredentials();
+    const credentials = _.cloneDeep(that.getCredentials());
     // Make sure options is an object (honors wrong calls of request)
     const requestOptions = _.isObject(options) ? options : {};
     const shouldCache = _.get(requestOptions, 'useCache', false);


Test patch:
diff --git a/lib/plugins/aws/provider/awsProvider.test.js b/lib/plugins/aws/provider/awsProvider.test.js
index c2952fe88e4..d3ce0ee9227 100644
--- a/lib/plugins/aws/provider/awsProvider.test.js
+++ b/lib/plugins/aws/provider/awsProvider.test.js
@@ -324,6 +324,7 @@ describe('AwsProvider', () => {
           },
         },
       };
+      expect(awsProvider.getCredentials()).to.deep.eql({ region: options.region });
 
       return awsProvider
         .request('CloudFormation',
@@ -332,6 +333,8 @@ describe('AwsProvider', () => {
           { region: 'ap-northeast-1' })
         .then(data => {
           expect(data).to.eql({ region: 'ap-northeast-1' });
+          // Requesting different region should not affect region in credentials
+          expect(awsProvider.getCredentials()).to.deep.eql({ region: options.region });
         });
     });