本文为您介绍使用云效产品功能遇到的问题与解决方案汇总。
成员使用服务管理实现RAM用户资源共享
当您的组织成员有多个RAM用户时,且每个RAM用户归属的阿里云账号都有自己的云服务资源,云效支持将多个RAM用户的阿里云资源添加至组织,实现云效流水线构建,部署发布任务。
比如,您的组织有 A和 B成员,您可通过添加RAM用户的方式,将 A 和 B成员的ECS云服务资源都加入到您的组织实现资源共享。
通过云效工作台,
,单击添加成员把RAM用户 A 和 B 都加入到您的组织。成员 A 和 B 分别登录云效,并在服务连接管理中分别添加 A 和 B 的 ECS 服务连接,使用范围具体结合自己的需求选择。
重要如果成员是RAM用户(子账号),可能会出现授权失败的情况,请联系阿里云账号为RAM用户授权AliyunRAMFullAccess权限。
服务连接创建完成后,
,可切换不同账号下的RAM授权来使用服务连接。
授权管理—添加多个阿里云账号的授权服务
当您需要将其他阿里云账号添加到组织中时,可在添加成员中通过链接邀请,复制邀请链接发送给相应成员,被邀请者只需打开链接并接受邀请,即可加入到对应云效组织。
通过钉钉进行人工卡点审批
目前流水线Flow支持添加
任务插件,您可以在Flow流水线中,添加人工卡点任务,实现钉钉接收发布前的审批确认,直接在钉钉客户端上操作流水线Flow审批任务。步骤一:绑定钉钉组织和个人信息
组织绑定:组织。
个人绑定:组织。
步骤二:流水线添加人工卡点并执行流水线
在流水线编排中,添加人工卡点组件。
选择具体的验证方式、验证者类型和验证人,保存触发流水线运行。
收到钉钉审批消息,进行验证操作。
解析红线异常问题
解析红线异常的问题排查与解决方案。
复制错误信息
单击错误信息,弹框出来的内容复制出来 .
双击复制红线信息。
运行排查用例
将红线信息数据放入下面用例里进行调试,排查问题.
排查所用到的示例代码如下:
import com.alibaba.fastjson.JSON; import java.io.Serializable; import java.lang.reflect.Field; import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; public class StatInfoTest { private static Pattern STAT_INFO_TITLE_PATTERN = Pattern.compile("^STAT_INFO_TITLE:\\s*(.+)\\s*"); private static Pattern REDLINE_INFO_PATTERN = Pattern.compile("^REDLINE_ITEM_LINE:\\s*(.+)\\s*"); private static Pattern STAT_PATTERN = Pattern.compile("^STAT_(VALUE|NAME|TITLE|URL|STYLE)_([^:]+):\\s*(.*)\\s*"); public static void main(String[] args) { // 下面为一个失败的示例数据 //String statOutMapStr = "{\"10_1682051393916__10_1682051404781\":[\"STAT_INFO_TITLE: \\\"\\\"\",\"STAT_NAME_Total: 缺陷\",\"STAT_VALUE_Total: ww\",\"STAT_STYLE_Total: Error\",\"STAT_NAME_Blocker: 漏洞\",\"STAT_VALUE_Blocker: ww\",\"STAT_STYLE_Blocker: Warning\",\"REDLINE_ITEM_LINE: {\\\"key\\\":\\\"Blocker\\\",\\\"threshold\\\":43,\\\"checkVal\\\":ww,\\\"type\\\":\\\"LE\\\",\\\"checked\\\":true,\\\"checkResult\\\":false}\",\"STAT_NAME_Critical: 坏味道\",\"STAT_VALUE_Critical: ww\",\"STAT_STYLE_Critical: Warning\",\"REDLINE_ITEM_LINE: {\\\"key\\\":\\\"Critical\\\",\\\"threshold\\\":34,\\\"checkVal\\\":ww,\\\"type\\\":\\\"LE\\\",\\\"checked\\\":true,\\\"checkResult\\\":false}\",\"STAT_NAME_Major: 覆盖率\",\"STAT_VALUE_Major: ww0\",\"STAT_STYLE_Major: Default\",\"REDLINE_ITEM_LINE: {\\\"key\\\":\\\"Major\\\",\\\"threshold\\\":4,\\\"checkVal\\\":ww0,\\\"type\\\":\\\"LE\\\",\\\"checked\\\":true,\\\"checkResult\\\":false}\",\"STAT_URL__REPORT: 127.0.0.1/dashboard?id=13212323%3A31313213213\"]}"; String statOutMapStr="请将卡片上的数据信息复制到此处进行调试"; parseStatInfo(statOutMapStr); } public static void parseStatInfo(String statOutMapStr) { Map<String, List<String>> statOutMap = JSON.parseObject(statOutMapStr, new HashMap<String, List<String>>().getClass()); List<StatGroup> statGroups = new ArrayList<>(); statOutMap.forEach((k, params) -> { StatGroup statGroup = new StatGroup<StatInfo>(); Map<String, StatInfo> statInfoMap = new LinkedHashMap<>(64); List<RedlineResultItem> redlines = new ArrayList<>(64); Optional.ofNullable(params).orElse(new ArrayList<>()) .forEach(str -> { Matcher matcher = STAT_PATTERN.matcher(str); if (matcher.find()) { String fieldName = matcher.group(1).toLowerCase(); String key = matcher.group(2); String value = matcher.group(3); StatInfo statInfo = statInfoMap.get(key); if (statInfo == null) { statInfo = new StatInfo(); statInfo.setKey(key); } statInfo.setField(fieldName, value); statInfoMap.put(key, statInfo); } // check redlines Matcher redlineMatcher = REDLINE_INFO_PATTERN.matcher(str); if (redlineMatcher.find()) { String redlineResult = redlineMatcher.group(1); RedlineResultItem redlineItem = JSON.parseObject(redlineResult, RedlineResultItem.class); // check if valid redline item if (redlineItem.getKey() != "" && redlineItem.getThreshold() != null) { redlines.add(redlineItem); } } }); statGroup.setTitle(getStatInfoTitle(params)); statGroup.setStatInfoMap(statInfoMap); statGroup.setRedlineResult(redlines); statGroups.add(statGroup); }); System.out.println(JSON.toJSONString(statGroups)); } private static String getStatInfoTitle(List<String> params) { String title = null; if (params != null) { for (String param : params) { Matcher matcher = STAT_INFO_TITLE_PATTERN.matcher(param); if (matcher.find()) { title = matcher.group(1); break; } } } return title; } static class StatGroup<T> { private String title; private Map<String, T> statInfoMap; private List<RedlineResultItem> redlineResult; public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public Map<String, T> getStatInfoMap() { return statInfoMap; } public void setStatInfoMap(Map<String, T> statInfoMap) { this.statInfoMap = statInfoMap; } public List<RedlineResultItem> getRedlineResult() { return redlineResult; } public void setRedlineResult( List<RedlineResultItem> redlineResult) { this.redlineResult = redlineResult; } } public static class RedlineResultItem { private String key; private Integer threshold; private Integer checkVal; private String type; private Boolean checked; private Boolean checkResult; public String getKey() { return key; } public void setKey(String key) { this.key = key; } public Integer getThreshold() { return threshold; } public void setThreshold(Integer threshold) { this.threshold = threshold; } public Integer getCheckVal() { return checkVal; } public void setCheckVal(Integer checkVal) { this.checkVal = checkVal; } public String getType() { return type; } public void setType(String type) { this.type = type; } public Boolean getChecked() { return checked; } public void setChecked(Boolean checked) { this.checked = checked; } public Boolean getCheckResult() { return checkResult; } public void setCheckResult(Boolean checkResult) { this.checkResult = checkResult; } } static class StatInfo implements Serializable { private static final long serialVersionUID = -7424772230982171781L; private String key; private String value; private String name; private String title; private String style; private String url; public String getKey() { return key; } public void setKey(String key) { this.key = key; } public String getValue() { return value; } public void setValue(String value) { this.value = value; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getStyle() { return style; } public void setStyle(String style) { this.style = style; } public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } public void setField(String fieldName, String value) { try { Field field = getClass().getDeclaredField(fieldName); field.set(this, value); } catch (Exception e) { } } } }
jenkins任务步骤出现403错误
jenkins任务步骤出现403错误的原因和解决方案。
问题现象
问题原因
调用Jenkins API 支持使用密码和Token两种方式。由于Jenkins在新版本进行了调整,不允许直接使用密码的方式调用API,会返回403报错,所以Jeknis 任务推荐使用API Token。
解决方案
创建API Token打开http://Jenkins_IP:8080/user/admin/configure,注意换成自己真实的Jenkins地址,如果没用admin用户,user后也要替换成存在的用户名,比如:http://localhost:8080/user/wangli/configure。按下图添加Token,记得要将Token复制出来备用,最后点保存按钮。
在流水线中使用API Token选择凭据类型时选择服务连接,然后在新建服务连接,新建服务授权/证书中,依次输入服务地址,用户名和刚生成的Token即可。
调用阿里云产品 API 异常
API异常的常见问题。
排查方案
主账号确认排查AliyunRDCDefaultRole角色是否被删除。
如果AliyunRDCDefaultRole 被删除了,就让主账号参考下图进行重新授权。
如果AliyunRDCDefaultRole 仍存在,请检查AliyunRDCDefaultRole对应的权限策略AliyunRDCRolePolicy是否正确。
如果 AliyunRDCDefaultRole 中有多个权限策略,请删除AliyunRDCRolePolicy以外的其他权限策略。
如果AliyunRDCRolePolicy 不存在,就先删除AliyunRDCDefaultRole,然后再参考方案1重新授权。
如果AliyunRDCRolePolicy 存在,但调用仍报错,就先解除AliyunRDCRolePolicy 授权,然后删除AliyunRDCDefaultRole,最后再参考方案1重新授权。
GetPipelineRun Action说明
Action | 对应API | 功能 | 示例 | 说明 |
PassPipelineValidate | 通过人工卡点 |
| disable: 是否有权限调用 validators:有权限通过人工卡点的用户的aliyunPk | |
RefusePipelineValidate | RefusePipelineValidator | 拒绝人工卡点 |
| disable: 是否有权限调用 validators: 有权限通过人工卡点的用户的aliyunPk |
RetryPipelineJobRun | RetryPipelineJobRun | 重试任务运行 |
| disable: 是否有权限调用 |
StopPipelineJobRun | StopPipelineJobRun | 取消任务运行 |
| disable: 是否有权限调用 |
SkipPipelineJobRun | SkipPipelineJobRun | 跳过失败任务 |
| disable: 是否有权限调用 |
LogPipelineJobRun | LogPipelineJobRun | 查看任务执行日志 |
| disable: 是否有权限调用 |
GetVMDeployOrder | GetVMDeployOrder | 获取ecs部署单详情 |
| disable: 是否有权限调用 deployOrderId: 部署单id |
GetPipelineEmasArtifactUrl | GetPipelineEmasArtifactUrl | 获取EMAS构建产物临时下载地址 |
| serviceConnectionId: 服务连接id files: 构建产物,支持多个构建产物 emasJobInstanceId: emas 任务id md5: 构建产物md5 disable: 是否有权限调用 |
GetPipelineArtifactUrl | GetPipelineArtifactUrl | 获取流水线构建产物临时下载地址 |
| disable: 是否有权限调用 files: 构建产物,支持多个构建产物 fileName: 构建产物名称 filePath: 构建产物路径 |
GetPipelineScanReportUrl | GetPipelineScanReportUrl | 获取扫描报告临时下载地址 | {"disable":false,"type":"GetPipelineScanReportUrl","params":{"reportPath":"assets/1xxx/1xxx/05e0edb9xxxxxxxx/index.html","reportInfo":{"Major":{"name":"issue","style":"text-danger","title":"Major","value":"6","key":"Major",}"Total":{"name":"issue","style":"text-danger","title":"Total","value":"6","key":"Total"}"Critical":{"name":"issue","style":"text-danger","title":"Critical","value":"0","key":"Critical"}"Blocker":{"name":"issue","style":"text-danger","title":"Blocker","value":"0","key":"Blocker"}"_REPORT":{"title":"report","value":"link","key":"_REPORT","url":"https://flow.aliyun.com/assets/2xxxxx/1xxxx/21212xxxxxxxxxxx/index.html"}"File":{"name":"issue","style":"text-danger","title":"File","value":"4","key":"File"}}}} | disable: 有没有权限调用 reportPath: 报告文件路径 reportInfo: 报告信息 |
调用API提示无权限
问题:
调用API接口提示401无权限: com.aliyun.tea.TeaException: code: 401, InvalidParam.NoPermission request 。
解决方案:
出现报错是由于当前账号没有权限调用云效API,如果通过ak,sk 鉴权方式调用,且调用账号为RAM子账号,需要子账号拥有AliyunRDCFullAccess 权限。