繁体   English   中英

WSO2 APIM的最小化部署

[英]MInimized deployment of WSO2 APIM

我们正在考虑为WSO2提供我们自己的UI,并通过调用Publisher / Store REST API使其与APIM网关一起使用。

有没有一种方法可以剥离WSO2 APIM的UI部分,并且只包含一个部署

  1. 门户
  2. 关键经理
  3. 发布者->仅REST API,没有UI
  4. 商店->仅REST API,没有UI

开箱就有这样的捆绑包吗? 否则,是否可以下载GitHub源代码或部署包并删除任何与UI相关的插件及其依赖库?

如果不需要任何UI组件,则可以从存储库/部署/服务器/ jaggaryapps位置删除发布者并存储jaggary Web应用程序。 如果签出源代码,则需要签出[1]中的产品仓库和[2]中的组件仓库,以执行必要的更改以删除UI内容,但这样做会增加复杂性并花费时间。 如果没有UI部分,则可以在1.10.0中使用REST API。 没有OOTB捆绑包。

[1] -https://github.com/wso2/product-apim

[2] -https://github.com/wso2/carbon-apimgt

这是我们执行此操作的脚本(感谢您的任何错误或评论,目前我们正在测试中)

#!/bin/bash
# WSO2 2.1.0
# Publish an API in several gateways, using internal REST API
# Reference
#   https://docs.wso2.com/display/AM210/apidocs/publisher/

# IMPORTANT: Change these values according your WSO2 APIM version∫
# Version 2.1.0
# declare APP_CLIENT_REGISTRATION="/client-registration/v0.11/register"
# declare -r URI_API_CTX="/api/am/publisher/v0.11"
# Version 2.1.0 update 14
declare -r APP_CLIENT_REGISTRATION="/client-registration/v0.12/register"
declare -r URI_API_CTX="/api/am/publisher/v0.12"

# Constants
declare -r URI_TOKEN="/token"
declare -r URI_API_APIS="${URI_API_CTX}/apis"
declare -r URI_API_ENVIRONMENTS="${URI_API_CTX}/environments"
declare -r URI_API_PUBLISH="${URI_API_CTX}/apis/change-lifecycle?action=Publish&apiId="
declare -r API_SCOPE_VIEW="apim:api_view"
declare -r API_SCOPE_PUBLISH="apim:api_publish"
declare -r API_SCOPE_CREATE="apim:api_create"

# Parameters
declare APIUSER=""
declare APIPASSWORD=""
declare APIMANAGER=""
declare APINAME=""
declare APIVERSION=""
declare -a APIGATEWAY
declare -i MANAGER_SERVICES_PORT=9443
declare -i MANAGER_NIOPT_PORT=8243

# Variables
# User login for aplication registration. User:Password in base64 (default admin:admin)
declare APIAUTH="YWRtaW46YWRtaW4="
# Client application token. ClientId:ClientSecret in base64
declare CLIENTTOKEN
# User access token (view)
declare ACCESSVIEWTOKEN
# User access token type (view)
declare ACCESSVIEWTOKENTYPE="Bearer"
# User access token (publish)
declare ACCESSPUBLISHTOKEN
# User access token type (publish)
declare ACCESSVIEWPUBLISHTYPE="Bearer"
# User access token (create)
declare ACCESSCREATETOKEN
# User access token type (create)
declare ACCESSVIEWCREATETYPE="Bearer"
# API internal ID
declare APIID

# echoErr
# Send message to error stream (/dev/stderr by default)

function echoErr() {
    printf "%s\n" "$*" >&2; 
}

# showHelp
# Usage info
showHelp() {
cat <<-EOF
    Usage: ${0##*/} [-u USER] [-p PASSWORD] APIMANAGER [-s ServicePort] [-n NioPTPort] APINAME APIVERSION APIGATEWAY [APIGATEWAY] ...
      Publish an API in the selected gateways

        -u USER         User name (if not defined, will ask for it)
        -p PASSWORD     User password (if not defined, will ask for it)
        -s ServicePort  Services Port in api manager host (by default 9443) 
        -n NioPTPort    Nio/PT Port in key manager host (by default 8243)
        APIMANAGER      API MANAGER / KEY MANAGER host name (e.g. apimanager.example.com)
        APINAME         API to publish (has to be in CREATED, PROTOTYPED or PUBLISH state)
        APIVERSION      API Version to publish          
        APIGATEWAYs     All of the gateway to publish the API (one or more)

    EOF
}

# getPassword
# get a password type field (without echo and double input)
function getPassword()
{
    local pwd=${3:-"NoSet"}
    local verify="_Set_No"
    local default=""

    if [ -z "$1" ] || [ -z "$2" ]
    then
        echo 'ERROR: Use getPassword "Message" VAR_NAME [default]'
        exit 1
    else
        if [ -n ${3} ]
        then
            default=$'\e[31m['${3}$']\e[0m'
        fi
        while true
        do
            read -sp "$1 $default" pwd
            echo ""
            # if empty (=Intro) use default if available
            if [ "$pwd" == "" ] && [ -n "$3" ]
            then
                pwd="$3"
                break
            fi
            # check password length
            if [ ${#pwd} -lt 6 ]
            then
                echo "Password too short. Minimum length is 6"
                continue
            else
            read -sp "Verify - $1 " verify
            echo ""
                if [ "$pwd" != "$verify" ]
                then
                    echo "Passwords do not match. Retype."
                else
                    break   
                fi
            fi
        done
        eval $2="$pwd"
    fi
}

# showGateways
# Print the list of available gateways in a friendly form
function showGateways() {
    local -i count
    local name
    local gwtype
    local endpoint

    if [ -z $1 ]
    then
        echo "Use: showGateways \$apiEnvironments"
    else

        count=$(echo $1|jq -r '.count')
        if [ "$count" -gt "0" ]
        then
                printf "%-20s %-10s %s\n" "Name" "Type" "Endpoint HTTPS" >&2
                printf "%-20s %-10s %s\n" "====================" "==========" "===============================================" >&2                                     
            for i in $(seq 0 $(( $count - 1 )) )
            do
                name=$(echo "$1"|jq -r '.list['$i'].name')
                gwtype=$(echo "$1"|jq -r '.list['$i'].type')
                endpoint=$(echo "$1"|jq -r '.list['$i'].endpoints.https')
                printf "%-20s %-10s %s\n" "$name" "$gwtype" "$endpoint" >&2         
            done
        fi
    fi
}

# validateGateway
# validate if all the gateways names (passed as parameter - global variable) are in environments
function validateGateways() {

    if [ -z $1 ]
    then
        echo "Use: validateGateways \$apiEnvironments"
        exit 1
    else
        for gateway in ${APIGATEWAY[@]}
        do
            jq -er \
                --arg gateway_name "$gateway" '
                    .list[] |
                    select(.name == $gateway_name)
                    ' <<<"$1" >/dev/null

            if [ $? -ne 0 ]
            then
                echo "ERROR: Gateway '$gateway' is not found"   >&2          
                return 1
            fi
        done
    fi
    return 0
}

# getClientToken
# Parse the answer of client registration, to get client token
# return (echo to stdout) the clientToken
function getClientToken() {
    local clientId
    local clientSecret
    local clientToken

    if [ -z $1 ]
    then
        echo "Use: getClientToken \$clientRegistration" >&2
        exit 1
    else
    # Parse answer to get ClientId and ClientSecret
        clientId=$(echo $clientRegistration|jq -r '.clientId')
        clientSecret=$(echo $clientRegistration|jq -r '.clientSecret')

        if [ "$clientId" == "" ] || [ "$clientSecret" == "" ] || [ "$clientId" == "null" ] || [ "$clientSecret" == "null" ]
        then
            return 1
        else 
            echo -n "$clientId:$clientSecret"|base64
            return 0
        fi
    fi
}

# getAccessToken
# Parse the answer of client API Login, to get client token
# return (echo to stdout) the accessToken
function getAccessToken() {
    local accessToken

    if [ -z $1 ]
    then
        echo "Use: getAccessToken \$clientAPILoginView|\$clientAPILoginPublish" >&2
        exit 1
    else
        # Parse answer to get ClientId and ClientSecret
        accessToken=$(echo $1|jq -r '.access_token')

        if [ "$accessToken" == "" ] || [ "$accessToken" == "null" ]
        then
            return 1
        else 
            echo -n "$accessToken"
            return 0
        fi
    fi
}

# getAccessTokenType
# Parse the answer of client API Login, to get client token type
# return (echo to stdout) the accessTokenType
function getAccessTokenType() {
    local tokenType

    if [ -z $1 ]
    then
        echo "Use: getAccessToken \$clientAPILoginView|\$clientAPILoginPublish" >&2
        exit 1
    else
        # Parse answer to get ClientId and ClientSecret
        tokenType=$(echo $1|jq -r '.token_type')

        if [ "$tokenType" == "" ] || [ "$tokenType" == "null" ]
        then
            return 1
        else 
            echo -n "$tokenType"
            return 0
        fi
    fi
}

# getAPIId
# Parse the answer of query API to get the API ID (checking version name)
# Thanks to https://stackoverflow.com/users/14122/charles-duffy
# return (echo to stdout) the APIID
function getAPIId() {

    if [ -z $1 ]
    then
        echo "Usage: getAPIId \$apiQuery" >&2
        exit 1
    else    
        # Parse answer to get API ID
        jq -er \
                --arg target_name "$APINAME" \
                --arg target_version "$APIVERSION" '
            .list[] |
            select(.name == $target_name) |
            select(.version == $target_version) |
            .id' <<<"$1"

    fi
}

# getAPIGatewayEnvironments
# Parse the answer of detailed query API to get the API gateway environments
# return (echo to stdout) the gateway environments
function getAPIGatewayEnvironments() {

    if [ -z "$1" ]
    then
        echo "Usage: getAPIGatewayEnvironments \$apiResource" >&2
        exit 1
    else    
        # Parse answer to get API ID
        jq -er '.gatewayEnvironments' <<<"$1"
    fi
}



# getAPIStatus
# Parse the answer of detailed query API to get the API status
# return (echo to stdout) the status
function getAPIStatus() {

    if [ -z "$1" ]
    then
        echo "Usage: getAPIStatus \$apiResource" >&2
        exit 1
    else    
        # Parse answer to get API ID
        jq -er '.status' <<<"$1"
    fi
}

# setGateways
# Update the field gatewayEnvironments in API resource from GATEWAY parameter array
# Return the new API resource update
function setGateways() {
    local gateways
    local oIFS      

    if [ -z "$1" ]
    then
        echo "Use: setGateways \$apiResource" >&2
        exit 1
    else
        oIFS="$IFS";IFS=',';gateways="${APIGATEWAY[*]}";IFS="$oIFS"
        jq -e '.gatewayEnvironments="'$gateways'"' <<<$1
    fi
}

# checkGateways
# check if the gateways has been updated correctly
function checkGateways() {
    local gateways
    local apiResourceGateways   
    local oIFS      

    if [ -z "$1" ]
    then
        echo "Use: checkGateways \$apiResourceUpdated" >&2
        exit 1
    else
        oIFS="$IFS";IFS=',';gateways="${APIGATEWAY[*]}";IFS="$oIFS"
        apiResourceGateways=$(echo $1|jq -r '.gatewayEnvironments')
        # Return value
        if [ -z "$apiResourceGateways" ] || [ "$apiResrouceGateways" == "null" ]
        then
            return 1
        fi
        # TODO: The gateways are sorted in different manner (reverse as API Manager??)
        #if [ "$gateways" != "$apiResourceGateways" ]
        #then
        #   return 1
        #fi
    fi
    return 0
}

# getParms
# Parse the parms and assign to variables
function getParms() {
    local OPTIND=1
    while getopts hu:p: opt $@
    do
        case $opt in
            h)
                showHelp
                exit 0
                ;;
            u)  
                APIUSER=$OPTARG
                ;;
            p)  
                APIPASSWORD=$OPTARG
                ;;
            s)  
                MANAGER_SERVICES_PORT=$OPTARG
                ;;
            n)  
                MANAGER_NIOPT_PORT=$OPTARG
                ;;
            *)
                showHelp >&2
                exit 1
                ;;
        esac
    done
    shift "$((OPTIND-1))"   # Discard the options and get parameter

    APIMANAGER=$1
    if [ "$APIMANAGER" == "" ]
    then
        echo "APIMANAGER host name is required"
        showHelp >&2
        exit 1
    fi
    shift 1

    APINAME=$1
    if [ "$APINAME" == "" ]
    then
        echo "API name to publish is required"
        showHelp >&2
        exit 1
    fi
    shift 1

    APIVERSION=$1
    if [ "$APIVERSION" == "" ]
    then
        echo "API version to publish is required"
        showHelp >&2
        exit 1
    fi
    shift 1

    if [ "$1" == "" ]
    then
        echo "You must indicate 1 or more gateway to publish is required"
        showHelp >&2
        exit 1
    else
        local i=1
        for arg in $@
        do
            APIGATEWAY[$i]="$1"
            let i=(i+1)
            shift 1
        done
    fi
}

###############################################################################
# Check required internal tools
if  ! type -t jq >/dev/null
then
    echo "jq not found. Install it, e.g. 'apt-get install jq'"
    exit 2
fi

# Read and parse Parms. Request required values missing
getParms $@

if [ "$APIUSER" == "" ]
then
    APIUSER=admin
    read -p $'Publisher user: \e[31m['${APIUSER}$']\e[0m ' parm
    APIUSER=${parm:-$APIUSER}   
fi

if [ "$APIPASSWORD" == "" ]
then
    APIPASSWORD=admin
    read -sp $'Publisher password: \e[31m['${APIPASSWORD}$']\e[0m ' parm
    APIPASSWORD=${parm:-$APIPASSWORD}
    echo ""
fi


# TEST ONLY: Delete (show parameter values)
# echo "USER=$APIUSER"
# echo "PASSWORD=$APIPASSWORD"
# echo "APIMANAGER=$APIMANAGER"
# echo "APINAME=$APINAME"
# for GWY in ${!APIGATEWAY[@]}
# do
#   echo "APIGATEWAY[$GWY]=${APIGATEWAY[$GWY]}"
# done


# Client registration
echo "Registering this script as a client application (rest_api_publisher)"
APIAUTH=$(echo -n $APIUSER:$APIPASSWORD|base64)
clientRegistration=$(
    curl -s -X POST "https://${APIMANAGER}:${MANAGER_SERVICES_PORT}${APP_CLIENT_REGISTRATION}" \
    -H "Authorization: Basic ${APIAUTH}" \
    -H "Content-Type: application/json" \
    -d @- <<-EOF
        {
            "callbackUrl": "www.google.lk",
            "clientName": "rest_api_publisher",
            "owner": "$APIUSER",
            "grantType": "password refresh_token",
            "saasApp": true
        }
    EOF
    )

if [ "$clientRegistration" == "" ]
then
    echo "ERROR: Empty answer from https://${APIMANAGER}:${MANAGER_SERVICES_PORT}${APP_CLIENT_REGISTRATION}. Is APIMANAGER correct?" >&2
    exit 3
fi

# Get Application Client Token
CLIENTTOKEN=$(getClientToken $clientRegistration)
if [ $? -ne 0 ]
then
    echo $clientRegistration >&2
    echo "ERROR: Cannot get ClientId/ClientSecret: Is user/password correct?" >&2
    exit 4
fi

# TEST ONLY: Delete
# echo "CLIENTTOKEN=$CLIENTTOKEN"

echo "Aplication rest_api_publisher registered"

# Client Login for get Access Token (and Token Type) - View Scope
echo "Obtaining access token for API query (scope api_view)"
clientAPILoginView=$(
    curl -s -X POST "https://${APIMANAGER}:${MANAGER_NIOPT_PORT}${URI_TOKEN}" \
    -H "Authorization: Basic ${CLIENTTOKEN}" \
    -d "grant_type=password&username=${APIUSER}&password=${APIPASSWORD}&scope=${API_SCOPE_VIEW}"
    )

ACCESSVIEWTOKEN=$(getAccessToken $clientAPILoginView) && ACCESSVIEWTOKENTYPE=$(getAccessTokenType $clientAPILoginView)
if [ $? -ne 0 ]
then
    echo $clientAPILoginView >&2
    echo "ERROR: Cannot get Access Token: Has the user '$APIUSER' in necesary role for scope ${API_SCOPE_VIEW}" >&2
    exit 5
fi

# TEST ONLY: Delete
# echo "Access View Token=$ACCESSVIEWTOKEN"
# echo "Token View Type=$ACCESSVIEWTOKENTYPE"

# Client Login for get Access Token (and Token Type) - Publish Scope
echo "Obtaining access token for API publish (scope api_publish)"
clientAPILoginPublish=$(
    curl -s -X POST "https://${APIMANAGER}:${MANAGER_NIOPT_PORT}${URI_TOKEN}" \
    -H "Authorization: Basic ${CLIENTTOKEN}" \
    -d "grant_type=password&username=${APIUSER}&password=${APIPASSWORD}&scope=${API_SCOPE_PUBLISH}"
    )

ACCESSPUBLISHTOKEN=$(getAccessToken $clientAPILoginPublish) && ACCESSPUBLISHTOKENTYPE=$(getAccessTokenType $clientAPILoginPublish)
if [ $? -ne 0 ]
then
    echo $clientAPILoginPublish >&2
    echo "ERROR: Cannot get Access Token: Has the user $APIUSER in necesary role for scope ${API_SCOPE_PUBLISH}" >&2
    exit 5
fi

# TEST ONLY: Delete
# echo "Access Publish Token=$ACCESSPUBLISHTOKEN"
# echo "Token Publish Type=$ACCESSPUBLISHTOKENTYPE"

# Client Login for get Access Token (and Token Type) - Publish Scope
echo "Obtaining access token for API create (scope api_create)"
clientAPILoginCreate=$(
    curl -s -X POST "https://${APIMANAGER}:${MANAGER_NIOPT_PORT}${URI_TOKEN}" \
    -H "Authorization: Basic ${CLIENTTOKEN}" \
    -d "grant_type=password&username=${APIUSER}&password=${APIPASSWORD}&scope=${API_SCOPE_CREATE}"
    )

ACCESSCREATETOKEN=$(getAccessToken $clientAPILoginCreate) && ACCESSCREATETOKENTYPE=$(getAccessTokenType $clientAPILoginCreate)
if [ $? -ne 0 ]
then
    echo $clientAPILoginCreate|jq . >&2
    echo "ERROR: Cannot get Access Token: Has the user $APIUSER in necesary role for scope ${API_SCOPE_CREATE}" >&2
    exit 5
fi

# TEST ONLY: Delete
# echo "Access Create Token=$ACCESSCREATETOKEN"
# echo "Token Create Type=$ACCESSCREATETOKENTYPE"

echo "All tokens obtained"

# Get API info (exists?)
echo "Checking API with name '${APINAME}' with version '${APIVERSION}' in '${APIMANAGER}'"
apiQuery=$(
    curl -s "https://${APIMANAGER}:${MANAGER_SERVICES_PORT}${URI_API_APIS}?query=name:$APINAME" \
    -H "Authorization: ${ACCESSVIEWTOKENTYPE} ${ACCESSVIEWTOKEN}" 
    )

# TEST ONLY: Delete
# echo "apiQuery=${apiQuery}"

APIID=$(getAPIId $apiQuery)
if [ $? -ne 0 ]
then
    echo $apiQuery >&2
    echo "ERROR: Cannot find an API ${APINAME} with version '${APIVERSION}' in '${APIMANAGER}'" >&2
    exit 6
fi

echo "API Found. APIID='$APIID'"

# Get availables gateways and validate gateways names
echo "Checking if requested gateways '${APIGATEWAY[@]}' are available in '${APIMANAGER}'"
apiEnvironments=$(
    curl -s "https://${APIMANAGER}:${MANAGER_SERVICES_PORT}${URI_API_ENVIRONMENTS}" \
    -H "Authorization: ${ACCESSVIEWTOKENTYPE} ${ACCESSVIEWTOKEN}" 
    )

# TEST ONLY: Delete
# echo "apiEnvironments=$apiEnvironments"

if ! validateGateways $apiEnvironments
then
    echo "Valid gateways are:"
    showGateways $apiEnvironments
    exit 7
fi

echo "API required gateways checked"

# Get API detailed info
echo "Getting API detailed info of '${APINAME}' with version '${APIVERSION}' in '${APIMANAGER}'"
apiResource=$(
    curl -s -S -f -X GET "https://${APIMANAGER}:${MANAGER_SERVICES_PORT}${URI_API_APIS}/${APIID}" \
    -H "Authorization: ${ACCESSVIEWTOKENTYPE} ${ACCESSVIEWTOKEN}" 
    )
if [ $? -ne 0 ]
then
    echo "ERROR: Cannot get API detailed information of '${APINAME}' with version '${APIVERSION}' in '${APIMANAGER}'" >&2
    exit 8
fi

# TEST ONLY: Delete
# jq . <<<$apiResource


currentGatewayEnvironments=$(getAPIGatewayEnvironments "$apiResource") && currentStatus=$(getAPIStatus "$apiResource")
if [ $? -ne 0 ]
then
    jq . <<<$apiResource >&2
    echo "ERROR: Cannot get API detailed information of '${APINAME}' with version '${APIVERSION}' in '${APIMANAGER}'" >&2
    exit 8
fi


echo "API is currently configured for gateways: '${currentGatewayEnvironments}'"
echo "API is currently in status: '${currentStatus}'"

# Update API gateways info
apiResourceUpdated=$(setGateways "$apiResource")

if [ $? -ne 0 ]
then
    echo $apiResourceUpdated | jq . >&2
    echo "ERROR: Cannot update gateways in API resource" >&2
    exit 9
fi

# TEST ONLY: Delete
jq . <<<$apiResouceUpdated >&2

# PENDING: Update also required information (e.g., Endpoints)

# Update gateways
echo "Updating API gateways of '${APINAME}' with version '${APIVERSION}' in '${APIMANAGER}' to '${APIGATEWAY[@]}'"
apiResourceUpdatedResponse=$(
    curl -s -S -f -X PUT "https://${APIMANAGER}:${MANAGER_SERVICES_PORT}${URI_API_APIS}/${APIID}" \
    -H "Content-Type: application/json" \
    -H "Authorization: ${ACCESSCREATETOKENTYPE} ${ACCESSCREATETOKEN}" \
    -d "$apiResourceUpdated"
    )
if [ $? -ne 0 ]
then
    # Retry request to show error in console
    curl -s -X PUT "https://${APIMANAGER}:${MANAGER_SERVICES_PORT}${URI_API_APIS}/${APIID}" \
    -H "Content-Type: application/json" \
    -H "Authorization: ${ACCESSCREATETOKENTYPE} ${ACCESSCREATETOKEN}" \
    -d "$apiResourceUpdated"|jq .
    echo "ERROR: Cannot update gateways in API resource. Check API for missing information (HTTP Endpoints, ...)" >&2
    exit 10
fi

# TEST ONLY: Delete
# jq . <<<$apiResourceUpdatedResponse

if ! checkGateways "$apiResourceUpdatedResponse"
then
    echo $apiResourceUpdated| jq . >&2
    echo "ERROR: Error updating gateways in API resource" >&2
    exit 9
fi

echo "API Updated"

# Publish
echo "Publishing '${APINAME}' with version '${APIVERSION}' in '${APIMANAGER}' "
apiResource=$(
    curl -s -S -f -X POST "https://${APIMANAGER}:${MANAGER_SERVICES_PORT}${URI_API_PUBLISH}${APIID}" \
    -H "Authorization: ${ACCESSPUBLISHTOKENTYPE} ${ACCESSPUBLISHTOKEN}" 
    )
if [ $? -ne 0 ]
then
    echo "ERROR: Publishing '${APINAME}' with version '${APIVERSION}' in '${APIMANAGER}'" >&2
    exit 10
fi
echo "API Published"

# Verify status and gateways
echo "Verify API detailed info of '${APINAME}' with version '${APIVERSION}' in '${APIMANAGER}'"
apiResource=$(
    curl -s -S -f -X GET "https://${APIMANAGER}:${MANAGER_SERVICES_PORT}${URI_API_APIS}/${APIID}" \
    -H "Authorization: ${ACCESSVIEWTOKENTYPE} ${ACCESSVIEWTOKEN}" 
    )
if [ $? -ne 0 ]
then
    echo "ERROR: Cannot get API detailed information of '${APINAME}' with version '${APIVERSION}' in '${APIMANAGER}'" >&2
    exit 11
fi

currentGatewayEnvironments=$(getAPIGatewayEnvironments "$apiResource") && currentStatus=$(getAPIStatus "$apiResource")
if [ $? -ne 0 ]
then
    jq . <<<$apiResource >&2
    echo "ERROR: Cannot get API detailed information of '${APINAME}' with version '${APIVERSION}' in '${APIMANAGER}'" >&2
    exit 12
fi


echo "API is now configured for gateways: '${currentGatewayEnvironments}'"
echo "API is now in status: '${currentStatus}'"

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM