

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

# Connect armada yang dikelola layanan ke server lisensi kustom
<a name="smf-byol"></a>

Anda dapat membawa server lisensi Anda sendiri untuk digunakan dengan armada yang dikelola layanan Deadline Cloud. Untuk membawa lisensi Anda sendiri, Anda dapat mengonfigurasi server lisensi menggunakan lingkungan antrian di peternakan Anda. Untuk mengonfigurasi server lisensi Anda, Anda harus sudah menyiapkan pertanian dan antrian.

Bagaimana Anda terhubung ke server lisensi perangkat lunak tergantung pada konfigurasi armada Anda dan persyaratan vendor perangkat lunak. Biasanya, Anda mengakses server dengan salah satu dari dua cara:
+ Langsung ke server lisensi. Pekerja Anda mendapatkan lisensi dari server lisensi vendor perangkat lunak menggunakan Internet. Semua pekerja Anda harus dapat terhubung ke server.
+ Melalui proxy lisensi. Pekerja Anda terhubung ke server proxy di jaringan lokal Anda. Hanya server proxy yang diizinkan untuk terhubung ke server lisensi vendor melalui Internet.

Dengan petunjuk di bawah ini, Anda menggunakan Amazon EC2 Systems Manager (SSM) untuk meneruskan port dari instans pekerja ke server lisensi atau instans proxy Anda. Dalam contoh di bawah ini jika server lisensi Anda tidak dapat memberikan lisensi, lisensi berbasis penggunaan Deadline Cloud akan digunakan. Hapus bagian yang tidak berlaku untuk pipeline atau produk yang tidak ingin Anda gunakan lisensi berbasis penggunaan setelah lisensi Anda habis.

**Topics**
+ [Langkah 1: Konfigurasikan lingkungan antrian](#configure-queue-environment)
+ [Langkah 2: (Opsional) Pengaturan instance proxy lisensi](#license-proxy)
+ [Langkah 3: pengaturan CloudFormation template](#byol-cfn-template)

## Langkah 1: Konfigurasikan lingkungan antrian
<a name="configure-queue-environment"></a>



Anda dapat mengonfigurasi lingkungan antrian dalam antrian untuk mengakses server lisensi Anda. Pertama, pastikan bahwa Anda memiliki AWS instance yang dikonfigurasi dengan akses server lisensi menggunakan salah satu metode berikut:
+ Server lisensi — Instance meng-host server lisensi secara langsung.
+ Proxy lisensi — Instance memiliki akses jaringan ke server lisensi, dan meneruskan port server lisensi ke server lisensi. Untuk detail tentang cara mengonfigurasi instance proxy lisensi, lihat[Langkah 2: (Opsional) Pengaturan instance proxy lisensi](#license-proxy).

Untuk informasi tentang mengonfigurasi variabel lingkungan lisensi, lihat[Langkah 3: Hubungkan aplikasi rendering ke titik akhir](cmf-ubl.md). Untuk penyiapan server lisensi khusus, alamat server lisensi tetap localhost, bukan titik akhir Amazon VPC.

**Untuk menambahkan izin yang diperlukan ke peran antrian**

1. Dari [konsol Cloud Deadline](https://console.aws.amazon.com/deadlinecloud/home), pilih **Buka Dasbor**.

1. Dari dasbor, pilih pertanian, lalu antrian yang ingin Anda konfigurasikan.

1. Dari detail antrian > peran layanan, pilih peran.

1. Pilih **Tambahkan izin**, lalu pilih **Buat kebijakan sebaris**.

1. Pilih editor kebijakan JSON, lalu salin dan tempel teks berikut ke editor.

------
#### [ JSON ]

****  

   ```
   {
       "Version":"2012-10-17",		 	 	 
       "Statement": [
           {
               "Sid": "",
               "Effect": "Allow",
               "Action": [
                   "ssm:StartSession"
               ],
               "Resource": [
                   "arn:aws:ssm:us-east-1::document/AWS-StartPortForwardingSession",
                   "arn:aws:ec2:us-east-1:111122223333:instance/instance_id"
               ]
           }
       ]
   }
   ```

------

1. Sebelum menyimpan kebijakan baru, ganti nilai berikut dalam teks kebijakan:
   + Ganti `region` dengan AWS Wilayah tempat peternakan Anda berada
   + Ganti `instance_id` dengan ID instance untuk server lisensi atau instance proxy yang Anda gunakan
   + Ganti `account_id` dengan nomor AWS rekening yang berisi peternakan Anda

1. Pilih **Berikutnya**.

1. Untuk nama Policy, masukkan**LicenseForwarding**.

1. Pilih **Buat kebijakan** untuk menyimpan perubahan dan membuat kebijakan dengan izin yang diperlukan.

**Untuk menambahkan lingkungan antrian baru ke antrian**

1. Dari [konsol Deadline Cloud](https://console.aws.amazon.com/deadlinecloud/home), pilih **Go to Dashboard** jika Anda belum melakukannya.

1. Dari dasbor, pilih pertanian, lalu antrian yang ingin Anda konfigurasikan.

1. Pilih **Lingkungan Antrian** > **Tindakan** > **Buat baru dengan YAMG**.

1. Salin dan tempel teks berikut ke editor skrip YAMG.

------
#### [ Windows ]

   ```
   specificationVersion: "environment-2023-09"
   parameterDefinitions:
    - name: LicenseInstanceId
      type: STRING
      description: >
       The Instance ID of the license server/proxy instance
      default: ""
    - name: LicenseInstanceRegion
      type: STRING
      description: >
       The region containing this farm
      default: ""
    - name: LicensePorts
      type: STRING
      description: >
       Comma-separated list of ports to be forwarded to the license server/proxy
       instance. Example: "2701,2702,7075,2703,6101,1715,1716,1717,7054,7055,30304"
      default: "2701,2702,7075,2703,6101,1715,1716,1717,7054,7055,30304"
   environment:
    name: BYOL License Forwarding
    variables:
     example_LICENSE: 2701@localhost
    script:
     actions:
      onEnter:
       command: bash
       args: [ "{{Env.File.Enter}}" ]
      onExit:
       command: bash
       args: [ "{{Env.File.Exit}}" ]
     embeddedFiles:
      - name: Enter
        type: TEXT
        runnable: True
        data: |
         curl "https://s3.amazonaws.com/session-manager-downloads/plugin/latest/windows/SessionManagerPlugin.zip" -o "{{Session.WorkingDirectory}}/ssm-plugin.zip"
         powershell -Command "Expand-Archive -Path '{{Session.WorkingDirectory}}/ssm-plugin.zip' -DestinationPath '{{Session.WorkingDirectory}}/ssm-plugin' -Force; Expand-Archive -Path '{{Session.WorkingDirectory}}/ssm-plugin/package.zip' -DestinationPath '{{Session.WorkingDirectory}}/ssm-plugin/package' -Force"
         conda activate
         python "{{Env.File.StartSession}}" "{{Session.WorkingDirectory}}/ssm-plugin/package/bin/session-manager-plugin.exe"
      - name: Exit
        type: TEXT
        runnable: True
        data: |
         echo Killing SSM Manager Plugin PIDs: $BYOL_SSM_PIDS
         for pid in ${BYOL_SSM_PIDS//,/ }; do kill $pid; done
      - name: StartSession
        type: TEXT
        data: |
         import boto3
         import json
         import subprocess
         import sys
         import os
         import tempfile
   
         instance_id = "{{Param.LicenseInstanceId}}"
         region = "{{Param.LicenseInstanceRegion}}"
         license_ports_list = "{{Param.LicensePorts}}".split(",")
   
         ssm_client = boto3.client("ssm", region_name=region)
         pids = []
   
         for port in license_ports_list:
           session_response = ssm_client.start_session(
             Target=instance_id,
             DocumentName="AWS-StartPortForwardingSession",
             Parameters={"portNumber": [port], "localPortNumber": [port]}
           )
   
           cmd = [
             sys.argv[1],
             json.dumps(session_response),
             region,
             "StartSession",
             "",
             json.dumps({"Target": instance_id}),
             f"https://ssm.{region}.amazonaws.com"
           ]
   
           process = subprocess.Popen(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
           pids.append(process.pid)
           print(f"SSM Port Forwarding Session started for port {port}")
   
         print(f"openjd_env: BYOL_SSM_PIDS={','.join(str(pid) for pid in pids)}")
   
         # Enabling UBL after the BYOL has run out requires prepending the BYOL configuration to the existing license setup
         # Remove the sections that do not apply to your pipeline, or you do not want to use UBL after exhausting the BYOL licenses.
         # The port numbers used may not match what your license server is serving.
   
         # Arnold
         os.environ["ADSKFLEX_LICENSE_FILE"] = f"2701@localhost;{os.environ.get('ADSKFLEX_LICENSE_FILE', '')}"
         print(f"openjd_env: ADSKFLEX_LICENSE_FILE={os.environ['ADSKFLEX_LICENSE_FILE']}")
   
         # Cinema4D
         os.environ["g_licenseServerRLM"] = f"localhost:7057;{os.environ.get('g_licenseServerRLM', '')}"
         print(f"openjd_env: g_licenseServerRLM={os.environ['g_licenseServerRLM']}")
   
         # Nuke
         os.environ["foundry_LICENSE"] = f"6101@localhost;{os.environ.get('foundry_LICENSE', '')}"
         print(f"openjd_env: foundry_LICENSE={os.environ['foundry_LICENSE']}")
   
         # SideFX
         os.environ["SESI_LMHOST"] = f"localhost:1715;{os.environ.get('SESI_LMHOST', '')}"
         print(f"openjd_env: SESI_LMHOST={os.environ['SESI_LMHOST']}")
   
         # Redshift and Red Giant
         os.environ["redshift_LICENSE"] = f"7054@localhost;7055@localhost;{os.environ.get('redshift_LICENSE', '')}"
         print(f"openjd_env: redshift_LICENSE={os.environ['redshift_LICENSE']}")
   
         # V-Ray doesn't support multiple license servers in a single environment variable
         # See https://documentation.chaos.com/space/LIC5/125050770/Sharing+a+License+Configuration+in+a+Network
         vray_license = os.environ.get('VRAY_AUTH_CLIENT_SETTINGS', '')
         xml_content = """<VRLClient>
           <LicServer>
             <Host>localhost</Host>
             <Port>30304</Port>"""
   
         if vray_license and vray_license.startswith('licset://'):
             server_parts = vray_license.removeprefix('licset://').split(':')
             if len(server_parts) >= 2:
                 xml_content += f"""
             <Host1>{server_parts[0]}</Host1>
             <Port1>{server_parts[1]}</Port1>"""
   
         xml_content += """
             <User></User>
             <Pass></Pass>
           </LicServer>
         </VRLClient>"""
   
         temp_dir = tempfile.gettempdir()
         xml_path = os.path.join(temp_dir, 'vrlclient.xml')
         
         with open(xml_path, 'w') as f:
             f.write(xml_content)
   
         os.environ["VRAY_AUTH_CLIENT_FILE_PATH"] = temp_dir
         print(f"openjd_env: VRAY_AUTH_CLIENT_FILE_PATH={os.environ['VRAY_AUTH_CLIENT_FILE_PATH']}")
   
         # Clear the existing VRAY_AUTH_CLIENT_SETTINGS so only the vrlclient.xml file is used.
         os.environ["VRAY_AUTH_CLIENT_SETTINGS"] = ''
         print(f"openjd_env: VRAY_AUTH_CLIENT_SETTINGS={os.environ['VRAY_AUTH_CLIENT_SETTINGS']}")
   
         # Print out the created xml file's contents
         print(f"V-Ray configuration file: {xml_path}")
         with open(xml_path, 'r') as f:
             print(f"{f.read()}")
   ```

------
#### [ Linux ]

   ```
   specificationVersion: "environment-2023-09"
   parameterDefinitions:
    - name: LicenseInstanceId
      type: STRING
      description: >
       The Instance ID of the license server/proxy instance
      default: ""
    - name: LicenseInstanceRegion
      type: STRING
      description: >
       The region containing this farm
      default: ""
    - name: LicensePorts
      type: STRING
      description: >
       Comma-separated list of ports to be forwarded to the license server/proxy
       instance. Example: "2701,2702,7075,2703,6101,1715,1716,1717,7054,7055,30304"
      default: "2701,2702,7075,2703,6101,1715,1716,1717,7054,7055,30304"
   environment:
    name: BYOL License Forwarding
    variables:
     example_LICENSE: 2701@localhost
    script:
     actions:
      onEnter:
       command: bash
       args: [ "{{Env.File.Enter}}" ]
      onExit:
       command: bash
       args: [ "{{Env.File.Exit}}" ]
     embeddedFiles:
      - name: Enter
        type: TEXT
        runnable: True
        data: |
         curl https://s3.amazonaws.com/session-manager-downloads/plugin/latest/linux_64bit/session-manager-plugin.rpm -Ls | rpm2cpio - | cpio -iv --to-stdout ./usr/local/sessionmanagerplugin/bin/session-manager-plugin > {{Session.WorkingDirectory}}/session-manager-plugin
         chmod +x {{Session.WorkingDirectory}}/session-manager-plugin
         conda activate
         python {{Env.File.StartSession}} {{Session.WorkingDirectory}}/session-manager-plugin
      - name: Exit
        type: TEXT
        runnable: True
        data: |
         echo Killing SSM Manager Plugin PIDs: $BYOL_SSM_PIDS
         for pid in ${BYOL_SSM_PIDS//,/ }; do kill $pid; done
      - name: StartSession
        type: TEXT
        data: |
         import boto3
         import json
         import subprocess
         import sys
         import os
         import tempfile
   
         instance_id = "{{Param.LicenseInstanceId}}"
         region = "{{Param.LicenseInstanceRegion}}"
         license_ports_list = "{{Param.LicensePorts}}".split(",")
   
         ssm_client = boto3.client("ssm", region_name=region)
         pids = []
   
         for port in license_ports_list:
           session_response = ssm_client.start_session(
             Target=instance_id,
             DocumentName="AWS-StartPortForwardingSession",
             Parameters={"portNumber": [port], "localPortNumber": [port]}
           )
   
           cmd = [
             sys.argv[1],
             json.dumps(session_response),
             region,
             "StartSession",
             "",
             json.dumps({"Target": instance_id}),
             f"https://ssm.{region}.amazonaws.com"
           ]
   
           process = subprocess.Popen(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
           pids.append(process.pid)
           print(f"SSM Port Forwarding Session started for port {port}")
   
         print(f"openjd_env: BYOL_SSM_PIDS={','.join(str(pid) for pid in pids)}")
   
         # Enabling UBL after the BYOL has run out requires prepending the BYOL configuration to the existing license setup
         # Remove the sections that do not apply to your pipeline, or you do not want to use UBL after exhausting the BYOL licenses.
         # The port numbers used may not match what your license server is serving.
   
         # Arnold
         os.environ["ADSKFLEX_LICENSE_FILE"] = f"2701@localhost:{os.environ.get('ADSKFLEX_LICENSE_FILE', '')}"
         print(f"openjd_env: ADSKFLEX_LICENSE_FILE={os.environ['ADSKFLEX_LICENSE_FILE']}")
   
         # Nuke
         os.environ["foundry_LICENSE"] = f"6101@localhost:{os.environ.get('foundry_LICENSE', '')}"
         print(f"openjd_env: foundry_LICENSE={os.environ['foundry_LICENSE']}")
   
         # SideFX
         os.environ["SESI_LMHOST"] = f"localhost:1715;{os.environ.get('SESI_LMHOST', '')}"
         print(f"openjd_env: SESI_LMHOST={os.environ['SESI_LMHOST']}")
   
         # Redshift and Red Giant
         os.environ["redshift_LICENSE"] = f"7054@localhost:7055@localhost:{os.environ.get('redshift_LICENSE', '')}"
         print(f"openjd_env: redshift_LICENSE={os.environ['redshift_LICENSE']}")
   
         # V-Ray doesn't support multiple license servers in a single environment variable
         # See https://documentation.chaos.com/space/LIC5/125050770/Sharing+a+License+Configuration+in+a+Network
         vray_license = os.environ.get('VRAY_AUTH_CLIENT_SETTINGS', '')
         xml_content = """<VRLClient>
           <LicServer>
             <Host>localhost</Host>
             <Port>30304</Port>"""
   
         if vray_license and vray_license.startswith('licset://'):
             server_parts = vray_license.removeprefix('licset://').split(':')
             if len(server_parts) >= 2:
                 xml_content += f"""
             <Host1>{server_parts[0]}</Host1>
             <Port1>{server_parts[1]}</Port1>"""
   
         xml_content += """
             <User></User>
             <Pass></Pass>
           </LicServer>
         </VRLClient>"""
   
         temp_dir = tempfile.gettempdir()
         xml_path = os.path.join(temp_dir, 'vrlclient.xml')
         
         with open(xml_path, 'w') as f:
             f.write(xml_content)
   
         os.environ["VRAY_AUTH_CLIENT_FILE_PATH"] = temp_dir
         print(f"openjd_env: VRAY_AUTH_CLIENT_FILE_PATH={os.environ['VRAY_AUTH_CLIENT_FILE_PATH']}")
   
         # Clear the existing VRAY_AUTH_CLIENT_SETTINGS so only the vrlclient.xml file is used.
         os.environ["VRAY_AUTH_CLIENT_SETTINGS"] = ''
         print(f"openjd_env: VRAY_AUTH_CLIENT_SETTINGS={os.environ['VRAY_AUTH_CLIENT_SETTINGS']}")
   
         # Print out the created xml file's contents
         print(f"V-Ray configuration file: {xml_path}")
         with open(xml_path, 'r') as f:
             print(f"{f.read()}")
   ```

------

1. Sebelum menyimpan lingkungan antrian, buat perubahan berikut pada teks lingkungan sesuai kebutuhan:
   + Perbarui nilai default untuk parameter berikut untuk mencerminkan lingkungan Anda:
     + **LicenseInstanceID - ID** instans Amazon EC2 dari server lisensi atau instans proxy Anda
     + **LicenseInstanceRegion**— AWS Wilayah yang berisi peternakan Anda
     + **LicensePorts**— Daftar port yang dipisahkan koma untuk diteruskan ke server lisensi atau instance proxy (misalnya 2700,2701)
   + Jika Anda ingin menggunakan lisensi berbasis penggunaan (UBL) setelah Bring your own license (BYOL) habis pastikan port sudah benar untuk server lisensi Anda. Jika Anda tidak ingin menggunakan UBL setelah kehabisan BYOL, tambahkan variabel lingkungan lisensi yang diperlukan ke bagian variabel.

      Variabel-variabel ini harus mengarahkan DCCs ke localhost pada port server lisensi. Misalnya, jika server lisensi Foundry Anda mendengarkan pada port 6101, Anda akan menambahkan variabel sebagai. **foundry\$1LICENSE: 6101@localhost**

1. (Opsional) Anda dapat membiarkan **Prioritas** disetel ke **0**, atau Anda dapat mengubahnya untuk mengurutkan prioritas secara berbeda di antara beberapa lingkungan antrian.

1. Pilih **Buat lingkungan antrian** untuk menyelamatkan lingkungan baru.

   Dengan pengaturan lingkungan antrian, pekerjaan yang dikirimkan ke antrian ini akan mengambil lisensi dari server lisensi yang dikonfigurasi.

## Langkah 2: (Opsional) Pengaturan instance proxy lisensi
<a name="license-proxy"></a>

Sebagai alternatif untuk menggunakan server lisensi, Anda dapat menggunakan proxy lisensi. Untuk membuat proxy lisensi, buat instans Amazon Linux 2023 baru yang memiliki akses jaringan ke server lisensi. Jika perlu, Anda dapat mengonfigurasi akses ini menggunakan koneksi VPN. Untuk informasi selengkapnya, lihat [Koneksi VPN](https://docs.aws.amazon.com/vpc/latest/userguide/vpn-connections.html) di *Panduan Pengguna Amazon VPC*.

Untuk menyiapkan instance proxy lisensi untuk Deadline Cloud, ikuti langkah-langkah dalam prosedur ini. Lakukan langkah-langkah konfigurasi berikut pada instance baru ini untuk mengaktifkan penerusan lalu lintas lisensi ke server lisensi Anda

1. Untuk menginstal HAProxy paket, masukkan

   ```
   sudo yum install haproxy
   ```

1. Perbarui bagian server lisensi dengarkan dari file konfigurasi**/etc/haproxy/haproxy.cfg** dengan yang berikut ini:

   1. Ganti **LicensePort1** dan **LicensePort2** dengan nomor port yang akan diteruskan ke server lisensi. Tambahkan atau hapus nilai yang dipisahkan koma untuk mengakomodasi jumlah port yang diperlukan.

   1. Ganti **LicenseServerHost**dengan nama host atau alamat IP server lisensi.

   ```
   lobal
       log         127.0.0.1 local2
       chroot      /var/lib/haproxy
       user        haproxy
       group       haproxy
       daemon
   
   defaults
       timeout queue           1m
       timeout connect         10s
       timeout client          1m
       timeout server          1m
       timeout http-keep-alive 10s
       timeout check           10s
   
   listen license-server
        bind *:LicensePort1,*:LicensePort2
        server license-server LicenseServerHost
   ```

1. Untuk mengaktifkan dan memulai HAProxy layanan, jalankan perintah berikut:

   ```
   sudo systemctl enable haproxy
   sudo service haproxy start
   ```

Setelah menyelesaikan langkah-langkah, permintaan lisensi yang dikirim ke localhost dari lingkungan antrian penerusan harus diteruskan ke server lisensi yang ditentukan.

## Langkah 3: pengaturan CloudFormation template
<a name="byol-cfn-template"></a>

Anda dapat menggunakan CloudFormation template untuk mengonfigurasi seluruh peternakan untuk menggunakan lisensi Anda sendiri.

1. Ubah template yang disediakan di langkah berikutnya untuk menambahkan variabel lingkungan lisensi yang diperlukan ke bagian **variabel** di bawah **BYOLQueueLingkungan**.

1. Gunakan CloudFormation template berikut.

   ```
   AWSTemplateFormatVersion: 2010-09-09
   Description: "Create &ADC; resources for BYOL"
   
   Parameters:
     LicenseInstanceId:
       Type: AWS::EC2::Instance::Id
       Description: Instance ID for the license server/proxy instance
     LicensePorts:
       Type: String
       Description: Comma-separated list of ports to forward to the license instance
   
   Resources:
     JobAttachmentBucket:
       Type: AWS::S3::Bucket
       Properties:
         BucketName: !Sub byol-example-ja-bucket-${AWS::AccountId}-${AWS::Region}
         BucketEncryption:
           ServerSideEncryptionConfiguration:
             - ServerSideEncryptionByDefault:
                 SSEAlgorithm: AES256
   
     Farm:
       Type: AWS::Deadline::Farm
       Properties:
         DisplayName: BYOLFarm
   
     QueuePolicy:
       Type: AWS::IAM::ManagedPolicy
       Properties:
         ManagedPolicyName: BYOLQueuePolicy
         PolicyDocument:
           Version: 2012-10-17
           Statement:
             - Effect: Allow
               Action:
                 - s3:GetObject
                 - s3:PutObject
                 - s3:ListBucket
                 - s3:GetBucketLocation
               Resource:
                 - !Sub ${JobAttachmentBucket.Arn}
                 - !Sub ${JobAttachmentBucket.Arn}/job-attachments/*
               Condition:
                 StringEquals:
                   aws:ResourceAccount: !Sub ${AWS::AccountId}
             - Effect: Allow
               Action: logs:GetLogEvents
               Resource: !Sub arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/deadline/${Farm.FarmId}/*
             - Effect: Allow
               Action:
                 - s3:ListBucket
                 - s3:GetObject
               Resource:
                 - "*"
               Condition:
                 ArnLike:
                   s3:DataAccessPointArn:
                     - arn:aws:s3:*:*:accesspoint/deadline-software-*
                 StringEquals:
                   s3:AccessPointNetworkOrigin: VPC
     
     BYOLSSMPolicy:
       Type: AWS::IAM::ManagedPolicy
       Properties:
         ManagedPolicyName: BYOLSSMPolicy
         PolicyDocument:
           Version: 2012-10-17
           Statement:
             - Effect: Allow
               Action:
                 - ssm:StartSession
               Resource:
                 - !Sub arn:aws:ssm:${AWS::Region}::document/AWS-StartPortForwardingSession
                 - !Sub arn:aws:ec2:${AWS::Region}:${AWS::AccountId}:instance/${LicenseInstanceId}
   
   
     WorkerPolicy:
       Type: AWS::IAM::ManagedPolicy
       Properties:
         ManagedPolicyName: BYOLWorkerPolicy
         PolicyDocument:
           Version: 2012-10-17
           Statement:
             - Effect: Allow
               Action:
                 - logs:CreateLogStream
               Resource: !Sub arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/deadline/${Farm.FarmId}/*
               Condition:
                 ForAnyValue:StringEquals:
                   aws:CalledVia:
                     - deadline.amazonaws.com
             - Effect: Allow
               Action:
                 - logs:PutLogEvents
                 - logs:GetLogEvents
               Resource: !Sub arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/deadline/${Farm.FarmId}/*
               
   
     QueueRole:
       Type: AWS::IAM::Role
       Properties:
         RoleName: BYOLQueueRole
         ManagedPolicyArns:
           - !Ref QueuePolicy
           - !Ref BYOLSSMPolicy
         AssumeRolePolicyDocument:
           Version: 2012-10-17
           Statement:
             - Effect: Allow
               Action:
                 - sts:AssumeRole
               Principal:
                 Service:
                   - credentials.deadline.amazonaws.com
                   - deadline.amazonaws.com
               Condition:
                 StringEquals:
                   aws:SourceAccount: !Sub ${AWS::AccountId}
                 ArnEquals:
                   aws:SourceArn: !Ref Farm
   
     WorkerRole:
       Type: AWS::IAM::Role
       Properties:
         RoleName: BYOLWorkerRole
         ManagedPolicyArns:
           - arn:aws:iam::aws:policy/AWSDeadlineCloud-FleetWorker
           - !Ref WorkerPolicy
         AssumeRolePolicyDocument:
           Version: 2012-10-17
           Statement:
             - Effect: Allow
               Action:
                 - sts:AssumeRole
               Principal:
                 Service: credentials.deadline.amazonaws.com
   
   
     Queue:
       Type: AWS::Deadline::Queue
       Properties:
         DisplayName: BYOLQueue
         FarmId: !GetAtt Farm.FarmId
         RoleArn: !GetAtt QueueRole.Arn
         JobRunAsUser:
           Posix:
             Group: ""
             User: ""
           RunAs: WORKER_AGENT_USER
         JobAttachmentSettings:
           RootPrefix: job-attachments
           S3BucketName: !Ref JobAttachmentBucket
     
     Fleet:
       Type: AWS::Deadline::Fleet
       Properties:
         DisplayName: BYOLFleet
         FarmId: !GetAtt Farm.FarmId
         MinWorkerCount: 1
         MaxWorkerCount: 2
         Configuration:
           ServiceManagedEc2:
             InstanceCapabilities:
               VCpuCount:
                 Min: 4
                 Max: 16
               MemoryMiB:
                 Min: 4096
                 Max: 16384
               OsFamily: LINUX
               CpuArchitectureType: x86_64
             InstanceMarketOptions:
               Type: on-demand
         RoleArn: !GetAtt WorkerRole.Arn
   
     QFA:
       Type: AWS::Deadline::QueueFleetAssociation
       Properties:
         FarmId: !GetAtt Farm.FarmId
         FleetId: !GetAtt Fleet.FleetId
         QueueId: !GetAtt Queue.QueueId
     
     CondaQueueEnvironment:
       Type: AWS::Deadline::QueueEnvironment
       Properties:
         FarmId: !GetAtt Farm.FarmId
         Priority: 5
         QueueId: !GetAtt Queue.QueueId
         TemplateType: YAML
         Template: |
           specificationVersion: 'environment-2023-09'
           parameterDefinitions:
           - name: CondaPackages
             type: STRING
             description: >
               This is a space-separated list of conda package match specifications to install for the job.
               E.g. "blender=3.6" for a job that renders frames in Blender 3.6.
   
               See https://docs.conda.io/projects/conda/en/latest/user-guide/concepts/pkg-specs.html#package-match-specifications
             default: ""
             userInterface:
               control: LINE_EDIT
               label: Conda Packages
           - name: CondaChannels
             type: STRING
             description: >
               This is a space-separated list of conda channels from which to install packages. &ADC; SMF packages are
               installed from the "deadline-cloud" channel that is configured by &ADC;.
   
               Add "conda-forge" to get packages from the https://conda-forge.org/ community, and "defaults" to get packages
               from Anaconda Inc (make sure your usage complies with https://www.anaconda.com/terms-of-use).
             default: "deadline-cloud"
             userInterface:
               control: LINE_EDIT
               label: Conda Channels
           environment:
             name: Conda
             script:
               actions:
                 onEnter:
                   command: "conda-queue-env-enter"
                   args: ["{{Session.WorkingDirectory}}/.env", "--packages", "{{Param.CondaPackages}}", "--channels", "{{Param.CondaChannels}}"]
                 onExit:
                   command: "conda-queue-env-exit"
     
     BYOLQueueEnvironment:
       Type: AWS::Deadline::QueueEnvironment
       Properties:
         FarmId: !GetAtt Farm.FarmId
         Priority: 10
         QueueId: !GetAtt Queue.QueueId
         TemplateType: YAML
         Template: !Sub |
           specificationVersion: "environment-2023-09"
           parameterDefinitions:
           - name: LicenseInstanceId
             type: STRING
             description: >
               The Instance ID of the license server/proxy instance
             default: ""
           - name: LicenseInstanceRegion
             type: STRING
             description: >
               The region containing this farm
             default: ""
           - name: LicensePorts
             type: STRING
             description: >
               Comma-separated list of ports to be forwarded to the license server/proxy
               instance. Example: "2701,2702,7075,2703,6101,1715,1716,1717,7054,7055,30304"
             default: "2701,2702,7075,2703,6101,1715,1716,1717,7054,7055,30304"
           environment:
           name: BYOL License Forwarding
           variables:
             example_LICENSE: 2701@localhost
           script:
             actions:
             onEnter:
               command: bash
               args: [ "{{Env.File.Enter}}" ]
             onExit:
               command: bash
               args: [ "{{Env.File.Exit}}" ]
             embeddedFiles:
             - name: Enter
               type: TEXT
               runnable: True
               data: |
                 curl https://s3.amazonaws.com/session-manager-downloads/plugin/latest/linux_64bit/session-manager-plugin.rpm -Ls | rpm2cpio - | cpio -iv --to-stdout ./usr/local/sessionmanagerplugin/bin/session-manager-plugin > {{Session.WorkingDirectory}}/session-manager-plugin
                 chmod +x {{Session.WorkingDirectory}}/session-manager-plugin
                 conda activate
                 python {{Env.File.StartSession}} {{Session.WorkingDirectory}}/session-manager-plugin
             - name: Exit
               type: TEXT
               runnable: True
               data: |
                 echo Killing SSM Manager Plugin PIDs: $BYOL_SSM_PIDS
                 for pid in ${BYOL_SSM_PIDS//,/ }; do kill $pid; done
             - name: StartSession
               type: TEXT
               data: |
                 import boto3
                 import json
                 import subprocess
                 import sys
                 import os
                 import tempfile
   
                 instance_id = "{{Param.LicenseInstanceId}}"
                 region = "{{Param.LicenseInstanceRegion}}"
                 license_ports_list = "{{Param.LicensePorts}}".split(",")
   
                 ssm_client = boto3.client("ssm", region_name=region)
                 pids = []
   
                 for port in license_ports_list:
                   session_response = ssm_client.start_session(
                     Target=instance_id,
                     DocumentName="AWS-StartPortForwardingSession",
                     Parameters={"portNumber": [port], "localPortNumber": [port]}
                   )
   
                   cmd = [
                     sys.argv[1],
                     json.dumps(session_response),
                     region,
                     "StartSession",
                     "",
                     json.dumps({"Target": instance_id}),
                     f"https://ssm.{region}.amazonaws.com"
                   ]
   
                   process = subprocess.Popen(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
                   pids.append(process.pid)
                   print(f"SSM Port Forwarding Session started for port {port}")
   
                 print(f"openjd_env: BYOL_SSM_PIDS={','.join(str(pid) for pid in pids)}")
   
                 # Enabling UBL after the "bring your own license" (BYOL) has run out requires prepending the BYOL configuration to the existing license setup
                 # Remove the sections that do not apply to your pipeline, or you do not want to use UBL after exhausting the BYOL licenses.
                 # The port numbers used may not match what your license server is serving.
   
                 # Arnold
                 os.environ["ADSKFLEX_LICENSE_FILE"] = f"2701@localhost:{os.environ.get('ADSKFLEX_LICENSE_FILE', '')}"
                 print(f"openjd_env: ADSKFLEX_LICENSE_FILE={os.environ['ADSKFLEX_LICENSE_FILE']}")
   
                 # Nuke
                 os.environ["foundry_LICENSE"] = f"6101@localhost:{os.environ.get('foundry_LICENSE', '')}"
                 print(f"openjd_env: foundry_LICENSE={os.environ['foundry_LICENSE']}")
   
                 # SideFX
                 os.environ["SESI_LMHOST"] = f"localhost:1715;{os.environ.get('SESI_LMHOST', '')}"
                 print(f"openjd_env: SESI_LMHOST={os.environ['SESI_LMHOST']}")
   
                 # Redshift and Red Giant
                 os.environ["redshift_LICENSE"] = f"7054@localhost:7055@localhost:{os.environ.get('redshift_LICENSE', '')}"
                 print(f"openjd_env: redshift_LICENSE={os.environ['redshift_LICENSE']}")
   
                 # V-Ray doesn't support multiple license servers in a single environment variable
                 # See https://documentation.chaos.com/space/LIC5/125050770/Sharing+a+License+Configuration+in+a+Network
                 vray_license = os.environ.get('VRAY_AUTH_CLIENT_SETTINGS', '')
                 xml_content = """<VRLClient>
                   <LicServer>
                     <Host>localhost</Host>
                     <Port>30304</Port>"""
   
                 if vray_license and vray_license.startswith('licset://'):
                     server_parts = vray_license.removeprefix('licset://').split(':')
                     if len(server_parts) >= 2:
                         xml_content += f"""
                     <Host1>{server_parts[0]}</Host1>
                     <Port1>{server_parts[1]}</Port1>"""
   
                 xml_content += """
                     <User></User>
                     <Pass></Pass>
                   </LicServer>
                 </VRLClient>"""
   
                 temp_dir = tempfile.gettempdir()
                 xml_path = os.path.join(temp_dir, 'vrlclient.xml')
                 
                 with open(xml_path, 'w') as f:
                     f.write(xml_content)
   
                 os.environ["VRAY_AUTH_CLIENT_FILE_PATH"] = temp_dir
                 print(f"openjd_env: VRAY_AUTH_CLIENT_FILE_PATH={os.environ['VRAY_AUTH_CLIENT_FILE_PATH']}")
   
                 # Clear the existing VRAY_AUTH_CLIENT_SETTINGS so only the vrlclient.xml file is used.
                 os.environ["VRAY_AUTH_CLIENT_SETTINGS"] = ''
                 print(f"openjd_env: VRAY_AUTH_CLIENT_SETTINGS={os.environ['VRAY_AUTH_CLIENT_SETTINGS']}")
   
                 # Print out the created xml file's contents
                 print(f"V-Ray configuration file: {xml_path}")
                 with open(xml_path, 'r') as f:
                     print(f"{f.read()}")
   ```

1. Saat menerapkan CloudFormation template, berikan parameter berikut:
   + Memperbarui **LicenseInstanceID dengan ID** Instans Amazon EC2 dari server lisensi atau instans proxy Anda
   + Perbarui **LicensePorts**dengan daftar port yang dipisahkan koma untuk diteruskan ke server lisensi atau instance proxy (misalnya 2700,2701)
   + Tambahkan variabel lingkungan lisensi dengan mengganti **example\$1LICENSE: 2700@localhost** dalam template

1. Terapkan template untuk menyiapkan peternakan Anda dengan membawa kemampuan lisensi Anda sendiri.