2 | Spinnaker orca 如何找到对应的 stage

首先,我们定义的 Stage 都实现了 StageDefinitionBuilder 接口,例如:

1
2
3
4
5
6
7
@Slf4j
@Component
@CompileStatic
class BakeStage implements StageDefinitionBuilder {
public static final String PIPELINE_CONFIG_TYPE = "bake"
// ...
}

其次,看一个 bean StageResolver,它在初始化的时候,将所有的 StageDefinitionBuilder 作为集合传递进去。

1
2
3
4
5
6
7
8
9
@Bean
public StageResolver stageResolver(
Collection<StageDefinitionBuilder> stageDefinitionBuilders,
Optional<Collection<SimpleStage>> simpleStages,
PluginManager pluginManager) {
Collection<SimpleStage> stages = simpleStages.orElseGet(ArrayList::new);
stages.addAll(pluginManager.getExtensions(SimpleStage.class));
return new StageResolver(stageDefinitionBuilders, stages);
}

并将所有的 bean 存入一个 map 中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public StageResolver(
Collection<StageDefinitionBuilder> stageDefinitionBuilders,
Collection<SimpleStage> simpleStages) {
for (StageDefinitionBuilder stageDefinitionBuilder : stageDefinitionBuilders) {
stageDefinitionBuilderByAlias.put(stageDefinitionBuilder.getType(), stageDefinitionBuilder);
for (String alias : stageDefinitionBuilder.aliases()) {
if (stageDefinitionBuilderByAlias.containsKey(alias)) {
throw new DuplicateStageAliasException("xxxooo");
}

stageDefinitionBuilderByAlias.put(alias, stageDefinitionBuilder);
}
}

simpleStages.forEach(
s -> stageDefinitionBuilderByAlias.put(s.getName(), new SimpleStageDefinitionBuilder(s)));
}

其中 map 的 key 与对应的 stage 的关系如下:

  1. type -> stage:stageDefinitionBuilderByAlias.put(stageDefinitionBuilder.getType(), stageDefinitionBuilder)
  2. alias -> stage:stageDefinitionBuilderByAlias.put(alias, stageDefinitionBuilder)

type 的默认实现是以 className 基础,将首字母小写后,去换掉结尾的 “Stage”、”StageDefinitionBuilder”,处理完成后做为 type。代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
/** @return the stage type this builder handles. */
default @Nonnull String getType() {
return getType(this.getClass());
}

static String getType(Class<? extends StageDefinitionBuilder> clazz) {
String className = clazz.getSimpleName();
return className.substring(0, 1).toLowerCase()
+ className
.substring(1)
.replaceFirst("StageDefinitionBuilder$", "")
.replaceFirst("Stage$", "");
}

alias 的获取方式是通过在 stage 的类上的注解:

1
2
3
4
5
6
7
default Collection<String> aliases() {
if (getClass().isAnnotationPresent(Aliases.class)) {
return Arrays.asList(getClass().getAnnotation(Aliases.class).value());
}

return Collections.emptyList();
}

最后,在 StartStageHandlerstage.plan() 方法中,会调用 StageResolvergetStageDefinitionBuilder() 方法。

1
2
3
4
5
@Override
public @Nonnull StageDefinitionBuilder builderFor(@Nonnull Stage stage) {
return stageResolver.getStageDefinitionBuilder(
stage.getType(), (String) stage.getContext().get("alias"));
}

在此方法中,会从 pipeline 相应的 stage 中,获取配置的 type 和 alias,并将它们作为 key,到 StageResolver 的 map stageDefinitionBuilderByAlias 中依次去 get。顺序是先用 type 去取,如果未取到,再用 alias 取到的 stage 对象。

1
2
3
4
5
6
7
8
9
10
11
12
@Nonnull
public StageDefinitionBuilder getStageDefinitionBuilder(@Nonnull String type, String typeAlias) {
StageDefinitionBuilder stageDefinitionBuilder =
stageDefinitionBuilderByAlias.getOrDefault(
type, stageDefinitionBuilderByAlias.get(typeAlias));

if (stageDefinitionBuilder == null) {
throw new NoSuchStageDefinitionBuilderException(type, stageDefinitionBuilderByAlias.keySet());
}

return stageDefinitionBuilder;
}

因此,在编写一个 Stage 类时,需要做完如下两个件事:

  • 在 xxxStage 类中实现 getType() 方法以覆盖默认获取 type 的方法
  • 依靠 xxxStage 类的名称(需要与前端沟通好相应的 type 字段和 alias 字段)

前者比较明显易懂,后者不是特别容易理解,但是 spinnaker 里面大多数是以后者的形式出现的。

2 | Spinnaker orca 如何找到对应的 stage

https://eucham.me/2020/10/31/60b943d025b2.html

作者

遇寻

发布于

2020-10-31

更新于

2022-04-20

许可协议

评论