Aws-cdk: python aws_config.CfnCustomRule.scope property conflict

Created on 1 Oct 2019  路  4Comments  路  Source: aws/aws-cdk

description of the bug

The python aws_config.CfnCustomRule construct's __init__() method improperly passes the construct's "scope" property to the jsii.create() method. It should be pass the property "scope_".

Reproduction Steps

scratch.py

from aws_cdk import core, aws_config


class ConfigRuleStack(core.Stack):
    def __init__(self, scope: core.Construct, id: str, **kwargs) -> None:
        super().__init__(scope, id)

        aws_config.CfnConfigRule(
            self, "myRule",
            source=aws_config.CfnConfigRule.SourceProperty(
                owner="AWS",
                source_identifier="REQUIRED_TAGS"
            ),
            scope=aws_config.CfnConfigRule.ScopeProperty(
                compliance_resource_types=["AWS::EC2::Volume"]
            )
        )


app = core.App()
ConfigRuleStack(app, "rules-stack")
app.synth()

Error Log

$ cdk synth -a "python3 scratch.py"
jsii.errors.JavaScriptError:
  Error: Expected object reference, got {"complianceResourceId":null,"complianceResourceTypes":["AWS::EC2::Volume"],"tagKey":null,"tagValue":null}
      at Object.deserialize (/home/username/Projects/foo/foo-aws-config/.venv/lib/python3.6/site-packages/jsii/_embedded/jsii/jsii-runtime.js:12380:23)
      at Kernel._toSandbox (/home/username/Projects/foo/foo-aws-config/.venv/lib/python3.6/site-packages/jsii/_embedded/jsii/jsii-runtime.js:7159:61)
      at /home/username/Projects/foo/foo-aws-config/.venv/lib/python3.6/site-packages/jsii/_embedded/jsii/jsii-runtime.js:7212:33
      at Array.map (<anonymous>)
      at Kernel._boxUnboxParameters (/home/username/Projects/foo/foo-aws-config/.venv/lib/python3.6/site-packages/jsii/_embedded/jsii/jsii-runtime.js:7212:19)
      at Kernel._toSandboxValues (/home/username/Projects/foo/foo-aws-config/.venv/lib/python3.6/site-packages/jsii/_embedded/jsii/jsii-runtime.js:7197:21)
      at /home/username/Projects/foo/foo-aws-config/.venv/lib/python3.6/site-packages/jsii/_embedded/jsii/jsii-runtime.js:6798:66
      at Kernel._wrapSandboxCode (/home/username/Projects/foo/foo-aws-config/.venv/lib/python3.6/site-packages/jsii/_embedded/jsii/jsii-runtime.js:7253:19)
      at Kernel._create (/home/username/Projects/foo/foo-aws-config/.venv/lib/python3.6/site-packages/jsii/_embedded/jsii/jsii-runtime.js:6798:26)
      at Kernel.create (/home/username/Projects/foo/foo-aws-config/.venv/lib/python3.6/site-packages/jsii/_embedded/jsii/jsii-runtime.js:6552:21)
      at KernelHost.processRequest (/home/username/Projects/foo/foo-aws-config/.venv/lib/python3.6/site-packages/jsii/_embedded/jsii/jsii-runtime.js:6327:28)
      at KernelHost.run (/home/username/Projects/foo/foo-aws-config/.venv/lib/python3.6/site-packages/jsii/_embedded/jsii/jsii-runtime.js:6270:14)
      at Immediate._onImmediate (/home/username/Projects/foo/foo-aws-config/.venv/lib/python3.6/site-packages/jsii/_embedded/jsii/jsii-runtime.js:6273:37)
      at processImmediate (internal/timers.js:439:21)

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "scratch.py", line 20, in <module>
    ConfigRuleStack(app, "rules-stack")
  File "/home/username/Projects/foo/foo-aws-config/.venv/lib/python3.6/site-packages/jsii/_runtime.py", line 66, in __call__
    inst = super().__call__(*args, **kwargs)
  File "scratch.py", line 15, in __init__
    compliance_resource_types=["AWS::EC2::Volume"]
  File "/home/username/Projects/foo/foo-aws-config/.venv/lib/python3.6/site-packages/jsii/_runtime.py", line 66, in __call__
    inst = super().__call__(*args, **kwargs)
  File "/home/username/Projects/foo/foo-aws-config/.venv/lib/python3.6/site-packages/aws_cdk/aws_config/__init__.py", line 153, in __init__
    jsii.create(CfnConfigRule, self, [scope, id, props])
  File "/home/username/Projects/foo/foo-aws-config/.venv/lib/python3.6/site-packages/jsii/_kernel/__init__.py", line 208, in create
    overrides=overrides,
  File "/home/username/Projects/foo/foo-aws-config/.venv/lib/python3.6/site-packages/jsii/_kernel/providers/process.py", line 331, in create
    return self._process.send(request, CreateResponse)
  File "/home/username/Projects/foo/foo-aws-config/.venv/lib/python3.6/site-packages/jsii/_kernel/providers/process.py", line 316, in send
    raise JSIIError(resp.error) from JavaScriptError(resp.stack)
jsii.errors.JSIIError: Expected object reference, got {"complianceResourceId":null,"complianceResourceTypes":["AWS::EC2::Volume"],"tagKey":null,"tagValue":null}
Subprocess exited with error 1

Environment

  • **CLI Version : 1.10.0 (build 19ae072)
  • **Framework Version: 1.10.0
  • **OS : Ubuntu 18.04
  • **Language :Python3.6.8

Synopsis

Most Construct classes take a positional argument called "scope" which represents the parent core.Construct object.

But in the in the CfnConfigRule class (lib/python3.6/site-packages/aws_cdk/aws_config/__init__.py), the positional argument "scope" is smartly changed to "scope_". It is likely because this class also has a named parameter "scope".

The problem is that on line 153 we call jsii.create(CfnConfigRule, self, [scope, id, props]) and pass the "scope" parameter (which is an IResolveable or a ScopeProperty object type) when we should be passing the scope_ parameter (which is a core.Construct) like this jsii.create(CfnConfigRule, self, [scope_, id, props]).

As such, it throws the error.

The class definition for CfnConfigRule is below;

lib/python3.6/site-packages/aws_cdk/aws_config/__init__.py
starting at line 130:

class CfnConfigRule(aws_cdk.core.CfnResource, metaclass=jsii.JSIIMeta, jsii_type="@aws-cdk/aws-config.CfnConfigRule"):
    """A CloudFormation ``AWS::Config::ConfigRule``.

    see
    :see: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-config-configrule.html
    cloudformationResource:
    :cloudformationResource:: AWS::Config::ConfigRule
    """
    def __init__(self, scope_: aws_cdk.core.Construct, id: str, *, source: typing.Union["SourceProperty", aws_cdk.core.IResolvable], config_rule_name: typing.Optional[str]=None, description: typing.Optional[str]=None, input_parameters: typing.Any=None, maximum_execution_frequency: typing.Optional[str]=None, scope: typing.Optional[ typing.Union[ typing.Optional[aws_cdk.core.IResolvable], typing.Optional["ScopeProperty"] ] ]=None ) -> None:
        """Create a new ``AWS::Config::ConfigRule``.

        :param scope: - scope in which this resource is defined.
        :param id: - scoped id of the resource.
        :param props: - resource properties.
        :param source: ``AWS::Config::ConfigRule.Source``.
        :param config_rule_name: ``AWS::Config::ConfigRule.ConfigRuleName``.
        :param description: ``AWS::Config::ConfigRule.Description``.
        :param input_parameters: ``AWS::Config::ConfigRule.InputParameters``.
        :param maximum_execution_frequency: ``AWS::Config::ConfigRule.MaximumExecutionFrequency``.
        :param scope: ``AWS::Config::ConfigRule.Scope``.
        """
        props = CfnConfigRuleProps(source=source, config_rule_name=config_rule_name, description=description, input_parameters=input_parameters, maximum_execution_frequency=maximum_execution_frequency, scope=scope)

        jsii.create(CfnConfigRule, self, [scope, id, props])

This is :bug: Bug Report

bug languagpython managemendevenv p1

Most helpful comment

That works! Thanks!

For others looking for an example of how to do this.

```
my_lambda = aws_lambda.Function.from_function_arn(
self, "myLambda",
function_arn=f"arn:aws:lambda:{lambda_region}:{lambda_account}:function:{lambda_name}"
)
my_rule = aws_config.CustomRule(
self, "myRule",
lambda_function=my_lambda,
configuration_changes=True,
)
remote_rule.scope_to_resource("AWS::EC2::VPC")

````

All 4 comments

As a workaround, can you try with the ManagedRule class and the scopeToResource()/scopeToTag() methods?

@jofoid, I demonstrated the problem in this issue using a managed rule because the code was simpler than a custom rule. I actually need to define a custom rule with the lambda hosted in a remote account.

I would use the aws_config.CustomRule construct, which works using the method you mentioned. But it requires an ILambda object for the lambda= parameter. In my case, the lambda is in a remote account and I need to provide an arn to the lambda rather than a lambda object... So I was forced to use the CfnConfigRule construct and ran into this bug with the scope= parameter.

The workaround I'm currently using is the core.CfnResource construct.

@peterb154 you should be able to use the CustomRule construct and import your existing Lambda function using the from_function_arn class method to get an IFunction object.

That works! Thanks!

For others looking for an example of how to do this.

```
my_lambda = aws_lambda.Function.from_function_arn(
self, "myLambda",
function_arn=f"arn:aws:lambda:{lambda_region}:{lambda_account}:function:{lambda_name}"
)
my_rule = aws_config.CustomRule(
self, "myRule",
lambda_function=my_lambda,
configuration_changes=True,
)
remote_rule.scope_to_resource("AWS::EC2::VPC")

````

Was this page helpful?
0 / 5 - 0 ratings