计算巢接入许可证使用说明

本文介绍了服务商如何接入许可证并校验许可证的有效性。

背景信息

服务商仅需在其服务中加入相应校验许可证的代码,即可完成许可证鉴权功能。

许可证校验只针对服务实例包含的服务(软件/应用),不校验服务实例的资源。

鉴权许可证是否有效

  1. 获取应用部署的ECS地域(regionld)信息。

    获取到的地域信息,会在后续步骤中使用,因此需要服务商记录。访问如下网址,获得地域信息。

    curl http://100.100.100.200/latest/meta-data/region-id

    返回示例

    cn-wulanchabu

    示例中返回的cn-wulanchabu,表示ECS部署地域为乌兰察布

  2. 鉴权许可证是否有效。

    调用CheckOutLicense,鉴权许可证是否有效。

    • 若发现某个服务实例到期仍未续费,计算巢将终止此服务实例的许可证,使其许可证不可用。这时,调用CheckOutLicense后,返回许可证不可用,服务商可根据返回结果完成后续处理。

    • 若用户未出现欠费情况,则应用发起的CheckOutLicense将持续有效;若用户在欠费后重新续费,这时调用CheckOutLicense后,返回许可证状态将从过期状态变成成功状态。

    在计算巢内发起API调用时(如调用CheckoutLicense、PushMeteringData等),计算巢会返回数字签名信息(即Token字段),服务商可以使用后文的方法计算数字签名信息的值,并将计算得到的数字签名信息和计算巢返回的数字签名信息进行对比,判断数据是否被篡改。更多信息,请参见计算巢校验数字签名说明

    调用CheckOutLicense格式如下:

    调用CheckOutLicense时,可以在调用命令中增加ServiceId(服务ID)或ServiceInstanceName(服务实例名称)等非必填参数,用来校验服务ID或服务实例名称的一致性。

    curl -H "Content-Type: application/json" -XPOST https://<regionId>.axt.aliyun.com/computeNest/license/check_out_license -d '{}'
    说明

    请将regionId替换成之前获取的地域信息。

    示例

    • 不加入ServiceIdServiceInstanceName等非必填参数时,仅校验许可证是否过期。

      curl -H "Content-Type: application/json" -XPOST https://cn-wulanchabu.axt.aliyun.com/computeNest/license/check_out_license -d '{}'
    • 调用命令中加入ServiceId时,计算巢会校验传入的服务ID是否与当前ECS所处服务实例对应服务的ID一致。

      curl -H "Content-Type: application/json" -XPOST https://cn-wulanchabu.axt.aliyun.com/computeNest/license/check_out_license -d '{"ServiceId": "service-1e2e93c150084exxxxxx"}'

      11.png

    • 调用命令中加入ServiceInstanceName时,在已有ACK场景中,服务实例创建时需要填写clusterId(集群ID),此集群可能不是通过计算巢创建,因此无法查询到服务实例信息。调用API时需要传入服务实例名称,以便查询服务实例信息,默认服务实例名称即服务实例ID。

      说明

      该功能当前仅支持已有ACK场景。

      curl -H "Content-Type: application/json" -XPOST https://cn-wulanchabu.axt.aliyun.com/computeNest/license/check_out_license -d '{"ServiceInstanceName": "si-8722386303094axxxxxx"}'

      12.png

    返回结果

    许可证未过期

    {
        "code":200,
        "requestId":"6af1efb7-c59c-4cee-9094-e1e3bbefb639",
        "instanceId":"i-0jl957dfri612gxxxxxx",
        "result":{
            "RequestId":"B22723B7-FC31-18F5-A33E-1AF4C82736AA",
            "ServiceInstanceId":"si-8722386303094axxxxxx",
            "LicenseMetadata":"{\"TemplateName\":\"Custom_Image_Ecs\",\"SpecificationName\":\"\",\"CustomData\":\"xxxx\"}",
            "TrialType":"NotTrial",
            "Token":"58d4574bd0d967bb431cd8936b5e80c4",
            "ExpireTime":"2023-08-28T06:27:08Z",
            "ServiceId":"service-1e2e93c150084exxxxxx",
            "Components":"{\"package_version\":\"yuncode5523100001\",\"SystemDiskSize\":\"40\",\"DataDiskSize\":\"100\"}"
        }
     }

    10.png

    操作结果中的各字段说明如下表所示。

    参数名称

    参数说明

    RequestId

    请求ID。

    ServiceInstanceId

    服务实例ID。

    LicenseMetadata

    许可证元数据。

    需要在许可证管理功能中定义该数据。

    TrialType

    服务试用类型。可能的值:

    • Trial:支持试用。

    • NotTrial:不支持试用。

    Token

    数字签名。

    ExpireTime

    服务实例的到期时间。

    ServiceId

    服务ID。

    Components

    云市场额外计费项信息。

    许可证已过期

    {
      "code":400,
      "requestId":"3b39185e-44d5-45eb-b178-7fa1bbd57672",
      "instanceId":"i-0jl892sv08nqob89533y",
      "errCode":"LicenseExpired",
      "errMsg":"LicenseExpired : The license of the current service instance si-093591ffbbea4307a624 has expired, expired time Tue Nov 08 16:56:59 CST 2022.\r\nRequestId : 3AF563FD-2FED-1B97-84A1-64F15B581264"
    }

    许可证已过期

    对于计算巢创建的服务实例,CheckOutLicense适用于试用服务实例、通过云市场创建的服务实例和具有自定义许可证的服务实例的场景。对于其余的场景调用CheckOutLicense时,会出现报错,如下示例所示。

    {
        "code":400,
        "requestId":"04733eac-e898-4816-9df2-76678278fb05",
        "instanceId":"i-0jl1gfh86wvmlx7sg9y2",
        "result":{
            "errCode":"LicenseNotExist",
            "errMsg":"LicenseNotExist : The current service instance pay type Permanent does not support checkout license.\r\nRequestId : 82C7B420-35B2-197C-8875-                 C976EB3ACD23"}
    }
                                

    返回结果

    使用CheckOutLicense鉴权应用部署的ECS为非计算巢创建的ECS时,鉴权会出现报错。

    
    {
        "code":400,
        "requestId":"236313f1-261e-41c5-b89c-659c66923601",
        "instanceId":"i-0jl9einm5x0tjxxxxxx",
        "result":{
            "errCode":"ServiceInstanceIdNotFound",
            "errMsg":"ServiceInstanceIdNotFoud : The specified service instance Id cannot be found, the instance Id is [i-0jl9einm5x0tjaf1ax50].\r\nRequestId : FC86793C-1FEB-102D-AAE5-B6EB14EB316E"}
    }
                            

    返回结果

    使用CheckOutLicense鉴权传入的服务ID与当前ECS所处服务实例对应服务的ID不一致时,鉴权会出现报错。

    {
        "code":400,
        "requestId":"20520d16-7fe9-4dcb-832b-16944125bd14",
        "instanceId":"i-0jl957dfri612gxxxxxx",
        "result":{
            "errCode":"InvalidParameter.ServiceId",
            "errMsg":"InvalidParameter.ServiceId : The current service instance does not belong to service service-test.\r\nRequestId : D65B2C7D-B561-1030-BBAD-78488AA41364"}
    }

    13.png

    Java代码示例

    根据上面的鉴权步骤,完整的Java代码示例如下:

    import javax.net.ssl.HttpsURLConnection;
    import java.io.BufferedReader;
    import java.io.DataOutputStream;
    import java.io.InputStreamReader;
    import java.net.HttpURLConnection;
    import java.net.URL;
    
    public class licenseManagerDemo {
        public static void main(String[] args) throws Exception {
            //步骤一:获取应用部署的ECS地域(regionId)信息
            //通过默认Url获取ECS的regionId
            URL getRegionIdURL = new URL("http://100.100.100.200/latest/meta-data/region-id");
            HttpURLConnection httpURLConnection = (HttpURLConnection) getRegionIdURL.openConnection();
            //设置超时时间
            httpURLConnection.setConnectTimeout(10000);
            httpURLConnection.setReadTimeout(10000);
            InputStreamReader inputStreamReader = new InputStreamReader(httpURLConnection.getInputStream());
            int readerRead = inputStreamReader.read();
            String regionId = "";
            while (readerRead != -1) {
                regionId = regionId + ((char) readerRead);
                readerRead = inputStreamReader.read();
            }
            System.out.println("RegionId : " + regionId);
    
            //步骤二:鉴权许可证是否有效
            //完成鉴权相关操作 : CheckOutLicense
            licenseManagerDemo licenseManagerDemo = new licenseManagerDemo();
            String checkOutLicenseResponse = licenseManagerDemo.checkOutLicense(regionId);
            String code = licenseManagerDemo.getCode(checkOutLicenseResponse);
            //循环执行 checkOutLicense
            while (true) {
                if (!"200".equals(code)) {
                    //处理返回不成功情况
                    break;
                } else {
                    //再次调用,示例时间为60分钟
                    Thread.sleep(3600000);
                    checkOutLicenseResponse = licenseManagerDemo.checkOutLicense(regionId);
                    code = licenseManagerDemo.getCode(checkOutLicenseResponse);
                    System.out.println(checkOutLicenseResponse);
                }
            }
        }
    
        private String checkOutLicense(String regionId) throws Exception {
            String urlFormat = "https://%s.axt.aliyun.com/computeNest/license/%s";
            String operation = "check_out_license";
            URL operationURL = new URL(String.format(urlFormat, regionId, operation));
            HttpsURLConnection httpsURLConnection = (HttpsURLConnection) operationURL.openConnection();
            httpsURLConnection.setRequestProperty("Content-Type", "application/json");
            httpsURLConnection.setDoOutput(true);
            httpsURLConnection.setConnectTimeout(10000);
            httpsURLConnection.setReadTimeout(10000);
    
            DataOutputStream dataOutputStream = new DataOutputStream(httpsURLConnection.getOutputStream());
            //包年包月场景CheckOutLicense参数
            String checkOutLicenseParameter = "{\"Channel\":\"ComputeNest\"}";
            dataOutputStream.writeBytes(checkOutLicenseParameter);
            dataOutputStream.flush();
            dataOutputStream.close();
    
            BufferedReader bufferedReader =
                    new BufferedReader(new InputStreamReader(httpsURLConnection.getInputStream()));
            String checkOutLicenseResponse = bufferedReader.readLine();
            System.out.println(checkOutLicenseResponse);
            bufferedReader.close();
            return checkOutLicenseResponse;
        }
    
        private String getCode(String response) {
            int codeIndexOf = response.indexOf("code");
            return response.substring(codeIndexOf + 6, codeIndexOf + 9);
        }
    }