更新时间:2024-07-03 GMT+08:00
分享

deploy.sh脚本说明

使用场景说明

  • 场景一:使用Jenkins构建生成的是软件包,如jar包,就使用脚本中的软件包部署场景,软件包部署会将构建出来的软件包上传到obs桶中,再使用新的jar包去升级CAE组件。
  • 场景二:使用Jenkins构建生成的是镜像,就使用脚本中的镜像部署场景,镜像部署会将构建出来的镜像上传到swr镜像仓库中,再使用新的镜像去升级CAE组件。

脚本内容

#!/bin/bash

#------------ 必填参数 ------------------
# region名称
region=''
# 项目id
project_id=''
# 环境名称
environment_name=''
# 应用名称
application_name=''
# 组件名称
component_name=''
# 部署类型: 1. software 2. image    software表示软件包部署, image表示镜像部署
deploy_type=''

#------------ 软件包部署场景必填参数 ---------------
# obsutil安装的可执行文件绝对路径
obsutil=''
# 存放软件包的obs桶名称
bucket_name=''
# 软件包在obs桶中的存放目录,默认是根目录,目录需要以/结尾,如果obs桶中没有这个目录,会自动创建出该目录
bucket_dir='/'

#------------ 镜像部署场景必填参数 ------------------
# swr组织名称
swr_organization=''
# AK 用于登录swr镜像仓库
AK=''
# swr登录密钥 用于登录swr镜像仓库
login_secret=''

#------------ 外部传入参数,不需要填,参考配置流水线构建任务中的流水线脚本参数build_target_name ------------------
# 软件包部署场景:构建出来的软件包名称,由外部build_target_name参数传入
software_package=''
# 镜像部署场景:构建后生成的镜像:镜像名称:版本名称,由外部build_target_name参数传入
machine_image_name=''

#必须传入一个参数,是软件包名称或镜像名称
#参数数量为1时,设置软件包名称或镜像名称
if [ $# == 1 ]; then
    if [[ "$deploy_type" == "software" ]]; then
        software_package=$1
    elif [[ "$deploy_type" == "image" ]]; then
        machine_image_name=$1
    fi
else
    echo "外部传入参数数量不为1,参考配置流水线构建任务中的流水线脚本参数build_target_name"
fi

# ----------------   以下代码不用改动   -------------------
enterprise_project_id='0'
environment_id=''
application_id=''
component_id=''

function splitVersion() {
    str=$1
    right=${str##*.}
    left=${str%.*}
    if [ ${#str} -eq ${#left} ]; then
        left=""
    fi
}

function addVersion() {
    v1=$1
    res=`echo $v1|awk '{print int($0)}'`
    if [ $res -gt 9998 ]; then
        res=0
    else
        res=$(($res+1))
    fi
}

# 升级版本号
# 版本号格式为:A.B.C或 A.B.C.D  A、B、C、D均为整数,每个整数不大于9999
# 示例:1.0.0 -> 1.0.1;1.0.9999 -> 1.1.0
function upgradeVersion() {
    left=$1
    start=0
    end=''
    res=0
    while ( [[ $res = 0 ]] && [ $start -lt 4 ] )
    do
        start=$(($start+1))
        splitVersion $left
        addVersion $right
        if [ $start -gt 1 ]; then
            end=`echo "$res.$end"`
        else
            end=`echo "$res$end"`
        fi
    done
    if [ ${#left} -ne 0 ]; then
        version="$left.$end"
    else
        version="$end"
    fi
}

#获取组件升级的版本号
function upgradeComponentVersion() {
    # 查询组件信息
    component_detials=`/usr/local/bin/hcloud CAE ShowComponent --cli-region="$region" --project_id="$project_id" --X-Enterprise-Project-ID="$enterprise_project_id" --X-Environment-ID="$environment_id" --application_id="$application_id" --component_id="$component_id"`

    # 获取组件当前的版本号
    version=`getJsonValuesByAwk  "$component_detials" "version" "defaultValue"`
    version=`echo "$version"  | cut -d  '"' -f  2`
    echo "current version: $version"
    if [[ "$version" == "defaultValue" ]]; then
        echo "get component detials and get component version error"
        echo "$component_detials"
        exit 126
    fi
    upgradeVersion $version
    echo "upgrade version: $version"
}

# 软件包部署使用场景
function obs_software_upgrade() {
    echo "upload jar to obs"
    # 软件包上传到obs的地址,格式:obs://{桶名}{jar包在obs桶中的存放目录}
    bucket_address="obs://$bucket_name$bucket_dir"
    # 上传到obs的jar包链接,格式:https://{桶名}.obs.{region}.myhuaweicloud.com/{jar包在obs桶中的存放目录}/
    obs_jar_url="https://$bucket_name.obs.$region.myhuaweicloud.com$bucket_dir$software_package"
    echo "software_package url: $obs_jar_url"
    # 将项目下构建生成的jar包上传到obs
    obs_result=`"$obsutil" cp ./target/*.jar "$bucket_address"`
    if [ $? -ne 0 ]; then
        echo "obsutil upload software package error"
        echo "$obs_result"
        exit 126
    fi
    # 打印上传结果
    echo "$obs_result"
    
    # 升级组件
    echo "upgrade component"
    action_result=`/usr/local/bin/hcloud CAE ExecuteAction --cli-region="$region" --project_id="$project_id" --X-Enterprise-Project-ID="$enterprise_project_id" --X-Environment-ID="$environment_id" --application_id="$application_id" --component_id="$component_id" --api_version='v1' --kind='Action' --metadata.name='upgrade' --metadata.annotations.version="$version" --spec.source.type='softwarePackage' --spec.source.sub_type='BinObs' --spec.source.url="$obs_jar_url"`
}

# 生成秒级时间格式字符串,用于上传SWR镜像时,在版本后添加时间格式后缀
function generateTimeFormatString() {
    ms=$(date +%s)
    time=$(date -d @$ms "+%Y%m%d%H%M%S")
    echo $time
}

# 镜像部署使用场景
function swr_image_upgrade() {

    # 上传到swr的镜像仓库路径,格式为:[镜像仓库地址]/[组织名称]/[镜像名称:版本名称]
    swr_image_url="swr.$region.myhuaweicloud.com/$swr_organization/$machine_image_name"
    # swr 镜像仓库地址
    swr_url="swr.$region.myhuaweicloud.com"

    # swr镜像版本拼接时间格式字符串
    time_format_string=`generateTimeFormatString`
    swr_image_url="$swr_image_url.$time_format_string"

    echo "upload image to swr"
    docker tag "$machine_image_name" "$swr_image_url"
    login_result=`docker login -u "$region"@"$AK" -p "$login_secret" "$swr_url"`
    # 打印登录swr镜像仓库结果
    #echo "$login_result"
    push_result=`docker push "$swr_image_url"`
    if [ $? -ne 0 ]; then
        echo "docker push error"
        echo "$push_result"
        exit 126
    fi
    # 打印推送镜像结果
    #echo "$push_result"
    logout_result=`docker logout "$swr_url"`
    # 打印退出登录swr镜像仓库的结果
    #echo "$logout_result"
    # 清除所有的历史记录,历史记录中可能会存在swr登录密钥信息,可以使用该命令清理所有的历史记录
    #history -c
    echo "upgrade component"
    # 升级 image镜像组件
    action_result=`/usr/local/bin/hcloud CAE ExecuteAction --cli-region="$region" --project_id="$project_id" --X-Enterprise-Project-ID="$enterprise_project_id" --X-Environment-ID="$environment_id" --application_id="$application_id" --component_id="$component_id" --api_version='v1' --kind='Action' --metadata.name='upgrade' --metadata.annotations.version="$version" --spec.source.type='image' --spec.source.url="$swr_image_url" `
}

### 方法简要说明:
### 1. 是查找一个字符串:带双引号的key。如果没找到,则直接返回defaultValue。
### 2. 查找最近的冒号,找到后认为值的部分开始了。
### 3. 如果有多个同名key,只打印第一个value
### 4. params: json, key, defaultValue
function getJsonValuesByAwk() {
    awk -v json="$1" -v key="$2" -v defaultValue="$3" 'BEGIN{
        foundKeyCount = 0
        pos = match(json, "\""key"\"[ \\t]*?:[ \\t]*");
        if (pos == 0) {if (foundKeyCount == 0) {print defaultValue;} exit 0;}
        ++foundKeyCount;
        start = 0; stop = 0; layer = 0;
        for (i = pos + length(key) + 1; i <= length(json); ++i) {
            lastChar = substr(json, i - 1, 1)
            currChar = substr(json, i, 1)
            if (start <= 0) {
                if (lastChar == ":") {
                    start = currChar == " " ? i + 1: i;
                    if (currChar == "{" || currChar == "[") {
                        layer = 1;
                    }
                }
            } else {
                if (currChar == "{" || currChar == "[") {
                    ++layer;
                }
                if (currChar == "}" || currChar == "]") {
                    --layer;
                }
                if ((currChar == "," || currChar == "}" || currChar == "]") && layer <= 0) {
                    stop = currChar == "," ? i : i + 1 + layer;
                    break;
                }
            }
        }
        if (start <= 0 || stop <= 0 || start > length(json) || stop > length(json) || start >= stop) {
            if (foundKeyCount == 0) {print defaultValue;} exit 0;
        } else {
            print substr(json, start, stop-start);
        }
    }'
}

### 方法简要说明:
###    从list返回的结果中,找到key=value时的tagKey值
###    查找json字符串'"key":"value"',找到后,以这个位置为结尾
###    查找{最后一次出现的位置lastIndex,再以lastIndex为起始点,查找tagKey,获取tagKey的值
### 
### params: json, key, value, tagKey, defaultValue
function getJsonValuesByAwkWithConditions() {
    awk -v json="$1" -v key="$2" -v value="$3" -v tagKey="$4" -v defaultValue="$5" 'BEGIN{
        foundKeyCount = 0
        pos = match(json, "\""key"\"[ \\t]*?:[ \\t]*\""value"\"");
        if (pos == 0) {print defaultValue; exit 0;}
        str1 = substr(json, 0, pos)
        lastIndex = 0
        while (match(str1, "{")) {
            lastIndex = lastIndex + RSTART
            str1 = substr(str1, RSTART + RLENGTH)
        }
        if (lastIndex == 0) {print defaultValue; exit 0;}
        newStr = substr(json, lastIndex)
        pos1 = match(newStr, "\""tagKey"\"[ \\t]*?:[ \\t]*");
        if (pos1 == 0) {print defaultValue; exit 0;}
        ++foundKeyCount;
        start = 0; stop = 0; layer = 0;
        for (i = pos1 + length(tagKey) + 1; i <= length(newStr); ++i) {
            lastChar = substr(newStr, i - 1, 1)
            currChar = substr(newStr, i, 1)
            if (start <= 0) {
                if (lastChar == ":") {
                    start = currChar == " " ? i + 1: i;
                    if (currChar == "{" || currChar == "[") {
                        layer = 1;
                    }
                }
            } else {
                if (currChar == "{" || currChar == "[") {
                    ++layer;
                }
                if (currChar == "}" || currChar == "]") {
                    --layer;
                }
                if ((currChar == "," || currChar == "}" || currChar == "]") && layer <= 0) {
                    stop = currChar == "," ? i : i + 1 + layer;
                    break;
                }
            }
        }
        if (start <= 0 || stop <= 0 || start > length(newStr) || stop > length(newStr) || start >= stop) {
            if (foundKeyCount == 0) {print defaultValue;} exit 0;
        } else {
            print substr(newStr, start, stop-start);
        }
    }'
}

# 获取enterprise_project_id environment_id application_id component_id
function initParpare() {
    # 获取environment_id
    listEnvsResult=`/usr/local/bin/hcloud CAE ListEnvironments --cli-region="$region" --project_id="$project_id"`
    environment_id=`getJsonValuesByAwkWithConditions  "$listEnvsResult" "name" "$environment_name" "id" "defaultValue"`
    environment_id=`echo "$environment_id"  | cut -d  '"' -f  2`
    echo "environment_id: $environment_id"
    if [[ "$environment_id" == "defaultValue" ]]; then
        echo "list environments and get environment_id error"
        echo "$listEnvsResult"
        exit 126
    fi

    # 获取enterprise_project_id
    enterprise_project_id=`getJsonValuesByAwk  "$listEnvsResult" "enterprise_project_id" "defaultValue"`
    enterprise_project_id=`echo "$enterprise_project_id"  | cut -d  '"' -f  2`
    echo "enterprise_project_id: $enterprise_project_id"
    if [[ "$enterprise_project_id" == "defaultValue" ]]; then
        echo "get enterprise_project_id error"
        echo "$listEnvsResult"
        exit 126
    fi

    # 获取application_id
    listAppsResult=`/usr/local/bin/hcloud CAE ListApplications  --cli-region="$region" --project_id="$project_id" --X-Environment-ID="$environment_id"`
    application_id=`getJsonValuesByAwkWithConditions  "$listAppsResult" "name" "$application_name" "id" "defaultValue"`
    application_id=`echo "$application_id"  | cut -d  '"' -f  2`
    echo "application_id: $application_id"
    if [[ "$application_id" == "defaultValue" ]]; then
        echo "list applications and get application_id error"
        echo "$listAppsResult"
        exit 126
    fi

    # 获取component_id
    listComponentsResult=`/usr/local/bin/hcloud CAE ListComponents  --cli-region="$region" --project_id="$project_id" --X-Environment-ID="$environment_id" --application_id="$application_id"`
    component_id=`getJsonValuesByAwkWithConditions  "$listComponentsResult" "name" "$component_name" "id" "defaultValue"`
    component_id=`echo "$component_id"  | cut -d  '"' -f  2`
    echo "component_id: $component_id"
    if [[ "$component_id" == "defaultValue" ]]; then
        echo "list components and get component_id error"
        echo "$listComponentsResult"
        exit 126
    fi
}

# 每隔15秒查询一次job状态,直到job完成
function waitDeployFinish() {
    sleep 10s
    id="$1"
    leni=${#id}
    id=${id:1:leni-2}
    echo "job_id= $id"
    job_status=""
    while [[ "$job_status" != "success" ]]; do
        job_status_result=`/usr/local/bin/hcloud CAE ShowJob --cli-region="$region" --project_id="$project_id" --job_id="$id" --X-Environment-ID="$environment_id"`
        job_status=`getJsonValuesByAwk  "$job_status_result" "status" "defaultValue"`
        if [[ "$job_status" == "defaultValue" ]]; then
            echo "ShowJob failed"
            echo "$job_status_result"
            return
        fi
        job_status=`echo "$job_status"  | cut -d  '"' -f  2`
        if [[ "$job_status" != "running" && "$job_status" != "success" ]]; then
            echo 'upgrade failed'
            echo "$job_status_result"
            return
        fi
        sleep 15s
    done
    echo 'upgrade success'
}

function deploy() {
    if [[ "$deploy_type" == "software" ]]; then
        obs_software_upgrade
    elif [[ "$deploy_type" == "image" ]]; then
        swr_image_upgrade
    else
        return
    fi
    
    # 打印升级组件的结果
    echo "upgrade result: $action_result"
    # 获取结果中的job_id
    job_id=`getJsonValuesByAwk  "$action_result" "job_id" "defaultValue"`
    if [[ "$job_id" == "defaultValue" ]]; then
        echo "upgrade failed"
        exit 126
    fi
    # 等待升级完成
    waitDeployFinish "$job_id"
}

function main() {
    initParpare
    upgradeComponentVersion
    deploy
}
main

脚本参数说明

表1 脚本参数说明

参数

是否必须

参数类型

描述

region

String

项目名称。

project_id

String

项目id。

environment_name

String

组件的环境名称。

application_name

String

组件的应用名称。

component_name

String

组件名称。

deploy_type

String

部署类型: software或image。

  • software表示软件包部署。
  • image表示镜像部署。

obsutil

String

当使用软件包部署如jar包部署时为必须参数。上传jar包到obs的工具安装的绝对路径。

示例:/root/tools/obsutil/obsutil_linux_amd64_5.4.6/obsutil。

bucket_name

String

当使用软件包部署时为必须参数。存放软件包的obs桶名称。

bucket_dir

String

当使用软件包部署时为必须参数。

软件包在obs桶中的存放目录,默认是根目录,目录需要以/结尾,如果obs桶中没有这个目录,会自动创建出该目录。如根目录“/”,根目录下面的test目录“/test/”。

swr_organization

String

当使用镜像部署时为必须参数。上传到swr的组织名称。

AK

String

当使用镜像部署时为必须参数。创建永久AK、SK中的AK参数,用于登录swr镜像仓库。

login_secret

String

当使用镜像部署时为必须参数。swr的登录密钥,用于登录swr镜像仓库。通过创建永久AK、SK获取的AK/SK,执行如下命令,返回的结果就是登录密钥:

printf "$AK" | openssl dgst -binary -sha256 -hmac "$SK" | od -An -vtx1 | sed 's/[ \n]//g' | sed 'N;s/\n//'

参数值获取

  • 获取region、project_id值:
    登录CAE控制台,在右上角个人账号上,单击“我的凭证”,查看所属区域的项目和项目ID,即为对应的region和project_id值。
    图1 我的凭证
    图2 项目列表
  • 获取组件所在的环境名称environment_name,应用名称application_name和组件名称component_name:

    登录CAE控制台,单击“组件列表”,找到目标组件,例如image组件,如图3所示。

    图3 查看组件信息

相关文档