Contoh 2: Skrip runbook - AWS Systems Manager

Terjemahan disediakan oleh mesin penerjemah. Jika konten terjemahan yang diberikan bertentangan dengan versi bahasa Inggris aslinya, utamakan versi bahasa Inggris.

Contoh 2: Skrip runbook

Contoh runbook ini membahas skenario berikut: Emily adalah Systems Engineer di AnyCompany Konsultan, LLC. Dia sebelumnya membuat dua runbook yang digunakan dalam hubungan orangtua-anak untuk melakukan patch pada grup instans Amazon Elastic Compute Cloud (Amazon EC2) yang meng-host database primer dan sekunder. Aplikasi mengakses database ini 24 jam sehari, jadi salah satu instance database harus selalu tersedia.

Berdasarkan persyaratan ini, ia membangun solusi yang menambal instance secara bertahap menggunakanAWS-RunPatchBaselineDokumen Systems Manager (SSM). Dengan menggunakan dokumen SSM ini, rekan-rekannya dapat meninjau informasi kepatuhan patch terkait setelah operasi patching selesai.

Kelompok utama contoh database ditambal pertama, diikuti oleh kelompok sekunder contoh database. Selain itu, untuk menghindari biaya tambahan dengan membiarkan instance berjalan yang sebelumnya dihentikan, Emily memastikan bahwa otomatisasi mengembalikan instance yang ditambal ke keadaan semula sebelum penambalan terjadi. Emily menggunakan tag yang terkait dengan grup instance database primer dan sekunder untuk mengidentifikasi instance mana yang harus ditambal sesuai urutan yang diinginkannya.

Solusi otomatisnya yang ada berhasil, tetapi dia ingin meningkatkan solusinya jika memungkinkan. Untuk membantu pemeliharaan konten runbook dan untuk memudahkan upaya pemecahan masalah, dia ingin memadatkan otomatisasi menjadi satu runbook dan menyederhanakan jumlah parameter input. Juga, dia ingin menghindari membuat beberapa otomatisasi anak.

Setelah Emily meninjau tindakan otomatisasi yang tersedia, dia menentukan bahwa dia dapat meningkatkan solusinya dengan menggunakanaws:executeScripttindakan untuk menjalankan skrip Python kustomnya. Dia sekarang mulai menulis konten untuk runbook sebagai berikut:

  1. Pertama, dia memberikan nilai untuk skema dan deskripsi runbook, dan mendefinisikan parameter input untuk runbook induk.

    Dengan menggunakanAutomationAssumeRoleparameter, Emily dan rekan-rekannya dapat menggunakan peran IAM yang ada yang memungkinkan Automation untuk melakukan tindakan dalam runbook atas nama mereka. Tidak sepertiContoh 1, yangAutomationAssumeRoleparameter sekarang diperlukan daripada opsional. Karena runbook ini termasukaws:executeScripttindakan, sebuahAWS Identity and Access Management(IAM) peran layanan (atau menganggap peran) selalu diperlukan. Persyaratan ini diperlukan karena beberapa skrip Python ditentukan untuk tindakan panggilanAWSOperasi API.

    Emily menggunakanPrimaryPatchGroupTagdanSecondaryPatchGroupTagparameter untuk menentukan tag yang terkait dengan kelompok primer dan sekunder contoh database yang akan ditambal. Untuk menyederhanakan parameter input yang diperlukan, dia memutuskan untuk menggunakanStringMapparameter daripada menggunakan beberapaStringparameter seperti yang dia gunakan dalam contoh 1 runbook. Secara opsional,Operation,RebootOption, danSnapshotIdparameter dapat digunakan untuk memberikan nilai untuk mendokumentasikan parameter untukAWS-RunPatchBaseline. Untuk mencegah nilai-nilai yang tidak valid dari yang disediakan untuk parameter dokumen, dia mendefinisikanallowedValuessesuai kebutuhan.

    YAML
    description: 'An example of an Automation runbook that patches groups of Amazon EC2 instances in stages.' schemaVersion: '0.3' assumeRole: '{{AutomationAssumeRole}}' parameters: AutomationAssumeRole: type: String description: '(Required) The Amazon Resource Name (ARN) of the IAM role that allows Automation to perform the actions on your behalf. If no role is specified, Systems Manager Automation uses your IAM permissions to operate this runbook.' PrimaryPatchGroupTag: type: StringMap description: '(Required) The tag for the primary group of instances you want to patch. Specify a key-value pair. Example: {"key" : "value"}' SecondaryPatchGroupTag: type: StringMap description: '(Required) The tag for the secondary group of instances you want to patch. Specify a key-value pair. Example: {"key" : "value"}' SnapshotId: type: String description: '(Optional) The snapshot ID to use to retrieve a patch baseline snapshot.' default: '' RebootOption: type: String description: '(Optional) Reboot behavior after a patch Install operation. If you choose NoReboot and patches are installed, the instance is marked as non-compliant until a subsequent reboot and scan.' allowedValues: - NoReboot - RebootIfNeeded default: RebootIfNeeded Operation: type: String description: '(Optional) The update or configuration to perform on the instance. The system checks if patches specified in the patch baseline are installed on the instance. The install operation installs patches missing from the baseline.' allowedValues: - Install - Scan default: Install
    JSON
    { "description":"An example of an Automation runbook that patches groups of Amazon EC2 instances in stages.", "schemaVersion":"0.3", "assumeRole":"{{AutomationAssumeRole}}", "parameters":{ "AutomationAssumeRole":{ "type":"String", "description":"(Required) The Amazon Resource Name (ARN) of the IAM role that allows Automation to perform the actions on your behalf. If no role is specified, Systems Manager Automation uses your IAM permissions to operate this runbook." }, "PrimaryPatchGroupTag":{ "type":"StringMap", "description":"(Required) The tag for the primary group of instances you want to patch. Specify a key-value pair. Example: {\"key\" : \"value\"}" }, "SecondaryPatchGroupTag":{ "type":"StringMap", "description":"(Required) The tag for the secondary group of instances you want to patch. Specify a key-value pair. Example: {\"key\" : \"value\"}" }, "SnapshotId":{ "type":"String", "description":"(Optional) The snapshot ID to use to retrieve a patch baseline snapshot.", "default":"" }, "RebootOption":{ "type":"String", "description":"(Optional) Reboot behavior after a patch Install operation. If you choose NoReboot and patches are installed, the instance is marked as non-compliant until a subsequent reboot and scan.", "allowedValues":[ "NoReboot", "RebootIfNeeded" ], "default":"RebootIfNeeded" }, "Operation":{ "type":"String", "description":"(Optional) The update or configuration to perform on the instance. The system checks if patches specified in the patch baseline are installed on the instance. The install operation installs patches missing from the baseline.", "allowedValues":[ "Install", "Scan" ], "default":"Install" } } },
  2. Dengan elemen tingkat atas didefinisikan, Emily melanjutkan dengan authoring tindakan yang membentukmainStepsdari runbook. Langkah pertama mengumpulkan ID dari semua instance yang terkait dengan tag yang ditentukan dalamPrimaryPatchGroupTagparameter dan outputStringMapparameter yang berisi ID instans dan status tabel tabel saat ini (). Output dari tindakan ini digunakan dalam tindakan selanjutnya.

    Perhatikan bahwascriptparameter input tidak mendukung runbook JSON. JSON runbook harus menyediakan konten skrip menggunakanattachmentparameter masukan.

    YAML
    mainSteps: - name: getPrimaryInstanceState action: 'aws:executeScript' timeoutSeconds: 120 onFailure: Abort inputs: Runtime: python3.7 Handler: getInstanceStates InputPayload: primaryTag: '{{PrimaryPatchGroupTag}}' Script: |- def getInstanceStates(events,context): import boto3 #Initialize client ec2 = boto3.client('ec2') tag = events['primaryTag'] tagKey, tagValue = list(tag.items())[0] instanceQuery = ec2.describe_instances( Filters=[ { "Name": "tag:" + tagKey, "Values": [tagValue] }] ) if not instanceQuery['Reservations']: noInstancesForTagString = "No instances found for specified tag." return({ 'noInstancesFound' : noInstancesForTagString }) else: queryResponse = instanceQuery['Reservations'] originalInstanceStates = {} for results in queryResponse: instanceSet = results['Instances'] for instance in instanceSet: instanceId = instance['InstanceId'] originalInstanceStates[instanceId] = instance['State']['Name'] return originalInstanceStates outputs: - Name: originalInstanceStates Selector: $.Payload Type: StringMap nextStep: verifyPrimaryInstancesRunning
    JSON
    "mainSteps":[ { "name":"getPrimaryInstanceState", "action":"aws:executeScript", "timeoutSeconds":120, "onFailure":"Abort", "inputs":{ "Runtime":"python3.7", "Handler":"getInstanceStates", "InputPayload":{ "primaryTag":"{{PrimaryPatchGroupTag}}" }, "Script":"..." }, "outputs":[ { "Name":"originalInstanceStates", "Selector":"$.Payload", "Type":"StringMap" } ], "nextStep":"verifyPrimaryInstancesRunning" },
  3. Emily menggunakan output dari tindakan sebelumnya di tindakan lainaws:executeScripttindakan untuk memverifikasi semua instance yang terkait dengan tag yang ditentukan dalamPrimaryPatchGroupTagparameter berada dalamrunningstatus.

    Jika status instance sudahrunningataushutting-down, script terus loop melalui contoh yang tersisa.

    Jika keadaan instancestopping, script polling untuk instance untuk mencapaistoppedStatus dan mulai instans.

    Jika keadaan instancestopped, script memulai instance.

    YAML
    - name: verifyPrimaryInstancesRunning action: 'aws:executeScript' timeoutSeconds: 600 onFailure: Abort inputs: Runtime: python3.7 Handler: verifyInstancesRunning InputPayload: targetInstances: '{{getPrimaryInstanceState.originalInstanceStates}}' Script: |- def verifyInstancesRunning(events,context): import boto3 #Initialize client ec2 = boto3.client('ec2') instanceDict = events['targetInstances'] for instance in instanceDict: if instanceDict[instance] == 'stopped': print("The target instance " + instance + " is stopped. The instance will now be started.") ec2.start_instances( InstanceIds=[instance] ) elif instanceDict[instance] == 'stopping': print("The target instance " + instance + " is stopping. Polling for instance to reach stopped state.") while instanceDict[instance] != 'stopped': poll = ec2.get_waiter('instance_stopped') poll.wait( InstanceIds=[instance] ) ec2.start_instances( InstanceIds=[instance] ) else: pass nextStep: waitForPrimaryRunningInstances
    JSON
    { "name":"verifyPrimaryInstancesRunning", "action":"aws:executeScript", "timeoutSeconds":600, "onFailure":"Abort", "inputs":{ "Runtime":"python3.7", "Handler":"verifyInstancesRunning", "InputPayload":{ "targetInstances":"{{getPrimaryInstanceState.originalInstanceStates}}" }, "Script":"..." }, "nextStep":"waitForPrimaryRunningInstances" },
  4. Emily memverifikasi bahwa semua instance yang terkait dengan tag yang ditentukan dalamPrimaryPatchGroupTagparameter yang dimulai atau sudah dalamrunningstatus. Kemudian dia menggunakan skrip lain untuk memverifikasi bahwa semua contoh, termasuk yang dimulai pada tindakan sebelumnya, telah mencapairunningstatus.

    YAML
    - name: waitForPrimaryRunningInstances action: 'aws:executeScript' timeoutSeconds: 300 onFailure: Abort inputs: Runtime: python3.7 Handler: waitForRunningInstances InputPayload: targetInstances: '{{getPrimaryInstanceState.originalInstanceStates}}' Script: |- def waitForRunningInstances(events,context): import boto3 #Initialize client ec2 = boto3.client('ec2') instanceDict = events['targetInstances'] for instance in instanceDict: poll = ec2.get_waiter('instance_running') poll.wait( InstanceIds=[instance] ) nextStep: returnPrimaryTagKey
    JSON
    { "name":"waitForPrimaryRunningInstances", "action":"aws:executeScript", "timeoutSeconds":300, "onFailure":"Abort", "inputs":{ "Runtime":"python3.7", "Handler":"waitForRunningInstances", "InputPayload":{ "targetInstances":"{{getPrimaryInstanceState.originalInstanceStates}}" }, "Script":"..." }, "nextStep":"returnPrimaryTagKey" },
  5. Emily menggunakan dua skrip lagi untuk mengembalikan individuStringnilai kunci dan nilai tag yang ditentukan dalamPrimaryPatchGroupTagparameter. Nilai-nilai yang dikembalikan oleh tindakan ini memungkinkannya untuk memberikan nilai langsung keTargetsparameter untukAWS-RunPatchBaselinedokumen. Otomatisasi kemudian dilanjutkan dengan menambal instance denganAWS-RunPatchBaselinedokumen menggunakanaws:runCommandtindakan.

    YAML
    - name: returnPrimaryTagKey action: 'aws:executeScript' timeoutSeconds: 120 onFailure: Abort inputs: Runtime: python3.7 Handler: returnTagValues InputPayload: primaryTag: '{{PrimaryPatchGroupTag}}' Script: |- def returnTagValues(events,context): tag = events['primaryTag'] tagKey = list(tag)[0] stringKey = "tag:" + tagKey return {'tagKey' : stringKey} outputs: - Name: Payload Selector: $.Payload Type: StringMap - Name: primaryPatchGroupKey Selector: $.Payload.tagKey Type: String nextStep: returnPrimaryTagValue - name: returnPrimaryTagValue action: 'aws:executeScript' timeoutSeconds: 120 onFailure: Abort inputs: Runtime: python3.7 Handler: returnTagValues InputPayload: primaryTag: '{{PrimaryPatchGroupTag}}' Script: |- def returnTagValues(events,context): tag = events['primaryTag'] tagKey = list(tag)[0] tagValue = tag[tagKey] return {'tagValue' : tagValue} outputs: - Name: Payload Selector: $.Payload Type: StringMap - Name: primaryPatchGroupValue Selector: $.Payload.tagValue Type: String nextStep: patchPrimaryInstances - name: patchPrimaryInstances action: 'aws:runCommand' onFailure: Abort timeoutSeconds: 7200 inputs: DocumentName: AWS-RunPatchBaseline Parameters: SnapshotId: '{{SnapshotId}}' RebootOption: '{{RebootOption}}' Operation: '{{Operation}}' Targets: - Key: '{{returnPrimaryTagKey.primaryPatchGroupKey}}' Values: - '{{returnPrimaryTagValue.primaryPatchGroupValue}}' MaxConcurrency: 10% MaxErrors: 10% nextStep: returnPrimaryToOriginalState
    JSON
    { "name":"returnPrimaryTagKey", "action":"aws:executeScript", "timeoutSeconds":120, "onFailure":"Abort", "inputs":{ "Runtime":"python3.7", "Handler":"returnTagValues", "InputPayload":{ "primaryTag":"{{PrimaryPatchGroupTag}}" }, "Script":"..." }, "outputs":[ { "Name":"Payload", "Selector":"$.Payload", "Type":"StringMap" }, { "Name":"primaryPatchGroupKey", "Selector":"$.Payload.tagKey", "Type":"String" } ], "nextStep":"returnPrimaryTagValue" }, { "name":"returnPrimaryTagValue", "action":"aws:executeScript", "timeoutSeconds":120, "onFailure":"Abort", "inputs":{ "Runtime":"python3.7", "Handler":"returnTagValues", "InputPayload":{ "primaryTag":"{{PrimaryPatchGroupTag}}" }, "Script":"..." }, "outputs":[ { "Name":"Payload", "Selector":"$.Payload", "Type":"StringMap" }, { "Name":"primaryPatchGroupValue", "Selector":"$.Payload.tagValue", "Type":"String" } ], "nextStep":"patchPrimaryInstances" }, { "name":"patchPrimaryInstances", "action":"aws:runCommand", "onFailure":"Abort", "timeoutSeconds":7200, "inputs":{ "DocumentName":"AWS-RunPatchBaseline", "Parameters":{ "SnapshotId":"{{SnapshotId}}", "RebootOption":"{{RebootOption}}", "Operation":"{{Operation}}" }, "Targets":[ { "Key":"{{returnPrimaryTagKey.primaryPatchGroupKey}}", "Values":[ "{{returnPrimaryTagValue.primaryPatchGroupValue}}" ] } ], "MaxConcurrency":"10%", "MaxErrors":"10%" }, "nextStep":"returnPrimaryToOriginalState" },
  6. Setelah operasi patching selesai, Emily ingin otomatisasi mengembalikan instance target yang terkait dengan tag yang ditentukan dalamPrimaryPatchGroupTagparameter ke keadaan yang sama sebelum otomatisasi dimulai. Dia melakukan ini dengan lagi menggunakan output dari tindakan pertama dalam skrip. Berdasarkan keadaan asli dari instance target, jika instance sebelumnya dalam keadaan apa pun selainrunning, instans dihentikan. Jika tidak, jika keadaan instancerunning, script terus loop melalui contoh yang tersisa.

    YAML
    - name: returnPrimaryToOriginalState action: 'aws:executeScript' timeoutSeconds: 600 onFailure: Abort inputs: Runtime: python3.7 Handler: returnToOriginalState InputPayload: targetInstances: '{{getPrimaryInstanceState.originalInstanceStates}}' Script: |- def returnToOriginalState(events,context): import boto3 #Initialize client ec2 = boto3.client('ec2') instanceDict = events['targetInstances'] for instance in instanceDict: if instanceDict[instance] == 'stopped' or instanceDict[instance] == 'stopping': ec2.stop_instances( InstanceIds=[instance] ) else: pass nextStep: getSecondaryInstanceState
    JSON
    { "name":"returnPrimaryToOriginalState", "action":"aws:executeScript", "timeoutSeconds":600, "onFailure":"Abort", "inputs":{ "Runtime":"python3.7", "Handler":"returnToOriginalState", "InputPayload":{ "targetInstances":"{{getPrimaryInstanceState.originalInstanceStates}}" }, "Script":"..." }, "nextStep":"getSecondaryInstanceState" },
  7. Operasi patching selesai untuk instance yang terkait dengan tag yang ditentukan dalamPrimaryPatchGroupTagparameter. Sekarang Emily menduplikasi semua tindakan sebelumnya dalam konten runbook-nya untuk menargetkan instance yang terkait dengan tag yang ditentukan dalamSecondaryPatchGroupTagparameter.

    YAML
    - name: getSecondaryInstanceState action: 'aws:executeScript' timeoutSeconds: 120 onFailure: Abort inputs: Runtime: python3.7 Handler: getInstanceStates InputPayload: secondaryTag: '{{SecondaryPatchGroupTag}}' Script: |- def getInstanceStates(events,context): import boto3 #Initialize client ec2 = boto3.client('ec2') tag = events['secondaryTag'] tagKey, tagValue = list(tag.items())[0] instanceQuery = ec2.describe_instances( Filters=[ { "Name": "tag:" + tagKey, "Values": [tagValue] }] ) if not instanceQuery['Reservations']: noInstancesForTagString = "No instances found for specified tag." return({ 'noInstancesFound' : noInstancesForTagString }) else: queryResponse = instanceQuery['Reservations'] originalInstanceStates = {} for results in queryResponse: instanceSet = results['Instances'] for instance in instanceSet: instanceId = instance['InstanceId'] originalInstanceStates[instanceId] = instance['State']['Name'] return originalInstanceStates outputs: - Name: originalInstanceStates Selector: $.Payload Type: StringMap nextStep: verifySecondaryInstancesRunning - name: verifySecondaryInstancesRunning action: 'aws:executeScript' timeoutSeconds: 600 onFailure: Abort inputs: Runtime: python3.7 Handler: verifyInstancesRunning InputPayload: targetInstances: '{{getSecondaryInstanceState.originalInstanceStates}}' Script: |- def verifyInstancesRunning(events,context): import boto3 #Initialize client ec2 = boto3.client('ec2') instanceDict = events['targetInstances'] for instance in instanceDict: if instanceDict[instance] == 'stopped': print("The target instance " + instance + " is stopped. The instance will now be started.") ec2.start_instances( InstanceIds=[instance] ) elif instanceDict[instance] == 'stopping': print("The target instance " + instance + " is stopping. Polling for instance to reach stopped state.") while instanceDict[instance] != 'stopped': poll = ec2.get_waiter('instance_stopped') poll.wait( InstanceIds=[instance] ) ec2.start_instances( InstanceIds=[instance] ) else: pass nextStep: waitForSecondaryRunningInstances - name: waitForSecondaryRunningInstances action: 'aws:executeScript' timeoutSeconds: 300 onFailure: Abort inputs: Runtime: python3.7 Handler: waitForRunningInstances InputPayload: targetInstances: '{{getSecondaryInstanceState.originalInstanceStates}}' Script: |- def waitForRunningInstances(events,context): import boto3 #Initialize client ec2 = boto3.client('ec2') instanceDict = events['targetInstances'] for instance in instanceDict: poll = ec2.get_waiter('instance_running') poll.wait( InstanceIds=[instance] ) nextStep: returnSecondaryTagKey - name: returnSecondaryTagKey action: 'aws:executeScript' timeoutSeconds: 120 onFailure: Abort inputs: Runtime: python3.7 Handler: returnTagValues InputPayload: secondaryTag: '{{SecondaryPatchGroupTag}}' Script: |- def returnTagValues(events,context): tag = events['secondaryTag'] tagKey = list(tag)[0] stringKey = "tag:" + tagKey return {'tagKey' : stringKey} outputs: - Name: Payload Selector: $.Payload Type: StringMap - Name: secondaryPatchGroupKey Selector: $.Payload.tagKey Type: String nextStep: returnSecondaryTagValue - name: returnSecondaryTagValue action: 'aws:executeScript' timeoutSeconds: 120 onFailure: Abort inputs: Runtime: python3.7 Handler: returnTagValues InputPayload: secondaryTag: '{{SecondaryPatchGroupTag}}' Script: |- def returnTagValues(events,context): tag = events['secondaryTag'] tagKey = list(tag)[0] tagValue = tag[tagKey] return {'tagValue' : tagValue} outputs: - Name: Payload Selector: $.Payload Type: StringMap - Name: secondaryPatchGroupValue Selector: $.Payload.tagValue Type: String nextStep: patchSecondaryInstances - name: patchSecondaryInstances action: 'aws:runCommand' onFailure: Abort timeoutSeconds: 7200 inputs: DocumentName: AWS-RunPatchBaseline Parameters: SnapshotId: '{{SnapshotId}}' RebootOption: '{{RebootOption}}' Operation: '{{Operation}}' Targets: - Key: '{{returnSecondaryTagKey.secondaryPatchGroupKey}}' Values: - '{{returnSecondaryTagValue.secondaryPatchGroupValue}}' MaxConcurrency: 10% MaxErrors: 10% nextStep: returnSecondaryToOriginalState - name: returnSecondaryToOriginalState action: 'aws:executeScript' timeoutSeconds: 600 onFailure: Abort inputs: Runtime: python3.7 Handler: returnToOriginalState InputPayload: targetInstances: '{{getSecondaryInstanceState.originalInstanceStates}}' Script: |- def returnToOriginalState(events,context): import boto3 #Initialize client ec2 = boto3.client('ec2') instanceDict = events['targetInstances'] for instance in instanceDict: if instanceDict[instance] == 'stopped' or instanceDict[instance] == 'stopping': ec2.stop_instances( InstanceIds=[instance] ) else: pass
    JSON
    { "name":"getSecondaryInstanceState", "action":"aws:executeScript", "timeoutSeconds":120, "onFailure":"Abort", "inputs":{ "Runtime":"python3.7", "Handler":"getInstanceStates", "InputPayload":{ "secondaryTag":"{{SecondaryPatchGroupTag}}" }, "Script":"..." }, "outputs":[ { "Name":"originalInstanceStates", "Selector":"$.Payload", "Type":"StringMap" } ], "nextStep":"verifySecondaryInstancesRunning" }, { "name":"verifySecondaryInstancesRunning", "action":"aws:executeScript", "timeoutSeconds":600, "onFailure":"Abort", "inputs":{ "Runtime":"python3.7", "Handler":"verifyInstancesRunning", "InputPayload":{ "targetInstances":"{{getSecondaryInstanceState.originalInstanceStates}}" }, "Script":"..." }, "nextStep":"waitForSecondaryRunningInstances" }, { "name":"waitForSecondaryRunningInstances", "action":"aws:executeScript", "timeoutSeconds":300, "onFailure":"Abort", "inputs":{ "Runtime":"python3.7", "Handler":"waitForRunningInstances", "InputPayload":{ "targetInstances":"{{getSecondaryInstanceState.originalInstanceStates}}" }, "Script":"..." }, "nextStep":"returnSecondaryTagKey" }, { "name":"returnSecondaryTagKey", "action":"aws:executeScript", "timeoutSeconds":120, "onFailure":"Abort", "inputs":{ "Runtime":"python3.7", "Handler":"returnTagValues", "InputPayload":{ "secondaryTag":"{{SecondaryPatchGroupTag}}" }, "Script":"..." }, "outputs":[ { "Name":"Payload", "Selector":"$.Payload", "Type":"StringMap" }, { "Name":"secondaryPatchGroupKey", "Selector":"$.Payload.tagKey", "Type":"String" } ], "nextStep":"returnSecondaryTagValue" }, { "name":"returnSecondaryTagValue", "action":"aws:executeScript", "timeoutSeconds":120, "onFailure":"Abort", "inputs":{ "Runtime":"python3.7", "Handler":"returnTagValues", "InputPayload":{ "secondaryTag":"{{SecondaryPatchGroupTag}}" }, "Script":"..." }, "outputs":[ { "Name":"Payload", "Selector":"$.Payload", "Type":"StringMap" }, { "Name":"secondaryPatchGroupValue", "Selector":"$.Payload.tagValue", "Type":"String" } ], "nextStep":"patchSecondaryInstances" }, { "name":"patchSecondaryInstances", "action":"aws:runCommand", "onFailure":"Abort", "timeoutSeconds":7200, "inputs":{ "DocumentName":"AWS-RunPatchBaseline", "Parameters":{ "SnapshotId":"{{SnapshotId}}", "RebootOption":"{{RebootOption}}", "Operation":"{{Operation}}" }, "Targets":[ { "Key":"{{returnSecondaryTagKey.secondaryPatchGroupKey}}", "Values":[ "{{returnSecondaryTagValue.secondaryPatchGroupValue}}" ] } ], "MaxConcurrency":"10%", "MaxErrors":"10%" }, "nextStep":"returnSecondaryToOriginalState" }, { "name":"returnSecondaryToOriginalState", "action":"aws:executeScript", "timeoutSeconds":600, "onFailure":"Abort", "inputs":{ "Runtime":"python3.7", "Handler":"returnToOriginalState", "InputPayload":{ "targetInstances":"{{getSecondaryInstanceState.originalInstanceStates}}" }, "Script":"..." } } ] }
  8. Emily meninjau konten runbook scripted yang telah selesai dan membuat runbook dalam hal yang samaAkun AWSdanWilayah AWSsebagai contoh target. Sekarang dia siap untuk menguji runbooknya untuk memastikan otomatisasi beroperasi seperti yang diinginkan sebelum menerapkannya ke lingkungan produksinya. Berikut ini adalah konten runbook scripted yang telah selesai.

    YAML
    description: An example of an Automation runbook that patches groups of Amazon EC2 instances in stages. schemaVersion: '0.3' assumeRole: '{{AutomationAssumeRole}}' parameters: AutomationAssumeRole: type: String description: '(Required) The Amazon Resource Name (ARN) of the IAM role that allows Automation to perform the actions on your behalf. If no role is specified, Systems Manager Automation uses your IAM permissions to operate this runbook.' PrimaryPatchGroupTag: type: StringMap description: '(Required) The tag for the primary group of instances you want to patch. Specify a key-value pair. Example: {"key" : "value"}' SecondaryPatchGroupTag: type: StringMap description: '(Required) The tag for the secondary group of instances you want to patch. Specify a key-value pair. Example: {"key" : "value"}' SnapshotId: type: String description: '(Optional) The snapshot ID to use to retrieve a patch baseline snapshot.' default: '' RebootOption: type: String description: '(Optional) Reboot behavior after a patch Install operation. If you choose NoReboot and patches are installed, the instance is marked as non-compliant until a subsequent reboot and scan.' allowedValues: - NoReboot - RebootIfNeeded default: RebootIfNeeded Operation: type: String description: '(Optional) The update or configuration to perform on the instance. The system checks if patches specified in the patch baseline are installed on the instance. The install operation installs patches missing from the baseline.' allowedValues: - Install - Scan default: Install mainSteps: - name: getPrimaryInstanceState action: 'aws:executeScript' timeoutSeconds: 120 onFailure: Abort inputs: Runtime: python3.7 Handler: getInstanceStates InputPayload: primaryTag: '{{PrimaryPatchGroupTag}}' Script: |- def getInstanceStates(events,context): import boto3 #Initialize client ec2 = boto3.client('ec2') tag = events['primaryTag'] tagKey, tagValue = list(tag.items())[0] instanceQuery = ec2.describe_instances( Filters=[ { "Name": "tag:" + tagKey, "Values": [tagValue] }] ) if not instanceQuery['Reservations']: noInstancesForTagString = "No instances found for specified tag." return({ 'noInstancesFound' : noInstancesForTagString }) else: queryResponse = instanceQuery['Reservations'] originalInstanceStates = {} for results in queryResponse: instanceSet = results['Instances'] for instance in instanceSet: instanceId = instance['InstanceId'] originalInstanceStates[instanceId] = instance['State']['Name'] return originalInstanceStates outputs: - Name: originalInstanceStates Selector: $.Payload Type: StringMap nextStep: verifyPrimaryInstancesRunning - name: verifyPrimaryInstancesRunning action: 'aws:executeScript' timeoutSeconds: 600 onFailure: Abort inputs: Runtime: python3.7 Handler: verifyInstancesRunning InputPayload: targetInstances: '{{getPrimaryInstanceState.originalInstanceStates}}' Script: |- def verifyInstancesRunning(events,context): import boto3 #Initialize client ec2 = boto3.client('ec2') instanceDict = events['targetInstances'] for instance in instanceDict: if instanceDict[instance] == 'stopped': print("The target instance " + instance + " is stopped. The instance will now be started.") ec2.start_instances( InstanceIds=[instance] ) elif instanceDict[instance] == 'stopping': print("The target instance " + instance + " is stopping. Polling for instance to reach stopped state.") while instanceDict[instance] != 'stopped': poll = ec2.get_waiter('instance_stopped') poll.wait( InstanceIds=[instance] ) ec2.start_instances( InstanceIds=[instance] ) else: pass nextStep: waitForPrimaryRunningInstances - name: waitForPrimaryRunningInstances action: 'aws:executeScript' timeoutSeconds: 300 onFailure: Abort inputs: Runtime: python3.7 Handler: waitForRunningInstances InputPayload: targetInstances: '{{getPrimaryInstanceState.originalInstanceStates}}' Script: |- def waitForRunningInstances(events,context): import boto3 #Initialize client ec2 = boto3.client('ec2') instanceDict = events['targetInstances'] for instance in instanceDict: poll = ec2.get_waiter('instance_running') poll.wait( InstanceIds=[instance] ) nextStep: returnPrimaryTagKey - name: returnPrimaryTagKey action: 'aws:executeScript' timeoutSeconds: 120 onFailure: Abort inputs: Runtime: python3.7 Handler: returnTagValues InputPayload: primaryTag: '{{PrimaryPatchGroupTag}}' Script: |- def returnTagValues(events,context): tag = events['primaryTag'] tagKey = list(tag)[0] stringKey = "tag:" + tagKey return {'tagKey' : stringKey} outputs: - Name: Payload Selector: $.Payload Type: StringMap - Name: primaryPatchGroupKey Selector: $.Payload.tagKey Type: String nextStep: returnPrimaryTagValue - name: returnPrimaryTagValue action: 'aws:executeScript' timeoutSeconds: 120 onFailure: Abort inputs: Runtime: python3.7 Handler: returnTagValues InputPayload: primaryTag: '{{PrimaryPatchGroupTag}}' Script: |- def returnTagValues(events,context): tag = events['primaryTag'] tagKey = list(tag)[0] tagValue = tag[tagKey] return {'tagValue' : tagValue} outputs: - Name: Payload Selector: $.Payload Type: StringMap - Name: primaryPatchGroupValue Selector: $.Payload.tagValue Type: String nextStep: patchPrimaryInstances - name: patchPrimaryInstances action: 'aws:runCommand' onFailure: Abort timeoutSeconds: 7200 inputs: DocumentName: AWS-RunPatchBaseline Parameters: SnapshotId: '{{SnapshotId}}' RebootOption: '{{RebootOption}}' Operation: '{{Operation}}' Targets: - Key: '{{returnPrimaryTagKey.primaryPatchGroupKey}}' Values: - '{{returnPrimaryTagValue.primaryPatchGroupValue}}' MaxConcurrency: 10% MaxErrors: 10% nextStep: returnPrimaryToOriginalState - name: returnPrimaryToOriginalState action: 'aws:executeScript' timeoutSeconds: 600 onFailure: Abort inputs: Runtime: python3.7 Handler: returnToOriginalState InputPayload: targetInstances: '{{getPrimaryInstanceState.originalInstanceStates}}' Script: |- def returnToOriginalState(events,context): import boto3 #Initialize client ec2 = boto3.client('ec2') instanceDict = events['targetInstances'] for instance in instanceDict: if instanceDict[instance] == 'stopped' or instanceDict[instance] == 'stopping': ec2.stop_instances( InstanceIds=[instance] ) else: pass nextStep: getSecondaryInstanceState - name: getSecondaryInstanceState action: 'aws:executeScript' timeoutSeconds: 120 onFailure: Abort inputs: Runtime: python3.7 Handler: getInstanceStates InputPayload: secondaryTag: '{{SecondaryPatchGroupTag}}' Script: |- def getInstanceStates(events,context): import boto3 #Initialize client ec2 = boto3.client('ec2') tag = events['secondaryTag'] tagKey, tagValue = list(tag.items())[0] instanceQuery = ec2.describe_instances( Filters=[ { "Name": "tag:" + tagKey, "Values": [tagValue] }] ) if not instanceQuery['Reservations']: noInstancesForTagString = "No instances found for specified tag." return({ 'noInstancesFound' : noInstancesForTagString }) else: queryResponse = instanceQuery['Reservations'] originalInstanceStates = {} for results in queryResponse: instanceSet = results['Instances'] for instance in instanceSet: instanceId = instance['InstanceId'] originalInstanceStates[instanceId] = instance['State']['Name'] return originalInstanceStates outputs: - Name: originalInstanceStates Selector: $.Payload Type: StringMap nextStep: verifySecondaryInstancesRunning - name: verifySecondaryInstancesRunning action: 'aws:executeScript' timeoutSeconds: 600 onFailure: Abort inputs: Runtime: python3.7 Handler: verifyInstancesRunning InputPayload: targetInstances: '{{getSecondaryInstanceState.originalInstanceStates}}' Script: |- def verifyInstancesRunning(events,context): import boto3 #Initialize client ec2 = boto3.client('ec2') instanceDict = events['targetInstances'] for instance in instanceDict: if instanceDict[instance] == 'stopped': print("The target instance " + instance + " is stopped. The instance will now be started.") ec2.start_instances( InstanceIds=[instance] ) elif instanceDict[instance] == 'stopping': print("The target instance " + instance + " is stopping. Polling for instance to reach stopped state.") while instanceDict[instance] != 'stopped': poll = ec2.get_waiter('instance_stopped') poll.wait( InstanceIds=[instance] ) ec2.start_instances( InstanceIds=[instance] ) else: pass nextStep: waitForSecondaryRunningInstances - name: waitForSecondaryRunningInstances action: 'aws:executeScript' timeoutSeconds: 300 onFailure: Abort inputs: Runtime: python3.7 Handler: waitForRunningInstances InputPayload: targetInstances: '{{getSecondaryInstanceState.originalInstanceStates}}' Script: |- def waitForRunningInstances(events,context): import boto3 #Initialize client ec2 = boto3.client('ec2') instanceDict = events['targetInstances'] for instance in instanceDict: poll = ec2.get_waiter('instance_running') poll.wait( InstanceIds=[instance] ) nextStep: returnSecondaryTagKey - name: returnSecondaryTagKey action: 'aws:executeScript' timeoutSeconds: 120 onFailure: Abort inputs: Runtime: python3.7 Handler: returnTagValues InputPayload: secondaryTag: '{{SecondaryPatchGroupTag}}' Script: |- def returnTagValues(events,context): tag = events['secondaryTag'] tagKey = list(tag)[0] stringKey = "tag:" + tagKey return {'tagKey' : stringKey} outputs: - Name: Payload Selector: $.Payload Type: StringMap - Name: secondaryPatchGroupKey Selector: $.Payload.tagKey Type: String nextStep: returnSecondaryTagValue - name: returnSecondaryTagValue action: 'aws:executeScript' timeoutSeconds: 120 onFailure: Abort inputs: Runtime: python3.7 Handler: returnTagValues InputPayload: secondaryTag: '{{SecondaryPatchGroupTag}}' Script: |- def returnTagValues(events,context): tag = events['secondaryTag'] tagKey = list(tag)[0] tagValue = tag[tagKey] return {'tagValue' : tagValue} outputs: - Name: Payload Selector: $.Payload Type: StringMap - Name: secondaryPatchGroupValue Selector: $.Payload.tagValue Type: String nextStep: patchSecondaryInstances - name: patchSecondaryInstances action: 'aws:runCommand' onFailure: Abort timeoutSeconds: 7200 inputs: DocumentName: AWS-RunPatchBaseline Parameters: SnapshotId: '{{SnapshotId}}' RebootOption: '{{RebootOption}}' Operation: '{{Operation}}' Targets: - Key: '{{returnSecondaryTagKey.secondaryPatchGroupKey}}' Values: - '{{returnSecondaryTagValue.secondaryPatchGroupValue}}' MaxConcurrency: 10% MaxErrors: 10% nextStep: returnSecondaryToOriginalState - name: returnSecondaryToOriginalState action: 'aws:executeScript' timeoutSeconds: 600 onFailure: Abort inputs: Runtime: python3.7 Handler: returnToOriginalState InputPayload: targetInstances: '{{getSecondaryInstanceState.originalInstanceStates}}' Script: |- def returnToOriginalState(events,context): import boto3 #Initialize client ec2 = boto3.client('ec2') instanceDict = events['targetInstances'] for instance in instanceDict: if instanceDict[instance] == 'stopped' or instanceDict[instance] == 'stopping': ec2.stop_instances( InstanceIds=[instance] ) else: pass
    JSON
    { "description":"An example of an Automation runbook that patches groups of Amazon EC2 instances in stages.", "schemaVersion":"0.3", "assumeRole":"{{AutomationAssumeRole}}", "parameters":{ "AutomationAssumeRole":{ "type":"String", "description":"(Required) The Amazon Resource Name (ARN) of the IAM role that allows Automation to perform the actions on your behalf. If no role is specified, Systems Manager Automation uses your IAM permissions to operate this runbook." }, "PrimaryPatchGroupTag":{ "type":"StringMap", "description":"(Required) The tag for the primary group of instances you want to patch. Specify a key-value pair. Example: {\"key\" : \"value\"}" }, "SecondaryPatchGroupTag":{ "type":"StringMap", "description":"(Required) The tag for the secondary group of instances you want to patch. Specify a key-value pair. Example: {\"key\" : \"value\"}" }, "SnapshotId":{ "type":"String", "description":"(Optional) The snapshot ID to use to retrieve a patch baseline snapshot.", "default":"" }, "RebootOption":{ "type":"String", "description":"(Optional) Reboot behavior after a patch Install operation. If you choose NoReboot and patches are installed, the instance is marked as non-compliant until a subsequent reboot and scan.", "allowedValues":[ "NoReboot", "RebootIfNeeded" ], "default":"RebootIfNeeded" }, "Operation":{ "type":"String", "description":"(Optional) The update or configuration to perform on the instance. The system checks if patches specified in the patch baseline are installed on the instance. The install operation installs patches missing from the baseline.", "allowedValues":[ "Install", "Scan" ], "default":"Install" } }, "mainSteps":[ { "name":"getPrimaryInstanceState", "action":"aws:executeScript", "timeoutSeconds":120, "onFailure":"Abort", "inputs":{ "Runtime":"python3.7", "Handler":"getInstanceStates", "InputPayload":{ "primaryTag":"{{PrimaryPatchGroupTag}}" }, "Script":"..." }, "outputs":[ { "Name":"originalInstanceStates", "Selector":"$.Payload", "Type":"StringMap" } ], "nextStep":"verifyPrimaryInstancesRunning" }, { "name":"verifyPrimaryInstancesRunning", "action":"aws:executeScript", "timeoutSeconds":600, "onFailure":"Abort", "inputs":{ "Runtime":"python3.7", "Handler":"verifyInstancesRunning", "InputPayload":{ "targetInstances":"{{getPrimaryInstanceState.originalInstanceStates}}" }, "Script":"..." }, "nextStep":"waitForPrimaryRunningInstances" }, { "name":"waitForPrimaryRunningInstances", "action":"aws:executeScript", "timeoutSeconds":300, "onFailure":"Abort", "inputs":{ "Runtime":"python3.7", "Handler":"waitForRunningInstances", "InputPayload":{ "targetInstances":"{{getPrimaryInstanceState.originalInstanceStates}}" }, "Script":"..." }, "nextStep":"returnPrimaryTagKey" }, { "name":"returnPrimaryTagKey", "action":"aws:executeScript", "timeoutSeconds":120, "onFailure":"Abort", "inputs":{ "Runtime":"python3.7", "Handler":"returnTagValues", "InputPayload":{ "primaryTag":"{{PrimaryPatchGroupTag}}" }, "Script":"..." }, "outputs":[ { "Name":"Payload", "Selector":"$.Payload", "Type":"StringMap" }, { "Name":"primaryPatchGroupKey", "Selector":"$.Payload.tagKey", "Type":"String" } ], "nextStep":"returnPrimaryTagValue" }, { "name":"returnPrimaryTagValue", "action":"aws:executeScript", "timeoutSeconds":120, "onFailure":"Abort", "inputs":{ "Runtime":"python3.7", "Handler":"returnTagValues", "InputPayload":{ "primaryTag":"{{PrimaryPatchGroupTag}}" }, "Script":"..." }, "outputs":[ { "Name":"Payload", "Selector":"$.Payload", "Type":"StringMap" }, { "Name":"primaryPatchGroupValue", "Selector":"$.Payload.tagValue", "Type":"String" } ], "nextStep":"patchPrimaryInstances" }, { "name":"patchPrimaryInstances", "action":"aws:runCommand", "onFailure":"Abort", "timeoutSeconds":7200, "inputs":{ "DocumentName":"AWS-RunPatchBaseline", "Parameters":{ "SnapshotId":"{{SnapshotId}}", "RebootOption":"{{RebootOption}}", "Operation":"{{Operation}}" }, "Targets":[ { "Key":"{{returnPrimaryTagKey.primaryPatchGroupKey}}", "Values":[ "{{returnPrimaryTagValue.primaryPatchGroupValue}}" ] } ], "MaxConcurrency":"10%", "MaxErrors":"10%" }, "nextStep":"returnPrimaryToOriginalState" }, { "name":"returnPrimaryToOriginalState", "action":"aws:executeScript", "timeoutSeconds":600, "onFailure":"Abort", "inputs":{ "Runtime":"python3.7", "Handler":"returnToOriginalState", "InputPayload":{ "targetInstances":"{{getPrimaryInstanceState.originalInstanceStates}}" }, "Script":"..." }, "nextStep":"getSecondaryInstanceState" }, { "name":"getSecondaryInstanceState", "action":"aws:executeScript", "timeoutSeconds":120, "onFailure":"Abort", "inputs":{ "Runtime":"python3.7", "Handler":"getInstanceStates", "InputPayload":{ "secondaryTag":"{{SecondaryPatchGroupTag}}" }, "Script":"..." }, "outputs":[ { "Name":"originalInstanceStates", "Selector":"$.Payload", "Type":"StringMap" } ], "nextStep":"verifySecondaryInstancesRunning" }, { "name":"verifySecondaryInstancesRunning", "action":"aws:executeScript", "timeoutSeconds":600, "onFailure":"Abort", "inputs":{ "Runtime":"python3.7", "Handler":"verifyInstancesRunning", "InputPayload":{ "targetInstances":"{{getSecondaryInstanceState.originalInstanceStates}}" }, "Script":"..." }, "nextStep":"waitForSecondaryRunningInstances" }, { "name":"waitForSecondaryRunningInstances", "action":"aws:executeScript", "timeoutSeconds":300, "onFailure":"Abort", "inputs":{ "Runtime":"python3.7", "Handler":"waitForRunningInstances", "InputPayload":{ "targetInstances":"{{getSecondaryInstanceState.originalInstanceStates}}" }, "Script":"..." }, "nextStep":"returnSecondaryTagKey" }, { "name":"returnSecondaryTagKey", "action":"aws:executeScript", "timeoutSeconds":120, "onFailure":"Abort", "inputs":{ "Runtime":"python3.7", "Handler":"returnTagValues", "InputPayload":{ "secondaryTag":"{{SecondaryPatchGroupTag}}" }, "Script":"..." }, "outputs":[ { "Name":"Payload", "Selector":"$.Payload", "Type":"StringMap" }, { "Name":"secondaryPatchGroupKey", "Selector":"$.Payload.tagKey", "Type":"String" } ], "nextStep":"returnSecondaryTagValue" }, { "name":"returnSecondaryTagValue", "action":"aws:executeScript", "timeoutSeconds":120, "onFailure":"Abort", "inputs":{ "Runtime":"python3.7", "Handler":"returnTagValues", "InputPayload":{ "secondaryTag":"{{SecondaryPatchGroupTag}}" }, "Script":"..." }, "outputs":[ { "Name":"Payload", "Selector":"$.Payload", "Type":"StringMap" }, { "Name":"secondaryPatchGroupValue", "Selector":"$.Payload.tagValue", "Type":"String" } ], "nextStep":"patchSecondaryInstances" }, { "name":"patchSecondaryInstances", "action":"aws:runCommand", "onFailure":"Abort", "timeoutSeconds":7200, "inputs":{ "DocumentName":"AWS-RunPatchBaseline", "Parameters":{ "SnapshotId":"{{SnapshotId}}", "RebootOption":"{{RebootOption}}", "Operation":"{{Operation}}" }, "Targets":[ { "Key":"{{returnSecondaryTagKey.secondaryPatchGroupKey}}", "Values":[ "{{returnSecondaryTagValue.secondaryPatchGroupValue}}" ] } ], "MaxConcurrency":"10%", "MaxErrors":"10%" }, "nextStep":"returnSecondaryToOriginalState" }, { "name":"returnSecondaryToOriginalState", "action":"aws:executeScript", "timeoutSeconds":600, "onFailure":"Abort", "inputs":{ "Runtime":"python3.7", "Handler":"returnToOriginalState", "InputPayload":{ "targetInstances":"{{getSecondaryInstanceState.originalInstanceStates}}" }, "Script":"..." } } ] }

Untuk informasi selengkapnya tentang tindakan otomatisasi yang digunakan dalam contoh ini, lihatReferensi tindakan Otomatisasi Systems Manager.