feat: add owner reference to service trait

This commit is contained in:
doraemonext 2022-06-01 11:31:30 +08:00
parent 0af2a39f3c
commit e853b8c431
37 changed files with 548 additions and 134 deletions

View File

@ -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")

View File

@ -0,0 +1,2 @@
create index idx_cluster_type
on am_cluster (cluster_type);

View File

@ -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()

View File

@ -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"]

View File

@ -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"]

View File

@ -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"]

View File

@ -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 -->

View File

@ -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/**")

View File

@ -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;
}
}

View File

@ -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();

View File

@ -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 模块
*/

View File

@ -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));
}
/**

View File

@ -46,6 +46,15 @@ public class DeployConfigEnvId {
return String.format("Unit:%s", unitId);
}
/**
* 返回空环境字符串标识通用类型
*
* @return 字符串标识
*/
public static String emptyUnitStr() {
return "Unit";
}
/**
* 返回 Stage 字符串标识
*

View File

@ -30,6 +30,13 @@ public interface WorkloadBinder {
*/
void setOwnerReference(String ownerReference);
/**
* 返回 Owner Reference 字符串
*
* @return Owner Reference JSON Object String
*/
String getOwnerReference();
/**
* 获取当前被绑定的 Component 对象
*

View File

@ -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;
}

View File

@ -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)) {

View File

@ -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");

View File

@ -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);

View File

@ -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,

View File

@ -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;
}

View File

@ -20,4 +20,6 @@ public class ClusterQueryCondition extends BaseCondition {
private String clusterId;
private String clusterName;
private String clusterType;
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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()));
}

View File

@ -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 对应的数据

View File

@ -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());
}
/**

View File

@ -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;

View File

@ -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;
}

View File

@ -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());

View File

@ -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);
}

View File

@ -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 "";
}
}

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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 接口定义

View File

@ -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;
}