Skip to content

Instantly share code, notes, and snippets.

@myh-st
Last active May 16, 2023 09:07
Show Gist options
  • Select an option

  • Save myh-st/47fbce4d9a85d6a9e64add9da4ce7d53 to your computer and use it in GitHub Desktop.

Select an option

Save myh-st/47fbce4d9a85d6a9e64add9da4ce7d53 to your computer and use it in GitHub Desktop.

Revisions

  1. myh-st revised this gist May 16, 2023. 1 changed file with 0 additions and 7 deletions.
    7 changes: 0 additions & 7 deletions sample-cicd-glue-cdk.md
    Original file line number Diff line number Diff line change
    @@ -1,10 +1,3 @@
    ---
    Crafted by [Genie](https://marketplace.visualstudio.com/items?itemName=genieai.chatgpt-vscode)

    ---

    ## You

    เขียน aws cdk ในการเชื่อมต่อ git codcommit เพื่อทำ ci/cd aws glue ประมาณ 3 jobs

    ## Genie
  2. myh-st renamed this gist May 16, 2023. 1 changed file with 0 additions and 0 deletions.
    File renamed without changes.
  3. myh-st created this gist May 16, 2023.
    241 changes: 241 additions & 0 deletions gistfile1.txt
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,241 @@
    ---
    Crafted by [Genie](https://marketplace.visualstudio.com/items?itemName=genieai.chatgpt-vscode)

    ---

    ## You

    เขียน aws cdk ในการเชื่อมต่อ git codcommit เพื่อทำ ci/cd aws glue ประมาณ 3 jobs

    ## Genie

    ตัวอย่างการใช้ AWS CDK สำหรับการเชื่อมต่อ Git CodeCommit และสร้าง CI/CD pipeline สำหรับ AWS Glue ที่ประกอบด้วย 3 jobs:

    1. สร้างไฟล์ `cdk.json` ที่รากของโปรเจคของคุณ (ถ้ายังไม่มี) และตั้งค่าคำสั่งเริ่มต้นสำหรับ CDK:

    ```json
    {
    "app": "npx ts-node --prefer-ts-exts infra/app.ts"
    }
    ```

    2. สร้างไดเรกทอรี `infra` และสร้างไฟล์ `infra/app.ts` ดังนี้:

    ```typescript
    import * as cdk from 'aws-cdk-lib';
    import { PipelineStack } from './pipeline-stack';

    const app = new cdk.App();
    new PipelineStack(app, 'PipelineStack');
    ```

    3. สร้างไฟล์ `infra/pipeline-stack.ts` ที่มีโค้ดต่อไปนี้:

    ```typescript
    import * as cdk from 'aws-cdk-lib';
    import { Construct } from 'constructs';
    import * as codecommit from 'aws-cdk-lib/aws-codecommit';
    import * as codepipeline from 'aws-cdk-lib/aws-codepipeline';
    import * as codepipeline_actions from 'aws-cdk-lib/aws-codepipeline-actions';
    import * as glue from 'aws-cdk-lib/aws-glue';
    import * as iam from 'aws-cdk-lib/aws-iam';

    export class PipelineStack extends cdk.Stack {
    constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    // Create a CodeCommit repository
    const repo = new codecommit.Repository(this, 'GlueJobsRepo', {
    repositoryName: 'glue-jobs-repo',
    });

    // Create a CodePipeline
    const pipeline = new codepipeline.Pipeline(this, 'GlueJobsPipeline', {
    pipelineName: 'glue-jobs-pipeline',
    });

    // Add source stage to the pipeline
    const sourceOutput = new codepipeline.Artifact();
    const sourceAction = new codepipeline_actions.CodeCommitSourceAction({
    actionName: 'CodeCommit_Source',
    repository: repo,
    output: sourceOutput,
    });
    pipeline.addStage({
    stageName: 'Source',
    actions: [sourceAction],
    });

    // Add deploy stage to the pipeline
    const deployAction = new codepipeline_actions.AwsLambdaInvokeAction({
    actionName: 'Deploy_Glue_Jobs',
    lambda: this.createDeploymentFunction(),
    userParameters: {
    glueJobNames: ['job1', 'job2', 'job3'],
    },
    });
    pipeline.addStage({
    stageName: 'Deploy',
    actions: [deployAction],
    });
    }

    private createDeploymentFunction(): lambda.Function {
    // Create an IAM role for the Lambda function
    const role = new iam.Role(this, 'DeploymentFunctionRole', {
    assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'),
    });
    role.addToPolicy(
    new iam.PolicyStatement({
    actions: [
    'glue:CreateJob',
    'glue:UpdateJob',
    'glue:DeleteJob',
    'glue:GetJob',
    ],
    resources: ['*'],
    })
    );

    // Create the Lambda function
    return new lambda.Function(this, 'DeploymentFunction', {
    runtime: lambda.Runtime.NODEJS_14_X,
    handler: 'index.handler',
    code: lambda.Code.fromAsset(path.join(__dirname, 'deployment-function')),
    role: role,
    });
    }
    }
    ```

    4. สร้างไดเรกทอรี `infra/deployment-function` และสร้างไฟล์ `infra/deployment-function/index.js` ที่มีโค้ดต่อไปนี้:

    ```javascript
    const AWS = require('aws-sdk');
    const glue = new AWS.Glue();

    exports.handler = async (event) => {
    const jobNames = event.userParameters.glueJobNames;

    for (const jobName of jobNames) {
    await createOrUpdateGlueJob(jobName);
    }
    };

    async function createOrUpdateGlueJob(jobName) {
    try {
    await glue.getJob({ JobName: jobName }).promise();
    console.log(`Updating Glue job: ${jobName}`);
    // Update the job with new settings
    } catch (error) {
    if (error.code === 'EntityNotFoundException') {
    console.log(`Creating Glue job: ${jobName}`);
    // Create the job with initial settings
    } else {
    throw error;
    }
    }
    }
    ```

    5. ติดตั้ง dependencies ของ CDK และ TypeScript ด้วยคำสั่ง:

    ```bash
    npm install aws-cdk-lib constructs typescript ts-node
    ```

    6. สั่งให้ CDK สร้าง stack ด้วยคำสั่ง:

    ```bash
    npx cdk deploy
    ```

    โค้ดด้านบนจะสร้าง CodeCommit repository และ CodePipeline ที่มี 2 stages: Source และ Deploy. ในขั้นตอนการ Deploy, Lambda function จะถูกเรียกใช้เพื่อสร้างหรืออัปเดต Glue jobs ตามที่ระบุใน `userParameters`. คุณสามารถปรับแต่งโค้ดใน `createOrUpdateGlueJob` เพื่อกำหนดค่าต่าง ๆ สำหรับ Glue jobs ของคุณ.

    ## You

    แล้ว code ของแต่ละ job ที่มี .py นั้นต้องเก็บไว้ที่ไหน

    ## Genie

    คุณสามารถเก็บไฟล์ `.py` ของแต่ละ job ในโฟลเดอร์ที่อยู่ใน CodeCommit repository ที่เราสร้างขึ้นก่อนหน้านี้ (ชื่อว่า `glue-jobs-repo`) โดยสามารถจัดระเบียบโค้ดของ Glue jobs ตามโครงสร้างโฟลเดอร์ที่คุณต้องการ ตัวอย่างเช่น:

    ```
    glue-jobs-repo/
    ├── job1/
    │ └── job1.py
    ├── job2/
    │ └── job2.py
    └── job3/
    └── job3.py
    ```

    เมื่อคุณมีโค้ดของ Glue jobs ใน repository แล้ว คุณต้องปรับแต่ง Lambda function ใน `infra/deployment-function/index.js` เพื่ออ่านไฟล์ `.py` และส่งค่าให้กับ Glue jobs ที่ถูกสร้างหรืออัปเดต คุณสามารถทำได้ดังนี้:

    1. ใน `infra/pipeline-stack.ts`, ปรับแต่ง `userParameters` ใน `AwsLambdaInvokeAction` โดยเพิ่มพารามิเตอร์ `jobScriptPaths`:

    ```typescript
    const deployAction = new codepipeline_actions.AwsLambdaInvokeAction({
    actionName: 'Deploy_Glue_Jobs',
    lambda: this.createDeploymentFunction(),
    userParameters: {
    glueJobNames: ['job1', 'job2', 'job3'],
    jobScriptPaths: ['job1/job1.py', 'job2/job2.py', 'job3/job3.py'], // Add this line
    },
    });
    ```

    2. ใน `infra/deployment-function/index.js`, ปรับแต่งฟังก์ชัน `handler` ให้รับพารามิเตอร์ `jobScriptPaths` และส่งค่าให้กับฟังก์ชัน `createOrUpdateGlueJob`:

    ```javascript
    exports.handler = async (event) => {
    const jobNames = event.userParameters.glueJobNames;
    const jobScriptPaths = event.userParameters.jobScriptPaths;

    for (let i = 0; i < jobNames.length; i++) {
    await createOrUpdateGlueJob(jobNames[i], jobScriptPaths[i]);
    }
    };
    ```

    3. ปรับแต่งฟังก์ชัน `createOrUpdateGlueJob` ใน `infra/deployment-function/index.js` เพื่อรับพารามิเตอร์ `jobScriptPath` และใช้ค่านี้เมื่อสร้างหรืออัปเดต Glue job:

    ```javascript
    async function createOrUpdateGlueJob(jobName, jobScriptPath) {
    // ... (existing code)

    // Replace the existing try block with the following:
    try {
    await glue.getJob({ JobName: jobName }).promise();
    console.log(`Updating Glue job: ${jobName}`);
    // Update the job with new settings and script path
    await glue.updateJob({
    JobName: jobName,
    JobUpdate: {
    Command: {
    ScriptLocation: `s3://your-bucket-name/${jobScriptPath}`,
    },
    },
    }).promise();
    } catch (error) {
    if (error.code === 'EntityNotFoundException') {
    console.log(`Creating Glue job: ${jobName}`);
    // Create the job with initial settings and script path
    await glue.createJob({
    Name: jobName,
    Role: 'your-glue-job-role-arn',
    Command: {
    Name: 'glueetl',
    ScriptLocation: `s3://your-bucket-name/${jobScriptPath}`,
    },
    }).promise();
    } else {
    throw error;
    }
    }
    }
    ```

    อย่าลืมแทนที่ `'your-bucket-name'` และ `'your-glue-job-role-arn'` ด้วยชื่อของ S3 bucket และ ARN ของ IAM role ที่ใช้กับ Glue jobs ของคุณ

    เมื่อคุณทำตามขั้นตอนด้านบนแล้ว โค้ดของ Glue jobs จะถูกอ่านจากไฟล์ `.py` ใน CodeCommit repository และส่งค่าให้กับ Glue jobs ที่ถูกสร้างหรืออัปเดต