def get_root_account_file(self, value=None):
        """
        Get root account file from user
        """

        valid = False

        while not valid:
            if self.unattended:
                root_account_file = value
            else:
                root_account_file = input(
                    'Enter root account file URL (required): ')

            if not root_account_file:
                self._error('root_account_file required')
                continue

            try:
                url_validator = URLValidator(schemes=['http', 'https'])
                url_validator(root_account_file)
            except ValidationError:
                self._error('Invalid URL')
                continue

            if Path(root_account_file).suffix != '.json':
                self._error('JSON file required')
                continue

            try:
                download_root_account_file(url=root_account_file)
            except Exception as e:
                capture_exception(e)
                logger.exception(e)
                self.stdout.write(
                    self.style.ERROR(f'Error downloading {root_account_file}'))
                self.stdout.write(self.style.ERROR(e))
                continue

            file_hash = get_file_hash(settings.ROOT_ACCOUNT_FILE_PATH)

            if not self.required_input['head_block_hash']:
                self.required_input['head_block_hash'] = file_hash

            self_address = format_address(
                ip_address=self.required_input.get('ip_address'),
                port=self.required_input.get('port'),
                protocol=self.required_input.get('protocol'),
            )
            root_account_file = get_root_account_file_url(address=self_address)

            self.required_input.update({
                'root_account_file': root_account_file,
                'root_account_file_hash': file_hash
            })
            valid = True
Example #2
0
 def add_arguments(self, parser: CommandParser):
     super(Command, self).add_arguments(parser)
     parser.add_argument(
         '--node_type', choices=[CONFIRMATION_VALIDATOR, PRIMARY_VALIDATOR])
     parser.add_argument(
         '--seed_block_identifier',
         type=str_length_validator(length=BLOCK_IDENTIFIER_LENGTH))
     parser.add_argument('--head_block_hash',
                         type=str_length_validator(length=HEAD_HASH_LENGTH))
     parser.add_argument('--root_account_file',
                         type=url_validator(suffix='.json'))
def main():
    ssm_client: SSMClient = boto3.client('ssm')

    p = argparse.ArgumentParser(description='AWS provision and deploy.')
    p.add_argument('--env',
                   default='prod',
                   type=str,
                   help='Environment to run, default is prod.')
    p.add_argument(
        '--s3-bucket',
        required=True,
        type=str,
        help=
        '* The name of the S3 bucket where this command uploads the artifacts that are referenced in '
        'the template.')
    p.add_argument('--db-pass',
                   type=str_length_validator(min_len=8),
                   help='Database password to set.')
    p.add_argument('--sentry-dsn',
                   type=url_validator(),
                   help='DSN to set up Sentry tracking')

    p.add_argument(
        '--node-type',
        choices=[CONFIRMATION_VALIDATOR, PRIMARY_VALIDATOR],
        default=CONFIRMATION_VALIDATOR,
        help=
        'Network standardized type of node, default: CONFIRMATION_VALIDATOR.')
    p.add_argument('--primary-url',
                   type=url_validator(),
                   help='Primary validator URL (ex. http://10.10.10.10).')
    p.add_argument('--primary-trust',
                   type=int_validator(),
                   help='Trust level for the validator.')

    p.add_argument('--sign-key',
                   type=str_length_validator(length=64),
                   help='Network sign key.')
    p.add_argument('--node-identifier',
                   type=str_length_validator(length=VERIFY_KEY_LENGTH),
                   help='Public key used to sign requests to other nodes.')
    p.add_argument('--account-number',
                   required=True,
                   type=str_length_validator(length=VERIFY_KEY_LENGTH),
                   help='* The account number where Tx fees will be sent.')
    p.add_argument('--default-transaction-fee',
                   required=True,
                   type=int,
                   help='* Tx fee cost.')
    p.add_argument(
        '--seed-block-identifier',
        type=str_length_validator(length=BLOCK_IDENTIFIER_LENGTH),
        help=
        'Identifier of the last block that was used when the root account file was generated.'
    )
    p.add_argument(
        '--root-account-file',
        required=True,
        type=url_validator(suffix='.json'),
        help=
        '* Record of all account balances at the moment in time that the validator was first set to '
        '"primary".')
    p.add_argument('--version-number',
                   required=True,
                   type=str_length_validator(max_len=32),
                   help='* API version.')

    args = p.parse_args()

    if args.node_type == CONFIRMATION_VALIDATOR and not args.primary_url:
        p.error(
            '--primary-url is required when --node-type is CONFIRMATION_VALIDATOR.'
        )

    if args.node_type == CONFIRMATION_VALIDATOR and not args.primary_trust:
        p.error(
            '--primary-trust is required when --node-type is CONFIRMATION_VALIDATOR.'
        )

    db_pass = args.db_pass
    if not db_pass:
        db_pass = token_urlsafe(32)

    private_key, public_key = create_account()
    private_key = private_key.encode(encoder=HexEncoder).decode('utf-8')
    public_key = public_key.encode(encoder=HexEncoder).decode('utf-8')

    deploy_args = [
        f'ParameterKey=EnvironmentName,ParameterValue={args.env.capitalize()}',
        f'ParameterKey=MasterUserPassword,ParameterValue={db_pass}',
        f'ParameterKey=NetworkSigningKey,ParameterValue={args.sign_key or private_key}',
        f'ParameterKey=NodeType,ParameterValue={args.node_type}',
        f'ParameterKey=NodeIdentifier,ParameterValue={args.node_identifier or public_key}',
        f'ParameterKey=AccountNumber,ParameterValue={args.account_number}',
        f'ParameterKey=DefaultTransactionFee,ParameterValue={args.default_transaction_fee}',
        f'ParameterKey=RootAccountFile,ParameterValue={args.root_account_file}',
        f'ParameterKey=VersionNumber,ParameterValue={args.version_number}',
    ]
    if args.seed_block_identifier:
        deploy_args.append(
            f'ParameterKey=SeedBlockIdentifier,ParameterValue={args.seed_block_identifier}'
        )

    if args.node_type == CONFIRMATION_VALIDATOR:
        primary = urlparse(args.primary_url)
        deploy_args.extend([
            f'ParameterKey=PrimaryIp,ParameterValue={primary.hostname}',
            f'ParameterKey=PrimaryProto,ParameterValue={primary.scheme}',
            f'ParameterKey=PrimaryPort,ParameterValue={primary.port or 80}',
            f'ParameterKey=PrimaryTrust,ParameterValue={args.primary_trust}'
        ])

    if args.sentry_dsn:
        deploy_args.append(
            f'ParameterKey=DjangoSentryDSN,ParameterValue={args.sentry_dsn}')

    try:
        secret_key = ssm_client.get_parameter(
            Name=
            f'{args.env.capitalize()}ValidatorDjangoSecretKey{args.node_type}'
        )['Parameter']['Value']
        print(secret_key)
    except (ssm_client.exceptions.ParameterNotFound,
            ssm_client.exceptions.InvalidKeyId):
        secret_key = get_random_secret_key()

    deploy_args.append(
        f'ParameterKey=DjangoSecretKey,ParameterValue={secret_key}')

    subprocess.call([
        'sam', 'package', '--template-file', 'stack/env.cfn.yaml',
        '--s3-bucket', args.s3_bucket, '--output-template-file',
        'outputtemplate.yaml'
    ])

    subprocess.call([
        'sam', 'deploy', '--stack-name',
        f'{args.env.capitalize()}Validator{args.node_type}'.replace('_', '-'),
        '--template-file', 'outputtemplate.yaml', '--parameter-overrides',
        ' '.join(deploy_args), '--capabilities', 'CAPABILITY_AUTO_EXPAND',
        'CAPABILITY_NAMED_IAM'
    ])