Jenkins Pipeline と API Manager API を使用した Flex Gateway の自動化

Jenkins Pipeline を使用して、接続モードでの Flex Gateway のワークフローを自動化できます。Jenkins Pipeline を使用すると、Flex Gateway を登録して実行し、API Manager API の機能 (API インスタンスの作成やデプロイなど) を使用できます。

接続モードでの Flex Gateway の自動化ワークフローは、​「API Manager API を使用した Flex Gateway の管理」​チュートリアルと多くの類似点があります。Jenkins Pipeline を使用して、API Manager API に対するコールを自動化できます。 API Manager API​ から機能を追加するには、例として​「API インスタンスを作成する」​および ​「API ポリシーを適用する」​ Pipeline フェーズを使用します。

このチュートリアルには、異なるコードブロックを含む異なる手順があります。手順を進めながら、コードブロックを同じ Jenkinsfile に追加します。Jenkins Pipeline で使用される構文についての詳細は、 Jenkins Pipeline ドキュメント​を参照してください。

代わりに Anypoint CLI を使用して Flex Gateway を自動化するには、「Jenkins Pipeline と Anypoint CLI を使用した Flex Gateway の自動化」を参照してください。

始める前に

Jenkins Pipeline をデプロイする前に、次のタスクを完了します。

  1. Flex Gateway をダウンロードします​。

  2. 接続アプリケーションを設定します​。

    1. [App acts on its behalf (client credentials) (アプリケーションが自身のために行動する (クライアントログイン情報))]​ 種別を使用し、以下のスコープを含めます。

      • API Manager: [Manage API Configuration (API 設定の管理)]​、​[Manage Policies (ポリシーの管理)]​、​[View Policies (ポリシーの参照)]​、​[Deploy API Proxies (API プロキシのデプロイ)]

      • Runtime Manager: [Read Servers (サーバーの参照)]​ および ​[Manage Servers (サーバーの管理)]

      • Exchange: [Exchange Viewer (Exchange 閲覧者)]

      • 一般: [View Organization (組織の表示)]

    2. 設定する接続アプリケーションの ​ID​ と​シークレット​を保存します。

  3. 作成または適用する Exchange アセット (API) のグループ ID、アセット ID、およびアセットバージョン (GAV) を収集します。

    Exchange から GAV を収集する手順は、次のとおりです。

    1. Exchange に移動します。

    2. 追加または適用するアセットを見つけます。

    3. URL からグループ ID とアセット ID を収集します。

      たとえば、API Manager API Exchange URL ​https://anypoint.mulesoft.com/exchange/portals/anypoint-platform/f1e97bc6-315a-4490-82a7-23abe036327a.anypoint-platform/api-manager-api/minor/1.0/pages/home/​ から収集された ID は次のとおりです。

      • グループ ID: f1e97bc6-315a-4490-82a7-23abe036327

      • アセット ID: api-manager-api

    4. [Latest Stable (最新の安定バージョン)]​ からアセットのバージョンを収集します。

      たとえば、API Gateway HTTP 基本認証ポリシーテンプレートから収集されたバージョンは ​1.3.1​ です。

  4. Anypoint Platform インスタンスから以下の情報を収集します。

初期設定

API インスタンスを作成して Flex Gateway にデプロイする前に、次の手順を完了する必要があります。

これらの Pipeline フェーズを実装したら、API を管理するための API Manager API 要求を作成して Pipeline をカスタマイズできます。

役立つ関数を定義する

まず、Jenkinsfile でこれらの役立つ関数を定義します。​pipeline​ ブロックの前に関数を定義します。

def parseYamlFile(String file) {
   object = readYaml file: file
   return object
}

def parseJsonFile(file) {
   object = readJSON file: file
   return object
}

役立つパラメーターを定義する

Jenkins Pipeline のコマンドは一部のパラメーターを再利用するため、Jenkinsfile の先頭でパラメーターを定義すると役立ちます。

含まれているパラメーター定義をテンプレートとして使用して、追加の API またはポリシーに必要なパラメーターを定義することもできます。

パラメーターを定義する手順は、次のとおりです。

  1. 次の情報を収集します。

    • <your-org-id>​: Flex Gateway を実行する組織の​組織 ID

    • <your-env-id>​: Flex Gateway を実行する組織の​環境 ID

    • <gateway-version>​: 使用している Flex Gateway のバージョン (例: 1.4.0​)

    • <connected-app-client-id>​: 接続アプリケーションの ​ID

    • <connected-app-client-secret>​: 接続アプリケーションの​シークレット​。

    • API GAV:

      • <asset-group-id>​: Exchange から取得したグループ ID

      • <asset-id-from-exchange>​: Exchange から取得した、作成する API のアセット ID

      • <asset-version>​: Exchange から取得した、作成する API のアセットバージョン

    • <gateway-name>​: Flex ゲートウェイの名前

  2. サンプルコンテンツを置き換えたら、パラメーター定義を Jenkinsfile に追加して、すべてのパラメーターが存在するかどうかを検証します。​stages​ ブロックの前の ​pipeline​ ブロックでパラメーターを定義します。

    parameters {
        string(name: 'ENV_ID', defaultValue: '<your-env-id>', description: 'Your environment id')
        string(name: 'ORG_ID', defaultValue: '<your-org-id>', description: 'Your organization id')
        string(name: 'FLEX_VERSION', defaultValue: '<gateway-version>', description: 'Flex version to run')
        string(name: 'CONNECTED_APP_CLIENT_ID', defaultValue: '<connected-app-client-id>', description: 'Your connected app client id')
        string(name: 'CONNECTED_APP_CLIENT_SECRET', defaultValue: '<connected-app-client-secret', description: 'Your connected app client secret')
        string(name: 'EXCHANGE_ASSET_ID', defaultValue: '<asset-id-from-exchange>', description: 'The id of the http api exchange asset')
        string(name: 'EXCHANGE_ASSET_VERSION', defaultValue: '<asset-version>', description: 'The version of the http api exchange asset')
        string(name: 'GATEWAY_NAME', defaultValue: '<gateway-name>', description: 'Unique gateway name')
    }
  3. Jenkinsfile で check parameters ​stage​ を ​stages​ ブロックに追加します。

    stage('Check parameters') {
        steps {
            script {
                if (!params.ENV_ID || !params.ORG_ID || !params.FLEX_VERSION || !params.CONNECTED_APP_CLIENT_ID || !params.CONNECTED_APP_CLIENT_SECRET || !params.EXCHANGE_ASSET_ID || !params.EXCHANGE_ASSET_VERSION || !params.GATEWAY_NAME)  {
                error("Not all parameters where specified")
                }
            }
        }
    }

    このフェーズが失敗した場合は、不足しているパラメーターを指定して Pipeline を再実行します。

登録して実行する

Jenkinsfile で登録フェーズと実行フェーズを ​stages​ ブロックに追加します。

stage('Register flex gateway') {
    steps {
        script {
            sh """
                docker run --entrypoint flexctl \
                    -v "\$(pwd)":/registration -u 0 mulesoft/flex-gateway:${params.FLEX_VERSION} \
                    register \
                    --client-id=${params.CONNECTED_APP_CLIENT_ID} \
                    --client-secret=${params.CONNECTED_APP_CLIENT_SECRET} \
                    --environment=${params.ENV_ID} \
                    --connected=true \
                    --organization=${params.ORG_ID} \
                    --output-directory=/registration \
                    ${params.GATEWAY_NAME}
                """
                if (!fileExists('registration.yaml')) {
                    error("Registration failed")
                }
        }
    }
}

stage('Run flex gateway') {
    steps {
        script {
            sh """
                docker run -d \
                -v "\$(pwd)":/usr/local/share/mulesoft/flex-gateway/conf.d \
                -p 8082:8082 \
                mulesoft/flex-gateway:${params.FLEX_VERSION} > containerId
            """
        }
    }
}

[Access Management (アクセス管理)] から認証トークンを取得する

Flex Gateway を登録して実行したら、後続の要求を認証するために、[Access Management (アクセス管理)] から有効な認証トークンを取得する必要があります。

Anypoint にログインするには、Jenkinsfile で ​stages​ ブロックに Anypoint login ​stage​ を追加します。

stage("Anypoint login") {
    steps {
        script {
            def cmd = """curl -s -w "%{http_code}" --location --request POST 'https://anypoint.mulesoft.com/accounts/api/v2/oauth2/token' -o 'login-response' \
                    --header 'Content-Type: application/json' \
                    --data-raw '{"grant_type": "client_credentials", "client_id": "${params.CONNECTED_APP_CLIENT_ID}", "client_secret": "${params.CONNECTED_APP_CLIENT_SECRET}"}'
                    """
            def status_code = sh(returnStdout: true, script: cmd).trim().toInteger()
            if (status_code > 399) {
                error("Anypoint login failed")
            }
        }
    }
}

このステップで返された認証トークンは、後続の要求のために保存されます。

API インスタンスを作成する

[Access Management (アクセス管理)] から認証トークンを取得すると、API インスタンスを作成して Flex Gateway にデプロイできるようになります。

このステップを繰り返して、複数の API インスタンスを追加できます。

たとえば、このフェーズでは、ポート ​8082​ および ​/httpbin​ パスでリスンし、​https://httpbin.org/​ にプロキシする API インスタンスを作成します。

API インスタンスを作成する手順は、次のとおりです。

  1. 次の情報を収集します。

    • <upstream-uri>​: API の URI アップストリーム

    • <your-proxy-uri>​: API インスタンスのプロキシ URI

    • "isCloudHub"​: Cloud Hub の状況 (例: null​ または ​true​)

  2. 必要に応じて、​"endpointUri"​ を収集するか、​"endpointUri"​ 項目を削除します。

    • <your-consumer-endpoint>​: API のコンシューマーエンドポイント (例: http://consumer-endpoint.com​)

  3. HTTP アドレスを置き換えたら、Jenkinsfile で create API instance ​stage​ を ​stages​ ブロックに追加します。

stage("Create API instance") {
    steps {
        script {
            def login_response = parseJsonFile('login-response')
            def cmd = """
                curl -s -w "%{http_code}" --location --request POST 'https://anypoint.mulesoft.com/apimanager/api/v1/organizations/${params.ORG_ID}/environments/${params.ENV_ID}/apis' -o 'api-response' \
                --header 'Authorization: Bearer ${login_response.access_token}' \
                --header 'Content-Type: application/json' \
                --data-raw '{
                "spec": {
                    "groupId": "${params.ORG_ID}",
                    "assetId": "${params.EXCHANGE_ASSET_ID}",
                    "version": "${params.EXCHANGE_ASSET_VERSION}"
                },
                "endpoint": {
                    "deploymentType": "HY",
                    "uri": "https://httpbin.org:443",
                    "proxyUri": "http://0.0.0.0:8082/httpbin",
                    "isCloudHub": null
                },
                "technology": "flexGateway"
                "endpointUri": "<your-consumer-endpoint>" // OPTIONAL
                }'
            """
            def status_code = sh(returnStdout: true, script: cmd).trim().toInteger()
            if (status_code > 399) {
                error("Error occurred while trying to create API instance")
            }
        }
    }
}

API ポリシーを適用する

API インスタンスを作成したら、そのインスタンスに接続モードポリシーを適用できます。

  1. 次の情報を収集します。

    • ポリシー GAV

      • <policy-group-id>​: Exchange のポリシーグループ ID

      • <policy-asset-id>​:Exchange のポリシーアセット ID (例: http-basic-authentication​)

      • <policy-asset-version>​: Exchange のポリシーアセットバージョン (例: 1.3.1​)

    • "configurationData"​: ポリシー設定データ

      設定データ項目はポリシーに依存します。​"username"​ パラメーターと ​"password"​ パラメーターは単なる例です。ポリシーの設定データを見つけるには、​「内部ポリシーディレクトリ」​を参照してください。

  2. サンプルコンテンツを置き換えたら、Jenkinsfile で apply policy ​stage​ を ​stages​ ブロックに追加します。

stage("Apply policy") {
   steps {
       script {
           def login_response = parseJsonFile('login-response')
           def api_response = parseJsonFile('api-response')


           def cmd = """
               curl -s -w "%{http_code}" -o /dev/null --location --request POST 'https://anypoint.mulesoft.com/apimanager/api/v1/organizations/${params.ORG_ID}/environments/${params.ENV_ID}/apis/${api_response.id}/policies' \
               --header 'Authorization: Bearer ${login_response.access_token}' \
               --header 'Content-Type: application/json' \
               --data-raw '{
                 "configurationData":{
                    "username": "user",
                    "password": "test"
                 },
                 "pointcutData": null,
                 "assetId": "<policy-asset-id>",
                 "assetVersion": "<policy-asset-id>",
                 "groupId": "<policy-group-id>"
                }'
           """


           def status_code = sh(returnStdout: true, script: cmd).trim().toInteger()
           if (status_code > 399) {
               error("Error occurred while trying to apply Basic Auth Policy to the API instance")
           }
       }
   }
}

API インスタンスのデプロイ

API インスタンスを作成したら、そのインスタンスをデプロイできます。

新しいインスタンスをデプロイするには、Jenkinsfile で deploy API ​stage​ を ​stages​ ブロックに追加します。

stage("Deploy API") {
    steps {
        script {
            def login_response = parseJsonFile('login-response')
            def api_response = parseJsonFile('api-response')
            def registration_file = parseYamlFile('registration.yaml')


            def cmd = """
                curl -s -w "%{http_code}" -o /dev/null --location --request POST 'https://anypoint.mulesoft.com/proxies/xapi/v1/organizations/${params.ORG_ID}/environments/${params.ENV_ID}/apis/${api_response.id}/deployments' \
                --header 'Content-Type: application/json' \
                --header 'Authorization: Bearer ${login_response.access_token}' \
                --data-raw '{
                "type": "HY",
                "gatewayVersion": "${params.FLEX_VERSION}",
                "targetId": "${registration_file.spec.platformConnection.agentId[0]}",
                "environmentId": "${params.ENV_ID}"
                }'
            """


            def status_code = sh(returnStdout: true, script: cmd).trim().toInteger()
            if (status_code > 399) {
                error("Error occurred while trying to deploy the API instance")
            }
        }
    }
}

API インスタンスがデプロイされていることを検証する

API インスタンスをデプロイしたら、Jenkinsfile で ​validate deployment​ stage を ​stages​ ブロックに追加して、インスタンスがデプロイされているかどうかを検証します。

stage("Validate deployment") {
    steps {
        script {
            sleep(time:10, unit:"SECONDS")


            def unauthorized_status_code = sh(script: "curl -s -w \"%{http_code}\" -o /dev/null http://localhost:8082/httpbin/headers -v", returnStdout: true).trim().toInteger()
            if (unauthorized_status_code != 401) {
                error("401 status code expected but the status code obtained is ${unauthorized_status_code}")
            }


            def authorized_status_code = sh(script: "curl -s -w \"%{http_code}\" -o /dev/null http://localhost:8082/httpbin/headers -v -u user:test", returnStdout: true).trim().toInteger()
            if (authorized_status_code != 200) {
                error("200 status code expected but the status code obtained is ${unauthorized_status_code}")
            }
        }
    }
}

Flex Gateway を停止して登録ファイルをアーカイブする

次のコードブロックを使用して、Flex Gateway を停止し、登録ファイルをアーカイブします。​stages​ ブロックの後の ​pipeline​ ブロックに ​post​ ブロックを追加します。

post {
   success {
       script {
           // Archive the build output artifacts.
           archiveArtifacts artifacts: 'registration.yaml'
       }
   }
   always {
       script {
           if (fileExists('containerId')) {
               sh(script: "docker rm -f ${readFile(file: 'containerId')}")
           }
       }
   }
}