1.1.3.5. Things CloudとIoT Connect Gatewayの自動構築コードを作成する

注釈

  • 本ページに記載の画像・設定項目は、2022年5月時点の情報です。Microsoft Azureの仕様変更により、内容が変更となる場合がありますのでご注意ください。

本項では、Things CloudおよびIoT Connect Gateway(以下ICGW)を自動構築する際に作成するAzure DevOps - Release PipelinesのSecure Files、Ansible Playbookファイル、Job/Task例を記載しています。

なお、本書中の設定値の「< >」の表記については、ご利用の環境により各自入力いただく箇所となります("<"から">"までを設定値に置き換えてください)。

Secure Filesを作成する

Smart Data Platform(以下SDPF)のAPI情報や、ICGW・Things Cloudのパラメーターを記載した.ymlファイルを作成し、Secure Filesに格納します。

なお、Secure Filesに格納されたファイルは自動で暗号化され、外部からは内容を確認できないようになっています。

アップロード後の内容の確認や修正はできませんのでご注意ください。

内容を編集したい場合は、Secure Fileを一度削除→再アップロードいただく形となります。

vars_icgw_thingscloud.yml(例)

SDPFのAPI情報や、ICGW・Things Cloudのアカウント・テナント・設定情報を保存したファイルです。

SDPFのAPI情報については、「1.1.3.3. Smart Data Platform APIの利用準備をする」を参照いただき、設定変更のうえご確認ください。

sdpf_apikey: <SDPF API鍵>
sdpf_secretkey: <SDPF API秘密鍵>
sdpf_tenantid: <SDPFワークスペースのテナントID(グローバル)>

token_host: https://api.ntt.com/keystone/v3/auth/tokens
icgw_host: https://api.ntt.com/iot-c-icgw/v1/tenants/

group_name: <ICGWでのSIMグループ名>
sim_imsi: "<SIMグループに割り当てるSIMのIMSI>"

tc_mqtt_client_id: <Things CloudのMQTT Client ID>

tc_auth_name: <認証設定名>
tc_auth_description: <認証設定の説明文>
tc_user_name: <対象テナントへのログインユーザー名>
tc_password: "<ログインユーザーのパスワード>"
tc_tenant_id: <Things Cloudのテナント名(▲▲▲.je1.thingscloud.ntt.comの"▲▲▲"部分>

tc_template_id: "<作成するSmartRESTテンプレートID"
tc_template_name: "<作成するSmartRESTテンプレート名>"

tc_pconv_name: <プロトコル変換設定名>
tc_host: <Things Cloudのホスト名(例: ▲▲▲.je1.thingscloud.ntt.com)>
tc_message_id: "992"

Ansible Playbookファイルを作成する

ICGWおよびThings Cloudの自動設定のため、ICGWおよびThings Cloudに対する操作を定義したAnsible Playbookファイルを作成します。

ファイルは、Azure DevOpsと連携させたリポジトリ内のコード保存ディレクトリに格納してください。

- hosts: localhost
  vars_files:
    - ../../../../../_temp/vars_icgw_thingscloud.yml
  vars:
    ID_Password: "{{ tc_user_name }}:{{ tc_password }}"

  tasks:
    - name: create Basic Authorization
      set_fact:
        Basic_Authorization: "{{ ID_Password | b64encode }}"

    - name: create Token
      uri:
        url: "https://{{ tc_tenant_id }}.je1.thingscloud.ntt.com/tenant/oauth/token"
        headers:
          Authorization: "Basic {{ Basic_Authorization }}"
          Content-Type: "application/x-www-form-urlencoded"
        status_code: 200
        method: "POST"
        body_format: "form-urlencoded"
        return_content: "yes"
        body:
               grant_type: "PASSWORD"
               username: "{{ tc_user_name }}"
               password: "{{ tc_password }}"
               tenant_id: "{{ tc_tenant_id }}"
      register: result

    - debug: msg="{{ result.content | from_json }}"

    - name: create Contents
      set_fact:
        Content: "{{ result.content | from_json }}"

    - name: create Token
      set_fact:
        Token: "{{ Content.access_token }}"

    - debug: msg="{{ Token }}"

    - name: create SmartRestTemplate
      uri:
        url: "https://{{ tc_tenant_id }}.je1.thingscloud.ntt.com/inventory/managedObjects"
        headers:
          Authorization: "Bearer {{ Token }}"
          Content-Type: "application/vnd.com.nsn.cumulocity.managedObject+json"
          Accept: "application/vnd.com.nsn.cumulocity.managedObject+json"
        status_code: 201
        method: "POST"
        body_format: "json"
        body:
               name: "{{ tc_template_name }}"
               type: "c8y_SmartRest2Template"
               com_cumulocity_model_smartrest_csv_CsvSmartRestTemplate: {"requestTemplates":[],"responseTemplates":[]}
      register: result1

    - debug: msg="{{result1.json.id}}"

    - name: SmartRestID
      set_fact:
        SmartRestTemplateID: "{{ result1.json.id }}"

    - debug: var=SmartRestTemplateID

    - debug: msg=https://{{ tc_tenant_id }}.je1.thingscloud.ntt.com/identity/globalIds/{{ SmartRestTemplateID }}/externalIds

    - name: setting ExternalId
      uri:
        url: "https://{{ tc_tenant_id }}.je1.thingscloud.ntt.com/identity/globalIds/{{ SmartRestTemplateID }}/externalIds"
        headers:
          Authorization: "Bearer {{ Token }}"
          Content-Type: "application/vnd.com.nsn.cumulocity.externalId+json"
          Accept: "*/*"
        status_code: 201
        method: "POST"
        body_format: "json"
        body:
              type: c8y_SmartRest2DeviceIdentifier
              externalId: "{{ tc_template_id }}"
      register: result2

    - debug: msg="{{ result2 }}"

    - name: create MessageTemplate
      uri:
        url: " https://{{ tc_tenant_id }}.je1.thingscloud.ntt.com/inventory/managedObjects/{{ SmartRestTemplateID }}"
        headers:
          Authorization: "Bearer {{ Token }}"
          Content-Type: "application/vnd.com.nsn.cumulocity.managedObject+json"
          Accept: "application/vnd.com.nsn.cumulocity.managedObject+json"
        status_code: 200
        method: "PUT"
        body_format: "json"
        body:
              id: "{{ SmartRestTemplateID }}"
              com_cumulocity_model_smartrest_csv_CsvSmartRestTemplate:
                requestTemplates:
                - name: Temperature-Humidity-Template
                  msgId: 992
                  api: MEASUREMENT
                  method: POST
                  response: false
                  byId: true
                  mandatoryValues:
                  - path: $.type
                    type: STRING
                    value: Temperature-Humidity
                  - path: $.time
                    type: DATE
                    value: null
                  customValues:
                  - path: Temperature.t.value
                    type: NUMBER
                    value: null
                  - path: Humidity.h.value
                    type: NUMBER
                    value: null
                  externalIdType: c8y_Serial
                  responseTemplates: []
      register: result3

    - debug: msg="{{ result3 }}"


    - name: Get Authentication Token
      uri:
        url: "{{ token_host }}"
        headers:
          Content-Type: "application/json"
        status_code: 201
        method: "POST"
        body_format: "json"
        body:
          {
            "auth": {
              "identity": {
                "methods": [
                  "password"
                ],
                "password": {
                  "user": {
                    "domain": {
                      "id": "default"
                    },
                    "name": "{{ sdpf_apikey }}",
                    "password": "{{ sdpf_secretkey }}"
                  }
                }
              },
              "scope": {
                "project": {
                  "id": "{{ sdpf_tenantid }}"
                }
              }
            }
          }
      register: token
    - name: Print Response
      debug:
        var: token.x_subject_token

    - name: Create Group and Assign Sim
      uri:
        url: "{{ icgw_host }}{{ sdpf_tenantid }}/groups"
        headers:
          X-Auth-Token: "{{ token.x_subject_token }}"
          Content-Type: "application/json"
        status_code: 201
        method: "POST"
        body_format: "json"
        body:
          {
            "name": "{{ group_name }}"
          }
      register: group
    - name: Print Response
      debug:
        var: group.json.id


    - name: Get Sim
      uri:
        url: "{{ icgw_host }}{{ sdpf_tenantid }}/sims?imsi={{ sim_imsi }}"
        headers:
          X-Auth-Token: "{{ token.x_subject_token }}"
          Content-Type: "application/json"
        status_code: 200
        method: "GET"
      register: sim
    - name: Print Response
      debug:
        var: sim.json.sims[0].msisdn

    - name: Assign Sim to Group
      uri:
        url: "{{ icgw_host }}{{ sdpf_tenantid }}/sims/{{ sim_imsi }}"
        headers:
          X-Auth-Token: "{{ token.x_subject_token }}"
          Content-Type: "application/json"
        status_code: 200
        method: "PUT"
        body_format: "json"
        body:
          {
            "groupId": "{{ group.json.id }}",
            "msisdn": "{{ sim.json.sims[0].msisdn }}",
            "mqttClientId": "{{ tc_mqtt_client_id }}"
          }

    - name: Create Authentication
      uri:
        url: "{{ icgw_host }}{{ sdpf_tenantid }}/authentications"
        headers:
          X-Auth-Token: "{{ token.x_subject_token }}"
          Content-Type: "application/json"
        status_code: 201
        method: "POST"
        body_format: "json"
        body:
          {
            "type": "things-iot-credentials",
            "name": "{{ tc_auth_name }}",
            "description": "{{ tc_auth_description }}",
            "tenantId": "{{ tc_tenant_id }}",
            "userName": "{{ tc_user_name }}",
            "password": "{{ tc_password }}"
          }
      register: auth
    - name: Print Response
      debug:
        var: auth.json.id

    - name: Set Protocol Conversion
      uri:
        url: "{{ icgw_host }}{{ sdpf_tenantid }}/groups/{{ group.json.id }}/pconv"
        headers:
          X-Auth-Token: "{{ token.x_subject_token }}"
          Content-Type: "applicaion/json"
        status_code: 201
        method: "POST"
        body_format: "json"
        body:
          {
            "enabled": true,
            "name": "{{ tc_pconv_name }}",
            "type": "mqtt",
            "destination":
              {
                "serviceType": "things-iot",
                "host": "{{ tc_host }}",
                "authenticationId": "{{ auth.json.id }}",
                "template": "{{ tc_message_id }}"
              }
          }

      register: pconv

Job「Setting Things Cloud & IoT Connect Gateway」

  • Display name: Setting Things Cloud & IoT Connect Gateway

  • Agent selection:
    • Agent pool: Azure Pipelines
    • Agent Specification: ubuntu-latest
    • Demands: (設定なし)
  • Execution plan:
    • Parallelism: None
    • Timeout: 0
    • Job cancel timeout: 1
  • Additional options:
    • Skip download of artifacts: Off
    • Allow scripts to access the OAuth token: Off
    • Run this job: Only when all previous jobs have succeeded
    Job

Task「[TC&ICGW]Download Secure File」

  • 利用Task「Download secure file」

    • Task version: 1.*

    • Display name: [TC&ICGW]Download Secure File

    • Secure File: <Secure Filesに保存したTCのパラメーターファイル>(vars_icgw_thingscloud.yml)

    • Retry Count: 8

    • Socket Timeout: (設定なし)

    • Control Options:
      • Enabled: On
      • Continue on error: Off
      • Number of retries if task failed: 0
      • Timeout: 0
      • Run this task: Only when all previous tasks have succeeded
    • Output Variables:
      • Reference name: (設定なし)
    Task 1

Task「[TC&ICGW]Run Ansible Playbook」

  • 利用Task「Command line」

    • Task version: 2.*

    • Display name: [TC&ICGW]Run Ansible Playbook

    • Script:

      ansible-playbook '<作業ディレクトリ>/<TC自動設定用のAnsible Playbookファイル>'
      
    • Advanced:
      • Working Directory: (設定なし)
      • Fail on Standard Error: Off
    • Control Options:
      • Enabled: On
      • Continue on error: Off
      • Number of retries if task failed: 0
      • Timeout: 0
      • Run this task: Only when all previous tasks have succeeded
    • Environment Variables: (設定なし)

    • Output Variables:
      • Reference name: (設定なし)
    Task 2