apollo一键部署配置脚本

公司目前有一个新的需求,就是在上线新的环境的时候,需要在apollo启动后,直接用shell脚本一键部署对应配置,大多数情况下都是搞java,没有怎么接触过shell脚本,临时参考和学习了很多博客上的文章,还有apollo也提供了两个作为例子的shell脚本,这样封装起来就方便一些,目前的情况是:

        1、apollo公共API目前只支持建集群、namespace、item配置,不支持建应用app,因此APP应用需要自己提前创建;

        2、要调用公共api还需要建立一个第三方的应用,生成对应的公共API token,然后还需要通过token对需要进行创建发布的配置对应应用进行授权。

以上工作都完成或者是通过SQL脚本前期都完成后,就可以开始脚本的工作了

1、是先定配置,我定的配置模板如下:

他是一个ini格式的配置文件

[h-common.TEST1.XXXDB.init]
name=XXXDB
appId=h-common
format=properties
isPublic=true
comment=这是一个说明
dataChangeCreatedBy=apollo
[h-common.MYAPPLICATION.init]
name=MYAPPLICATION
appId=h-common
format=properties
isPublic=false
comment=这是一个说明2
dataChangeCreatedBy=apollo
[h-common.TEST1.XXXDB.properties]
eureka.client.service-url.defaultZone=http://eureka:eurekaps@127.0.0.1:8070/eureka/
magic.oauth.login.encrypt=magic.oauth,login.encrypt
magic.graylog.opened=true
magic.qraylog.ip=127.0.0.1
[h-common.MYAPPLICATION.properties]
server.port=9090
spring.application.name=upmsName

注:

  • .init]结尾的section节点部分是创建apollo中namespace所需要的参数,相当于是在项目中新建一个空的配置文件,而isPublic属性为true则为所有应用可以关联的公共配置,需要加上apollo中的部门前缀(默认为TEST1),为false则为当前应用私有的配置,不需要加部门前缀

  • .properties]结尾的section节点部分是创建namespace下的item配置,和项目中properties格式文件内容一致

  • .ini配置文件中配置内容前后和"="中间都不要有多余的空格

  • .ini配置文件中目前配置内容格式固定为properties,不支持xml、yml、yaml、json、txt等

2、shell脚本

在执行目录下会有两个脚本:

  • openapi.sh

  • namespaceItemExecute.sh

openapi.sh是apollo自带:

#!/bin/bash
#
# Copyright 2023 Apollo Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

# title                     openapi.sh
# description               functions to call openapi through http
# author                    wxq
# date                      2021-09-12
# Chinese reference website https://www.apolloconfig.com/#/zh/usage/apollo-open-api-platform
# English reference website https://www.apolloconfig.com/#/en/usage/apollo-open-api-platform

####################################### Global variables #######################################
# portal's address, just support 1 address without suffix '/'
# Don't use http://ip:port/ with suffix '/' or multiple address http://ip1:port1,http://ip2:port2
APOLLO_PORTAL_ADDRESS=${APOLLO_PORTAL_ADDRESS:-http://ip:port}
APOLLO_OPENAPI_TOKEN=${APOLLO_OPENAPI_TOKEN:-please_change_me_by_environment_variable}
CURL_OPTIONS=${CURL_OPTIONS:-}

echo "apollo portal address: ${APOLLO_PORTAL_ADDRESS}"
echo "curl options: ${CURL_OPTIONS}"
####################################### end of Global variables #######################################

####################################### basic http call #######################################
#######################################
# Http get by curl.
# Globals:
#   APOLLO_PORTAL_ADDRESS:  portal's address
#   APOLLO_OPENAPI_TOKEN:   openapi's token
#   CURL_OPTIONS:           options in curl
# Arguments:
#   url_suffix
#######################################
function openapi_get() {
  local url_suffix=$1

  local url="${APOLLO_PORTAL_ADDRESS}/${url_suffix}"
  curl ${CURL_OPTIONS} --header "Authorization: ${APOLLO_OPENAPI_TOKEN}" --header "Content-Type: application/json;charset=UTF-8" "${url}"
}

#######################################
# Http post by curl.
# Globals:
#   APOLLO_PORTAL_ADDRESS:  portal's address
#   APOLLO_OPENAPI_TOKEN:   openapi's token
#   CURL_OPTIONS:           options in curl
# Arguments:
#   url_suffix
#   body
#######################################
function openapi_post() {
  local url_suffix=$1
  local body=$2

  local url="${APOLLO_PORTAL_ADDRESS}/${url_suffix}"
  curl ${CURL_OPTIONS} --header "Authorization: ${APOLLO_OPENAPI_TOKEN}" --header "Content-Type: application/json;charset=UTF-8" --data "${body}" "${url}"
}

#######################################
# Http put by curl.
# Globals:
#   APOLLO_PORTAL_ADDRESS:  portal's address
#   APOLLO_OPENAPI_TOKEN:   openapi's token
#   CURL_OPTIONS:           options in curl
# Arguments:
#   url_suffix
#   body
#######################################
function openapi_put() {
  local url_suffix=$1
  local body=$2

  local url="${APOLLO_PORTAL_ADDRESS}/${url_suffix}"
  curl -g ${CURL_OPTIONS} --header "Authorization: ${APOLLO_OPENAPI_TOKEN}" --header "Content-Type: application/json;charset=UTF-8" -X PUT --data "${body}" "${url}"
}

#######################################
# Http delete by curl.
# Globals:
#   APOLLO_PORTAL_ADDRESS:  portal's address
#   APOLLO_OPENAPI_TOKEN:   openapi's token
#   CURL_OPTIONS:           options in curl
# Arguments:
#   url_suffix
#   body
#######################################
function openapi_delete() {
  local url_suffix=$1
  local body=$2

  local url="${APOLLO_PORTAL_ADDRESS}/${url_suffix}"
  curl ${CURL_OPTIONS} --header "Authorization: ${APOLLO_OPENAPI_TOKEN}" --header "Content-Type: application/json;charset=UTF-8" -X DELETE --data "${body}" "${url}"
}
####################################### end of basic http call #######################################


####################################### cluster #######################################
#######################################
# Get cluster.
# 获取集群
# Arguments:
#   env
#   appId
#   clusterName
#######################################
function cluster_get() {
    local env=$1
    local appId=$2
    local clusterName=$3
    openapi_get "openapi/v1/envs/${env}/apps/${appId}/clusters/${clusterName}"
}

#######################################
# Create cluster in app's environment.
# 创建集群
# Arguments:
#   env
#   appId
#   clusterName
#   dataChangeCreatedBy
#######################################
function cluster_create() {
  local env=$1
  local appId=$2
  local clusterName=$3
  local dataChangeCreatedBy=$4
  openapi_post "openapi/v1/envs/${env}/apps/${appId}/clusters" "$(cat <<BODY
{
    "name":"${clusterName}",
    "appId":"${appId}",
    "dataChangeCreatedBy":"${dataChangeCreatedBy}"
}
BODY
)"
}
####################################### end of cluster #######################################

####################################### namespace #######################################
#######################################
# Create a namespace of a app.
# 创建namespace
# Arguments:
#   appId
#   name
#   format
#   isPublic
#   comment
#   dataChangeCreatedBy
#######################################
function namespace_create() {
  local appId=$1
  local name=$2
  local format=$3
  local isPublic=$4
  local comment=$5
  local dataChangeCreatedBy=$6

  openapi_post "openapi/v1/apps/${appId}/appnamespaces" "$(cat <<BODY
{
  "name": "${name}",
  "appId": "${appId}",
  "format": "${format}",
  "isPublic": ${isPublic},
  "comment": "${comment}",
  "dataChangeCreatedBy": "${dataChangeCreatedBy}"
}
BODY
)"
}

#######################################
# Release a namespace.
# 发布配置
# Arguments:
#   env
#   appId
#   clusterName
#   namespaceName
#   releaseTitle
#   releaseComment
#   releasedBy
#######################################
function namespace_release() {
  local env=$1
  local appId=$2
  local clusterName=$3
  local namespaceName=$4
  
  local releaseTitle=$5
  local releaseComment=$6
  local releasedBy=$7

  openapi_post "openapi/v1/envs/${env}/apps/${appId}/clusters/${clusterName}/namespaces/${namespaceName}/releases" "$(cat <<BODY
{
    "releaseTitle":"${releaseTitle}",
    "releaseComment":"${releaseComment}",
    "releasedBy":"${releasedBy}"
}
BODY
)"
}
####################################### end of namespace #######################################


####################################### item #######################################
#######################################
# Create an item of a namespace.
# 新增配置
# Arguments:
#   env
#   appId
#   clusterName
#   namespaceName
#   key
#   value
#   comment
#   dataChangeCreatedBy
#######################################
function item_create() {
  local env=$1
  local appId=$2
  local clusterName=$3
  local namespaceName=$4
  local key=$5
  local value=$6
  local comment=$7
  local dataChangeCreatedBy=$8

  openapi_post "openapi/v1/envs/${env}/apps/${appId}/clusters/${clusterName}/namespaces/${namespaceName}/items" "$(cat <<BODY
{
    "key":"${key}",
    "value":"${value}",
    "comment":"${comment}",
    "dataChangeCreatedBy":"${dataChangeCreatedBy}"
}
BODY
)"
}

#######################################
# Update an item of a namespace.
# 修改配置
# Arguments:
#   env
#   appId
#   clusterName
#   namespaceName
#   key
#   value
#   comment
#   dataChangeLastModifiedBy
#######################################
function item_update() {
  local env=$1
  local appId=$2
  local clusterName=$3
  local namespaceName=$4
  local key=$5
  local value=$6
  local comment=$7
  local dataChangeLastModifiedBy=$8

  openapi_put "openapi/v1/envs/${env}/apps/${appId}/clusters/${clusterName}/namespaces/${namespaceName}/items/${key}" "$(cat <<BODY
{
  "key":"${key}",
  "value":"${value}",
  "comment":"${comment}",
  "dataChangeLastModifiedBy":"${dataChangeLastModifiedBy}"
}
BODY
)"
}

#######################################
# Update an item of a namespace, if item doesn's exist, create it.
# 修改配置,当配置不存在时自动创建
# Arguments:
#   env
#   appId
#   clusterName
#   namespaceName
#   key
#   value
#   comment
#   dataChangeLastModifiedBy
#######################################
function item_update_create_if_not_exists() {
  local env=$1
  local appId=$2
  local clusterName=$3
  local namespaceName=$4
  local key=$5
  local value=$6
  local comment=$7
  local dataChangeLastModifiedBy=$8
  local dataChangeCreatedBy=$9

  openapi_put "openapi/v1/envs/${env}/apps/${appId}/clusters/${clusterName}/namespaces/${namespaceName}/items/${key}?createIfNotExists=true" "$(cat <<BODY
{
  "key":"${key}",
  "value":"${value}",
  "comment":"${comment}",
  "dataChangeLastModifiedBy":"${dataChangeLastModifiedBy}",
  "dataChangeCreatedBy":"${dataChangeCreatedBy}"
}
BODY
)"
}

#######################################
# Delete an item of a namespace.
# 删除配置
# Arguments:
#   env
#   appId
#   clusterName
#   namespaceName
#   key
#   operator
#######################################
function item_delete() {
  local env=$1
  local appId=$2
  local clusterName=$3
  local namespaceName=$4
  local key=$5
  local operator=$6

  openapi_delete "openapi/v1/envs/${env}/apps/${appId}/clusters/${clusterName}/namespaces/${namespaceName}/items/${key}?operator=${operator}"
}
####################################### end of item #######################################

namespaceItemExecute.sh是自己写的,有些地方还不是很完善,参考了很多博客资料,忘记地址了,后面如果找到会提供

#!/bin/bash

file_path_ori=$1
# export global varialbes
export APOLLO_PORTAL_ADDRESS=$2
export APOLLO_OPENAPI_TOKEN=$3
export CURL_OPTIONS=""
# load functions
# 获取当前执行文件的绝对路径
current_file=$(readlink -f "$0")
absolute_path=$(dirname "$current_file")
source $absolute_path"/openapi.sh"

# 新增namespace方法
namespace_init() {
	file_path=$1
	echo $file_path  "namespace_init"
	printf "\n\n"
	name=
	appId=
	format=
	isPublic=
	comment="create by openapi, bash scripts for release"
	dataChangeCreatedBy='apollo'
	# 先匹配以.init]结尾的节点 
	namespace_section_list=$(awk '/\.init\]$/' ${file_path} | sed 's/\[//g;s/\]//g')
	for namespace_section in $namespace_section_list; do
		# 匹配以.init]结尾的节点 条件1:去除第一行 条件2:去除空行 条件3:去除其他section的内容
		namespace_list=$(awk -F ',' "/\[${namespace_section}\]$/{a=1}a==1" ${file_path}|sed -e '1d' -e '/^$/d' -e '/^\[.*\]/,$d')
		# 遍历每一行,将每一行的内容按等号分割,并处理键值对
		for line in $namespace_list; do
			#key=$(echo $line | cut -d '=' -f 1)
			key=$(echo $line|cut -d '=' -f -1)
			#value=$(echo $line | cut -d '=' -f 2)
			value=$(echo ${line#*=})
			if [ "$key" = 'name' ]; then
					name=$value
			elif [ "$key" = 'appId' ]; then
					appId=$value
			elif [ "$key" = 'format' ]; then
					format=$value
			elif [ "$key" = 'isPublic' ]; then
					isPublic=$value
			elif [ "$key" = 'comment' ]; then
					comment=$value
			elif [ "$key" = 'dataChangeCreatedBy' ]; then
					dataChangeCreatedBy=$value
			fi
		done
		echo 'namespace create start----------------------'
		echo $name "--->" $appId "--->" $format "--->" $comment "--->" $dataChangeCreatedBy	
		namespace_create ${appId} ${name} ${format} ${isPublic} ${comment} ${dataChangeCreatedBy}
		echo 'namespace create end----------------------'
		printf "\n\n"
		echo 'namespace release start----------------------'
		namespace_name=""
		if [ "$isPublic" = 'true' ]; then
			namespace_name="TEST1."$name
		else
			namespace_name=$name
		fi
		release "dev" $appId "default" $namespace_name
		echo 'namespace release end----------------------'
	done
}
# 新增item方法
item_init() {
	file_path=$1
	echo $file_path  "item_init"
	printf "\n\n"
	key=
	value=
	comment="openapi-create-item"
	dataChangeCreatedBy='apollo'
	# 先匹配以.properties]结尾的节点 
	namespace_section_list=$(awk '/\.properties\]$/' ${file_path} | sed 's/\[//g;s/\]//g')
	for namespace_section in $namespace_section_list; do
		namespace=""
		# namespace_section 进行切分,通过.进行切分
		appId=$(echo $namespace_section | cut -d '.' -f 1)
		second_name=$(echo $namespace_section | cut -d '.' -f 2)
		third_name=$(echo $namespace_section | cut -d '.' -f 3)
		forth_name=$(echo $namespace_section | cut -d '.' -f 4)
		if [ "$forth_name" = 'properties' ]; then
			namespace=$second_name'.'$third_name
		else
			namespace=$second_name
		fi
		# 匹配以.properties]结尾的节点 条件1:去除第一行 条件2:去除空行 条件3:去除其他section的内容
		namespace_list=$(awk -F ',' "/\[${namespace_section}\]$/{a=1}a==1" ${file_path}|sed -e '1d' -e '/^$/d' -e '/^\[.*\]/,$d')
		# 遍历每一行,将每一行的内容按等号分割,并处理键值对
		for line in $namespace_list; do
			# key=$(echo $line | cut -d '=' -f 1)
			# value=$(echo $line | cut -d '=' -f 2)
			key=$(echo $line|cut -d '=' -f -1)
			value=$(echo ${line#*=})
			echo "line="$line
			# $(echo ${line#*=}) 这个方法如何等于后面是*可能会查找文件
			if [[ $value =~ $file_path ]]
			then
				value=$(echo $line|cut -d '=' -f 2)
				echo '包含'"$file_path""$(echo $line|cut -d '=' -f 2)"
				echo $value
			else
				value=$value
				echo '不包含'"$file_path"
			fi
			echo "item---->" $key "--->" $value "--->" $comment "--->" $dataChangeCreatedBy 
			# item_create "dev" ${appId} "default" ${namespace} ${key} ${value} ${comment} ${dataChangeCreatedBy}	
			echo 'item_update_create_if_not_exists start-----------------------------'
			item_update_create_if_not_exists "dev" ${appId} default ${namespace} ${key} "$value" ${comment} ${dataChangeCreatedBy} ${dataChangeCreatedBy}
			echo 'item_update_create_if_not_exists end-----------------------------'
		done
		# 每一次完成namespace中item的全部新增,则进行发布
		echo 'item release start-----------------------------'
		release "dev" $appId "default" $namespace
		echo 'item release end-----------------------------'
	done
}

# 发布方法
release() {
	env_release=$1
	app_id=$2
	cluster_name=$3
	namespace=$4
	# 获取当前时间戳
	releaseTitle=$(date +"%Y%m%d%H%M%S%N")"-version"
	releaseComment="公共api发布namespace"
	releasedBy="apollo"
	echo "release----->env_release:" $env_release "----->app_id:" $app_id "----->cluster_name:" $cluster_name "----->namespace:" $namespace
	echo "release----->releaseTitle:" $releaseTitle "----->releaseComment:" $releaseComment "----->releasedBy:" $releasedBy
	namespace_release ${env_release} ${app_id} ${cluster_name} ${namespace} ${releaseTitle} ${releaseComment} ${releasedBy}
	printf "\n\n"
}



echo $file_path_ori  "--------start-------"
printf "\n"
namespace_init $file_path_ori
item_init $file_path_ori

openapi.sh为接收参数通过curl请求apollo公共API调用,namespaceItemExecute.sh为解析对应xxx.ini配置文件,然后封装对应参数调用openapi.sh脚本中相关方法执行对应操作,执行例子如下:

sh namespaceItemExecute.sh namespace.ini http://127.0.0.1:8070 token

这个脚本需要传入三个参数:

  1. 需要解析的.ini配置文件路径和文件名,如:namespace.ini

  2. apollo中portal服务对应的请求请求地址,如:http://159.45.0.68:8070/mfapollo

  3. apollo开放平台第三方应用对应token,如:ce86a34e63bf5ac1c35fc3ba8723sdgsaersdd035635ae45c0c83b0d28;对应的第三方应用创建、token生成、赋权等地址在Apollo

在执行这个脚本之前,需要先创建apollo中对应的应用,这个脚本目前只是提供了配置文件和对应配置内容的初始化操作

任何语言的第三方应用都可以调用Apollo的Open API,在调用接口时,需要设置注意以下两点:

  • Http Header中增加一个Authorization字段,字段值为申请的token

  • Http Header的Content-Type字段需要设置成application/json;charset=UTF-8

参考地址:

Shell script - Linux下解析ini配置文件 - 简书

Linux之sed命令详解 - zakun - 博客园

Linux sed 命令 | 菜鸟教程

Shell - 第3页-Chinaunix

linux Shell 读取和写入ini配置文件 (脚本实现读取和写入,附使用方法和讲解)_sh如何往ini添加数据-CSDN博客

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值