├── .mvn ├── maven.config └── extensions.xml ├── .github ├── CODEOWNERS ├── release-drafter.yml ├── dependabot.yml └── workflows │ ├── release-drafter.yml │ └── jenkins-security-scan.yml ├── .gitignore ├── src ├── main │ ├── resources │ │ ├── io │ │ │ └── jenkins │ │ │ │ └── plugins │ │ │ │ └── alibabacloud │ │ │ │ └── pkg │ │ │ │ └── deployment │ │ │ │ ├── OssUploadAndOosExecStep │ │ │ │ ├── help-batchNumber_zh_CN.html │ │ │ │ ├── help-localPath_zh_CN.html │ │ │ │ ├── help-objectName_zh_CN.html │ │ │ │ ├── help-invokeScript_zh_CN.html │ │ │ │ ├── help-resourceType_zh_CN.html │ │ │ │ ├── help-destinationDir_zh_CN.html │ │ │ │ ├── help-batchNumber.html │ │ │ │ ├── help-objectName.html │ │ │ │ ├── help-invokeScript.html │ │ │ │ ├── help-localPath.html │ │ │ │ ├── help-region.html │ │ │ │ ├── help-region_zh_CN.html │ │ │ │ ├── help-destinationDir.html │ │ │ │ ├── help-resourceType.html │ │ │ │ ├── help-bucket_zh_CN.html │ │ │ │ ├── help-resourceId_zh_CN.html │ │ │ │ ├── help-bucket.html │ │ │ │ ├── help-mode_zh_CN.html │ │ │ │ ├── help-pausePolicy_zh_CN.html │ │ │ │ ├── help-resourceId.html │ │ │ │ ├── help-mode.html │ │ │ │ ├── help-pausePolicy.html │ │ │ │ └── config.jelly │ │ │ │ ├── AliyunEcsOpsByOssFilePublisher │ │ │ │ ├── help-batchNumber_zh_CN.html │ │ │ │ ├── help-localPath_zh_CN.html │ │ │ │ ├── help-objectName_zh_CN.html │ │ │ │ ├── help-resourceType_zh_CN.html │ │ │ │ ├── help-destinationDir_zh_CN.html │ │ │ │ ├── help-invokeScript_zh_CN.html │ │ │ │ ├── help-objectName.html │ │ │ │ ├── help-batchNumber.html │ │ │ │ ├── help-localPath.html │ │ │ │ ├── help-invokeScript.html │ │ │ │ ├── help-region_zh_CN.html │ │ │ │ ├── help-destinationDir.html │ │ │ │ ├── help-resourceType.html │ │ │ │ ├── help-bucket_zh_CN.html │ │ │ │ ├── help-region.html │ │ │ │ ├── help-bucket.html │ │ │ │ ├── help-resourceId_zh_CN.html │ │ │ │ ├── help-resourceId.html │ │ │ │ └── config.jelly │ │ │ │ ├── OosExecuteNotifyStep │ │ │ │ ├── help-notifyType_zh_CN.html │ │ │ │ ├── help-executeId_zh_CN.html │ │ │ │ ├── help-executeId.html │ │ │ │ ├── help-notifyType.html │ │ │ │ ├── help-region_zh_CN.html │ │ │ │ ├── help-region.html │ │ │ │ └── config.jelly │ │ │ │ ├── OosStatusQueryStep │ │ │ │ ├── help-executeId_zh_CN.html │ │ │ │ ├── help-executeId.html │ │ │ │ ├── help-region_zh_CN.html │ │ │ │ ├── config.jelly │ │ │ │ └── help-region.html │ │ │ │ └── PluginImpl │ │ │ │ └── config.jelly │ │ └── index.jelly │ └── java │ │ └── io │ │ └── jenkins │ │ └── plugins │ │ └── alibabacloud │ │ └── pkg │ │ └── deployment │ │ ├── utils │ │ ├── Status.java │ │ ├── ResourceType.java │ │ ├── StepUtils.java │ │ └── AliyunClientFactory.java │ │ ├── PluginImpl.java │ │ ├── OosStatusQueryStep.java │ │ ├── OosExecuteNotifyStep.java │ │ ├── AliyunEcsOpsByOssFilePublisher.java │ │ └── OssUploadAndOosExecStep.java └── test │ └── java │ └── io │ └── jenkins │ └── plugins │ └── alibabacloud │ └── pkg │ └── deployment │ ├── OosStatusQueryStepTest.java │ ├── AliyunEcsOpsTest.java │ ├── OosExecuteNotifyStepTest.java │ ├── AliyunEcsOpsByOssFilePublisherTest.java │ └── OssUploadAndOosExecStepTest.java ├── Jenkinsfile ├── LICENSE ├── README.md └── pom.xml /.mvn/maven.config: -------------------------------------------------------------------------------- 1 | -Pconsume-incrementals 2 | -Pmight-produce-incrementals 3 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @jenkinsci/alibabacloud-pkg-deployment-plugin-developers 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.DS_Store 2 | *.classpath 3 | *.settings 4 | *.project 5 | *.iml 6 | *.idea 7 | target 8 | logs 9 | work -------------------------------------------------------------------------------- /.github/release-drafter.yml: -------------------------------------------------------------------------------- 1 | _extends: .github 2 | tag-template: ${artifactId}-$NEXT_MINOR_VERSION 3 | template: | 4 | # What's Changed 5 | $CHANGES 6 | -------------------------------------------------------------------------------- /src/main/resources/io/jenkins/plugins/alibabacloud/pkg/deployment/OssUploadAndOosExecStep/help-batchNumber_zh_CN.html: -------------------------------------------------------------------------------- 1 |
2 | OOS执行模版执行批数。 3 |
-------------------------------------------------------------------------------- /src/main/resources/io/jenkins/plugins/alibabacloud/pkg/deployment/OssUploadAndOosExecStep/help-localPath_zh_CN.html: -------------------------------------------------------------------------------- 1 |
2 | Jenkins已构建项目的目录路径。 3 |
-------------------------------------------------------------------------------- /Jenkinsfile: -------------------------------------------------------------------------------- 1 | buildPlugin( 2 | useContainerAgent: true, 3 | configurations: [ 4 | [platform: 'linux', jdk: 11], 5 | [platform: 'windows', jdk: 11], 6 | ]) -------------------------------------------------------------------------------- /src/main/resources/io/jenkins/plugins/alibabacloud/pkg/deployment/AliyunEcsOpsByOssFilePublisher/help-batchNumber_zh_CN.html: -------------------------------------------------------------------------------- 1 |
2 | OOS模版任务执行批数。 3 |
-------------------------------------------------------------------------------- /src/main/resources/io/jenkins/plugins/alibabacloud/pkg/deployment/OssUploadAndOosExecStep/help-objectName_zh_CN.html: -------------------------------------------------------------------------------- 1 |
2 | 上传至OSS bucket 的文件名。 3 |
-------------------------------------------------------------------------------- /src/main/resources/index.jelly: -------------------------------------------------------------------------------- 1 | 2 |
3 | This plugin integrates Jenkins with Alibabacloud Package Deployment. 4 |
5 | -------------------------------------------------------------------------------- /src/main/resources/io/jenkins/plugins/alibabacloud/pkg/deployment/AliyunEcsOpsByOssFilePublisher/help-localPath_zh_CN.html: -------------------------------------------------------------------------------- 1 |
2 | Jenkins已构建项目的目录路径。 3 |
-------------------------------------------------------------------------------- /src/main/resources/io/jenkins/plugins/alibabacloud/pkg/deployment/AliyunEcsOpsByOssFilePublisher/help-objectName_zh_CN.html: -------------------------------------------------------------------------------- 1 |
2 | 上传至OSS bucket 的文件名。 3 |
-------------------------------------------------------------------------------- /src/main/resources/io/jenkins/plugins/alibabacloud/pkg/deployment/OssUploadAndOosExecStep/help-invokeScript_zh_CN.html: -------------------------------------------------------------------------------- 1 |
2 | ECS下载 OOS 文件后部署项目脚本。 3 |
4 | -------------------------------------------------------------------------------- /src/main/resources/io/jenkins/plugins/alibabacloud/pkg/deployment/OssUploadAndOosExecStep/help-resourceType_zh_CN.html: -------------------------------------------------------------------------------- 1 |
2 | 目前只支持操作两种资源:ESS 和 ECS。 3 |
-------------------------------------------------------------------------------- /src/main/resources/io/jenkins/plugins/alibabacloud/pkg/deployment/AliyunEcsOpsByOssFilePublisher/help-resourceType_zh_CN.html: -------------------------------------------------------------------------------- 1 |
2 | 目前只支持操作两种资源:ESS 和 ECS。 3 |
-------------------------------------------------------------------------------- /src/main/resources/io/jenkins/plugins/alibabacloud/pkg/deployment/OssUploadAndOosExecStep/help-destinationDir_zh_CN.html: -------------------------------------------------------------------------------- 1 |
2 | ECS用于下载 OSS 文件以及部署项目的位置。 3 |
-------------------------------------------------------------------------------- /src/main/resources/io/jenkins/plugins/alibabacloud/pkg/deployment/AliyunEcsOpsByOssFilePublisher/help-destinationDir_zh_CN.html: -------------------------------------------------------------------------------- 1 |
2 | ECS用于下载 OSS 文件以及部署项目的位置。 3 |
-------------------------------------------------------------------------------- /src/main/resources/io/jenkins/plugins/alibabacloud/pkg/deployment/AliyunEcsOpsByOssFilePublisher/help-invokeScript_zh_CN.html: -------------------------------------------------------------------------------- 1 |
2 | ECS下载 OOS 文件后部署项目脚本。 3 |
4 | -------------------------------------------------------------------------------- /src/main/resources/io/jenkins/plugins/alibabacloud/pkg/deployment/OssUploadAndOosExecStep/help-batchNumber.html: -------------------------------------------------------------------------------- 1 |
2 | The OOS template execution batch Number. 3 |
-------------------------------------------------------------------------------- /src/main/resources/io/jenkins/plugins/alibabacloud/pkg/deployment/OssUploadAndOosExecStep/help-objectName.html: -------------------------------------------------------------------------------- 1 |
2 | The file name uploaded to the OSS bucket. 3 |
-------------------------------------------------------------------------------- /src/main/resources/io/jenkins/plugins/alibabacloud/pkg/deployment/AliyunEcsOpsByOssFilePublisher/help-objectName.html: -------------------------------------------------------------------------------- 1 |
2 | The file name uploaded to the OSS bucket. 3 |
-------------------------------------------------------------------------------- /src/main/resources/io/jenkins/plugins/alibabacloud/pkg/deployment/AliyunEcsOpsByOssFilePublisher/help-batchNumber.html: -------------------------------------------------------------------------------- 1 |
2 | The OOS template task execution batch Number. 3 |
-------------------------------------------------------------------------------- /src/main/resources/io/jenkins/plugins/alibabacloud/pkg/deployment/OssUploadAndOosExecStep/help-invokeScript.html: -------------------------------------------------------------------------------- 1 |
2 | The deploy script run after ECS download OOS File. 3 |
-------------------------------------------------------------------------------- /src/main/resources/io/jenkins/plugins/alibabacloud/pkg/deployment/OssUploadAndOosExecStep/help-localPath.html: -------------------------------------------------------------------------------- 1 |
2 | The directory path of the built project for jenkins. 3 |
-------------------------------------------------------------------------------- /src/main/resources/io/jenkins/plugins/alibabacloud/pkg/deployment/OssUploadAndOosExecStep/help-region.html: -------------------------------------------------------------------------------- 1 |
2 | 阿里云 ECS 、ESS、OSS、OOS资源所在的地域。 3 | 样例: cn-hangzhou。 4 |
-------------------------------------------------------------------------------- /src/main/resources/io/jenkins/plugins/alibabacloud/pkg/deployment/AliyunEcsOpsByOssFilePublisher/help-localPath.html: -------------------------------------------------------------------------------- 1 |
2 | The directory path of the built project for jenkins. 3 |
-------------------------------------------------------------------------------- /src/main/resources/io/jenkins/plugins/alibabacloud/pkg/deployment/OssUploadAndOosExecStep/help-region_zh_CN.html: -------------------------------------------------------------------------------- 1 |
2 | 阿里云 ECS 、ESS、OSS、OOS资源所在的地域。 3 | 样例: cn-hangzhou。 4 |
-------------------------------------------------------------------------------- /src/main/resources/io/jenkins/plugins/alibabacloud/pkg/deployment/AliyunEcsOpsByOssFilePublisher/help-invokeScript.html: -------------------------------------------------------------------------------- 1 |
2 | The deploy script run after ECS download OOS File. 3 |
-------------------------------------------------------------------------------- /src/main/resources/io/jenkins/plugins/alibabacloud/pkg/deployment/AliyunEcsOpsByOssFilePublisher/help-region_zh_CN.html: -------------------------------------------------------------------------------- 1 |
2 | 阿里云 ECS 、ESS、OSS、OOS资源所在的地域。 3 | 样例: cn-hangzhou。 4 |
-------------------------------------------------------------------------------- /src/main/resources/io/jenkins/plugins/alibabacloud/pkg/deployment/OssUploadAndOosExecStep/help-destinationDir.html: -------------------------------------------------------------------------------- 1 |
2 | The Location of ECS used to download OSS file and deloy project. 3 |
4 | 5 | -------------------------------------------------------------------------------- /src/main/resources/io/jenkins/plugins/alibabacloud/pkg/deployment/OssUploadAndOosExecStep/help-resourceType.html: -------------------------------------------------------------------------------- 1 |
2 | Currently,only two resources are supported. 3 | Example: ESS and ECS. 4 |
-------------------------------------------------------------------------------- /src/main/resources/io/jenkins/plugins/alibabacloud/pkg/deployment/AliyunEcsOpsByOssFilePublisher/help-destinationDir.html: -------------------------------------------------------------------------------- 1 |
2 | The Location of ECS used to download OSS file and deloy project. 3 |
4 | 5 | -------------------------------------------------------------------------------- /src/main/resources/io/jenkins/plugins/alibabacloud/pkg/deployment/AliyunEcsOpsByOssFilePublisher/help-resourceType.html: -------------------------------------------------------------------------------- 1 |
2 | Currently,only two resources are supported. 3 | Example: ESS and ECS. 4 |
-------------------------------------------------------------------------------- /src/main/resources/io/jenkins/plugins/alibabacloud/pkg/deployment/OssUploadAndOosExecStep/help-bucket_zh_CN.html: -------------------------------------------------------------------------------- 1 |
2 | 阿里云OSSbucket名称
3 | 登陆OSS控制台配置 4 |
-------------------------------------------------------------------------------- /src/main/resources/io/jenkins/plugins/alibabacloud/pkg/deployment/AliyunEcsOpsByOssFilePublisher/help-bucket_zh_CN.html: -------------------------------------------------------------------------------- 1 |
2 | 阿里云OSS bucket 名称
3 | 登陆 OSS 控制台配置 4 |
-------------------------------------------------------------------------------- /src/main/resources/io/jenkins/plugins/alibabacloud/pkg/deployment/AliyunEcsOpsByOssFilePublisher/help-region.html: -------------------------------------------------------------------------------- 1 |
2 | Specifies the geographic region in which your ESS or ECS or OSS or OOS will run. 3 | Example: cn-hangzhou. 4 |
-------------------------------------------------------------------------------- /src/main/resources/io/jenkins/plugins/alibabacloud/pkg/deployment/OosExecuteNotifyStep/help-notifyType_zh_CN.html: -------------------------------------------------------------------------------- 1 |
2 | OOS 模版暂停任务运行的下一步骤 3 | 取值如下: 4 | 8 |
-------------------------------------------------------------------------------- /src/main/resources/io/jenkins/plugins/alibabacloud/pkg/deployment/OosStatusQueryStep/help-executeId_zh_CN.html: -------------------------------------------------------------------------------- 1 |
2 | OOS模版任务ID 3 | 查看 4 | 详情登陆OOS控制台 5 |
6 | 样例: exec-XXXXXXX 7 |
-------------------------------------------------------------------------------- /src/main/resources/io/jenkins/plugins/alibabacloud/pkg/deployment/OssUploadAndOosExecStep/help-resourceId_zh_CN.html: -------------------------------------------------------------------------------- 1 |
2 | 资源Id 3 | 样例如下: 4 | ESS:asg-sdsfbhdxxxxxxxxxx 5 | ECS:i-dbhcbxxxxxxxxxxx 或者 i-dbhcbxxxxxxxxxxx,i-dbhcbxxxxxxx (ECS 支持多个实例Id以逗号分割拼接) 6 |
-------------------------------------------------------------------------------- /src/main/resources/io/jenkins/plugins/alibabacloud/pkg/deployment/OosExecuteNotifyStep/help-executeId_zh_CN.html: -------------------------------------------------------------------------------- 1 |
2 | OOS模版暂停任务ID 3 | 查看 4 | 详情登陆OOS控制台 5 |
6 | 样例: exec-XXXXXXX 7 |
-------------------------------------------------------------------------------- /src/main/resources/io/jenkins/plugins/alibabacloud/pkg/deployment/OssUploadAndOosExecStep/help-bucket.html: -------------------------------------------------------------------------------- 1 |
2 | Aliyun OSS BucketName
3 | config 4 | You can upload the built project to OSS bucket 5 |
-------------------------------------------------------------------------------- /src/main/resources/io/jenkins/plugins/alibabacloud/pkg/deployment/AliyunEcsOpsByOssFilePublisher/help-bucket.html: -------------------------------------------------------------------------------- 1 |
2 | Aliyun OSS BucketName
3 | config 4 | You can upload the built project to OSS bucket. 5 |
-------------------------------------------------------------------------------- /src/main/resources/io/jenkins/plugins/alibabacloud/pkg/deployment/AliyunEcsOpsByOssFilePublisher/help-resourceId_zh_CN.html: -------------------------------------------------------------------------------- 1 |
2 | 资源Id 3 | 样例如下: 4 | ESS:asg-sdsfbhdxxxxxxxxxx 5 | ECS:i-dbhcbxxxxxxxxxxx 或者 i-dbhcbxxxxxxxxxxx,i-dbhcbxxxxxxx (ECS 支持多个实例Id以逗号分割拼接) 6 |
-------------------------------------------------------------------------------- /src/main/resources/io/jenkins/plugins/alibabacloud/pkg/deployment/OosStatusQueryStep/help-executeId.html: -------------------------------------------------------------------------------- 1 |
2 | OOS template task id. 3 | Details 4 | Please login OOS console
5 | Example: exec-XXXXX 6 |
-------------------------------------------------------------------------------- /src/main/resources/io/jenkins/plugins/alibabacloud/pkg/deployment/OssUploadAndOosExecStep/help-mode_zh_CN.html: -------------------------------------------------------------------------------- 1 |
2 | OOS 模版执行模式 3 | 取值如下: 4 | 9 |
-------------------------------------------------------------------------------- /src/main/resources/io/jenkins/plugins/alibabacloud/pkg/deployment/OosExecuteNotifyStep/help-executeId.html: -------------------------------------------------------------------------------- 1 |
2 | OOS template pause task id. 3 | Details 4 | Please login OOS console.
5 | Example: exec-XXXXX 6 |
-------------------------------------------------------------------------------- /src/main/java/io/jenkins/plugins/alibabacloud/pkg/deployment/utils/Status.java: -------------------------------------------------------------------------------- 1 | package io.jenkins.plugins.alibabacloud.pkg.deployment.utils; 2 | 3 | /** 4 | * oss template execution status. 5 | */ 6 | public enum Status { 7 | Success, 8 | Failed, 9 | Waiting, 10 | Cancelled, 11 | } 12 | -------------------------------------------------------------------------------- /src/main/resources/io/jenkins/plugins/alibabacloud/pkg/deployment/OosStatusQueryStep/help-region_zh_CN.html: -------------------------------------------------------------------------------- 1 |
2 | OOS模版任务所在地域 3 | 查看OOS支持地域获取所有支持的地域列表 5 |
6 | 样例: 华东1(杭州) 7 |
-------------------------------------------------------------------------------- /src/main/resources/io/jenkins/plugins/alibabacloud/pkg/deployment/OssUploadAndOosExecStep/help-pausePolicy_zh_CN.html: -------------------------------------------------------------------------------- 1 |
2 | OOS 模版执行的循环模式 3 | 取值如下: 4 | 9 |
-------------------------------------------------------------------------------- /src/main/resources/io/jenkins/plugins/alibabacloud/pkg/deployment/OosExecuteNotifyStep/help-notifyType.html: -------------------------------------------------------------------------------- 1 |
2 | The OOS template pause task next step. 3 | Valid values: 4 | 8 |
-------------------------------------------------------------------------------- /src/main/resources/io/jenkins/plugins/alibabacloud/pkg/deployment/OosExecuteNotifyStep/help-region_zh_CN.html: -------------------------------------------------------------------------------- 1 |
2 | OOS模版暂停任务执行地域 3 | 查看OOS支持地域获取所有支持的地域列表 5 |
6 | 样例: 华东1(杭州) 7 |
-------------------------------------------------------------------------------- /src/main/resources/io/jenkins/plugins/alibabacloud/pkg/deployment/OssUploadAndOosExecStep/help-resourceId.html: -------------------------------------------------------------------------------- 1 |
2 | ID of resource. 3 | Example: 4 | ESS:asg-sdsfbhdxxxxxxxxxx 5 | ECS:i-dbhcbxxxxxxxxxxx or i-dbhcbxxxxxxxxxxx,i-dbhcbxxxxxxx (ECS supports comma separated concatenation of multiple instance IDs) 6 |
-------------------------------------------------------------------------------- /src/main/resources/io/jenkins/plugins/alibabacloud/pkg/deployment/AliyunEcsOpsByOssFilePublisher/help-resourceId.html: -------------------------------------------------------------------------------- 1 |
2 | ID of resource. 3 | Example: 4 | ESS:asg-sdsfbhdxxxxxxxxxx 5 | ECS:i-dbhcbxxxxxxxxxxx or i-dbhcbxxxxxxxxxxx,i-dbhcbxxxxxxx (ECS supports comma separated concatenation of multiple instance IDs) 6 |
-------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuring-dependabot-version-updates 2 | 3 | version: 2 4 | updates: 5 | - package-ecosystem: maven 6 | directory: / 7 | schedule: 8 | interval: monthly 9 | - package-ecosystem: github-actions 10 | directory: / 11 | schedule: 12 | interval: monthly 13 | -------------------------------------------------------------------------------- /src/main/resources/io/jenkins/plugins/alibabacloud/pkg/deployment/OosStatusQueryStep/config.jelly: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/main/resources/io/jenkins/plugins/alibabacloud/pkg/deployment/OosStatusQueryStep/help-region.html: -------------------------------------------------------------------------------- 1 |
2 | Specifies the geographic region in which your OOS template task. 3 | OOS support region 4 | for more about what regions are.
5 | Example: China (Hangzhou) 6 |
-------------------------------------------------------------------------------- /src/main/resources/io/jenkins/plugins/alibabacloud/pkg/deployment/OosExecuteNotifyStep/help-region.html: -------------------------------------------------------------------------------- 1 |
2 | Specifies the geographic region in which your OOS template pause task. 3 | OOS support region 4 | for more about what regions are.
5 | Example: China (Hangzhou) 6 |
-------------------------------------------------------------------------------- /.mvn/extensions.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | io.jenkins.tools.incrementals 4 | git-changelist-maven-extension 5 | 1.6 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/main/resources/io/jenkins/plugins/alibabacloud/pkg/deployment/OssUploadAndOosExecStep/help-mode.html: -------------------------------------------------------------------------------- 1 |
2 | The OOS template execution mode. 3 | Valid values: 4 | 9 |
-------------------------------------------------------------------------------- /src/main/resources/io/jenkins/plugins/alibabacloud/pkg/deployment/OosExecuteNotifyStep/config.jelly: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/main/resources/io/jenkins/plugins/alibabacloud/pkg/deployment/OssUploadAndOosExecStep/help-pausePolicy.html: -------------------------------------------------------------------------------- 1 |
2 | The OOS template loop mode. 3 | Valid values: 4 | 9 |
-------------------------------------------------------------------------------- /src/test/java/io/jenkins/plugins/alibabacloud/pkg/deployment/OosStatusQueryStepTest.java: -------------------------------------------------------------------------------- 1 | package io.jenkins.plugins.alibabacloud.pkg.deployment; 2 | 3 | import org.junit.Assert; 4 | import org.junit.Test; 5 | 6 | public class OosStatusQueryStepTest { 7 | @Test 8 | public void gettersWorkAsExpected() { 9 | OosStatusQueryStep step = new OosStatusQueryStep("cn-hangzhou","exec-xxxxxx"); 10 | Assert.assertEquals("cn-hangzhou", step.getRegion()); 11 | Assert.assertEquals("exec-xxxxxx", step.getExecuteId()); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /.github/workflows/release-drafter.yml: -------------------------------------------------------------------------------- 1 | # Automates creation of Release Drafts using Release Drafter 2 | # More Info: https://github.com/jenkinsci/.github/blob/master/.github/release-drafter.adoc 3 | 4 | on: 5 | push: 6 | branches: 7 | - master 8 | - main 9 | 10 | jobs: 11 | update_release_draft: 12 | runs-on: ubuntu-latest 13 | steps: 14 | # Drafts your next Release notes as Pull Requests are merged into the default branch 15 | - uses: release-drafter/release-drafter@v5 16 | env: 17 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 18 | -------------------------------------------------------------------------------- /src/main/java/io/jenkins/plugins/alibabacloud/pkg/deployment/utils/ResourceType.java: -------------------------------------------------------------------------------- 1 | package io.jenkins.plugins.alibabacloud.pkg.deployment.utils; 2 | 3 | public enum ResourceType { 4 | 5 | ESS("ESS", "ESS ScalingGroup"), 6 | ECS("ECS", "ECS Instance"); 7 | 8 | String type; 9 | String name; 10 | 11 | ResourceType(String type, String name) { 12 | this.type = type; 13 | this.name = name; 14 | } 15 | 16 | public String getType() { 17 | return type; 18 | } 19 | 20 | public String getName() { 21 | return name; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/test/java/io/jenkins/plugins/alibabacloud/pkg/deployment/AliyunEcsOpsTest.java: -------------------------------------------------------------------------------- 1 | package io.jenkins.plugins.alibabacloud.pkg.deployment; 2 | 3 | import com.gargoylesoftware.htmlunit.WebAssert; 4 | import com.gargoylesoftware.htmlunit.html.HtmlPage; 5 | import org.junit.Rule; 6 | import org.jvnet.hudson.test.JenkinsRule; 7 | 8 | public class AliyunEcsOpsTest { 9 | @Rule 10 | public JenkinsRule j = new JenkinsRule(); 11 | public void testConfig() throws Exception { 12 | HtmlPage page = j.new WebClient().goTo("configure"); 13 | WebAssert.assertTextPresent(page, "Alibaba Cloud"); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/test/java/io/jenkins/plugins/alibabacloud/pkg/deployment/OosExecuteNotifyStepTest.java: -------------------------------------------------------------------------------- 1 | package io.jenkins.plugins.alibabacloud.pkg.deployment; 2 | 3 | import org.junit.Assert; 4 | import org.junit.Test; 5 | 6 | public class OosExecuteNotifyStepTest { 7 | @Test 8 | public void gettersWorkAsExpected(){ 9 | OosExecuteNotifyStep step = new OosExecuteNotifyStep("cn-hangzhou","exec-xxxxxx","Approve"); 10 | Assert.assertEquals("cn-hangzhou", step.getRegion()); 11 | Assert.assertEquals("exec-xxxxxx", step.getExecuteId()); 12 | Assert.assertEquals("Approve", step.getNotifyType()); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/io/jenkins/plugins/alibabacloud/pkg/deployment/utils/StepUtils.java: -------------------------------------------------------------------------------- 1 | package io.jenkins.plugins.alibabacloud.pkg.deployment.utils; 2 | 3 | import hudson.EnvVars; 4 | import hudson.model.TaskListener; 5 | 6 | import java.util.Arrays; 7 | import java.util.HashSet; 8 | import java.util.Set; 9 | 10 | public class StepUtils { 11 | public static > Set requires(T... classes) { 12 | return new HashSet<>(Arrays.asList(classes)); 13 | } 14 | 15 | public static Set> requiresDefault() { 16 | return requires(EnvVars.class, TaskListener.class); 17 | } 18 | 19 | } 20 | 21 | -------------------------------------------------------------------------------- /.github/workflows/jenkins-security-scan.yml: -------------------------------------------------------------------------------- 1 | # More information about the Jenkins security scan can be found at the developer docs: https://www.jenkins.io/redirect/jenkins-security-scan/ 2 | 3 | name: Jenkins Security Scan 4 | on: 5 | push: 6 | branches: 7 | - "master" 8 | - "main" 9 | pull_request: 10 | types: [ opened, synchronize, reopened ] 11 | workflow_dispatch: 12 | 13 | permissions: 14 | security-events: write 15 | contents: read 16 | actions: read 17 | 18 | jobs: 19 | security-scan: 20 | uses: jenkins-infra/jenkins-security-scan/.github/workflows/jenkins-security-scan.yaml@v2 21 | with: 22 | java-cache: 'maven' # Optionally enable use of a build dependency cache. Specify 'maven' or 'gradle' as appropriate. 23 | java-version: 11 # What version of Java to set up for the build. 24 | -------------------------------------------------------------------------------- /src/main/resources/io/jenkins/plugins/alibabacloud/pkg/deployment/PluginImpl/config.jelly: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | You must be provide an AccessKey pair 7 | See 8 | 9 | Alibaba Cloud documentation 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Alibaba Cloud 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/test/java/io/jenkins/plugins/alibabacloud/pkg/deployment/AliyunEcsOpsByOssFilePublisherTest.java: -------------------------------------------------------------------------------- 1 | package io.jenkins.plugins.alibabacloud.pkg.deployment; 2 | 3 | import hudson.model.FreeStyleProject; 4 | import org.junit.Rule; 5 | import org.junit.Test; 6 | import org.jvnet.hudson.test.JenkinsRule; 7 | import org.jvnet.hudson.test.recipes.LocalData; 8 | 9 | import static org.hamcrest.Matchers.containsString; 10 | import static org.hamcrest.Matchers.not; 11 | import static org.junit.Assert.assertThat; 12 | 13 | public class AliyunEcsOpsByOssFilePublisherTest { 14 | @Rule 15 | public JenkinsRule j = new JenkinsRule(); 16 | 17 | @Test 18 | public void testRoundTripConfiguration() throws Exception { 19 | final AliyunEcsOpsByOssFilePublisher publisher = new AliyunEcsOpsByOssFilePublisher( 20 | "cn-hangzhou", 21 | "ESS", 22 | "asg-XXXXXXXX", 23 | "testBucket", 24 | "/testLocation", 25 | "/", 26 | "/root", 27 | 1, 28 | ""); 29 | final AliyunEcsOpsByOssFilePublisher afterPublisher = j.configRoundtrip(publisher); 30 | j.assertEqualDataBoundBeans(publisher, afterPublisher); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/resources/io/jenkins/plugins/alibabacloud/pkg/deployment/AliyunEcsOpsByOssFilePublisher/config.jelly: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /src/test/java/io/jenkins/plugins/alibabacloud/pkg/deployment/OssUploadAndOosExecStepTest.java: -------------------------------------------------------------------------------- 1 | package io.jenkins.plugins.alibabacloud.pkg.deployment; 2 | 3 | import org.junit.Assert; 4 | import org.junit.Test; 5 | 6 | public class OssUploadAndOosExecStepTest { 7 | @Test 8 | public void gettersWorkAsExpected() { 9 | OssUploadAndOosExecStep step = new OssUploadAndOosExecStep("cn-hangzhou","ESS", 10 | "asg-XXXX","bucketTest","workspace/Test.zip","/","Automatic","EveryBatchPause",1,"/root/ceshi.zip", 11 | ""); 12 | Assert.assertEquals("cn-hangzhou", step.getRegion()); 13 | Assert.assertEquals("ESS", step.getResourceType()); 14 | Assert.assertEquals("asg-XXXX", step.getResourceId()); 15 | Assert.assertEquals("bucketTest", step.getBucket()); 16 | Assert.assertEquals("workspace/Test.zip", step.getObjectName()); 17 | Assert.assertEquals("/", step.getLocalPath()); 18 | Assert.assertEquals("Automatic", step.getMode()); 19 | Assert.assertEquals("EveryBatchPause", step.getPausePolicy()); 20 | Assert.assertEquals(1, step.getBatchNumber()); 21 | Assert.assertEquals("/root/ceshi.zip", step.getDestinationDir()); 22 | Assert.assertEquals("", step.getInvokeScript()); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/resources/io/jenkins/plugins/alibabacloud/pkg/deployment/OssUploadAndOosExecStep/config.jelly: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /src/main/java/io/jenkins/plugins/alibabacloud/pkg/deployment/utils/AliyunClientFactory.java: -------------------------------------------------------------------------------- 1 | package io.jenkins.plugins.alibabacloud.pkg.deployment.utils; 2 | 3 | import com.aliyun.oss.OSS; 4 | import com.aliyun.oss.OSSClientBuilder; 5 | import com.aliyuncs.DefaultAcsClient; 6 | import com.aliyuncs.IAcsClient; 7 | import com.aliyuncs.profile.DefaultProfile; 8 | import io.jenkins.plugins.alibabacloud.pkg.deployment.PluginImpl; 9 | 10 | /** 11 | * product oos client and oss client. 12 | */ 13 | public class AliyunClientFactory { 14 | private static final String endpointFormat = "https://oss-%s.aliyuncs.com"; 15 | 16 | private OSS ossClient; 17 | private IAcsClient oosClient; 18 | 19 | public OSS getOssClient() { 20 | return ossClient; 21 | } 22 | 23 | public void setOssClient(OSS ossClient) { 24 | this.ossClient = ossClient; 25 | } 26 | 27 | public IAcsClient getOosClient() { 28 | return oosClient; 29 | } 30 | 31 | public void setOosClient(IAcsClient oosClient) { 32 | this.oosClient = oosClient; 33 | } 34 | 35 | public void build(String region) { 36 | String accessKeyId = PluginImpl.getInstance().getAccessKeyId(); 37 | String accessKeySecret = PluginImpl.getInstance().getAccessKeySecret(); 38 | this.ossClient = new OSSClientBuilder().build(String.format(endpointFormat, region), accessKeyId, accessKeySecret); 39 | DefaultProfile profile = DefaultProfile.getProfile( 40 | region, accessKeyId, accessKeySecret 41 | ); 42 | this.oosClient = new DefaultAcsClient(profile); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/io/jenkins/plugins/alibabacloud/pkg/deployment/PluginImpl.java: -------------------------------------------------------------------------------- 1 | package io.jenkins.plugins.alibabacloud.pkg.deployment; 2 | 3 | import hudson.Extension; 4 | import hudson.ExtensionList; 5 | import hudson.util.Secret; 6 | import jenkins.model.GlobalConfiguration; 7 | import net.sf.json.JSONObject; 8 | import org.jenkinsci.Symbol; 9 | import org.kohsuke.stapler.DataBoundConstructor; 10 | import org.kohsuke.stapler.DataBoundSetter; 11 | import org.kohsuke.stapler.StaplerRequest; 12 | 13 | /** 14 | * plugin extension: 15 | * global setting 16 | */ 17 | @Extension 18 | @Symbol("pipelineStepsAliyun") 19 | public class PluginImpl extends GlobalConfiguration { 20 | @SuppressWarnings("lgtm[jenkins/plaintext-storage]") 21 | private String accessKeyId; 22 | private Secret accessKeySecret; 23 | 24 | @DataBoundConstructor 25 | public PluginImpl() { 26 | load(); 27 | } 28 | 29 | @DataBoundSetter 30 | public void setAccessKeyId(String accessKeyId) { 31 | this.accessKeyId = accessKeyId; 32 | } 33 | 34 | @DataBoundSetter 35 | public void setAccessKeySecret(Secret accessKeySecret) { 36 | this.accessKeySecret = accessKeySecret; 37 | } 38 | 39 | @Override 40 | public boolean configure(StaplerRequest req, JSONObject json) throws FormException { 41 | accessKeyId = json.getString("accessKeyId"); 42 | accessKeySecret = Secret.fromString(json.getString("accessKeySecret")); 43 | save(); 44 | return true; 45 | } 46 | 47 | public static PluginImpl getInstance() { 48 | return ExtensionList.lookup(PluginImpl.class).get(0); 49 | } 50 | 51 | public String getAccessKeyId() { 52 | return this.accessKeyId; 53 | } 54 | 55 | public String getAccessKeySecret() { 56 | return Secret.toString(this.accessKeySecret); 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Alibabacloud Package Deployment Jenkins plugin 2 | ============================= 3 | 4 | Plugins for deployment package on Alibaba Cloud. 5 | * The plugin provides a post-build step:upon a successful build,it will compress the specified working directory, upload it to OSS, and then download OSS files to ECS through OOS for deployment 6 | * This plugins adds Jenkins pipeline steps to interact with the Aliyun API. 7 | 8 | 9 | Setting up 10 | ---------- 11 | 12 | After building and installing the plugin, some simple configuration is needed 13 | for your project.Please set global configuration of Aliyun Ak/Sk. 14 | 15 | # How to use post-build step 16 | 17 | ### Freestyle 18 | 19 | 1. Open up your project configuration 20 | 2. In the `Post-build Actions` section, select "Alibabacloud Automatic Package Deployment" 21 | 3. ResourceType,ResourceId, objectName, bucket, and region are so on all 22 | required options. 23 | 4. Temporary access keys. These will use the global keys from the Jenkins 24 | instance. 25 | 26 | ### Pipeline 27 | 28 | 1. Create a [Jenkins Pipeline](https://plugins.jenkins.io/workflow-aggregator/) project 29 | 2. Use the Pipeline Snippet Generator 30 | 3. For 'Sample Step', choose 'step: General Build Step' 31 | 4. For 'Build Step', choose 'Alibabacloud Automatic Package Deployment' 32 | 5. populate variables and then 'Generate Groovy' 33 | 34 | Here is a rather blank example: 35 | 36 | step([$class: 'AliyunEcsOpsByOssFilePublisher', region: 'cn-hangzhou', resourceType: 'ESS', resourceId: '', bucket: '', objectName: '', localPath: '', destinationDir: '', batchNumber: 1, invokeScript: '']) 37 | 38 | # How to use pipeline steps to interact with the Aliyun API 39 | 40 | * [ossUploadAndOosExec](####ossUploadAndOosExec) 41 | * [oosStatusQuery](####oosStatusQuery) 42 | * [oosExecuteNotify](####oosExecuteNotify) 43 | 44 | #### ossUploadAndOosExec 45 | 46 | Upload built project to OSS and execution OOS template download OSS file to smartly deploy on ECS instances. 47 | 48 | ```groovy 49 | executeId = ossUploadAndOosExec(batchNumber: 3, mode: 'FailurePause', bucket: 'testBucket', destinationDir: '/root/test.zip', invokeScript: '', localPath: '/', objectName: 'test.zip', pausePolicy: 'EveryBatchPause', region: 'cn-hangzhou', resourceId: 'asg-bp15XXXXX', resourceType: 'ESS') 50 | ``` 51 | 52 | ##### oosStatusQuery 53 | 54 | Query OOS template task status by OSS template task id. 55 | 56 | ```groovy 57 | oosStatusQuery(executeId: "exec-XXXXXXXXX", region: 'cn-hangzhou') 58 | ``` 59 | 60 | #### oosExecuteNotify 61 | 62 | Oos template pause task execution next step,like Approve or Cancelled. 63 | 64 | ```groovy 65 | oosExecuteNotify(executeId: "exec-XXXXXXXXX", region: 'cn-hangzhou', notifyType: "Approve") 66 | ``` -------------------------------------------------------------------------------- /src/main/java/io/jenkins/plugins/alibabacloud/pkg/deployment/OosStatusQueryStep.java: -------------------------------------------------------------------------------- 1 | package io.jenkins.plugins.alibabacloud.pkg.deployment; 2 | 3 | import com.aliyuncs.IAcsClient; 4 | import com.aliyuncs.oos.model.v20190601.ListExecutionsRequest; 5 | import com.aliyuncs.oos.model.v20190601.ListExecutionsResponse; 6 | import edu.umd.cs.findbugs.annotations.NonNull; 7 | import hudson.Extension; 8 | import io.jenkins.plugins.alibabacloud.pkg.deployment.utils.AliyunClientFactory; 9 | import io.jenkins.plugins.alibabacloud.pkg.deployment.utils.StepUtils; 10 | import org.jenkinsci.plugins.workflow.steps.*; 11 | import org.kohsuke.stapler.DataBoundConstructor; 12 | import java.util.List; 13 | import java.util.Set; 14 | 15 | /** 16 | * This class is a pipeline step: 17 | * query oos template execution status by oos template execute id. 18 | */ 19 | public class OosStatusQueryStep extends Step { 20 | //oos template execute region. 21 | private final String region; 22 | //oos template execute id. 23 | private final String executeId; 24 | 25 | // getXXX functions are obtain data. 26 | public String getExecuteId() { 27 | return executeId; 28 | } 29 | 30 | public String getRegion() { 31 | return region; 32 | } 33 | 34 | // bind data 35 | @DataBoundConstructor 36 | public OosStatusQueryStep(String region, String executeId) { 37 | this.executeId = executeId; 38 | this.region = region; 39 | } 40 | 41 | // step execution point. 42 | @Override 43 | public StepExecution start(StepContext stepContext) throws Exception { 44 | return new Execution(stepContext, this); 45 | } 46 | 47 | //plugin extension 48 | @Extension 49 | public static class DescriptorImpl extends StepDescriptor { 50 | 51 | @Override 52 | public Set> getRequiredContext() { 53 | return StepUtils.requiresDefault(); 54 | } 55 | 56 | @Override 57 | public String getFunctionName() { 58 | return "oosStatusQuery"; 59 | } 60 | 61 | @NonNull 62 | @Override 63 | public String getDisplayName() { 64 | return "query oos execute status"; 65 | } 66 | } 67 | 68 | // specific behavior of execution and return oos template execute status. 69 | public static class Execution extends SynchronousNonBlockingStepExecution { 70 | private static final long serialVersionUID = 175374543031461563L; 71 | private final transient OosStatusQueryStep step; 72 | 73 | protected Execution(@NonNull StepContext context, OosStatusQueryStep step) { 74 | super(context); 75 | this.step = step; 76 | } 77 | 78 | /** 79 | * run include: 80 | * query oos template execute status by oos template execute id. 81 | */ 82 | @Override 83 | protected String run() throws Exception { 84 | AliyunClientFactory instance = new AliyunClientFactory(); 85 | instance.build(this.step.region); 86 | IAcsClient oosClient = instance.getOosClient(); 87 | ListExecutionsRequest request = new ListExecutionsRequest(); 88 | request.setExecutionId(this.step.executeId); 89 | String status = null; 90 | // avoid frequent queries. 91 | Thread.sleep(500); 92 | List executions = oosClient.getAcsResponse(request).getExecutions(); 93 | if (executions.size() > 0) { 94 | status = executions.get(0).getStatus(); 95 | } else { 96 | throw new Exception("oos executeId:" + this.step.executeId + " is not exist"); 97 | } 98 | return status; 99 | } 100 | } 101 | 102 | } 103 | -------------------------------------------------------------------------------- /src/main/java/io/jenkins/plugins/alibabacloud/pkg/deployment/OosExecuteNotifyStep.java: -------------------------------------------------------------------------------- 1 | package io.jenkins.plugins.alibabacloud.pkg.deployment; 2 | 3 | import com.aliyuncs.IAcsClient; 4 | import com.aliyuncs.oos.model.v20190601.CancelExecutionRequest; 5 | import com.aliyuncs.oos.model.v20190601.ListExecutionsRequest; 6 | import com.aliyuncs.oos.model.v20190601.ListExecutionsResponse; 7 | import com.aliyuncs.oos.model.v20190601.NotifyExecutionRequest; 8 | import edu.umd.cs.findbugs.annotations.NonNull; 9 | import hudson.Extension; 10 | import io.jenkins.plugins.alibabacloud.pkg.deployment.utils.AliyunClientFactory; 11 | import io.jenkins.plugins.alibabacloud.pkg.deployment.utils.Status; 12 | import io.jenkins.plugins.alibabacloud.pkg.deployment.utils.StepUtils; 13 | import org.jenkinsci.plugins.workflow.steps.*; 14 | import org.kohsuke.stapler.DataBoundConstructor; 15 | 16 | import java.util.List; 17 | import java.util.Set; 18 | 19 | /** 20 | * This class is a pipeline step: 21 | * oos template execution direction,like approve or cancle. 22 | */ 23 | public class OosExecuteNotifyStep extends Step { 24 | private final String region; 25 | //oos template execute id. 26 | private final String executeId; 27 | //oos template execution direction,like approve or cancle. 28 | private final String notifyType; 29 | 30 | public String getRegion() { 31 | return region; 32 | } 33 | 34 | public String getExecuteId() { 35 | return executeId; 36 | } 37 | 38 | public String getNotifyType() { 39 | return notifyType; 40 | } 41 | 42 | // bind data 43 | @DataBoundConstructor 44 | public OosExecuteNotifyStep(String region, String executeId, String notifyType) { 45 | this.region = region; 46 | this.executeId = executeId; 47 | this.notifyType = notifyType; 48 | } 49 | 50 | // step execution point. 51 | @Override 52 | public StepExecution start(StepContext stepContext) throws Exception { 53 | return new Execution(stepContext, this); 54 | } 55 | 56 | //plugin extension 57 | @Extension 58 | public static class DescriptorImpl extends StepDescriptor { 59 | @Override 60 | public Set> getRequiredContext() { 61 | return StepUtils.requiresDefault(); 62 | } 63 | 64 | @Override 65 | public String getFunctionName() { 66 | return "oosExecuteNotify"; 67 | } 68 | 69 | @NonNull 70 | @Override 71 | public String getDisplayName() { 72 | return "notify oos Execute"; 73 | } 74 | } 75 | 76 | //oos template execution direction,like approve or cancle. 77 | public static class Execution extends SynchronousNonBlockingStepExecution { 78 | private static final long serialVersionUID = -6033716865337394259L; 79 | private final transient OosExecuteNotifyStep step; 80 | 81 | protected Execution(@NonNull StepContext context, OosExecuteNotifyStep step) { 82 | super(context); 83 | this.step = step; 84 | } 85 | 86 | /** 87 | * run include: 88 | * oos template execution direction. 89 | */ 90 | @Override 91 | protected Void run() throws Exception { 92 | AliyunClientFactory instance = new AliyunClientFactory(); 93 | instance.build(this.step.region); 94 | IAcsClient oosClient = instance.getOosClient(); 95 | ListExecutionsRequest request = new ListExecutionsRequest(); 96 | request.setExecutionId(this.step.executeId); 97 | String status = null; 98 | List executions = oosClient.getAcsResponse(request).getExecutions(); 99 | if (executions.size() > 0) { 100 | status = executions.get(0).getStatus(); 101 | } else { 102 | throw new Exception("oos executeId:" + this.step.executeId + "is not exist"); 103 | } 104 | if ("Approve".equalsIgnoreCase(this.step.notifyType)) { 105 | if (Status.Waiting.name().equalsIgnoreCase(status)) { 106 | NotifyExecutionRequest notifyExecutionRequest = new NotifyExecutionRequest(); 107 | notifyExecutionRequest.setExecutionId(this.step.executeId); 108 | notifyExecutionRequest.setNotifyType(this.step.notifyType); 109 | oosClient.getAcsResponse(notifyExecutionRequest); 110 | } 111 | } 112 | if ("Cancelled".equalsIgnoreCase(this.step.notifyType)) { 113 | if (!Status.Success.name().equalsIgnoreCase(status) && !Status.Failed.name().equalsIgnoreCase(status) && !Status.Cancelled.name().equalsIgnoreCase(status)) { 114 | CancelExecutionRequest cancelExecutionRequest = new CancelExecutionRequest(); 115 | cancelExecutionRequest.setExecutionId(this.step.executeId); 116 | oosClient.getAcsResponse(cancelExecutionRequest); 117 | } 118 | } 119 | return null; 120 | } 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.jenkins-ci.plugins 7 | plugin 8 | 4.59 9 | 10 | 11 | io.jenkins.plugins 12 | alibabacloud-pkg-deployment 13 | 1.0-SNAPSHOT 14 | hpi 15 | 16 | 2.361.4 17 | 1.6.5 18 | 19 | Alibabacloud Package Deployment 20 | Plugins for deployment package on Alibaba Cloud 21 | 22 | 23 | MIT License 24 | http://opensource.org/licenses/MIT 25 | repo 26 | 27 | 28 | 29 | 30 | linan.zln 31 | Linan Zhang 32 | wb-zln530580@alibaba-inc.com 33 | 34 | 35 | 36 | scm:git:https://github.com/jenkinsci/${project.artifactId}-plugin.git 37 | scm:git:https://github.com/jenkinsci/${project.artifactId}-plugin 38 | scm:git:https://github.com/jenkinsci/${project.artifactId}-plugin 39 | 40 | 41 | 42 | org.jenkins-ci.plugins.workflow 43 | workflow-step-api 44 | 45 | 46 | com.alibaba 47 | fastjson 48 | 2.0.27 49 | 50 | 51 | com.aliyun.oss 52 | aliyun-sdk-oss 53 | 3.16.2 54 | 55 | 56 | org.codehaus.jettison 57 | jettison 58 | 59 | 60 | com.aliyun 61 | aliyun-java-sdk-kms 62 | 63 | 64 | com.aliyun 65 | aliyun-java-sdk-ram 66 | 67 | 68 | com.aliyun 69 | aliyun-java-sdk-core 70 | 71 | 72 | 73 | 74 | com.aliyun 75 | aliyun-java-sdk-core 76 | 4.5.10 77 | 78 | 79 | org.ini4j 80 | ini4j 81 | 82 | 83 | org.slf4j 84 | slf4j-api 85 | 86 | 87 | org.jacoco 88 | org.jacoco.agent 89 | 90 | 91 | org.apache.httpcomponents 92 | httpclient 93 | 94 | 95 | org.apache.httpcomponents 96 | httpcore 97 | 98 | 99 | com.google.code.gson 100 | gson 101 | 102 | 103 | 104 | 105 | com.aliyun 106 | aliyun-java-sdk-oos 107 | 1.5.10 108 | 109 | 110 | 111 | 112 | 113 | io.jenkins.tools.bom 114 | bom-2.361.x 115 | 1981.v17df70e84a_a_1 116 | import 117 | pom 118 | 119 | 120 | 121 | 122 | 123 | repo.jenkins-ci.org 124 | https://repo.jenkins-ci.org/public/ 125 | 126 | 127 | 128 | 129 | repo.jenkins-ci.org 130 | https://repo.jenkins-ci.org/public/ 131 | 132 | 133 | 134 | -------------------------------------------------------------------------------- /src/main/java/io/jenkins/plugins/alibabacloud/pkg/deployment/AliyunEcsOpsByOssFilePublisher.java: -------------------------------------------------------------------------------- 1 | package io.jenkins.plugins.alibabacloud.pkg.deployment; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import com.aliyun.oss.model.*; 5 | import com.aliyuncs.exceptions.ClientException; 6 | import com.aliyuncs.oos.model.v20190601.ListExecutionsRequest; 7 | import com.aliyuncs.oos.model.v20190601.StartExecutionRequest; 8 | import com.aliyuncs.oos.model.v20190601.StartExecutionResponse; 9 | import edu.umd.cs.findbugs.annotations.NonNull; 10 | import hudson.*; 11 | import hudson.model.AbstractProject; 12 | import hudson.model.Run; 13 | import hudson.model.TaskListener; 14 | import hudson.tasks.BuildStepDescriptor; 15 | import hudson.tasks.BuildStepMonitor; 16 | import hudson.tasks.Publisher; 17 | import hudson.util.FormValidation; 18 | import hudson.util.ListBoxModel; 19 | import io.jenkins.plugins.alibabacloud.pkg.deployment.utils.AliyunClientFactory; 20 | import io.jenkins.plugins.alibabacloud.pkg.deployment.utils.ResourceType; 21 | import jenkins.tasks.SimpleBuildStep; 22 | import org.apache.commons.lang.StringUtils; 23 | import org.jenkinsci.Symbol; 24 | import org.kohsuke.stapler.DataBoundConstructor; 25 | import org.kohsuke.stapler.QueryParameter; 26 | import org.kohsuke.stapler.interceptor.RequirePOST; 27 | 28 | import java.io.*; 29 | import java.util.*; 30 | 31 | /** 32 | * This class is a jenkins execute step: 33 | * apply to freestyle job post bulid or pipeline step 34 | */ 35 | public class AliyunEcsOpsByOssFilePublisher extends Publisher implements SimpleBuildStep { 36 | /** 37 | * ESS_TEMPLATE_NAME and ECS_TEMPLATE_NAME are OOS template name. 38 | */ 39 | private final static String ESS_TEMPLATE_NAME = "ACS-ESS-RollingUpdateByDownloadOSSFileAndRunCommand"; 40 | private final static String ECS_TEMPLATE_NAME = "ACS-ECS-BulkyDownloadOSSFileAndRunCommand"; 41 | 42 | //ess or ecs resource location 43 | private final String region; 44 | 45 | //resource type: ESS or ECS 46 | private final String resourceType; 47 | 48 | /** 49 | * resource id: 50 | * ESS:scalingGroupId 51 | * ECS: instanceIds by comma separated 52 | */ 53 | private final String resourceId; 54 | 55 | // oss bucket name. 56 | private final String bucket; 57 | 58 | // bulit project upload OSS bucket specific path. 59 | private final String objectName; 60 | 61 | //package project path:must be directory. 62 | private final String localPath; 63 | 64 | //OOS template download OSS bucket File to ECS specific file path 65 | private final String destinationDir; 66 | 67 | //OOS template number of execution batches. 68 | private final int batchNumber; 69 | 70 | //OOS template execute script on ECS after download OSS bucket File to ECS specific file path. 71 | private final String invokeScript; 72 | 73 | // bind data 74 | @DataBoundConstructor 75 | public AliyunEcsOpsByOssFilePublisher(String region, String resourceType, String resourceId, String bucket, String objectName, String localPath, String destinationDir, int batchNumber, String invokeScript) { 76 | this.region = region; 77 | this.resourceType = resourceType; 78 | this.resourceId = resourceId; 79 | this.bucket = bucket; 80 | this.objectName = objectName; 81 | this.localPath = localPath; 82 | this.destinationDir = destinationDir; 83 | this.batchNumber = batchNumber; 84 | this.invokeScript = invokeScript; 85 | } 86 | 87 | // getXXX functions are obtain data. 88 | public int getBatchNumber() { 89 | return batchNumber; 90 | } 91 | 92 | public String getRegion() { 93 | return region; 94 | } 95 | 96 | public String getResourceType() { 97 | return resourceType; 98 | } 99 | 100 | public String getResourceId() { 101 | return resourceId; 102 | } 103 | 104 | public String getBucket() { 105 | return bucket; 106 | } 107 | 108 | public String getObjectName() { 109 | return objectName; 110 | } 111 | 112 | public String getLocalPath() { 113 | return localPath; 114 | } 115 | 116 | public String getDestinationDir() { 117 | return destinationDir; 118 | } 119 | 120 | public String getInvokeScript() { 121 | return invokeScript; 122 | } 123 | 124 | /** 125 | * perform is core function: it can be automatically executed based on the project built. 126 | */ 127 | @Override 128 | public void perform(@NonNull Run build, @NonNull FilePath workspace, @NonNull EnvVars env, @NonNull Launcher launcher, @NonNull TaskListener listener) throws InterruptedException, IOException { 129 | /** 130 | * get and check localPath 131 | * */ 132 | final Map envVars = build.getEnvironment(listener); 133 | String localPathFromEnv = getLocalPathFromEnv(envVars); 134 | String localPath = StringUtils.trimToEmpty(localPathFromEnv); 135 | if (!localPath.isEmpty() && !localPath.startsWith("/")) { 136 | localPath = "/" + localPath; 137 | } 138 | FilePath sourcePath = workspace.withSuffix(localPath).absolutize(); 139 | if (!sourcePath.isDirectory() || !isSubDirectory(workspace, sourcePath)) { 140 | throw new IllegalArgumentException("Provided path (resolved as '" + sourcePath 141 | + "') is not a subdirectory of the workspace (resolved as '" + workspace + "')"); 142 | } 143 | final FilePath sourceDirectory = sourcePath; 144 | //acquired build name 145 | final String projectName = build.getDisplayName(); 146 | //log util 147 | final PrintStream logger = listener.getLogger(); 148 | listener.getLogger().println("resourceType:" + resourceType); 149 | AliyunClientFactory instance = new AliyunClientFactory(); 150 | instance.build(this.region); 151 | // Compress and upload the specific path of the built project. 152 | zipAndUpload(instance, projectName, sourceDirectory, logger); 153 | //batch automatic execution oos template according to resource type. 154 | String executionId = null; 155 | StartExecutionRequest request = new StartExecutionRequest(); 156 | //query execute status until execution end. 157 | ListExecutionsRequest executionsRequest = new ListExecutionsRequest(); 158 | if ("ESS".equals(resourceType)) { 159 | // ess resource execute template. 160 | executionId = essResourceExec(request, instance, listener); 161 | executionsRequest.setExecutionId(executionId); 162 | executionsRequest.setTemplateName(ESS_TEMPLATE_NAME); 163 | } else { 164 | // ecs resource execute template. 165 | executionId = ecsResourceExec(request, instance, listener); 166 | executionsRequest.setExecutionId(executionId); 167 | executionsRequest.setTemplateName(ECS_TEMPLATE_NAME); 168 | } 169 | 170 | String status = null; 171 | while (!"Success".equalsIgnoreCase(status) && !"Failed".equalsIgnoreCase(status) && !"Cancelled".equalsIgnoreCase(status)) { 172 | try { 173 | Thread.sleep(500); 174 | status = instance.getOosClient().getAcsResponse(executionsRequest).getExecutions().get(0).getStatus(); 175 | listener.getLogger().println("ExecutionId Status:" + status); 176 | } catch (ClientException e) { 177 | e.printStackTrace(); 178 | } 179 | } 180 | } 181 | 182 | // ess resource execute oos Template : ESS_TEMPLATE_NAME 183 | private String essResourceExec(StartExecutionRequest request, AliyunClientFactory instance, TaskListener listener) { 184 | request.setTemplateName(ESS_TEMPLATE_NAME); 185 | String parameter = 186 | "{\"invokeDestinationDir\":\"" + 187 | "" + destinationDir + "" + 188 | "\"," + 189 | "\"scalingGroupId\":\"" + 190 | "" + resourceId + "" + 191 | "\"," + 192 | "\"invokeScript\":\"" + 193 | invokeScript + 194 | "\"," + 195 | "\"OSSRegion\":\"" + 196 | "" + region + "" + 197 | "\"," + 198 | "\"whetherSaveToFile\":true," + 199 | "\"URLExpirationTime\":6000," + 200 | "\"batchNumber\":" + 201 | "" + 202 | this.batchNumber + 203 | "" + 204 | "," + 205 | "\"rollbackBucketName\":\"" + 206 | "" + bucket + "" + 207 | "\"," + 208 | "\"rollbackObjectName\":\"" + 209 | "" + objectName + "" + 210 | "\"," + 211 | "\"rollbackDestinationDir\":\"" + 212 | "" + destinationDir + "" + 213 | "\"," + 214 | "\"invokeBucketName\":\"" + 215 | "" + bucket + "" + 216 | "\"," + 217 | "\"invokeObjectName\":\"" + 218 | "" + objectName + "" + 219 | "\"," + 220 | "\"invokeType\":\"" + 221 | "" + "invoke" + "" + 222 | "\"}"; 223 | request.setParameters(parameter); 224 | StartExecutionResponse response = null; 225 | String executionId = null; 226 | try { 227 | response = instance.getOosClient().getAcsResponse(request); 228 | executionId = response.getExecution().getExecutionId(); 229 | listener.getLogger().println("you can login aliyun oos console to query oos template implementation progress:" + "https://oos.console.aliyun.com/" + region + "/execution/detail/" + executionId); 230 | } catch (ClientException e) { 231 | listener.getLogger().println("execute oos template error info:"); 232 | listener.getLogger().println(e); 233 | } 234 | return executionId; 235 | } 236 | 237 | // ecs resource execute oos Template : ECS_TEMPLATE_NAME 238 | private String ecsResourceExec(StartExecutionRequest request, AliyunClientFactory instance, TaskListener listener) { 239 | request.setTemplateName(ECS_TEMPLATE_NAME); 240 | String[] instanceIdString = this.resourceId.split(","); 241 | HashSet hashSet = new HashSet<>(Arrays.asList(instanceIdString)); 242 | int ids = hashSet.size(); 243 | int batchNumber = this.batchNumber; 244 | if(ids < batchNumber){ 245 | batchNumber = ids; 246 | } 247 | int base = ids / batchNumber; 248 | int[] batchArray = new int[batchNumber]; 249 | Arrays.fill(batchArray, base); 250 | for (int i = ids % batchNumber; i > 0; i--) { 251 | batchArray[i - 1]++; 252 | } 253 | String batchSpeed = JSON.toJSON(batchArray).toString(); 254 | List list = new ArrayList<>(hashSet); 255 | String instanceIds = JSON.toJSON(list).toString(); 256 | String parameter = 257 | "{\"bucketName\":\"" + 258 | this.bucket + 259 | "\"," + 260 | "\"objectName\":\"" + 261 | this.objectName + 262 | "\"," + 263 | " \"rateControl\": " + 264 | "{\"Mode\": \"Batch\"," + 265 | " \"MaxErrors\": 0, " + 266 | "\"BatchPauseOption\": \"" + 267 | "Automatic" + 268 | "\", " + 269 | "\"Batch\": " + 270 | batchSpeed + 271 | "}, " + 272 | "" + 273 | "\"destinationDir\":\"" + 274 | this.destinationDir + 275 | "\"," + 276 | "\"commandContent\":\"" + 277 | this.invokeScript + 278 | "\"," + 279 | "\"targets\":" + 280 | "{\"ResourceIds\":" + 281 | instanceIds + 282 | "," + 283 | "\"RegionId\":\"" + 284 | this.region + 285 | "\"," + 286 | "\"Type\":\"ResourceIds\"}," + 287 | "\"OSSRegion\":\"" + 288 | this.region + 289 | "\"}"; 290 | request.setParameters(parameter); 291 | StartExecutionResponse response = null; 292 | String executionId = null; 293 | try { 294 | response = instance.getOosClient().getAcsResponse(request); 295 | executionId = response.getExecution().getExecutionId(); 296 | listener.getLogger().println("you can login aliyun oos console to query oos template implementation progress:" + "https://oos.console.aliyun.com/" + region + "/execution/detail/" + executionId); 297 | } catch (ClientException e) { 298 | listener.getLogger().println("execute oos template error info:"); 299 | listener.getLogger().println(e); 300 | } 301 | return executionId; 302 | } 303 | 304 | //compress directory of localPath and upload to OSS. 305 | private void zipAndUpload(AliyunClientFactory instance, String projectName, FilePath sourceDirectory, PrintStream logger) throws InterruptedException, IOException { 306 | File zipFile = zipProject(projectName, sourceDirectory, logger); 307 | uploadOssFile(instance, zipFile, logger); 308 | } 309 | 310 | private File zipProject(String projectName, FilePath sourceDirectory, PrintStream logger) throws IOException, InterruptedException { 311 | File zipFile = null; 312 | File versionFile; 313 | versionFile = new File(sourceDirectory + "/"); 314 | InputStreamReader reader = null; 315 | String version = null; 316 | try { 317 | reader = new InputStreamReader(new FileInputStream(versionFile), "UTF-8"); 318 | char[] chars = new char[(int) versionFile.length() - 1]; 319 | reader.read(chars); 320 | version = new String(chars); 321 | reader.close(); 322 | } catch (IOException e) { 323 | e.printStackTrace(); 324 | } finally { 325 | if (reader != null) { 326 | reader.close(); 327 | } 328 | } 329 | if (version != null) { 330 | zipFile = new File("/tmp/" + projectName + "-" + version + ".zip"); 331 | final boolean fileCreated = zipFile.createNewFile(); 332 | if (!fileCreated) { 333 | logger.println("File already exists, overwriting: " + zipFile.getPath()); 334 | } 335 | } else { 336 | zipFile = File.createTempFile(projectName + "-", ".zip"); 337 | } 338 | logger.println("Zipping files into " + zipFile.getAbsolutePath()); 339 | 340 | FileOutputStream outputStream = new FileOutputStream(zipFile); 341 | try { 342 | sourceDirectory.zip( 343 | outputStream, 344 | new FileFilter() { 345 | @Override 346 | public boolean accept(File pathname) { 347 | return true; 348 | } 349 | } 350 | ); 351 | } finally { 352 | outputStream.close(); 353 | } 354 | return zipFile; 355 | } 356 | 357 | private void uploadOssFile(AliyunClientFactory instance, File zipFile, PrintStream logger) { 358 | String bucketName = this.bucket; 359 | try { 360 | InitiateMultipartUploadRequest request = new InitiateMultipartUploadRequest(bucketName, objectName); 361 | InitiateMultipartUploadResult upresult = instance.getOssClient().initiateMultipartUpload(request); 362 | String uploadId = upresult.getUploadId(); 363 | List partETags = new ArrayList(); 364 | final long partSize = 1 * 1024 * 1024L; 365 | long fileLength = zipFile.length(); 366 | int partCount = (int) (fileLength / partSize); 367 | if (fileLength % partSize != 0) { 368 | partCount++; 369 | } 370 | for (int i = 0; i < partCount; i++) { 371 | long startPos = i * partSize; 372 | long curPartSize = (i + 1 == partCount) ? (fileLength - startPos) : partSize; 373 | InputStream instream = new FileInputStream(zipFile); 374 | instream.skip(startPos); 375 | UploadPartRequest uploadPartRequest = new UploadPartRequest(); 376 | uploadPartRequest.setBucketName(bucketName); 377 | uploadPartRequest.setKey(objectName); 378 | uploadPartRequest.setUploadId(uploadId); 379 | uploadPartRequest.setInputStream(instream); 380 | uploadPartRequest.setPartSize(curPartSize); 381 | uploadPartRequest.setPartNumber(i + 1); 382 | UploadPartResult uploadPartResult = instance.getOssClient().uploadPart(uploadPartRequest); 383 | partETags.add(uploadPartResult.getPartETag()); 384 | } 385 | CompleteMultipartUploadRequest completeMultipartUploadRequest = 386 | new CompleteMultipartUploadRequest(bucketName, objectName, uploadId, partETags); 387 | CompleteMultipartUploadResult completeMultipartUploadResult = instance.getOssClient().completeMultipartUpload(completeMultipartUploadRequest); 388 | logger.println(completeMultipartUploadResult.getETag()); 389 | } catch (Exception e) { 390 | logger.println(e); 391 | } finally { 392 | final boolean deleted = zipFile.delete(); 393 | if (!deleted) { 394 | logger.println("Failed to clean up file " + zipFile.getPath()); 395 | } 396 | if (instance.getOssClient() != null) { 397 | instance.getOssClient().shutdown(); 398 | } 399 | } 400 | } 401 | 402 | @Override 403 | public DescriptorImpl getDescriptor() { 404 | return (DescriptorImpl) super.getDescriptor(); 405 | } 406 | 407 | private boolean isSubDirectory(FilePath parent, FilePath child) { 408 | FilePath parentFolder = child; 409 | while (parentFolder != null) { 410 | if (parent.equals(parentFolder)) { 411 | return true; 412 | } 413 | parentFolder = parentFolder.getParent(); 414 | } 415 | return false; 416 | } 417 | 418 | public String getLocalPathFromEnv(Map envVars) { 419 | return Util.replaceMacro(this.localPath, envVars); 420 | } 421 | 422 | @Override 423 | public BuildStepMonitor getRequiredMonitorService() { 424 | return BuildStepMonitor.NONE; 425 | } 426 | 427 | /** 428 | * extension build step descriptor: 429 | * accessKeyId and accessKeySecret set global configuration in system management. 430 | * can set select component. 431 | */ 432 | @Extension 433 | @Symbol("Alibabacloud Automatic Package Deployment") 434 | public static final class DescriptorImpl extends BuildStepDescriptor { 435 | @RequirePOST 436 | @SuppressWarnings("lgtm[jenkins/no-permission-check]") 437 | public FormValidation doCheckObjectName(@QueryParameter String objectName) { 438 | if (objectName.startsWith("/")) 439 | return FormValidation.error("objectName can not start with '/'"); 440 | return FormValidation.ok(); 441 | } 442 | 443 | // select component about region. 444 | public ListBoxModel doFillRegionItems() throws ClientException { 445 | ListBoxModel model = new ListBoxModel(); 446 | model.add("华东1(杭州)", "cn-hangzhou"); 447 | model.add("华北1(青岛)", "cn-qingdao"); 448 | model.add("华北2(北京)", "cn-beijing"); 449 | model.add("华北3(张家口)", "cn-zhangjiakou"); 450 | model.add("华北5(呼和浩特)", "cn-huhehaote"); 451 | model.add("华北6(乌兰察布)", "cn-wulanchabu"); 452 | model.add("华东2(上海)", "cn-shanghai"); 453 | model.add("华南1(深圳)", "cn-shenzhen"); 454 | model.add("华南2(河源)", "cn-heyuan"); 455 | model.add("华南3(广州)", "cn-guangzhou"); 456 | model.add("西南1(成都)", "cn-chengdu"); 457 | model.add("中国(香港)", "cn-hongkong"); 458 | model.add("亚太东北 1 (东京)", "ap-northeast-1"); 459 | model.add("韩国(首尔)", "ap-northeast-2"); 460 | model.add("亚太东南 1 (新加坡)", "ap-southeast-1"); 461 | model.add("亚太东南 2 (悉尼)", "ap-southeast-2"); 462 | model.add("亚太东南 3 (吉隆坡)", "ap-southeast-3"); 463 | model.add("菲律宾(马尼拉)", "ap-southeast-6"); 464 | model.add("亚太东南 5 (雅加达)", "ap-southeast-5"); 465 | model.add("亚太南部 1 (孟买)", "ap-south-1"); 466 | model.add("泰国(曼谷)", "ap-southeast-7"); 467 | model.add("美国东部 1 (弗吉尼亚)", "us-east-1"); 468 | model.add("美国西部 1 (硅谷)", "us-west-1"); 469 | model.add("英国 (伦敦)", "eu-west-1"); 470 | model.add("中东东部 1 (迪拜)", "me-east-1"); 471 | model.add("沙特(利雅得)", "me-central-1"); 472 | model.add("欧洲中部 1 (法兰克福)", "eu-central-1"); 473 | return model; 474 | } 475 | 476 | // select component about resource type. 477 | @RequirePOST 478 | @SuppressWarnings("lgtm[jenkins/no-permission-check]") 479 | public ListBoxModel doFillResourceTypeItems() throws ClientException { 480 | ListBoxModel items = new ListBoxModel(); 481 | for (ResourceType resourceType : ResourceType.values()) { 482 | items.add(resourceType.getName(), resourceType.getType()); 483 | } 484 | return items; 485 | } 486 | 487 | 488 | @Override 489 | public boolean isApplicable(Class jobType) { 490 | return true; 491 | } 492 | 493 | //extension plugin name. 494 | @NonNull 495 | @Override 496 | public String getDisplayName() { 497 | return "Alibabacloud Automatic Package Deployment"; 498 | } 499 | } 500 | 501 | } 502 | -------------------------------------------------------------------------------- /src/main/java/io/jenkins/plugins/alibabacloud/pkg/deployment/OssUploadAndOosExecStep.java: -------------------------------------------------------------------------------- 1 | package io.jenkins.plugins.alibabacloud.pkg.deployment; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import com.aliyun.oss.OSS; 5 | import com.aliyun.oss.model.*; 6 | import com.aliyuncs.IAcsClient; 7 | import com.aliyuncs.exceptions.ClientException; 8 | import com.aliyuncs.oos.model.v20190601.ListExecutionsRequest; 9 | import com.aliyuncs.oos.model.v20190601.StartExecutionRequest; 10 | import com.aliyuncs.oos.model.v20190601.StartExecutionResponse; 11 | import edu.umd.cs.findbugs.annotations.NonNull; 12 | import hudson.Extension; 13 | import hudson.FilePath; 14 | import hudson.Util; 15 | import hudson.model.Run; 16 | import hudson.model.TaskListener; 17 | import hudson.util.FormValidation; 18 | import hudson.util.ListBoxModel; 19 | import io.jenkins.plugins.alibabacloud.pkg.deployment.utils.AliyunClientFactory; 20 | import io.jenkins.plugins.alibabacloud.pkg.deployment.utils.StepUtils; 21 | import org.apache.commons.lang.StringUtils; 22 | import org.jenkinsci.plugins.workflow.steps.*; 23 | import org.kohsuke.stapler.DataBoundConstructor; 24 | import org.kohsuke.stapler.QueryParameter; 25 | import org.kohsuke.stapler.interceptor.RequirePOST; 26 | 27 | import java.io.*; 28 | import java.util.*; 29 | /** 30 | * This class is a pipeline step: 31 | * 1.compress specific directory 32 | * 2.upload to oss 33 | * 3.execute oos template (download oss file to ecs specific path) 34 | */ 35 | public class OssUploadAndOosExecStep extends Step { 36 | /** 37 | * ESS_TEMPLATE_NAME and ECS_TEMPLATE_NAME are OOS template name. 38 | */ 39 | private final static String ESS_TEMPLATE_NAME = "ACS-ESS-RollingUpdateByDownloadOSSFileAndRunCommand"; 40 | private final static String ECS_TEMPLATE_NAME = "ACS-ECS-BulkyDownloadOSSFileAndRunCommand"; 41 | 42 | //ess or ecs resource location 43 | private final String region; 44 | 45 | //resource type: ESS or ECS 46 | private final String resourceType; 47 | 48 | /** 49 | * resource id: 50 | * ESS:scalingGroupId 51 | * ECS: instanceIds by comma separated 52 | */ 53 | private final String resourceId; 54 | // oss bucket name. 55 | private final String bucket; 56 | // bulit project upload OSS bucket specific path. 57 | private final String objectName; 58 | //package project path:must be directory. 59 | private final String localPath; 60 | //the OOS template execution mode. Valid values:Automatic、FailurePause、Debug. 61 | private final String mode; 62 | //the OOS template loop mode. Valid values: Automatic、FirstBatchPause、EveryBatchPause. 63 | private final String pausePolicy; 64 | //OOS template number of execution batches. 65 | private final int batchNumber; 66 | //OOS template download OSS bucket File to ECS specific file path 67 | private final String destinationDir; 68 | //OOS template execute script on ECS after download OSS bucket File to ECS specific file path. 69 | private final String invokeScript; 70 | 71 | // getXXX functions are obtain data. 72 | public String getRegion() { 73 | return region; 74 | } 75 | 76 | public String getResourceType() { 77 | return resourceType; 78 | } 79 | 80 | public String getResourceId() { 81 | return resourceId; 82 | } 83 | 84 | public String getBucket() { 85 | return bucket; 86 | } 87 | 88 | public String getObjectName() { 89 | return objectName; 90 | } 91 | 92 | public String getLocalPath() { 93 | return localPath; 94 | } 95 | 96 | public String getMode() { 97 | return mode; 98 | } 99 | 100 | public String getPausePolicy() { 101 | return pausePolicy; 102 | } 103 | 104 | public int getBatchNumber() { 105 | return batchNumber; 106 | } 107 | 108 | public String getDestinationDir() { 109 | return destinationDir; 110 | } 111 | 112 | public String getInvokeScript() { 113 | return invokeScript; 114 | } 115 | 116 | // bind data 117 | @DataBoundConstructor 118 | public OssUploadAndOosExecStep(String region, String resourceType, String resourceId, String bucket, String objectName, String localPath, String mode, String pausePolicy, int batchNumber, String destinationDir, String invokeScript) { 119 | this.region = region; 120 | this.resourceType = resourceType; 121 | this.resourceId = resourceId; 122 | this.bucket = bucket; 123 | this.objectName = objectName; 124 | this.localPath = localPath; 125 | this.mode = mode; 126 | this.pausePolicy = pausePolicy; 127 | this.batchNumber = batchNumber; 128 | this.destinationDir = destinationDir; 129 | this.invokeScript = invokeScript; 130 | } 131 | 132 | // step execution point. 133 | @Override 134 | public StepExecution start(StepContext stepContext) throws Exception { 135 | return new Execution(stepContext, this); 136 | } 137 | 138 | //plugin extension 139 | @Extension 140 | public static class DescriptorImpl extends StepDescriptor { 141 | 142 | @Override 143 | public Set> getRequiredContext() { 144 | return StepUtils.requires(TaskListener.class, Run.class, FilePath.class); 145 | } 146 | 147 | @Override 148 | public String getFunctionName() { 149 | return "ossUploadAndOosExec"; 150 | } 151 | 152 | @NonNull 153 | @Override 154 | public String getDisplayName() { 155 | return "OSS upload built project and OOS execute"; 156 | } 157 | 158 | public ListBoxModel doFillRegionItems() { 159 | ListBoxModel model = new ListBoxModel(); 160 | model.add("华东1(杭州)", "cn-hangzhou"); 161 | model.add("华北1(青岛)", "cn-qingdao"); 162 | model.add("华北2(北京)", "cn-beijing"); 163 | model.add("华北3(张家口)", "cn-zhangjiakou"); 164 | model.add("华北5(呼和浩特)", "cn-huhehaote"); 165 | model.add("华北6(乌兰察布)", "cn-wulanchabu"); 166 | model.add("华东2(上海)", "cn-shanghai"); 167 | model.add("华南1(深圳)", "cn-shenzhen"); 168 | model.add("华南2(河源)", "cn-heyuan"); 169 | model.add("华南3(广州)", "cn-guangzhou"); 170 | model.add("西南1(成都)", "cn-chengdu"); 171 | model.add("中国(香港)", "cn-hongkong"); 172 | model.add("亚太东北 1 (东京)", "ap-northeast-1"); 173 | model.add("韩国(首尔)", "ap-northeast-2"); 174 | model.add("亚太东南 1 (新加坡)", "ap-southeast-1"); 175 | model.add("亚太东南 2 (悉尼)", "ap-southeast-2"); 176 | model.add("亚太东南 3 (吉隆坡)", "ap-southeast-3"); 177 | model.add("菲律宾(马尼拉)", "ap-southeast-6"); 178 | model.add("亚太东南 5 (雅加达)", "ap-southeast-5"); 179 | model.add("亚太南部 1 (孟买)", "ap-south-1"); 180 | model.add("泰国(曼谷)", "ap-southeast-7"); 181 | model.add("美国东部 1 (弗吉尼亚)", "us-east-1"); 182 | model.add("美国西部 1 (硅谷)", "us-west-1"); 183 | model.add("英国 (伦敦)", "eu-west-1"); 184 | model.add("中东东部 1 (迪拜)", "me-east-1"); 185 | model.add("沙特(利雅得)", "me-central-1"); 186 | model.add("欧洲中部 1 (法兰克福)", "eu-central-1"); 187 | return model; 188 | } 189 | 190 | public ListBoxModel doFillResourceTypeItems() { 191 | ListBoxModel model = new ListBoxModel(); 192 | model.add("ESS ScalingGroup", "ESS"); 193 | model.add("ECS Instance", "ECS"); 194 | return model; 195 | } 196 | 197 | public ListBoxModel doFillModeItems() { 198 | ListBoxModel model = new ListBoxModel(); 199 | model.add("自动执行", "Automatic"); 200 | model.add("失败暂停", "FailurePause"); 201 | model.add("单步执行", "Debug"); 202 | return model; 203 | } 204 | 205 | @RequirePOST 206 | @SuppressWarnings("lgtm[jenkins/no-permission-check]") 207 | public FormValidation doCheckObjectName(@QueryParameter String objectName) { 208 | if (objectName.startsWith("/")) 209 | return FormValidation.error("objectName can not start with '/'"); 210 | return FormValidation.ok(); 211 | } 212 | 213 | public ListBoxModel doFillPausePolicyItems() { 214 | ListBoxModel model = new ListBoxModel(); 215 | model.add("不暂停", "Automatic"); 216 | model.add("第一批暂停", "FirstBatchPause"); 217 | model.add("每批暂停", "EveryBatchPause"); 218 | return model; 219 | } 220 | 221 | } 222 | 223 | // specific behavior of execution and return oos template execute id. 224 | public static class Execution extends SynchronousNonBlockingStepExecution { 225 | private static final long serialVersionUID = 1L; 226 | private final transient OssUploadAndOosExecStep step; 227 | 228 | protected Execution(@NonNull StepContext context, OssUploadAndOosExecStep step) { 229 | super(context); 230 | this.step = step; 231 | } 232 | 233 | /** 234 | * run include: 235 | * 1.compress specific directory 236 | * 2.upload compressed file to oss 237 | * 3.OOS template execute script on ECS after OOS template download OSS bucket File to ECS specific file path. 238 | */ 239 | @Override 240 | protected String run() throws Exception { 241 | AliyunClientFactory instance = new AliyunClientFactory(); 242 | instance.build(this.step.region); 243 | IAcsClient oosClient = instance.getOosClient(); 244 | OSS ossClient = instance.getOssClient(); 245 | TaskListener listener = getContext().get(TaskListener.class); 246 | Run build = getContext().get(Run.class); 247 | FilePath workspace = getContext().get(FilePath.class); 248 | final Map envVars = build.getEnvironment(listener); 249 | String localPathFromEnv = getLocalPathFromEnv(envVars); 250 | String localPath = StringUtils.trimToEmpty(localPathFromEnv); 251 | if (!this.step.localPath.isEmpty() && !this.step.localPath.startsWith("/")) { 252 | localPath = "/" + this.step.localPath; 253 | } 254 | FilePath sourcePath = workspace.withSuffix(localPath).absolutize(); 255 | if (!sourcePath.isDirectory() || !isSubDirectory(workspace, sourcePath)) { 256 | throw new IllegalArgumentException("Provided path (resolved as '" + sourcePath 257 | + "') is not a subdirectory of the workspace (resolved as '" + workspace + "')"); 258 | } 259 | final FilePath sourceDirectory = sourcePath; 260 | final String projectName = build.getDisplayName(); 261 | final PrintStream logger = listener.getLogger(); 262 | zipAndUpload(ossClient, projectName, sourceDirectory, logger); 263 | String executionId = null; 264 | StartExecutionRequest request = new StartExecutionRequest(); 265 | request.setMode(this.step.mode); 266 | ListExecutionsRequest executionsRequest = new ListExecutionsRequest(); 267 | if ("ESS".equals(this.step.resourceType)) { 268 | executionId = essResourceExec(request, oosClient, listener); 269 | executionsRequest.setExecutionId(executionId); 270 | executionsRequest.setTemplateName(ESS_TEMPLATE_NAME); 271 | } else { 272 | executionId = ecsResourceExec(request, oosClient, listener); 273 | executionsRequest.setExecutionId(executionId); 274 | executionsRequest.setTemplateName(ECS_TEMPLATE_NAME); 275 | } 276 | String status = null; 277 | while (!"Success".equalsIgnoreCase(status) && !"Failed".equalsIgnoreCase(status) && !"Cancelled".equalsIgnoreCase(status) && !"Waiting".equalsIgnoreCase(status)) { 278 | try { 279 | Thread.sleep(5000); 280 | status = oosClient.getAcsResponse(executionsRequest).getExecutions().get(0).getStatus(); 281 | listener.getLogger().println("ExecutionId Status:" + status); 282 | } catch (ClientException e) { 283 | e.printStackTrace(); 284 | } 285 | } 286 | return executionId; 287 | } 288 | 289 | // ecs resource execute oos Template : ECS_TEMPLATE_NAME 290 | private String ecsResourceExec(StartExecutionRequest request, IAcsClient oosClient, TaskListener listener) { 291 | request.setTemplateName(ECS_TEMPLATE_NAME); 292 | String[] instanceIdString = this.step.resourceId.split(","); 293 | HashSet hashSet = new HashSet<>(Arrays.asList(instanceIdString)); 294 | int ids = hashSet.size(); 295 | int batchNumber = this.step.batchNumber; 296 | if(ids < batchNumber){ 297 | batchNumber = ids; 298 | } 299 | int base = ids / batchNumber; 300 | int[] batchArray = new int[batchNumber]; 301 | Arrays.fill(batchArray, base); 302 | for (int i = ids % batchNumber; i > 0; i--) { 303 | batchArray[i - 1]++; 304 | } 305 | String batchSpeed = JSON.toJSON(batchArray).toString(); 306 | List list = new ArrayList<>(hashSet); 307 | String instanceIds = JSON.toJSON(list).toString(); 308 | String parameter = 309 | "{\"bucketName\":\"" + 310 | this.step.bucket + 311 | "\"," + 312 | "\"objectName\":\"" + 313 | this.step.objectName + 314 | "\"," + 315 | " \"rateControl\": " + 316 | "{\"Mode\": \"Batch\"," + 317 | " \"MaxErrors\": 0, " + 318 | "\"BatchPauseOption\": \"" + 319 | this.step.pausePolicy + 320 | "\", " + 321 | "\"Batch\": " + 322 | batchSpeed + 323 | "}, " + 324 | "" + 325 | "\"destinationDir\":\"" + 326 | this.step.destinationDir + 327 | "\"," + 328 | "\"commandContent\":\"" + 329 | this.step.invokeScript + 330 | "\"," + 331 | "\"targets\":" + 332 | "{\"ResourceIds\":" + 333 | instanceIds + 334 | "," + 335 | "\"RegionId\":\"" + 336 | this.step.region + 337 | "\"," + 338 | "\"Type\":\"ResourceIds\"}," + 339 | "\"OSSRegion\":\"" + 340 | this.step.region + 341 | "\"}"; 342 | request.setParameters(parameter); 343 | StartExecutionResponse response = null; 344 | String executionId = null; 345 | try { 346 | response = oosClient.getAcsResponse(request); 347 | executionId = response.getExecution().getExecutionId(); 348 | listener.getLogger().println("you can login aliyun oos console to query oos template implementation progress:" + "https://oos.console.aliyun.com/" + this.step.region + "/execution/detail/" + executionId); 349 | } catch (ClientException e) { 350 | listener.getLogger().println("execute oos template error info:"); 351 | listener.getLogger().println(e); 352 | } 353 | return executionId; 354 | } 355 | 356 | // ess resource execute oos Template : ESS_TEMPLATE_NAME 357 | private String essResourceExec(StartExecutionRequest request, IAcsClient oosClient, TaskListener listener) { 358 | request.setTemplateName(ESS_TEMPLATE_NAME); 359 | String parameter = 360 | "{\"invokeDestinationDir\":\"" + 361 | "" + this.step.destinationDir + "" + 362 | "\"," + 363 | "\"scalingGroupId\":\"" + 364 | "" + this.step.resourceId + "" + 365 | "\"," + 366 | "\"invokeScript\":\"" + 367 | this.step.invokeScript + 368 | "\"," + 369 | "\"OSSRegion\":\"" + 370 | "" + this.step.region + "" + 371 | "\"," + 372 | "\"batchPauseOption\":\"" + 373 | "" + this.step.pausePolicy + "" + 374 | "\"," + 375 | "\"whetherSaveToFile\":true," + 376 | "\"URLExpirationTime\":" + 377 | "6000" + 378 | "," + 379 | "\"batchNumber\":" + 380 | "" + 381 | this.step.batchNumber + 382 | "" + 383 | "," + 384 | "\"rollbackBucketName\":\"" + 385 | "" + this.step.bucket + "" + 386 | "\"," + 387 | "\"rollbackObjectName\":\"" + 388 | "" + this.step.objectName + "" + 389 | "\"," + 390 | "\"rollbackDestinationDir\":\"" + 391 | "" + this.step.destinationDir + "" + 392 | "\"," + 393 | "\"invokeBucketName\":\"" + 394 | "" + this.step.bucket + "" + 395 | "\"," + 396 | "\"invokeObjectName\":\"" + 397 | "" + this.step.objectName + "" + 398 | "\"," + 399 | "\"invokeType\":\"" + 400 | "" + "invoke" + "" + 401 | "\"}"; 402 | request.setParameters(parameter); 403 | StartExecutionResponse response = null; 404 | String executionId = null; 405 | try { 406 | response = oosClient.getAcsResponse(request); 407 | executionId = response.getExecution().getExecutionId(); 408 | listener.getLogger().println("you can login aliyun oos console to query oos template implementation progress:" + "https://oos.console.aliyun.com/" + this.step.region + "/execution/detail/" + executionId); 409 | } catch (ClientException e) { 410 | listener.getLogger().println("execute oos template error info:"); 411 | listener.getLogger().println(e); 412 | } 413 | return executionId; 414 | } 415 | 416 | //compress directory of localPath and upload to OSS. 417 | private void zipAndUpload(OSS ossClient, String projectName, FilePath sourceDirectory, PrintStream logger) throws InterruptedException, IOException { 418 | File zipFile = null; 419 | File versionFile; 420 | versionFile = new File(sourceDirectory + "/"); 421 | InputStreamReader reader = null; 422 | String version = null; 423 | try { 424 | reader = new InputStreamReader(new FileInputStream(versionFile), "UTF-8"); 425 | char[] chars = new char[(int) versionFile.length() - 1]; 426 | reader.read(chars); 427 | version = new String(chars); 428 | reader.close(); 429 | } catch (IOException e) { 430 | e.printStackTrace(); 431 | } finally { 432 | if (reader != null) { 433 | reader.close(); 434 | } 435 | } 436 | if (version != null) { 437 | zipFile = new File("/tmp/" + projectName + "-" + version + ".zip"); 438 | final boolean fileCreated = zipFile.createNewFile(); 439 | if (!fileCreated) { 440 | logger.println("File already exists, overwriting: " + zipFile.getPath()); 441 | } 442 | } else { 443 | zipFile = File.createTempFile(projectName + "-", ".zip"); 444 | } 445 | 446 | FileOutputStream outputStream = new FileOutputStream(zipFile); 447 | try { 448 | sourceDirectory.zip( 449 | outputStream, 450 | new FileFilter() { 451 | @Override 452 | public boolean accept(File pathname) { 453 | return true; 454 | } 455 | } 456 | ); 457 | } finally { 458 | outputStream.close(); 459 | } 460 | String bucketName = this.step.bucket; 461 | 462 | try { 463 | InitiateMultipartUploadRequest request = new InitiateMultipartUploadRequest(bucketName, this.step.objectName); 464 | InitiateMultipartUploadResult upresult = ossClient.initiateMultipartUpload(request); 465 | String uploadId = upresult.getUploadId(); 466 | List partETags = new ArrayList(); 467 | final long partSize = 1 * 1024 * 1024L; 468 | long fileLength = zipFile.length(); 469 | int partCount = (int) (fileLength / partSize); 470 | if (fileLength % partSize != 0) { 471 | partCount++; 472 | } 473 | for (int i = 0; i < partCount; i++) { 474 | long startPos = i * partSize; 475 | long curPartSize = (i + 1 == partCount) ? (fileLength - startPos) : partSize; 476 | InputStream instream = new FileInputStream(zipFile); 477 | instream.skip(startPos); 478 | UploadPartRequest uploadPartRequest = new UploadPartRequest(); 479 | uploadPartRequest.setBucketName(bucketName); 480 | uploadPartRequest.setKey(this.step.objectName); 481 | uploadPartRequest.setUploadId(uploadId); 482 | uploadPartRequest.setInputStream(instream); 483 | uploadPartRequest.setPartSize(curPartSize); 484 | uploadPartRequest.setPartNumber(i + 1); 485 | UploadPartResult uploadPartResult = ossClient.uploadPart(uploadPartRequest); 486 | partETags.add(uploadPartResult.getPartETag()); 487 | } 488 | CompleteMultipartUploadRequest completeMultipartUploadRequest = 489 | new CompleteMultipartUploadRequest(bucketName, this.step.objectName, uploadId, partETags); 490 | CompleteMultipartUploadResult completeMultipartUploadResult = ossClient.completeMultipartUpload(completeMultipartUploadRequest); 491 | logger.println(completeMultipartUploadResult.getETag()); 492 | } catch (Exception e) { 493 | logger.println(e); 494 | } finally { 495 | final boolean deleted = zipFile.delete(); 496 | if (!deleted) { 497 | logger.println("Failed to clean up file " + zipFile.getPath()); 498 | } 499 | if (ossClient != null) { 500 | ossClient.shutdown(); 501 | } 502 | } 503 | } 504 | 505 | private boolean isSubDirectory(FilePath parent, FilePath child) { 506 | FilePath parentFolder = child; 507 | while (parentFolder != null) { 508 | if (parent.equals(parentFolder)) { 509 | return true; 510 | } 511 | parentFolder = parentFolder.getParent(); 512 | } 513 | return false; 514 | } 515 | 516 | public String getLocalPathFromEnv(Map envVars) { 517 | return Util.replaceMacro(this.step.localPath, envVars); 518 | } 519 | } 520 | 521 | } 522 | --------------------------------------------------------------------------------