mirror of https://github.com/alibaba/SREWorks.git
feat: add owner reference to service trait
This commit is contained in:
parent
0af2a39f3c
commit
e853b8c431
|
|
@ -4,27 +4,64 @@ import logging
|
|||
import os
|
||||
import sys
|
||||
|
||||
import requests
|
||||
from oauthlib.oauth2 import LegacyApplicationClient
|
||||
from requests_oauthlib import OAuth2Session
|
||||
|
||||
CREATOR = "122592"
|
||||
logger = logging.getLogger()
|
||||
logger.setLevel(logging.INFO)
|
||||
|
||||
handler = logging.StreamHandler(sys.stdout)
|
||||
handler.setLevel(logging.INFO)
|
||||
formatter = logging.Formatter('[%(asctime)s] [%(module)s.%(funcName)s:%(lineno)d] [%(levelname)s] - %(message)s')
|
||||
handler.setFormatter(formatter)
|
||||
logger.addHandler(handler)
|
||||
|
||||
CURRENT_PATH = os.path.dirname(os.path.abspath(__file__))
|
||||
ENDPOINT = 'http://' + os.getenv('ENDPOINT_PAAS_APPMANAGER')
|
||||
CLIENT_ID = os.getenv('APPMANAGER_CLIENT_ID')
|
||||
CLIENT_SECRET = os.getenv('APPMANAGER_CLIENT_SECRET')
|
||||
USERNAME = os.getenv('APPMANAGER_ACCESS_ID')
|
||||
PASSWORD = os.getenv('APPMANAGER_ACCESS_SECRET')
|
||||
CREATOR = '122592'
|
||||
HEADERS = {
|
||||
'X-EmpId': CREATOR
|
||||
}
|
||||
ENDPOINT = "http://" + os.getenv("ENDPOINT_PAAS_APPMANAGER")
|
||||
|
||||
formatter = logging.Formatter('[%(asctime)s] - [%(levelname)s] - %(message)s')
|
||||
logger = logging.getLogger()
|
||||
logger.setLevel(logging.INFO)
|
||||
stdout_hdlr = logging.StreamHandler(sys.stdout)
|
||||
stdout_hdlr.setFormatter(formatter)
|
||||
logger.addHandler(stdout_hdlr)
|
||||
|
||||
|
||||
def _insert_cluster(cluster, master_url, oauth_token):
|
||||
class AppManagerClient(object):
|
||||
|
||||
def __init__(self, endpoint, client_id, client_secret, username, password):
|
||||
os.environ.setdefault('OAUTHLIB_INSECURE_TRANSPORT', '1')
|
||||
self._endpoint = endpoint
|
||||
self._client_id = client_id
|
||||
self._client_secret = client_secret
|
||||
self._username = username
|
||||
self._password = password
|
||||
self._token = self._fetch_token()
|
||||
|
||||
@property
|
||||
def client(self):
|
||||
return OAuth2Session(self._client_id, token=self._token)
|
||||
|
||||
def _fetch_token(self):
|
||||
"""
|
||||
获取 appmanager access token
|
||||
"""
|
||||
oauth = OAuth2Session(client=LegacyApplicationClient(client_id=CLIENT_ID))
|
||||
return oauth.fetch_token(
|
||||
token_url=os.path.join(ENDPOINT, 'oauth/token'),
|
||||
username=self._username,
|
||||
password=self._password,
|
||||
client_id=self._client_id,
|
||||
client_secret=self._client_secret
|
||||
)
|
||||
|
||||
|
||||
def _insert_cluster(r, cluster, master_url, oauth_token):
|
||||
"""
|
||||
插入集群
|
||||
"""
|
||||
response = requests.post("%s/clusters" % ENDPOINT, headers=HEADERS, json={
|
||||
response = r.post("%s/clusters" % ENDPOINT, headers=HEADERS, json={
|
||||
'clusterId': cluster,
|
||||
'clusterName': cluster,
|
||||
'clusterType': 'kubernetes',
|
||||
|
|
@ -43,11 +80,11 @@ def _insert_cluster(cluster, master_url, oauth_token):
|
|||
sys.exit(1)
|
||||
|
||||
|
||||
def _update_cluster(cluster, master_url, oauth_token):
|
||||
def _update_cluster(r, cluster, master_url, oauth_token):
|
||||
"""
|
||||
更新集群
|
||||
"""
|
||||
response = requests.put("%s/clusters/%s" % (ENDPOINT, cluster), headers=HEADERS, json={
|
||||
response = r.put("%s/clusters/%s" % (ENDPOINT, cluster), headers=HEADERS, json={
|
||||
'clusterName': cluster,
|
||||
'clusterType': 'kubernetes',
|
||||
'clusterConfig': {
|
||||
|
|
@ -65,17 +102,17 @@ def _update_cluster(cluster, master_url, oauth_token):
|
|||
sys.exit(1)
|
||||
|
||||
|
||||
def init_cluster():
|
||||
def init_cluster(r):
|
||||
"""
|
||||
初始化 appmanager 集群
|
||||
:return:
|
||||
"""
|
||||
cluster_mapping = {}
|
||||
items = requests.get("%s/clusters" % ENDPOINT, headers=HEADERS).json().get('data', {}).get('items', [])
|
||||
items = r.get("%s/clusters" % ENDPOINT, headers=HEADERS).json().get('data', {}).get('items', [])
|
||||
for item in items:
|
||||
cluster_mapping[item['clusterId']] = {
|
||||
'masterUrl': item.get('clusterConfig',{}).get('masterUrl'),
|
||||
'oauthToken': item.get('clusterConfig',{}).get('oauthToken'),
|
||||
'masterUrl': item.get('clusterConfig', {}).get('masterUrl'),
|
||||
'oauthToken': item.get('clusterConfig', {}).get('oauthToken'),
|
||||
}
|
||||
|
||||
# 获取当前的 masterUrl 和 oauthToken 信息
|
||||
|
|
@ -87,13 +124,14 @@ def init_cluster():
|
|||
clusters = ["master"]
|
||||
for cluster in clusters:
|
||||
if not cluster_mapping.get(cluster):
|
||||
_insert_cluster(cluster, master_url, oauth_token)
|
||||
elif cluster_mapping[cluster].get('masterUrl') != master_url or cluster_mapping[cluster].get('oauthToken') != oauth_token:
|
||||
_update_cluster(cluster, master_url, oauth_token)
|
||||
_insert_cluster(r, cluster, master_url, oauth_token)
|
||||
elif cluster_mapping[cluster].get('masterUrl') != master_url \
|
||||
or cluster_mapping[cluster].get('oauthToken') != oauth_token:
|
||||
_update_cluster(r, cluster, master_url, oauth_token)
|
||||
else:
|
||||
logger.info('no need to update cluster %s' % cluster)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
init_cluster()
|
||||
logger.info("initjob success")
|
||||
init_cluster(AppManagerClient(ENDPOINT, CLIENT_ID, CLIENT_SECRET, USERNAME, PASSWORD).client)
|
||||
logger.info("cluster initjob success")
|
||||
|
|
|
|||
|
|
@ -0,0 +1,2 @@
|
|||
create index idx_cluster_type
|
||||
on am_cluster (cluster_type);
|
||||
|
|
@ -0,0 +1,110 @@
|
|||
# coding: utf-8
|
||||
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
|
||||
import requests
|
||||
from oauthlib.oauth2 import LegacyApplicationClient
|
||||
from requests_oauthlib import OAuth2Session
|
||||
|
||||
logger = logging.getLogger()
|
||||
logger.setLevel(logging.INFO)
|
||||
|
||||
handler = logging.StreamHandler(sys.stdout)
|
||||
handler.setLevel(logging.INFO)
|
||||
formatter = logging.Formatter('[%(asctime)s] [%(module)s.%(funcName)s:%(lineno)d] [%(levelname)s] - %(message)s')
|
||||
handler.setFormatter(formatter)
|
||||
logger.addHandler(handler)
|
||||
|
||||
CURRENT_PATH = os.path.dirname(os.path.abspath(__file__))
|
||||
ENDPOINT = 'http://' + os.getenv('ENDPOINT_PAAS_APPMANAGER')
|
||||
CLIENT_ID = os.getenv('APPMANAGER_CLIENT_ID')
|
||||
CLIENT_SECRET = os.getenv('APPMANAGER_CLIENT_SECRET')
|
||||
USERNAME = os.getenv('APPMANAGER_ACCESS_ID')
|
||||
PASSWORD = os.getenv('APPMANAGER_ACCESS_SECRET')
|
||||
NAMESPACE = 'apsara-bigdata-manager'
|
||||
STAGE = 'prod'
|
||||
|
||||
|
||||
class AppManagerClient(object):
|
||||
|
||||
def __init__(self, endpoint, client_id, client_secret, username, password):
|
||||
os.environ.setdefault('OAUTHLIB_INSECURE_TRANSPORT', '1')
|
||||
self._endpoint = endpoint
|
||||
self._client_id = client_id
|
||||
self._client_secret = client_secret
|
||||
self._username = username
|
||||
self._password = password
|
||||
self._token = self._fetch_token()
|
||||
|
||||
@property
|
||||
def client(self):
|
||||
return OAuth2Session(self._client_id, token=self._token)
|
||||
|
||||
def _fetch_token(self):
|
||||
"""
|
||||
获取 appmanager access token
|
||||
"""
|
||||
oauth = OAuth2Session(client=LegacyApplicationClient(client_id=CLIENT_ID))
|
||||
return oauth.fetch_token(
|
||||
token_url=os.path.join(ENDPOINT, 'oauth/token'),
|
||||
username=self._username,
|
||||
password=self._password,
|
||||
client_id=self._client_id,
|
||||
client_secret=self._client_secret
|
||||
)
|
||||
|
||||
|
||||
def apply(r, url, post_body):
|
||||
"""
|
||||
导入 post_body 对应 URL
|
||||
:return:
|
||||
"""
|
||||
response = r.post(ENDPOINT + url, json=post_body)
|
||||
response_json = response.json()
|
||||
code = response_json.get('code')
|
||||
if code != 200 and code != 10002:
|
||||
logger.error('import to appmanager failed, url=%s, body=%s, response=%s' % (url, post_body, response.text))
|
||||
sys.exit(1)
|
||||
logger.info('import to appmanager success, url=%s, body=%s' % (url, post_body))
|
||||
|
||||
|
||||
def apply_all():
|
||||
try:
|
||||
r = AppManagerClient(ENDPOINT, CLIENT_ID, CLIENT_SECRET, USERNAME, PASSWORD).client
|
||||
except Exception as e:
|
||||
logger.error("cannot find appmanager client auth info, skip")
|
||||
r = requests
|
||||
|
||||
apply(r, '/namespaces', {
|
||||
'namespaceId': 'apsara-bigdata-manager',
|
||||
'namespaceName': '服务专用(apsara-bigdata-manager)',
|
||||
'namespaceExt': {}
|
||||
})
|
||||
apply(r, '/namespaces', {
|
||||
'namespaceId': 'default',
|
||||
'namespaceName': '前端配置专用(default)',
|
||||
'namespaceExt': {}
|
||||
})
|
||||
apply(r, '/namespaces/apsara-bigdata-manager/stages', {
|
||||
'stageId': 'master',
|
||||
'stageName': '服务专用(master)',
|
||||
'stageExt': {}
|
||||
})
|
||||
apply(r, '/namespaces/apsara-bigdata-manager/stages', {
|
||||
'stageId': 'slave',
|
||||
'stageName': '服务专用(slave)',
|
||||
'stageExt': {}
|
||||
})
|
||||
apply(r, '/namespaces/default/stages', {
|
||||
'stageId': 'prod',
|
||||
'stageName': '前端配置专用',
|
||||
'stageExt': {}
|
||||
})
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if os.getenv("SREWORKS_INIT") != "enable":
|
||||
apply_all()
|
||||
|
|
@ -6,5 +6,5 @@ COPY ./APP-META-PRIVATE/cluster-init /app/sbin
|
|||
|
||||
# 安装依赖,构建镜像
|
||||
RUN sed -i 's/mirrors.tuna.tsinghua.edu.cn/mirrors.aliyun.com/g' /etc/apk/repositories \
|
||||
&& pip install -i http://mirrors.aliyun.com/pypi/simple --trusted-host mirrors.aliyun.com requests
|
||||
&& pip install -i http://mirrors.aliyun.com/pypi/simple --trusted-host mirrors.aliyun.com requests requests_oauthlib
|
||||
ENTRYPOINT ["/app/sbin/cluster_run.sh"]
|
||||
|
|
@ -18,8 +18,10 @@ COPY --from=build /app/${APP_NAME}-start-standalone/target/${APP_NAME}/BOOT-INF/
|
|||
COPY --from=build /app/${APP_NAME}-start-standalone/target/${APP_NAME}/BOOT-INF/classes/jinja /app/jinja
|
||||
RUN wget -O /app/helm "https://abm-storage.oss-cn-zhangjiakou.aliyuncs.com/lib/helm" \
|
||||
&& chmod +x /app/helm \
|
||||
&& wget -O /app/kustomize "https://abm-storage.oss-cn-zhangjiakou.aliyuncs.com/lib/kustomize" \
|
||||
&& chmod +x /app/kustomize
|
||||
&& wget -O /app/kustomize "https://abm-storage.oss-cn-zhangjiakou.aliyuncs.com/lib/kustomize" \
|
||||
&& chmod +x /app/kustomize \
|
||||
&& wget -O /app/kubectl "https://abm-storage.oss-cn-zhangjiakou.aliyuncs.com/lib/kubectl" \
|
||||
&& chmod +x /app/kubectl
|
||||
|
||||
WORKDIR /app
|
||||
ENTRYPOINT ["/app/sbin/run_sreworks.sh"]
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
FROM ${MAVEN_IMAGE} AS build
|
||||
COPY . /app
|
||||
WORKDIR /app
|
||||
RUN mkdir /root/.m2/ && curl ${MAVEN_SETTINGS_XML} -o /root/.m2/settings.xml
|
||||
RUN mvn -Dmaven.test.skip=true clean package -U
|
||||
|
||||
# Release
|
||||
FROM ${MAVEN_IMAGE} AS release
|
||||
USER root
|
||||
WORKDIR /root
|
||||
ARG APP_NAME=tesla-appmanager
|
||||
# Copy Jars
|
||||
COPY --from=build /app/${APP_NAME}-start-standalone/target/${APP_NAME}.jar /app/${APP_NAME}-standalone.jar
|
||||
COPY --from=build /app/${APP_NAME}-start-standalone/target/${APP_NAME}/BOOT-INF/classes/application-docker.properties /app/config/application.properties
|
||||
# Copy Resources
|
||||
COPY --from=build /app/${APP_NAME}-start-standalone/target/${APP_NAME}/BOOT-INF/classes/dynamicscripts /app/dynamicscripts
|
||||
COPY --from=build /app/${APP_NAME}-start-standalone/target/${APP_NAME}/BOOT-INF/classes/jinja /app/jinja
|
||||
RUN wget -O /app/helm "${HELM_BIN_URL}" \
|
||||
&& chmod +x /app/helm \
|
||||
&& wget -O /app/kustomize "${KUSTOMIZE_BIN_URL}" \
|
||||
&& chmod +x /app/kustomize
|
||||
|
||||
WORKDIR /app
|
||||
ENTRYPOINT ["/app/sbin/run_sreworks.sh"]
|
||||
|
|
@ -57,7 +57,7 @@
|
|||
<hikaricp.version>5.0.1</hikaricp.version>
|
||||
|
||||
<!-- tesla -->
|
||||
<tesla.spring.boot.version>2.1.7</tesla.spring.boot.version>
|
||||
<tesla.spring.boot.version>2.1.9</tesla.spring.boot.version>
|
||||
<task-flow-service.version>1.1.0</task-flow-service.version>
|
||||
|
||||
<!-- other -->
|
||||
|
|
|
|||
|
|
@ -47,8 +47,6 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
|
|||
web.ignoring()
|
||||
.antMatchers("/status.taobao")
|
||||
.antMatchers("/actuator/**")
|
||||
.antMatchers("/clusters**")
|
||||
.antMatchers("/clusters/**")
|
||||
.antMatchers("/traits**")
|
||||
.antMatchers("/flow-manager/**")
|
||||
.antMatchers("/traits/**")
|
||||
|
|
|
|||
|
|
@ -0,0 +1,50 @@
|
|||
package com.alibaba.tesla.appmanager.common.enums;
|
||||
|
||||
/**
|
||||
* 集群类型
|
||||
*
|
||||
* @author yaoxing.gyx@alibaba-inc.com
|
||||
*/
|
||||
public enum ClusterTypeEnum {
|
||||
|
||||
/**
|
||||
* 普通 K8S 集群
|
||||
*/
|
||||
KUBERNETES("kubernetes"),
|
||||
|
||||
/**
|
||||
* 资源集群
|
||||
*/
|
||||
RESOURCE_CLUSTER("resource-cluster"),
|
||||
|
||||
/**
|
||||
* 虚拟集群
|
||||
*/
|
||||
VC("vc");
|
||||
|
||||
private final String text;
|
||||
|
||||
ClusterTypeEnum(final String text) {
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return text;
|
||||
}
|
||||
|
||||
/**
|
||||
* String to Enum
|
||||
*
|
||||
* @param text String
|
||||
* @return Enum
|
||||
*/
|
||||
public static ClusterTypeEnum fromString(String text) {
|
||||
for (ClusterTypeEnum item : ClusterTypeEnum.values()) {
|
||||
if (item.text.equalsIgnoreCase(text)) {
|
||||
return item;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
@ -74,7 +74,12 @@ public enum ComponentTypeEnum {
|
|||
/**
|
||||
* ABM Helm Component
|
||||
*/
|
||||
ABM_HELM;
|
||||
ABM_HELM,
|
||||
|
||||
/**
|
||||
* ABM Status Component
|
||||
*/
|
||||
ABM_STATUS;
|
||||
|
||||
public static ComponentTypeEnum parse(String value) {
|
||||
ComponentTypeEnum result = Enums.getIfPresent(ComponentTypeEnum.class, value).orNull();
|
||||
|
|
|
|||
|
|
@ -77,6 +77,16 @@ public enum DynamicScriptKindEnum {
|
|||
*/
|
||||
DEPLOY_ABM_HELM_COMPONENT,
|
||||
|
||||
/**
|
||||
* 构建 ABM Status 模块
|
||||
*/
|
||||
BUILD_ABM_STATUS_COMPONENT,
|
||||
|
||||
/**
|
||||
* 部署 ABM Status 模块
|
||||
*/
|
||||
DEPLOY_ABM_STATUS_COMPONENT,
|
||||
|
||||
/**
|
||||
* 通用构建 Resource Addon 模块
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -424,8 +424,8 @@ public class DeployConfigServiceImpl implements DeployConfigService {
|
|||
}
|
||||
}
|
||||
throw new AppException(AppErrorCode.DEPLOY_ERROR,
|
||||
String.format("cannot find best deploy config with given condition|clusterId=%s|namespaceId=%s|" +
|
||||
"stageId=%s", clusterId, namespaceId, stageId));
|
||||
String.format("cannot find best deploy config with given condition(general type)|" +
|
||||
"clusterId=%s|namespaceId=%s|stageId=%s", clusterId, namespaceId, stageId));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -469,7 +469,7 @@ public class DeployConfigServiceImpl implements DeployConfigService {
|
|||
}
|
||||
}
|
||||
|
||||
// 兜底
|
||||
// 通过无 appId 的部署配置记录进行二次查找
|
||||
List<DeployConfigDO> filteredAppRecords = appRecords.stream()
|
||||
.filter(item -> StringUtils.isEmpty(item.getEnvId()))
|
||||
.collect(Collectors.toList());
|
||||
|
|
@ -496,9 +496,11 @@ public class DeployConfigServiceImpl implements DeployConfigService {
|
|||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// 再不行就报错了
|
||||
throw new AppException(AppErrorCode.DEPLOY_ERROR,
|
||||
String.format("cannot find best deploy config with given condition|clusterId=%s|namespaceId=%s|" +
|
||||
"stageId=%s", clusterId, namespaceId, stageId));
|
||||
String.format("cannot find best deploy config with given condition(specified name)|clusterId=%s|" +
|
||||
"namespaceId=%s|stageId=%s", clusterId, namespaceId, stageId));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -46,6 +46,15 @@ public class DeployConfigEnvId {
|
|||
return String.format("Unit:%s", unitId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回空环境字符串标识(通用类型)
|
||||
*
|
||||
* @return 字符串标识
|
||||
*/
|
||||
public static String emptyUnitStr() {
|
||||
return "Unit";
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回 Stage 字符串标识
|
||||
*
|
||||
|
|
|
|||
|
|
@ -30,6 +30,13 @@ public interface WorkloadBinder {
|
|||
*/
|
||||
void setOwnerReference(String ownerReference);
|
||||
|
||||
/**
|
||||
* 返回 Owner Reference 字符串
|
||||
*
|
||||
* @return Owner Reference JSON Object String
|
||||
*/
|
||||
String getOwnerReference();
|
||||
|
||||
/**
|
||||
* 获取当前被绑定的 Component 对象
|
||||
*
|
||||
|
|
|
|||
|
|
@ -1,11 +1,10 @@
|
|||
package com.alibaba.tesla.appmanager.domain.req.cluster;
|
||||
|
||||
import com.alibaba.tesla.appmanager.common.BaseRequest;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
import lombok.experimental.SuperBuilder;
|
||||
|
||||
/**
|
||||
* Cluster 查询请求
|
||||
|
|
@ -13,10 +12,10 @@ import java.io.Serializable;
|
|||
* @author yaoxing.gyx@alibaba-inc.com
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@SuperBuilder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class ClusterQueryReq implements Serializable {
|
||||
public class ClusterQueryReq extends BaseRequest {
|
||||
|
||||
private static final long serialVersionUID = -1872143932301240289L;
|
||||
|
||||
|
|
@ -29,4 +28,9 @@ public class ClusterQueryReq implements Serializable {
|
|||
* Cluster 名称
|
||||
*/
|
||||
private String clusterName;
|
||||
|
||||
/**
|
||||
* Cluster 类型
|
||||
*/
|
||||
private String clusterType;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -258,6 +258,16 @@ public class GroovyHandlerFactory {
|
|||
DynamicScriptKindEnum.DEPLOY_ABM_HELM_COMPONENT.toString(),
|
||||
DefaultConstant.DEFAULT_GROOVY_HANDLER);
|
||||
}
|
||||
case ABM_STATUS:
|
||||
if (ComponentActionEnum.BUILD.equals(action)) {
|
||||
return get(scriptClass,
|
||||
DynamicScriptKindEnum.BUILD_ABM_STATUS_COMPONENT.toString(),
|
||||
DefaultConstant.DEFAULT_GROOVY_HANDLER);
|
||||
} else {
|
||||
return get(scriptClass,
|
||||
DynamicScriptKindEnum.DEPLOY_ABM_STATUS_COMPONENT.toString(),
|
||||
DefaultConstant.DEFAULT_GROOVY_HANDLER);
|
||||
}
|
||||
case INTERNAL_ADDON:
|
||||
if ("productops".equals(componentName)) {
|
||||
if (ComponentActionEnum.BUILD.equals(action)) {
|
||||
|
|
|
|||
|
|
@ -356,7 +356,7 @@ public class K8sMicroServiceMetaDO implements Serializable {
|
|||
if (StringUtils.isNotEmpty(kind)) {
|
||||
microServiceExtJson.put("kind", kind);
|
||||
} else {
|
||||
throw new AppException(AppErrorCode.INVALID_USER_ARGS, "kind parameter is required");
|
||||
microServiceExtJson.put("kind", "AdvancedStatefulSet");
|
||||
}
|
||||
|
||||
if (CollectionUtils.isNotEmpty(envList)) {
|
||||
|
|
@ -450,7 +450,7 @@ public class K8sMicroServiceMetaDO implements Serializable {
|
|||
if (StringUtils.isNotEmpty(initContainerListString)) {
|
||||
initContainerList = JSON.parseArray(initContainerListString, InitContainerDTO.class);
|
||||
} else {
|
||||
containerObjectList = Collections.emptyList();
|
||||
initContainerList = Collections.emptyList();
|
||||
}
|
||||
|
||||
String repoString = microServiceExtJson.getString("repo");
|
||||
|
|
|
|||
|
|
@ -136,6 +136,10 @@ public class AppController extends BaseController {
|
|||
if (StringUtils.isEmpty(appId)) {
|
||||
return buildSucceedResult(Boolean.TRUE);
|
||||
}
|
||||
String cloudType = System.getenv("CLOUD_TYPE");
|
||||
if ("Internal".equals(cloudType)) {
|
||||
return buildClientErrorResult("Deleting apps is now prohibited");
|
||||
}
|
||||
|
||||
boolean result = appMetaProvider.delete(appId);
|
||||
return buildSucceedResult(result);
|
||||
|
|
|
|||
|
|
@ -24,33 +24,14 @@ public class DeployAppComponentRunnerScene extends AbstractLocalDagBase {
|
|||
node("DeployAppTraitNode");
|
||||
|
||||
edge("DeployAppDeciderNode", "DeployAppCreateComponentNode",
|
||||
String.format("#DeployAppDeciderNode['output']['%s'] == '%s' || " +
|
||||
"#DeployAppDeciderNode['output']['%s'] == '%s' || " +
|
||||
"#DeployAppDeciderNode['output']['%s'] == '%s' || " +
|
||||
"#DeployAppDeciderNode['output']['%s'] == '%s' || " +
|
||||
"#DeployAppDeciderNode['output']['%s'] == '%s' || " +
|
||||
"#DeployAppDeciderNode['output']['%s'] == '%s' || " +
|
||||
"#DeployAppDeciderNode['output']['%s'] == '%s' || " +
|
||||
"#DeployAppDeciderNode['output']['%s'] == '%s' || " +
|
||||
"#DeployAppDeciderNode['output']['%s'] == '%s'",
|
||||
AppFlowParamKey.COMPONENT_TYPE,
|
||||
ComponentTypeEnum.K8S_MICROSERVICE,
|
||||
AppFlowParamKey.COMPONENT_TYPE,
|
||||
ComponentTypeEnum.INTERNAL_ADDON,
|
||||
AppFlowParamKey.COMPONENT_TYPE,
|
||||
ComponentTypeEnum.ABM_CHART,
|
||||
AppFlowParamKey.COMPONENT_TYPE,
|
||||
ComponentTypeEnum.HELM,
|
||||
AppFlowParamKey.COMPONENT_TYPE,
|
||||
ComponentTypeEnum.ABM_OPERATOR_TVD,
|
||||
AppFlowParamKey.COMPONENT_TYPE,
|
||||
ComponentTypeEnum.ABM_KUSTOMIZE,
|
||||
AppFlowParamKey.COMPONENT_TYPE,
|
||||
ComponentTypeEnum.ABM_HELM,
|
||||
AppFlowParamKey.COMPONENT_TYPE,
|
||||
ComponentTypeEnum.ASI_COMPONENT,
|
||||
AppFlowParamKey.COMPONENT_TYPE,
|
||||
ComponentTypeEnum.K8S_JOB));
|
||||
String.format("#DeployAppDeciderNode['output']['%s'] != '%s' && " +
|
||||
"#DeployAppDeciderNode['output']['%s'] != '%s' && " +
|
||||
"#DeployAppDeciderNode['output']['%s'] != '%s' && " +
|
||||
"#DeployAppDeciderNode['output']['%s'] != '%s'",
|
||||
AppFlowParamKey.COMPONENT_TYPE, ComponentTypeEnum.RESOURCE_ADDON,
|
||||
AppFlowParamKey.COMPONENT_TYPE, ComponentTypeEnum.TRAIT_ADDON,
|
||||
AppFlowParamKey.COMPONENT_TYPE, ComponentTypeEnum.CUSTOM_ADDON,
|
||||
AppFlowParamKey.COMPONENT_TYPE, ""));
|
||||
edge("DeployAppDeciderNode", "DeployAppCreateResourceAddonNode",
|
||||
String.format("#DeployAppDeciderNode['output']['%s'] == '%s'",
|
||||
AppFlowParamKey.COMPONENT_TYPE,
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@ import org.springframework.stereotype.Service;
|
|||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Cluster 服务
|
||||
|
|
@ -48,8 +47,8 @@ public class ClusterProviderImpl implements ClusterProvider {
|
|||
public Pagination<ClusterDTO> queryByCondition(ClusterQueryReq request) {
|
||||
ClusterQueryCondition condition = new ClusterQueryCondition();
|
||||
ClassUtil.copy(request, condition);
|
||||
List<ClusterDO> results = clusterService.list(condition);
|
||||
return Pagination.valueOf(results, item -> clusterConvert.to(item));
|
||||
Pagination<ClusterDO> results = clusterService.list(condition);
|
||||
return Pagination.transform(results, item -> clusterConvert.to(item));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -117,8 +116,9 @@ public class ClusterProviderImpl implements ClusterProvider {
|
|||
|
||||
// 如果设置某个集群的 masterFlag 为 true,那么设置其余所有 cluster 的 masterFlag 为 false
|
||||
if (request.getMasterFlag() != null && request.getMasterFlag()) {
|
||||
List<ClusterDO> allClusters = clusterService.list(ClusterQueryCondition.builder().build());
|
||||
for (ClusterDO cluster : allClusters) {
|
||||
ClusterQueryCondition condition = ClusterQueryCondition.builder().build();
|
||||
Pagination<ClusterDO> allClusters = clusterService.list(condition);
|
||||
for (ClusterDO cluster : allClusters.getItems()) {
|
||||
if (cluster.getClusterId().equals(clusterId)) {
|
||||
continue;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,4 +20,6 @@ public class ClusterQueryCondition extends BaseCondition {
|
|||
private String clusterId;
|
||||
|
||||
private String clusterName;
|
||||
|
||||
private String clusterType;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,12 +3,11 @@ package com.alibaba.tesla.appmanager.server.repository.condition;
|
|||
import com.alibaba.tesla.appmanager.common.BaseCondition;
|
||||
import com.alibaba.tesla.appmanager.common.enums.DeployComponentStateEnum;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.SuperBuilder;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Component 部署单查询条件类
|
||||
|
|
@ -37,6 +36,8 @@ public class DeployComponentQueryCondition extends BaseCondition {
|
|||
|
||||
private DeployComponentStateEnum deployStatus;
|
||||
|
||||
private List<DeployComponentStateEnum> deployStatusList;
|
||||
|
||||
private Long deployProcessId;
|
||||
|
||||
private String orderBy;
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ public class ClusterRepositoryImpl implements ClusterRepository {
|
|||
|
||||
@Override
|
||||
public List<ClusterDO> selectByCondition(ClusterQueryCondition condition) {
|
||||
condition.doPagination();
|
||||
return clusterDOMapper.selectByExample(buildExample(condition));
|
||||
}
|
||||
|
||||
|
|
@ -53,6 +54,9 @@ public class ClusterRepositoryImpl implements ClusterRepository {
|
|||
if (StringUtils.isNotEmpty(condition.getClusterName())) {
|
||||
criteria.andClusterNameEqualTo(condition.getClusterName());
|
||||
}
|
||||
if (StringUtils.isNotEmpty(condition.getClusterType())) {
|
||||
criteria.andClusterTypeEqualTo(condition.getClusterType());
|
||||
}
|
||||
return example;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import org.springframework.stereotype.Service;
|
|||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
@Slf4j
|
||||
|
|
@ -89,6 +90,11 @@ public class DeployComponentRepositoryImpl implements DeployComponentRepository
|
|||
if (condition.getDeployStatus() != null) {
|
||||
criteria.andDeployStatusEqualTo(condition.getDeployStatus().name());
|
||||
}
|
||||
if (condition.getDeployStatusList() != null && condition.getDeployStatusList().size() > 0) {
|
||||
criteria.andDeployStatusIn(condition.getDeployStatusList().stream()
|
||||
.map(Enum::name)
|
||||
.collect(Collectors.toList()));
|
||||
}
|
||||
if (condition.getDeployProcessId() != null && condition.getDeployProcessId() > 0) {
|
||||
criteria.andDeployProcessIdEqualTo(String.valueOf(condition.getDeployProcessId()));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,9 @@
|
|||
package com.alibaba.tesla.appmanager.server.service.cluster;
|
||||
|
||||
import com.alibaba.tesla.appmanager.common.pagination.Pagination;
|
||||
import com.alibaba.tesla.appmanager.server.repository.condition.ClusterQueryCondition;
|
||||
import com.alibaba.tesla.appmanager.server.repository.domain.ClusterDO;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 集群服务
|
||||
*
|
||||
|
|
@ -18,7 +17,7 @@ public interface ClusterService {
|
|||
* @param condition 请求数据
|
||||
* @return 查询结果
|
||||
*/
|
||||
List<ClusterDO> list(ClusterQueryCondition condition);
|
||||
Pagination<ClusterDO> list(ClusterQueryCondition condition);
|
||||
|
||||
/**
|
||||
* 获取指定 clusterId 对应的数据
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package com.alibaba.tesla.appmanager.server.service.cluster.impl;
|
|||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.alibaba.tesla.appmanager.common.exception.AppErrorCode;
|
||||
import com.alibaba.tesla.appmanager.common.exception.AppException;
|
||||
import com.alibaba.tesla.appmanager.common.pagination.Pagination;
|
||||
import com.alibaba.tesla.appmanager.server.repository.ClusterRepository;
|
||||
import com.alibaba.tesla.appmanager.server.repository.condition.ClusterQueryCondition;
|
||||
import com.alibaba.tesla.appmanager.server.repository.domain.ClusterDO;
|
||||
|
|
@ -14,6 +15,7 @@ import org.springframework.beans.factory.annotation.Autowired;
|
|||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
@Service
|
||||
@Slf4j
|
||||
|
|
@ -29,8 +31,9 @@ public class ClusterServiceImpl implements ClusterService {
|
|||
* @return 查询结果
|
||||
*/
|
||||
@Override
|
||||
public List<ClusterDO> list(ClusterQueryCondition condition) {
|
||||
return clusterRepository.selectByCondition(condition);
|
||||
public Pagination<ClusterDO> list(ClusterQueryCondition condition) {
|
||||
List<ClusterDO> result = clusterRepository.selectByCondition(condition);
|
||||
return Pagination.valueOf(result, Function.identity());
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ import java.util.concurrent.ConcurrentMap;
|
|||
**/
|
||||
@Service
|
||||
@Slf4j
|
||||
public class ComponentPackageManager implements ApplicationListener<ComponentPackageLoadEvent> {
|
||||
public class ComponentPackageBuilderExecutorManager implements ApplicationListener<ComponentPackageLoadEvent> {
|
||||
@Autowired
|
||||
private ApplicationContext context;
|
||||
|
||||
|
|
@ -21,7 +21,7 @@ import com.alibaba.tesla.appmanager.server.repository.condition.ComponentPackage
|
|||
import com.alibaba.tesla.appmanager.server.repository.domain.ComponentPackageDO;
|
||||
import com.alibaba.tesla.appmanager.server.repository.domain.ComponentPackageTaskDO;
|
||||
import com.alibaba.tesla.appmanager.server.service.componentpackage.ComponentPackageBuilderService;
|
||||
import com.alibaba.tesla.appmanager.server.service.componentpackage.ComponentPackageManager;
|
||||
import com.alibaba.tesla.appmanager.server.service.componentpackage.ComponentPackageBuilderExecutorManager;
|
||||
import com.alibaba.tesla.appmanager.server.service.componentpackage.handler.BuildComponentHandler;
|
||||
import com.alibaba.tesla.appmanager.server.service.componentpackage.instance.ComponentPackageBase;
|
||||
import com.alibaba.tesla.appmanager.server.storage.Storage;
|
||||
|
|
@ -49,7 +49,7 @@ public class ComponentPackageBuilderServiceImpl implements ComponentPackageBuild
|
|||
@Autowired
|
||||
private PackageProperties packageProperties;
|
||||
@Autowired
|
||||
private ComponentPackageManager componentPackageManager;
|
||||
private ComponentPackageBuilderExecutorManager componentPackageBuilderExecutorManager;
|
||||
@Autowired
|
||||
private ComponentPackageTaskRepository componentPackageTaskRepository;
|
||||
@Autowired
|
||||
|
|
@ -178,7 +178,7 @@ public class ComponentPackageBuilderServiceImpl implements ComponentPackageBuild
|
|||
switch (componentType) {
|
||||
case K8S_MICROSERVICE:
|
||||
case K8S_JOB: {
|
||||
ComponentPackageBase instance = componentPackageManager.getInstance(componentType.name());
|
||||
ComponentPackageBase instance = componentPackageBuilderExecutorManager.getInstance(componentType.name());
|
||||
instance.exportComponentPackage(taskDO);
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -266,10 +266,14 @@ public class ImageBuilderServiceImpl implements ImageBuilderService {
|
|||
throws IOException {
|
||||
Jinjava jinjava = new Jinjava();
|
||||
Path dockerfileTemplate;
|
||||
String dockerfileTemplateStr = request.getDockerfileTemplate();
|
||||
if (StringUtils.isEmpty(dockerfileTemplateStr)) {
|
||||
dockerfileTemplateStr = "Dockerfile";
|
||||
}
|
||||
if (StringUtils.isEmpty(request.getRepoPath())) {
|
||||
dockerfileTemplate = Paths.get(cloneDir.toString(), request.getDockerfileTemplate());
|
||||
dockerfileTemplate = Paths.get(cloneDir.toString(), dockerfileTemplateStr);
|
||||
} else {
|
||||
dockerfileTemplate = Paths.get(cloneDir.toString(), request.getRepoPath(), request.getDockerfileTemplate());
|
||||
dockerfileTemplate = Paths.get(cloneDir.toString(), request.getRepoPath(), dockerfileTemplateStr);
|
||||
}
|
||||
String template = FileUtils.readFileToString(dockerfileTemplate.toFile(), StandardCharsets.UTF_8);
|
||||
String renderedTemplate = jinjava.render(template, request.getDockerfileTemplateArgs());
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
package com.alibaba.tesla.appmanager.server.service.informer;
|
||||
|
||||
import com.alibaba.tesla.appmanager.common.enums.ClusterTypeEnum;
|
||||
import com.alibaba.tesla.appmanager.common.enums.DynamicScriptKindEnum;
|
||||
import com.alibaba.tesla.appmanager.common.exception.AppErrorCode;
|
||||
import com.alibaba.tesla.appmanager.common.exception.AppException;
|
||||
import com.alibaba.tesla.appmanager.common.pagination.Pagination;
|
||||
import com.alibaba.tesla.appmanager.dynamicscript.core.GroovyHandlerFactory;
|
||||
import com.alibaba.tesla.appmanager.dynamicscript.core.GroovyHandlerItem;
|
||||
import com.alibaba.tesla.appmanager.kubernetes.KubernetesClientFactory;
|
||||
|
|
@ -61,14 +63,16 @@ public class InformerManager {
|
|||
@Scheduled(cron = "${appmanager.cron-job.informer-manager-refresh:0 * * * * *}")
|
||||
@SchedulerLock(name = "informerManagerFactoryRefresh")
|
||||
public void init() throws IOException {
|
||||
List<ClusterDO> clusters = clusterService.list(ClusterQueryCondition.builder().build());
|
||||
for (ClusterDO cluster : clusters) {
|
||||
Pagination<ClusterDO> clusters = clusterService.list(ClusterQueryCondition.builder()
|
||||
.clusterType(ClusterTypeEnum.KUBERNETES.toString())
|
||||
.build());
|
||||
for (ClusterDO cluster : clusters.getItems()) {
|
||||
initCluster(cluster);
|
||||
}
|
||||
|
||||
// 通过差值确认需要删除的集群
|
||||
HashSet<String> clusterIdSet = new HashSet<>(clusterMd5Map.keySet());
|
||||
clusterIdSet.removeAll(clusters.stream().map(ClusterDO::getClusterId).collect(Collectors.toSet()));
|
||||
clusterIdSet.removeAll(clusters.getItems().stream().map(ClusterDO::getClusterId).collect(Collectors.toSet()));
|
||||
for (String clusterId : clusterIdSet) {
|
||||
removeCluster(clusterId);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -523,7 +523,7 @@ public class RtAppInstanceServiceImpl implements RtAppInstanceService {
|
|||
.build());
|
||||
} catch (Exception e) {
|
||||
log.error("cannot getOrCreate application cr|clusterId={}|namespaceId={}|appInstanceId={}|" +
|
||||
"exception={}", clusterId, namespaceId, appInstanceName, e.getMessage());
|
||||
"exception={}", clusterId, namespaceId, appInstanceName, ExceptionUtils.getStackTrace(e));
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,6 +24,14 @@ public interface RtComponentInstanceService {
|
|||
/**
|
||||
* 上报 Component 实例状态
|
||||
*
|
||||
* @param request 上报数据请求
|
||||
* @param ignoreError 是否忽略错误 true or false,错误时抛出 AppException
|
||||
*/
|
||||
void report(ReportRtComponentInstanceStatusReq request, boolean ignoreError);
|
||||
|
||||
/**
|
||||
* 上报 Component 实例状态 (忽略错误)
|
||||
*
|
||||
* @param request 上报数据请求
|
||||
*/
|
||||
void report(ReportRtComponentInstanceStatusReq request);
|
||||
|
|
|
|||
|
|
@ -80,10 +80,11 @@ public class RtComponentInstanceServiceImpl implements RtComponentInstanceServic
|
|||
/**
|
||||
* 上报 Component 实例状态
|
||||
*
|
||||
* @param request 上报数据请求
|
||||
* @param request 上报数据请求
|
||||
* @param ignoreError 是否忽略错误 true or false,错误时抛出 AppException
|
||||
*/
|
||||
@Override
|
||||
public void report(ReportRtComponentInstanceStatusReq request) {
|
||||
public void report(ReportRtComponentInstanceStatusReq request, boolean ignoreError) {
|
||||
String componentInstanceId = request.getComponentInstanceId();
|
||||
RtComponentInstanceQueryCondition condition = RtComponentInstanceQueryCondition.builder()
|
||||
.componentInstanceId(componentInstanceId)
|
||||
|
|
@ -105,12 +106,18 @@ public class RtComponentInstanceServiceImpl implements RtComponentInstanceServic
|
|||
.stageId(request.getStageId())
|
||||
.build());
|
||||
if (appInstance == null) {
|
||||
log.warn("action=componentInstanceStatusReport|cannot find app instance by component instance query " +
|
||||
"condition|appInstanceId={}|componentInstanceId={}|appId={}|clusterId={}|namespaceId={}|" +
|
||||
"componentName={}|status={}", appInstanceId, componentInstanceId,
|
||||
String errorMessage = String.format("action=componentInstanceStatusReport|cannot find app instance by " +
|
||||
"component instance query condition|appInstanceId=%s|componentInstanceId=%s|appId=%s|" +
|
||||
"clusterId=%s|namespaceId=%s|componentName=%s|status=%s",
|
||||
appInstanceId, componentInstanceId,
|
||||
request.getAppId(), request.getClusterId(), request.getNamespaceId(), request.getComponentName(),
|
||||
request.getStatus());
|
||||
return;
|
||||
if (ignoreError) {
|
||||
log.warn(errorMessage);
|
||||
return;
|
||||
} else {
|
||||
throw new AppException(AppErrorCode.UNKNOWN_ERROR, errorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
// 获取 component type 对象实例
|
||||
|
|
@ -131,7 +138,13 @@ public class RtComponentInstanceServiceImpl implements RtComponentInstanceServic
|
|||
record.setConditions(JSONObject.toJSONString(request.getConditions()));
|
||||
int updated = repository.updateByCondition(record, condition);
|
||||
if (updated == 0) {
|
||||
log.debug("report request has ignored because of lock version|condition={}", conditionStr);
|
||||
if (ignoreError) {
|
||||
log.debug("report request has ignored because of lock version|condition={}", conditionStr);
|
||||
} else {
|
||||
throw new AppException(AppErrorCode.LOCKER_VERSION_EXPIRED,
|
||||
String.format("report request has ignored because of lock version|condition=%s",
|
||||
conditionStr));
|
||||
}
|
||||
} else {
|
||||
log.debug("report request has processed|condition={}", conditionStr);
|
||||
}
|
||||
|
|
@ -154,7 +167,13 @@ public class RtComponentInstanceServiceImpl implements RtComponentInstanceServic
|
|||
try {
|
||||
repository.insert(record);
|
||||
} catch (Exception e) {
|
||||
log.info("report request has ignored because of race condition|condition={}", conditionStr);
|
||||
if (ignoreError) {
|
||||
log.info("report request has ignored because of race condition|condition={}", conditionStr);
|
||||
} else {
|
||||
throw new AppException(AppErrorCode.LOCKER_VERSION_EXPIRED,
|
||||
String.format("report request has ignored becuase of race condition|condition=%s",
|
||||
conditionStr));
|
||||
}
|
||||
}
|
||||
}
|
||||
log.info("action=componentInstanceStatusReport|component instance status has reported|appInstanceId={}|" +
|
||||
|
|
@ -166,6 +185,16 @@ public class RtComponentInstanceServiceImpl implements RtComponentInstanceServic
|
|||
rtAppInstanceService.asyncTriggerStatusUpdate(appInstanceId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 上报 Component 实例状态 (忽略错误)
|
||||
*
|
||||
* @param request 上报数据请求
|
||||
*/
|
||||
@Override
|
||||
public void report(ReportRtComponentInstanceStatusReq request) {
|
||||
report(request, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取实时 component instance 状态列表
|
||||
*
|
||||
|
|
@ -193,8 +222,8 @@ public class RtComponentInstanceServiceImpl implements RtComponentInstanceServic
|
|||
/**
|
||||
* 查询当前的组件实例,如果存在则返回,否则返回 null
|
||||
*
|
||||
* @param condition 查询条件 (appId/componentType/componentName/clusterId/namespaceId/stageId 必选,
|
||||
* clusterId/namespaceId/stage 可为空)
|
||||
* @param condition 查询条件 (appId/componentType/componentName/clusterId/namespaceId/stageId 必选,
|
||||
* clusterId/namespaceId/stage 可为空)
|
||||
* @return 实时组件实例 DO 对象 or null
|
||||
*/
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -0,0 +1,67 @@
|
|||
apiVersion: core.oam.dev/v1alpha2
|
||||
kind: ApplicationConfiguration
|
||||
metadata:
|
||||
annotations:
|
||||
appId: testapp
|
||||
appInstanceName: "test-app-instance"
|
||||
name: deploy-abm-status
|
||||
spec:
|
||||
parameterValues:
|
||||
- name: "kubeconfig"
|
||||
value: "fake_config"
|
||||
- name: "namespaceId"
|
||||
value: "default"
|
||||
components:
|
||||
- revisionName: ABM_KUSTOMIZE|kustomize-demo-chart@0.0.2@test|_
|
||||
scopes:
|
||||
- scopeRef:
|
||||
apiVersion: flyadmin.alibaba.com/v1alpha1
|
||||
kind: Cluster
|
||||
name: "{{ Global.clusterId }}"
|
||||
- scopeRef:
|
||||
apiVersion: flyadmin.alibaba.com/v1alpha1
|
||||
kind: Namespace
|
||||
name: "{{ Global.namespaceId }}"
|
||||
parameterValues:
|
||||
- name: kubeconfig
|
||||
value: "{{ Global.kubeconfig }}"
|
||||
toFieldPaths:
|
||||
- spec.base64Kubeconfig
|
||||
- name: path
|
||||
value: "overlays/staging"
|
||||
toFieldPaths:
|
||||
- spec.path
|
||||
- revisionName: ABM_STATUS|general-status@kustomize-demo-chart|_
|
||||
scopes:
|
||||
- scopeRef:
|
||||
apiVersion: flyadmin.alibaba.com/v1alpha1
|
||||
kind: Cluster
|
||||
name: "{{ Global.clusterId }}"
|
||||
- scopeRef:
|
||||
apiVersion: flyadmin.alibaba.com/v1alpha1
|
||||
kind: Namespace
|
||||
name: "{{ Global.namespaceId }}"
|
||||
dependencies:
|
||||
- component: ABM_KUSTOMIZE|kustomize-demo-chart@0.0.2@test
|
||||
parameterValues:
|
||||
- name: kubeconfig
|
||||
value: "{{ Global.kubeconfig }}"
|
||||
toFieldPaths:
|
||||
- spec.base64Kubeconfig
|
||||
- name: options
|
||||
value:
|
||||
groups:
|
||||
- namespace: default
|
||||
labels:
|
||||
a: b
|
||||
c: d
|
||||
resources:
|
||||
- v1/pods
|
||||
- batch/v1/jobs
|
||||
- namespace: n1
|
||||
labels:
|
||||
e: f
|
||||
resources:
|
||||
- pods
|
||||
toFieldPaths:
|
||||
- spec.options
|
||||
|
|
@ -4,9 +4,7 @@ import com.alibaba.fastjson.JSONObject;
|
|||
import com.alibaba.tesla.appmanager.domain.core.WorkloadResource;
|
||||
import com.alibaba.tesla.appmanager.domain.schema.DeployAppSchema;
|
||||
import com.alibaba.tesla.appmanager.domain.schema.TraitDefinition;
|
||||
import io.fabric8.kubernetes.api.model.OwnerReference;
|
||||
import org.apache.commons.lang3.NotImplementedException;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
/**
|
||||
* Trait 实现基类
|
||||
|
|
@ -38,7 +36,7 @@ public class BaseTrait implements Trait {
|
|||
/**
|
||||
* Owner Reference
|
||||
*/
|
||||
private OwnerReference ownerReference;
|
||||
private String ownerReference;
|
||||
|
||||
/**
|
||||
* 绑定到当前 Trait 的 SpecComponent 对象
|
||||
|
|
@ -80,13 +78,14 @@ public class BaseTrait implements Trait {
|
|||
this.component = component;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getOwnerReference() {
|
||||
return this.ownerReference;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOwnerReference(String ownerReference) {
|
||||
if (StringUtils.isNotEmpty(ownerReference)) {
|
||||
this.ownerReference = JSONObject.parseObject(ownerReference, OwnerReference.class);
|
||||
} else {
|
||||
this.ownerReference = null;
|
||||
}
|
||||
this.ownerReference = ownerReference;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ package com.alibaba.tesla.appmanager.trait;
|
|||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.alibaba.tesla.appmanager.domain.core.TaskExecutor;
|
||||
import com.alibaba.tesla.appmanager.domain.core.WorkloadBinder;
|
||||
import io.fabric8.kubernetes.api.model.OwnerReference;
|
||||
|
||||
/**
|
||||
* Trait 接口定义
|
||||
|
|
|
|||
|
|
@ -11,8 +11,10 @@ import com.alibaba.tesla.appmanager.domain.schema.TraitDefinition;
|
|||
import com.alibaba.tesla.appmanager.kubernetes.KubernetesClientFactory;
|
||||
import com.alibaba.tesla.appmanager.spring.util.SpringBeanUtil;
|
||||
import com.alibaba.tesla.appmanager.trait.BaseTrait;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import io.fabric8.kubernetes.api.model.OwnerReference;
|
||||
import io.fabric8.kubernetes.api.model.Service;
|
||||
import io.fabric8.kubernetes.api.model.ServiceBuilder;
|
||||
import io.fabric8.kubernetes.api.model.ServiceSpec;
|
||||
|
|
@ -48,6 +50,7 @@ public class ServiceTrait extends BaseTrait {
|
|||
|
||||
// 获取基本信息
|
||||
String namespace = workloadRef.getMetadata().getNamespace();
|
||||
String ownerReference = getOwnerReference();
|
||||
|
||||
// 支持多个 Service 配置
|
||||
JSONArray services = getSpec().getJSONArray("services");
|
||||
|
|
@ -70,8 +73,8 @@ public class ServiceTrait extends BaseTrait {
|
|||
if (spec == null) {
|
||||
throw new AppException(AppErrorCode.INVALID_USER_ARGS, "spec is required in service trait");
|
||||
}
|
||||
JSONObject cr = generateService(namespace, name, labels, annotations, spec);
|
||||
applyService(clusterId, cr, namespace, name, labels, annotations);
|
||||
JSONObject cr = generateService(namespace, name, labels, annotations, ownerReference, spec);
|
||||
applyService(clusterId, cr, namespace, name, labels, annotations, ownerReference);
|
||||
}
|
||||
} else {
|
||||
String name = workloadRef.getMetadata().getName();
|
||||
|
|
@ -87,8 +90,8 @@ public class ServiceTrait extends BaseTrait {
|
|||
if (annotations.size() == 0) {
|
||||
annotations = (JSONObject) workloadRef.getMetadata().getAnnotations();
|
||||
}
|
||||
JSONObject cr = generateService(namespace, name, labels, annotations, getSpec());
|
||||
applyService(clusterId, cr, namespace, name, labels, annotations);
|
||||
JSONObject cr = generateService(namespace, name, labels, annotations, ownerReference, getSpec());
|
||||
applyService(clusterId, cr, namespace, name, labels, annotations, ownerReference);
|
||||
|
||||
// 写入暴露值
|
||||
getSpec().put("serviceName", name);
|
||||
|
|
@ -97,15 +100,18 @@ public class ServiceTrait extends BaseTrait {
|
|||
|
||||
/**
|
||||
* 应用 Service 到集群中
|
||||
* @param clusterId 集群 ID
|
||||
* @param cr CR
|
||||
* @param namespace Namespace
|
||||
* @param name Name
|
||||
* @param labels Labels
|
||||
* @param annotations Annotations
|
||||
*
|
||||
* @param clusterId 集群 ID
|
||||
* @param cr CR
|
||||
* @param namespace Namespace
|
||||
* @param name Name
|
||||
* @param labels Labels
|
||||
* @param annotations Annotations
|
||||
* @param ownerReference Owner Reference
|
||||
*/
|
||||
private void applyService(
|
||||
String clusterId, JSONObject cr, String namespace, String name, JSONObject labels, JSONObject annotations) {
|
||||
String clusterId, JSONObject cr, String namespace, String name, JSONObject labels,
|
||||
JSONObject annotations, String ownerReference) {
|
||||
KubernetesClientFactory clientFactory = SpringBeanUtil.getBean(KubernetesClientFactory.class);
|
||||
DefaultKubernetesClient client = clientFactory.get(clusterId);
|
||||
// 应用到集群
|
||||
|
|
@ -135,15 +141,34 @@ public class ServiceTrait extends BaseTrait {
|
|||
Service result = client.services()
|
||||
.inNamespace(namespace)
|
||||
.withName(name)
|
||||
.edit(s -> new ServiceBuilder(s)
|
||||
.editMetadata()
|
||||
.withLabels(JSON.parseObject(finalLabels.toJSONString(), new TypeReference<Map<String, String>>() {
|
||||
}))
|
||||
.withAnnotations(JSON.parseObject(finalAnnotations.toJSONString(), new TypeReference<Map<String, String>>() {
|
||||
}))
|
||||
.endMetadata()
|
||||
.withSpec(newSpec)
|
||||
.build());
|
||||
.edit(s -> {
|
||||
if (StringUtils.isNotEmpty(ownerReference)) {
|
||||
try {
|
||||
return new ServiceBuilder(s)
|
||||
.editMetadata()
|
||||
.withLabels(JSON.parseObject(finalLabels.toJSONString(), new TypeReference<Map<String, String>>() {
|
||||
}))
|
||||
.withAnnotations(JSON.parseObject(finalAnnotations.toJSONString(), new TypeReference<Map<String, String>>() {
|
||||
}))
|
||||
.withOwnerReferences(mapper.readValue(ownerReference, OwnerReference.class))
|
||||
.endMetadata()
|
||||
.withSpec(newSpec)
|
||||
.build();
|
||||
} catch (JsonProcessingException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
} else {
|
||||
return new ServiceBuilder(s)
|
||||
.editMetadata()
|
||||
.withLabels(JSON.parseObject(finalLabels.toJSONString(), new TypeReference<Map<String, String>>() {
|
||||
}))
|
||||
.withAnnotations(JSON.parseObject(finalAnnotations.toJSONString(), new TypeReference<Map<String, String>>() {
|
||||
}))
|
||||
.endMetadata()
|
||||
.withSpec(newSpec)
|
||||
.build();
|
||||
}
|
||||
});
|
||||
log.info("cr yaml has updated in kubernetes|cluster={}|namespace={}|name={}|labels={}|" +
|
||||
"annotations={}|newSpec={}|result={}", clusterId, namespace, name,
|
||||
JSONObject.toJSONString(labels), JSONObject.toJSONString(annotations),
|
||||
|
|
@ -168,13 +193,16 @@ public class ServiceTrait extends BaseTrait {
|
|||
/**
|
||||
* 创建服务 JSON spec
|
||||
*
|
||||
* @param namespace 命名空间
|
||||
* @param name 标识名称
|
||||
* @param spec spec 定义
|
||||
* @param namespace 命名空间
|
||||
* @param name 标识名称
|
||||
* @param labels Labels
|
||||
* @param annotations Annotations
|
||||
* @param spec spec 定义
|
||||
* @return JSONObject
|
||||
*/
|
||||
private JSONObject generateService(
|
||||
String namespace, String name, JSONObject labels, JSONObject annotations, JSONObject spec) {
|
||||
String namespace, String name, JSONObject labels, JSONObject annotations, String ownerReference,
|
||||
JSONObject spec) {
|
||||
String serviceStr = JSONObject.toJSONString(ImmutableMap.of(
|
||||
"apiVersion", "v1",
|
||||
"kind", "Service",
|
||||
|
|
@ -191,6 +219,11 @@ public class ServiceTrait extends BaseTrait {
|
|||
)
|
||||
));
|
||||
JSONObject service = JSONObject.parseObject(serviceStr);
|
||||
if (StringUtils.isNotEmpty(ownerReference)) {
|
||||
service.getJSONObject("metadata").put("ownerReferences", new JSONArray());
|
||||
service.getJSONObject("metadata").getJSONArray("ownerReferences")
|
||||
.add(JSONObject.parseObject(ownerReference));
|
||||
}
|
||||
service.getJSONObject("spec").putAll(spec);
|
||||
return service;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue