
# 操作步骤
#### 场景说明
当前示例包含4个组件，分别为componentA、componentB、componentC和componentD。
组件依赖关系为：componentD依赖componentB和componentC，componentB和componentC依赖componentA。
现在使用jenkins流水线来编排部署这4个组件，支持单个或多个组件升级而不用考虑依赖关系单个组件依次升级。
#### 配置jenkins流水线
1. 进入jenkins的系统管理页面，单击"新建任务"。 
   图1新建任务   
   ![](https://support.huaweicloud.com/bestpractice-cae/zh-cn_image_0000001734389969.png "点击放大")
   
   
2. 输入任务名称，选择任务类型为"流水线"。 
   图2创建流水线   
   ![](https://support.huaweicloud.com/bestpractice-cae/zh-cn_image_0000001742927217.png "点击放大")
   
   
3. 在"General"页面中，添加"扩展选项参数"。 
   图3添加参数   
   ![](https://support.huaweicloud.com/bestpractice-cae/zh-cn_image_0000001734357473.png "点击放大")
   
   
4. 参考[图4]配置需要编排的组件。
   
   表1配置构建参数 
   | 参数名称                    | 描述                        | 示例                                          |
   |:---|:---|:---|
   | Name                    | 设置参数的名称，构建时选择的组件会存放在该变量名。 | Model_Name                                  |
   | Description             | 设置构建参数的描述。                | 选择需要升级的组件                                   |
   | Parameter Type          | 选择基本参数类型。                 | Check Boxes                                 |
   | Number of Visible Items | 设置流水线编排的组件数量。             | 4                                           |
   | Delimiter               | 设置组件之间的分隔符，设置为逗号（,）。      | ,                                           |
   | Value                   | 设置流水线编排的组件名称，用逗号（,）分隔。    | componentA,componentB,componentC,componentD |
      
   图4配置构建参数   
   ![](https://support.huaweicloud.com/bestpractice-cae/zh-cn_image_0000001695207152.png "点击放大")
   
   
5. 选择"流水线"，在"流水线"页面进行脚本配置，脚本内容请参考[流水线脚本]。
   
   图5配置流水线脚本   
   ![](https://support.huaweicloud.com/bestpractice-cae/zh-cn_image_0000001734394573.png "点击放大")
   
   
6. 脚本配置完成后，单击"保存"。
 
 #### 流水线脚本
流水线脚本支持componentA、componentB、componentC和componentD，4个组件中的一个或多个同时升级，并且按照依赖顺序先升级componentA，再并行升级componentB和componentC，最后升级componentD。如果构建时没有勾选到的组件会跳过，不执行升级。
```
pipeline {
    agent any
    environment{
        //构建时选择的组件以‘,’隔开的格式存在变量Model_Name里
        //判断变量Model_Name里的可选组件是否存在，如果存在，把组件名赋值给对应变量，如果不存在，把字符串"error"赋值给对应变量。
        //用于判断后续组件是否需要构建
        _componentA="${sh(script:' echo $Model_Name| grep -w -o "componentA" || echo "error" ', returnStdout: true).trim()}"
        _componentB="${sh(script:' echo $Model_Name| grep -w -o "componentB" || echo "error" ', returnStdout: true).trim()}"
        _componentC="${sh(script:' echo $Model_Name| grep -w -o "componentC" || echo "error" ', returnStdout: true).trim()}"
        _componentD="${sh(script:' echo $Model_Name| grep -w -o "componentD" || echo "error" ', returnStdout: true).trim()}"
    }
    stages {
        stage('Build componentA') {
            //when条件判断当环境变量"_componentA" = "componentA"时，表示构建时选择了该组件，执行此stage，否则跳过此stage
            when { environment name: '_componentA', value: 'componentA' }
            steps {
               sh ''' echo "start to build componentA" '''
               script{
                  //build(job: 'componentA') 表示执行componentA任务，这个任务是jenkins中创建的任务名称，用于componentA组件升级的任务
                  def componentBuild=build(job: 'componentA')
                  //打印执行任务的结果
                  println componentBuild.getResult()
               }
            }
        }
        stage('Build parallel jobs') {
            //failFast true 表示parallel并行的stage中只要有一个失败，其他并行任务也会中止
            //不加failFast true，parallel中失败的stage不会影响其他并行的stage执行，直到所有的并行任务执行完成
            //failFast true //按需添加 
            //parallel 表示里面的stage是并行执行的，只要其中有一个stage执行失败，则"Build parallel jobs"这个stage是失败的，它后续的stage不会执行
            parallel {
                stage('Build componentB') {
                    when { environment name: '_componentB', value: 'componentB' }
                    steps {
                       sh ''' echo "start to build componentB" '''
                       script{
                          def componentBuild=build(job: 'componentB')
                          println componentBuild.getResult()
                        }
                    }
                }
                stage('Build componentC') {
                    when { environment name: '_componentC', value: 'componentC' }
                    steps {
                       sh ''' echo "start to build componentC" '''
                       script{
                          def componentBuild=build(job: 'componentC')
                          println componentBuild.getResult()
                       }
                    }
                }
            }
        }
        stage('Build componentD') {
            when { environment name: '_componentD', value: 'componentD' }
            steps {
               sh ''' echo "start to build componentD" '''
               script{
                  def componentBuild=build(job: 'componentD')
                  println componentBuild.getResult()
               }
            }
        }
    }
}
```
#### 脚本说明
每个组件都需要在pipeline中的envionment获取组件参数，用于判断参数化构建时是否选中，执行下面脚本：
```
_{component_name}="${sh(script:' echo $Model_Name| grep -w -o "{component_name}" || echo "error" ', returnStdout: true).trim()}"
```
表2参数说明 
| 参数名称             | 描述                                                                                   |
|:---|:---|
| Model_Name       | [配置构建参数]中的Name。                                      |
| {component_name} | [配置构建参数]中的Choose Source for Value中的value里面填写的组件名称之一。 |
   
每个组件都需要配置一个stage，用于组件的升级任务，如果是串行执行的，则按照先后顺序放置stage的位置，如果是并行执行的任务就放置在stage('Build parallel jobs')中的parallel中。
stage脚本：
```
stage('Build {component_name}') {
    
    when { environment name: '_{component_name}', value: '{component_name}' }
    steps {
       sh ''' echo "start to build {component_name}" '''
       script{
          def componentBuild=build(job: '{component_jenkins_task}')
          //打印执行任务的结果
          println componentBuild.getResult()
       }
    }
}
```
表3参数说明 
| 参数                       | 描述                                                                                      |
|:---|:---|
| {component_name}         | [配置构建参数]中的Choose Source for Value中的value里面填写的组件名称之一。    |
| {component_jenkins_task} | jenkins中创建的用于组件升级的任务名称，例如：用于componentA组件升级的任务名称为如[图6]所示。 |
   
图6组件升级任务名称   
![](https://support.huaweicloud.com/bestpractice-cae/zh-cn_image_0000001690035054.png "点击放大")
#### 使用流水线升级多个组件
1. 选择流水线，单击"参数化构建"。 
   图7参数化构建   
   ![](https://support.huaweicloud.com/bestpractice-cae/zh-cn_image_0000001734395229.png "点击放大")
   
   
2. 选择要升级的组件，可以选择一个或多个同时升级，本示例选择全部组件同时升级，单击"开始构建"。 
   图8选择组件   
   ![](https://support.huaweicloud.com/bestpractice-cae/zh-cn_image_0000001734355357.png "点击放大")
   
   
3. 可在构建历史中查看流水线任务执行结果。 
   图9查看执行结果   
   ![](https://support.huaweicloud.com/bestpractice-cae/zh-cn_image_0000001734355565.png "点击放大")
   
   
4. 流水线日志如下所示，可以看出先升级componentA，再并行升级componentB和componentC，最后升级componentD。 
   ```
   Started by user admin
   Running in Durability level: MAX_SURVIVABILITY
   [Pipeline] Start of Pipeline
   [Pipeline] node
   Running on Jenkins in /root/.jenkins/workspace/pipeline-arrange
   [Pipeline] {
   [Pipeline] sh
   + echo componentA,componentB,componentC,componentD
   + grep -w -o componentA
   [Pipeline] sh
   + echo componentA,componentB,componentC,componentD
   + grep -w -o componentD
   [Pipeline] sh
   + echo componentA,componentB,componentC,componentD
   + grep -w -o componentB
   [Pipeline] sh
   + echo componentA,componentB,componentC,componentD
   + grep -w -o componentC
   [Pipeline] withEnv
   [Pipeline] {
   [Pipeline] stage
   [Pipeline] { (Build componentA)
   [Pipeline] sh
   + echo 'start to build componentA'
   start to build componentA
   [Pipeline] script
   [Pipeline] {
   [Pipeline] build
   Scheduling project: componentA
   Starting building: componentA #13
   [Pipeline] echo
   SUCCESS
   [Pipeline] }
   [Pipeline] // script
   [Pipeline] }
   [Pipeline] // stage
   [Pipeline] stage
   [Pipeline] { (Build parallel jobs)
   [Pipeline] parallel
   [Pipeline] { (Branch: Build componentB)
   [Pipeline] { (Branch: Build componentC)
   [Pipeline] stage
   [Pipeline] { (Build componentB)
   [Pipeline] stage
   [Pipeline] { (Build componentC)
   [Pipeline] sh
   [Pipeline] sh
   + echo 'start to build componentB'
   start to build componentB
   [Pipeline] script
   + echo 'start to build componentC'
   start to build componentC
   [Pipeline] {
   [Pipeline] script
   [Pipeline] {
   [Pipeline] build
   Scheduling project: componentB
   [Pipeline] build
   Scheduling project: componentC
   Starting building: componentB #12
   Starting building: componentC #12
   [Pipeline] echo
   SUCCESS
   [Pipeline] }
   [Pipeline] // script
   [Pipeline] }
   [Pipeline] // stage
   [Pipeline] }
   [Pipeline] echo
   SUCCESS
   [Pipeline] }
   [Pipeline] // script
   [Pipeline] }
   [Pipeline] // stage
   [Pipeline] }
   [Pipeline] // parallel
   [Pipeline] }
   [Pipeline] // stage
   [Pipeline] stage
   [Pipeline] { (Build componentD)
   [Pipeline] sh
   + echo 'start to build componentD'
   start to build componentD
   [Pipeline] script
   [Pipeline] {
   [Pipeline] build
   Scheduling project: componentD
   Starting building: componentD #10
   [Pipeline] echo
   SUCCESS
   [Pipeline] }
   [Pipeline] // script
   [Pipeline] }
   [Pipeline] // stage
   [Pipeline] }
   [Pipeline] // withEnv
   [Pipeline] }
   [Pipeline] // node
   [Pipeline] End of Pipeline
   Finished: SUCCESS
   ```
   
   
5. [登录CAE控制台](https://support.huaweicloud.com/usermanual-cae/cae_03_0001.html#section1)，在组件列表查看组件状态，"最近一次变更状态/时间"列显示状态为"升级成功"，表示组件升级成功。
   
   图10查看组件   
   ![](https://support.huaweicloud.com/bestpractice-cae/zh-cn_image_0000001935790781.png "点击放大")
   
   
 
