Ejemplo n.º 1
0
    def update_from_vpc(self, vpc_stack, settings=None):
        """
        Override for EFS to update settings from VPC Stack

        :param ecs_composex.vpc.vpc_stack.XStack vpc_stack:
        :param ecs_composex.common.settings.ComposeXSettings settings:
        :return:
        """
        subnets_params = self.subnets_param
        if self.subnets_override:
            for subnet_az in vpc_stack.vpc_resource.azs:
                if subnet_az.title == self.subnets_override:
                    subnets_params = subnet_az
                    break
            else:
                raise KeyError(
                    f"{self.module.res_key}.{self.name} - "
                    f"Override subnet name {self.subnets_override} is not defined in x-vpc",
                    list(vpc_stack.vpc_resource.azs.keys()),
                )
        for count, az in enumerate(vpc_stack.vpc_resource.azs[subnets_params]):
            self.stack.stack_template.add_resource(
                MountTarget(
                    f"{self.logical_name}MountPoint{az.title().strip().split('-')[-1]}",
                    FileSystemId=Ref(self.cfn_resource),
                    SecurityGroups=[GetAtt(self.db_sg, "GroupId")],
                    SubnetId=Select(count, Ref(STORAGE_SUBNETS)),
                ))
Ejemplo n.º 2
0
def _write_file_into_efs(region, vpc_stack, efs_stack, request, key_name,
                         cfn_stacks_factory):
    """Write file stack contains a mount target and a instance to write a empty file with random name into the efs."""
    write_file_template = Template()
    write_file_template.set_version("2010-09-09")
    write_file_template.set_description(
        "Stack to write a file to the existing EFS")
    default_security_group_id = get_default_vpc_security_group(
        vpc_stack.cfn_outputs["VpcId"], region)
    write_file_template.add_resource(
        MountTarget(
            "MountTargetResource",
            FileSystemId=efs_stack.cfn_resources["FileSystemResource"],
            SubnetId=vpc_stack.cfn_outputs["PublicSubnetId"],
            SecurityGroups=[default_security_group_id],
        ))
    random_file_name = random_alphanumeric()
    user_data = (
        """
        #cloud-config
        package_update: true
        package_upgrade: true
        runcmd:
        - yum install -y nfs-utils
        - file_system_id_1=""" +
        efs_stack.cfn_resources["FileSystemResource"] + """
        - efs_mount_point_1=/mnt/efs/fs1
        - mkdir -p "${!efs_mount_point_1}"
        - mount -t nfs4 -o nfsvers=4.1,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2,noresvport,_netdev """
        +
        """"${!file_system_id_1}.efs.${AWS::Region}.${AWS::URLSuffix}:/" "${!efs_mount_point_1}"
        - touch ${!efs_mount_point_1}/""" + random_file_name + """
        - umount ${!efs_mount_point_1}
        - opt/aws/bin/cfn-signal -e $? --stack ${AWS::StackName} --resource InstanceToWriteEFS --region ${AWS::Region}
        """)
    write_file_template.add_resource(
        Instance(
            "InstanceToWriteEFS",
            CreationPolicy={"ResourceSignal": {
                "Timeout": "PT10M"
            }},
            ImageId=retrieve_latest_ami(region, "alinux2"),
            InstanceType="c5.xlarge",
            SubnetId=vpc_stack.cfn_outputs["PublicSubnetId"],
            UserData=Base64(Sub(user_data)),
            KeyName=key_name,
            DependsOn=["MountTargetResource"],
        ))
    write_file_stack = CfnStack(
        name=generate_stack_name("integ-tests-efs-write-file",
                                 request.config.getoption("stackname_suffix")),
        region=region,
        template=write_file_template.to_json(),
    )
    cfn_stacks_factory.create_stack(write_file_stack)

    cfn_stacks_factory.delete_stack(write_file_stack.name, region)

    return random_file_name
Ejemplo n.º 3
0
    SecurityGroupIngress=[efs_security_group_rule],
    VpcId=Ref(vpcid_param),
    GroupDescription="Allow NFS over TCP")
template.add_resource(efs_security_group)

# Create FileSystem. This is the actual filesystem, which has one or more
# mount targets. Give it some tags so we can identify it later.
tags = Tags(Name='MyEFSFileSystem')
efs_file_system = FileSystem("MyEFSFileSystem", FileSystemTags=tags)
template.add_resource(efs_file_system)

# create MountTarget. You really want a mount target in each subnet where
# it's required, but for the purpose of this example we'll
# put it in just one.
efs_mount_target = MountTarget("MyEFSMountTarget",
                               FileSystemId=Ref(efs_file_system),
                               SecurityGroups=[Ref(efs_security_group)],
                               SubnetId=Ref(subnetid_param))
template.add_resource(efs_mount_target)

# Create the policy that allows the instance to describe file systems and tags,
# so it can lookup the file system using AWS tags. An alternative would be to
# pass in the FileSystem name as UserData.
efs_host_role = Role(
    "EFSHostRole",
    AssumeRolePolicyDocument=PolicyDocument(Statement=[
        Statement(Effect=Allow,
                  Action=[
                      Action('elasticfilesystem', 'DescribeFileSystems'),
                      Action('elasticfilesystem', 'DescribeTags')
                  ],
                  Resource=["*"])
Ejemplo n.º 4
0
def main(args):
    t = Template()

    # [0 shared_dir, 1 efs_fs_id, 2 performance_mode, 3 efs_kms_key_id,
    # 4 provisioned_throughput, 5 encrypted, 6 throughput_mode, 7 exists_valid_head_node_mt, 8 exists_valid_compute_mt]
    efs_options = t.add_parameter(
        Parameter(
            "EFSOptions",
            Type="CommaDelimitedList",
            Description="Comma separated list of efs related options, 9 parameters in total",
        )
    )
    compute_security_group = t.add_parameter(
        Parameter("ComputeSecurityGroup", Type="String", Description="Security Group for Mount Target")
    )
    head_node_subnet_id = t.add_parameter(
        Parameter("MasterSubnetId", Type="String", Description="Head node subnet id for head node mount target")
    )
    compute_subnet_id = t.add_parameter(
        Parameter(
            "ComputeSubnetId",
            Type="String",
            Description="User provided compute subnet id. Will be use to create compute mount target if needed.",
        )
    )

    create_efs = t.add_condition(
        "CreateEFS",
        And(Not(Equals(Select(str(0), Ref(efs_options)), "NONE")), Equals(Select(str(1), Ref(efs_options)), "NONE")),
    )
    create_head_node_mt = t.add_condition(
        "CreateMasterMT",
        And(Not(Equals(Select(str(0), Ref(efs_options)), "NONE")), Equals(Select(str(7), Ref(efs_options)), "NONE")),
    )
    no_mt_in_compute_az = t.add_condition("NoMTInComputeAZ", Equals(Select(str(8), Ref(efs_options)), "NONE"))
    use_user_provided_compute_subnet = t.add_condition(
        "UseUserProvidedComputeSubnet", Not(Equals(Ref(compute_subnet_id), "NONE"))
    )
    # Need to create compute mount target if:
    # user is providing a compute subnet and
    # there is no existing MT in compute subnet's AZ(includes case where head node AZ == compute AZ).
    #
    # If user is not providing a compute subnet, either we are using the head node subnet as compute subnet,
    # or we will be creating a compute subnet that is in the same AZ as head node subnet,
    # see ComputeSubnet resource in the main stack.
    # In both cases no compute MT is needed.
    create_compute_mt = t.add_condition(
        "CreateComputeMT", And(Condition(use_user_provided_compute_subnet), Condition(no_mt_in_compute_az))
    )

    use_performance_mode = t.add_condition("UsePerformanceMode", Not(Equals(Select(str(2), Ref(efs_options)), "NONE")))
    use_efs_encryption = t.add_condition("UseEFSEncryption", Equals(Select(str(5), Ref(efs_options)), "true"))
    use_efs_kms_key = t.add_condition(
        "UseEFSKMSKey", And(Condition(use_efs_encryption), Not(Equals(Select(str(3), Ref(efs_options)), "NONE")))
    )
    use_throughput_mode = t.add_condition("UseThroughputMode", Not(Equals(Select(str(6), Ref(efs_options)), "NONE")))
    use_provisioned = t.add_condition("UseProvisioned", Equals(Select(str(6), Ref(efs_options)), "provisioned"))
    use_provisioned_throughput = t.add_condition(
        "UseProvisionedThroughput",
        And(Condition(use_provisioned), Not(Equals(Select(str(4), Ref(efs_options)), "NONE"))),
    )

    fs = t.add_resource(
        FileSystem(
            "EFSFS",
            PerformanceMode=If(use_performance_mode, Select(str(2), Ref(efs_options)), NoValue),
            ProvisionedThroughputInMibps=If(use_provisioned_throughput, Select(str(4), Ref(efs_options)), NoValue),
            ThroughputMode=If(use_throughput_mode, Select(str(6), Ref(efs_options)), NoValue),
            Encrypted=If(use_efs_encryption, Select(str(5), Ref(efs_options)), NoValue),
            KmsKeyId=If(use_efs_kms_key, Select(str(3), Ref(efs_options)), NoValue),
            Condition=create_efs,
        )
    )

    t.add_resource(
        MountTarget(
            "MasterSubnetEFSMT",
            FileSystemId=If(create_efs, Ref(fs), Select(str(1), Ref(efs_options))),
            SecurityGroups=[Ref(compute_security_group)],
            SubnetId=Ref(head_node_subnet_id),
            Condition=create_head_node_mt,
        )
    )

    t.add_resource(
        MountTarget(
            "ComputeSubnetEFSMT",
            FileSystemId=If(create_efs, Ref(fs), Select(str(1), Ref(efs_options))),
            SecurityGroups=[Ref(compute_security_group)],
            SubnetId=Ref(compute_subnet_id),
            Condition=create_compute_mt,
        )
    )

    t.add_output(
        Output(
            "FileSystemId",
            Description="ID of the FileSystem",
            Value=If(create_efs, Ref(fs), Select("1", Ref(efs_options))),
        )
    )

    # Specify output file path
    json_file_path = args.target_path
    output_file = open(json_file_path, "w")
    output_file.write(t.to_json())
    output_file.close()
def main(args):
    t = Template()

    # [0 shared_dir, 1 efs_fs_id, 2 performance_mode, 3 efs_kms_key_id,
    # 4 provisioned_throughput, 5 encrypted, 6 throughput_mode, 7 exists_valid_mt]
    efs_options = t.add_parameter(
        Parameter(
            "EFSOptions",
            Type="CommaDelimitedList",
            Description="Comma separated list of efs related options, "
            "8 parameters in total",
        ))
    compute_security_group = t.add_parameter(
        Parameter("ComputeSecurityGroup",
                  Type="String",
                  Description="SecurityGroup for Mount Target"))
    subnet_id = t.add_parameter(
        Parameter("SubnetId",
                  Type="String",
                  Description="SubnetId for Mount Target"))
    create_efs = t.add_condition(
        "CreateEFS",
        And(Not(Equals(Select(str(0), Ref(efs_options)), "NONE")),
            Equals(Select(str(1), Ref(efs_options)), "NONE")),
    )
    create_mt = t.add_condition(
        "CreateMT",
        And(Not(Equals(Select(str(0), Ref(efs_options)), "NONE")),
            Equals(Select(str(7), Ref(efs_options)), "NONE")),
    )
    use_performance_mode = t.add_condition(
        "UsePerformanceMode",
        Not(Equals(Select(str(2), Ref(efs_options)), "NONE")))
    use_efs_encryption = t.add_condition(
        "UseEFSEncryption", Equals(Select(str(5), Ref(efs_options)), "true"))
    use_efs_kms_key = t.add_condition(
        "UseEFSKMSKey",
        And(Condition(use_efs_encryption),
            Not(Equals(Select(str(3), Ref(efs_options)), "NONE"))))
    use_throughput_mode = t.add_condition(
        "UseThroughputMode",
        Not(Equals(Select(str(6), Ref(efs_options)), "NONE")))
    use_provisioned = t.add_condition(
        "UseProvisioned",
        Equals(Select(str(6), Ref(efs_options)), "provisioned"))
    use_provisioned_throughput = t.add_condition(
        "UseProvisionedThroughput",
        And(Condition(use_provisioned),
            Not(Equals(Select(str(4), Ref(efs_options)), "NONE"))),
    )

    fs = t.add_resource(
        FileSystem(
            "EFSFS",
            PerformanceMode=If(use_performance_mode,
                               Select(str(2), Ref(efs_options)), NoValue),
            ProvisionedThroughputInMibps=If(use_provisioned_throughput,
                                            Select(str(4), Ref(efs_options)),
                                            NoValue),
            ThroughputMode=If(use_throughput_mode,
                              Select(str(6), Ref(efs_options)), NoValue),
            Encrypted=If(use_efs_encryption, Select(str(5), Ref(efs_options)),
                         NoValue),
            KmsKeyId=If(use_efs_kms_key, Select(str(3), Ref(efs_options)),
                        NoValue),
            Condition=create_efs,
        ))

    mt = t.add_resource(
        MountTarget(
            "EFSMT",
            FileSystemId=If(create_efs, Ref(fs),
                            Select(str(1), Ref(efs_options))),
            SecurityGroups=[Ref(compute_security_group)],
            SubnetId=Ref(subnet_id),
            Condition=create_mt,
        ))

    t.add_output(
        Output(
            "FileSystemId",
            Description="ID of the FileSystem",
            Value=If(create_efs, Ref(fs), Select("1", Ref(efs_options))),
        ))

    # Specify output file path
    json_file_path = args.target_path
    output_file = open(json_file_path, "w")
    output_file.write(t.to_json())
    output_file.close()
Ejemplo n.º 6
0
    def test_efs(self):
        test_stack_name = 'TestNFSUsingEFS'
        init_cf_env(test_stack_name)
        ###
        t = Template()
        fs = t.add_resource(FileSystem("MyFileSystem"))

        client_sg = ts_add_security_group(t, name="ClientSecurityGroup")
        efs_client_sg = t.add_resource(
            SecurityGroup(
                "EFSClientSecurityGroup",  # This security group is just used to mark traffic to Mount Target
                GroupDescription="EFS Mount target client",
                VpcId=get_default_vpc()))
        mt_security_group = t.add_resource(
            SecurityGroup(
                "MountTargetSecurityGroup",
                GroupDescription='EFS Mount target',
                VpcId=get_default_vpc(),
                SecurityGroupIngress=[
                    SecurityGroupRule(
                        IpProtocol='tcp',
                        SourceSecurityGroupId=Ref(
                            efs_client_sg
                        ),  # Only allow traffic from the EFS client security group.
                        FromPort=2049,
                        ToPort=2049),
                ],
            ))

        mount_target_a = t.add_resource(
            MountTarget("MountTargetA",
                        FileSystemId=Ref(fs),
                        SecurityGroups=[Ref(mt_security_group)],
                        SubnetId=get_first_subnet()))
        mount_target_b = t.add_resource(
            MountTarget("MountTargetB",
                        FileSystemId=Ref(fs),
                        SecurityGroups=[Ref(mt_security_group)],
                        SubnetId=get_subnet(index=1)))

        instance_a = ts_add_instance_with_public_ip(
            t, [Ref(client_sg), Ref(efs_client_sg)],
            name='InstanceA',
            subnet_id=get_first_subnet())
        instance_a.DependsOn = "MountTargetA"
        instance_b = ts_add_instance_with_public_ip(
            t, [Ref(client_sg), Ref(efs_client_sg)],
            name='InstanceB',
            subnet_id=get_subnet(index=1))
        instance_b.DependsOn = "MountTargetB"

        t.add_output([
            Output(
                "PublicIPA",
                Value=GetAtt(instance_a, "PublicIp"),
            ),
            Output(
                "PublicIPB",
                Value=GetAtt(instance_b, "PublicIp"),
            ),
            Output("Region", Value=Ref("AWS::Region")),
            Output("FileSystemId", Value=Ref(fs)),
        ])

        dump_template(t, True)
        create_stack(test_stack_name, t)
        outputs = get_stack_outputs(test_stack_name)
        public_ip_a = get_output_value(outputs, 'PublicIPA')
        public_ip_b = get_output_value(outputs, 'PublicIPB')
        region = get_output_value(outputs, 'Region')
        fs_id = get_output_value(outputs, 'FileSystemId')

        nfs_url = f'{fs_id}.efs.{region}.amazonaws.com'  # use mount target IP if across VPC or on-premise
        share_path = '/var/share'
        run(f'ssh {SSH_OPTIONS} ec2-user@{public_ip_a} sudo mkdir {share_path}'
            )
        run(f"""ssh {SSH_OPTIONS} ec2-user@{public_ip_a} 'echo "{nfs_url}:/ {share_path} nfs4 nfsvers=4.1,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2,_netdev 0 0" | sudo tee -a /etc/fstab'"""
            )
        run(f'ssh {SSH_OPTIONS} ec2-user@{public_ip_a} sudo mount -a')
        run(f'ssh {SSH_OPTIONS} ec2-user@{public_ip_a} sudo touch {share_path}/hello'
            )

        run(f'ssh {SSH_OPTIONS} ec2-user@{public_ip_b} sudo mkdir {share_path}'
            )
        run(f"""ssh {SSH_OPTIONS} ec2-user@{public_ip_b} 'echo "{nfs_url}:/ {share_path} nfs4 nfsvers=4.1,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2,_netdev 0 0" | sudo tee -a /etc/fstab'"""
            )
        run(f'ssh {SSH_OPTIONS} ec2-user@{public_ip_b} sudo mount -a')
        stdout = run(
            f'ssh {SSH_OPTIONS} ec2-user@{public_ip_b} sudo ls {share_path}')
        self.assertIn('hello', stdout)