Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Adopt SDK-standard behavior when no environment is specified #128

Merged
merged 3 commits into from
Jun 19, 2018

Conversation

RomainMuller
Copy link
Contributor

@RomainMuller RomainMuller commented Jun 19, 2018

  • Use environment variables in a way that is consistent with what the
    various AWS SDKs and CLIs do:
    • AWS_SHARED_CREDENTIALS_FILE can be used to override the location
      of the ~/.aws/credentials file
    • AWS_CONFIG_FILE can be used to override the location of the
      .aws/config file
  • Ensure the environment variable instructing the JS AWS SDK to load up
    data from the ~/.aws/config file gets set by the toolkit before
    aws-sdk is loaded
  • Create ~/.aws/credentials if ~/.aws/config exists, since the JS
    AWS SDK will start by loading configuration from there, and will fail
    if it does not exist
  • Retire the default-account and default-region keys from the
    context map, and replace them with aws:cdk:toolkit: keys that
    cannot be user-provided
  • Obtain the default region from AWS.config.region instead of trying
    to "manually" source from environment variables.

Fixes #59

* Use environment variables in a way that is consistent with what the
  various AWS SDKs and CLIs do:
  + `AWS_REGION` has precedence over `AWS_DEFAULT_REGION`
  + `AWS_SHARED_CREDENTIALS_FILE` can be used to override the location
    of the `~/.aws/credentials` file
  + `AWS_CONFIG_FILE` can be used to override the location of the
    `.aws/config` file
* Ensure the environment variable instructing the JS AWS SDK to load up
  data from the `~/.aws/config` file gets set by the toolkit before
  `aws-sdk` is loaded
* Create `~/.aws/credentials` if `~/.aws/config` exists, since the JS
  AWS SDK will start by loading configuration from there, and will fail
  if it does not exist
* Retire the `default-account` and `default-region` keys from the
  `context` map, and replace them with `aws:cdk:toolkit:` keys that
  cannot be user-provided

Fixes #59
@@ -401,7 +404,7 @@ async function initCommandLine() {
for (const stack of synthesizedStacks) {
if (stackIds.length !== 1) { highlight(stack.name); }
if (!stack.environment) {
throw new Error(`Stack ${stack.name} has no environment`);
throw new Error(`Stack ${stack.name} does not define an environment, and no usable default environment was found.`);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this going to be the error we emit when there are no credentials defined? If it is, it should indicate that instead of talking about environments, which, in the simple "getting started" case, are not something users actually even aware of.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was trying to come up with a phrasing to this effect, but nothing felt good. Will try again :)

* This ensures the correct environment is set-up so the AWS SDK properly
* loads up configruation stored in the shared credentials file (usually
* found at ~/.aws/credentials) and the aws config file (usually found at
* ~/.aws/config), if either is present.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add the URL of this pull request here

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK


if (fs.existsSync(awsConfigFile) && !fs.existsSync(sharedCredentialsFile)) {
/*
* Write an empty credentials file if there's a config fil, otherwise the SDK will simply bail out,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"fil" => "file"

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there some reference to that behavior that we can link to?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't believe so... The JS SDK documentation is extremely fuzzy about that. Short of linking to the particular line of code that fails to check for file existence...

import * as os from 'os';
import * as path from 'path';

export const sharedCredentialsFile =
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To ensure consistent behavior in the future in case the default of AWS_SHARED_CREDENTIALS_FILE changes in the SDK but we don't update here, why not just do:

process.env.AWS_SHARED_CREDENTIALS_FILE = process.env.AWS_SHARED_CREDENTIALS_FILE || path.join(...)

This way, if the SDK behavior will change for some reason and we don't update the toolkit (yet), the toolkit will "force" the SDK to read from the right file.

Also, this removes the need to export anything from this module and we won't need to require it twice.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All evidence (in particular, the reason why you have to set AWS_SDK_LOAD_CONFIG to have ~/.aws/config even considered by the JS SDK) indicates that SDKs are not going to change how those files are handled without a major version bump. That feels like unnecessary future-proofing.

And I would rather not use the process' environment as a fact way to manage global variables. I don't see why there's a problem in the double-require. Node's require will cache & only load once anyway.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair enough. For some reason I have a sense that since this is a "special" module, it would be better if it didn't export anything, so it's usage will strictly be reserved for the purpose of statically initializing the SDK.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It no longer exports anything - the main reason to export was to provide clear & effective debug messages to know "where did the region come from", but now using AWS.config.region, which is as SDK-esque as it gets.

@@ -72,12 +58,16 @@ export class SDK {
}

public defaultRegion() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since we need to read the account ID anyway by issuing a request to AWS, wouldn't it make more sense to read the region this way as well and avoid duplicating the SDKs behavior?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Which region to I configure in order to build the service endpoint URL that I will call in order to get the region? OH WAIT!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Obvsiouly you shouldn't configure a region. I believe the SDKs have a default region and we want the toolkit to behave exactly like them.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah right. It didn't work when I tested but that was because of initialization order. Now only using config.region.

function prohibitContextKey(self: Settings, key: string) {
if (!self.settings.context) { return; }
if (key in self.settings.context) {
throw new Error(`The 'context.${key}' key was found in ${fs_path.resolve(fileName)}, but it is illegal. Please remove it.`);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of "illegal" we should say "it is deprecated"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Deprecated implies it can still be used. Since this throws, it can no longer be used.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So maybe "no longer supported".

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Deal!

for (const contextKey of Object.keys(self.settings.context)) {
if (contextKey.startsWith(prefix)) {
// tslint:disable-next-line:max-line-length
warning(`A key starting with '${prefix}' key was found in ${fs_path.resolve(fileName)} ('context.${prefix}'), it might cause surprising behavior and should be removed.`);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use the terminology "reserved context key"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yap.

@eladb eladb merged commit 2263a5b into master Jun 19, 2018
@eladb eladb deleted the rmuller/default-environment branch June 19, 2018 13:59
@NGL321 NGL321 added the contribution/core This is a PR that came from AWS. label Sep 27, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
contribution/core This is a PR that came from AWS.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Unexpected behavior of default environment (region/account)
3 participants