[DeploymentManager] Deploy test envs using Murano
* deploy environement using custom object model * store openstack credentials * use object model from the config within application repository Change-Id: I18f1eb590845acbd7a8287797b29cbd727b113da
This commit is contained in:
parent
d7be94d354
commit
2110eec0e8
7
deployment-manager/.gitignore
vendored
Normal file
7
deployment-manager/.gitignore
vendored
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
*.classpath
|
||||||
|
*.project
|
||||||
|
*.iml
|
||||||
|
*.settings
|
||||||
|
.idea/
|
||||||
|
work/
|
||||||
|
target/
|
0
deployment-manager/CONTRIBUTING.md
Normal file
0
deployment-manager/CONTRIBUTING.md
Normal file
201
deployment-manager/LICENSE
Normal file
201
deployment-manager/LICENSE
Normal file
@ -0,0 +1,201 @@
|
|||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright {yyyy} {name of copyright owner}
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
29
deployment-manager/README.md
Normal file
29
deployment-manager/README.md
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
# Openstack Murano Deployment Manager Plugin
|
||||||
|
|
||||||
|
This plugin manages Openstack Murano environments
|
||||||
|
|
||||||
|
# Build
|
||||||
|
mvn clean verify
|
||||||
|
Creates the plugin HPI package for use with Jenkins.
|
||||||
|
|
||||||
|
# Run by Maven
|
||||||
|
mvn hpi:run
|
||||||
|
Runs Jenkins with the plugin installed
|
||||||
|
|
||||||
|
# License
|
||||||
|
|
||||||
|
(The Apache v2 License)
|
||||||
|
|
||||||
|
Copyright 2016 Google Inc. All Rights Reserved.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
139
deployment-manager/pom.xml
Normal file
139
deployment-manager/pom.xml
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<groupId>org.jenkins-ci.plugins</groupId>
|
||||||
|
<artifactId>plugin</artifactId>
|
||||||
|
<version>2.15</version>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<name>Murano Deployment Manager Jenkins Plugin</name>
|
||||||
|
|
||||||
|
<description>
|
||||||
|
This plugin provides integration with Openstack Murano
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<url>https://wiki.jenkins-ci.org/display/JENKINS/Murano+Deployment+Manager+Plugin</url>
|
||||||
|
<artifactId>murano-deployment-manager</artifactId>
|
||||||
|
<packaging>hpi</packaging>
|
||||||
|
<version>0.1-SNAPSHOT</version>
|
||||||
|
|
||||||
|
<licenses>
|
||||||
|
<license>
|
||||||
|
<name>The Apache V2 License</name>
|
||||||
|
<url>http://www.apache.org/licenses/LICENSE-2.0</url>
|
||||||
|
<distribution>repo</distribution>
|
||||||
|
</license>
|
||||||
|
</licenses>
|
||||||
|
|
||||||
|
<developers>
|
||||||
|
<developer>
|
||||||
|
<name>Alexey Khivin</name>
|
||||||
|
<email>akhivin@gmail.com</email>
|
||||||
|
</developer>
|
||||||
|
</developers>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<java.level>8</java.level>
|
||||||
|
<jenkins.version>2.23</jenkins.version>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
<openstack4jversion>3.0.2</openstack4jversion>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<repositories>
|
||||||
|
<repository>
|
||||||
|
<id>repo.jenkins-ci.org</id>
|
||||||
|
<name>Jenkins Repository</name>
|
||||||
|
<url>http://repo.jenkins-ci.org/public/</url>
|
||||||
|
</repository>
|
||||||
|
<repository>
|
||||||
|
<id>jgit-repository</id>
|
||||||
|
<name>Eclipse JGit Repository</name>
|
||||||
|
<url>http://download.eclipse.org/jgit/maven</url>
|
||||||
|
</repository>
|
||||||
|
</repositories>
|
||||||
|
|
||||||
|
<pluginRepositories>
|
||||||
|
<pluginRepository>
|
||||||
|
<id>repo.jenkins-ci.org</id>
|
||||||
|
<url>http://repo.jenkins-ci.org/public/</url>
|
||||||
|
</pluginRepository>
|
||||||
|
</pluginRepositories>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-deploy-plugin</artifactId>
|
||||||
|
<version>2.8.2</version>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.maven.wagon</groupId>
|
||||||
|
<artifactId>wagon-http</artifactId>
|
||||||
|
<version>1.0-beta-6</version>
|
||||||
|
<type>jar</type>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
<scm>
|
||||||
|
<connection>scm:git:git://github.com/jenkinsci/${project.artifactId}-plugin.git</connection>
|
||||||
|
<developerConnection>scm:git:git@github.com:jenkinsci/${project.artifactId}-plugin.git</developerConnection>
|
||||||
|
<url>https://github.com/jenkinsci/${project.artifactId}-plugin</url>
|
||||||
|
<tag>HEAD</tag>
|
||||||
|
</scm>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.mockito</groupId>
|
||||||
|
<artifactId>mockito-all</artifactId>
|
||||||
|
<version>RELEASE</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.pacesys</groupId>
|
||||||
|
<artifactId>openstack4j-core</artifactId>
|
||||||
|
<version>${openstack4jversion}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.pacesys.openstack4j.connectors</groupId>
|
||||||
|
<artifactId>openstack4j-httpclient</artifactId>
|
||||||
|
<version>${openstack4jversion}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.googlecode.json-simple</groupId>
|
||||||
|
<artifactId>json-simple</artifactId>
|
||||||
|
<version>1.1.1</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.httpcomponents</groupId>
|
||||||
|
<artifactId>httpclient</artifactId>
|
||||||
|
<version>4.5.1</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.fasterxml.jackson.core</groupId>
|
||||||
|
<artifactId>jackson-databind</artifactId>
|
||||||
|
<version>2.8.3</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.fasterxml.jackson.dataformat</groupId>
|
||||||
|
<artifactId>jackson-dataformat-yaml</artifactId>
|
||||||
|
<version>2.7.4</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.jenkins-ci.plugins</groupId>
|
||||||
|
<artifactId>credentials</artifactId>
|
||||||
|
<version>LATEST</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</project>
|
@ -0,0 +1,28 @@
|
|||||||
|
package org.openstack.murano.jenkins_plugins.muranoci.deploy;
|
||||||
|
|
||||||
|
import hudson.model.Descriptor;
|
||||||
|
import net.sf.json.JSONObject;
|
||||||
|
import org.kohsuke.stapler.StaplerRequest;
|
||||||
|
|
||||||
|
import static java.util.Objects.requireNonNull;
|
||||||
|
|
||||||
|
public abstract class AbstractMuranoDeploymentDescriptor
|
||||||
|
extends Descriptor<MuranoDeployment> {
|
||||||
|
|
||||||
|
protected AbstractMuranoDeploymentDescriptor(Class<? extends MuranoDeployment> clazz) {
|
||||||
|
super(requireNonNull(clazz));
|
||||||
|
load();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean configure(StaplerRequest req, JSONObject json) throws FormException {
|
||||||
|
save();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract boolean isApplicable(Descriptor descriptor);
|
||||||
|
public abstract String getDisplayName();
|
||||||
|
}
|
@ -0,0 +1,36 @@
|
|||||||
|
package org.openstack.murano.jenkins_plugins.muranoci.deploy;
|
||||||
|
|
||||||
|
import hudson.Extension;
|
||||||
|
import hudson.ExtensionPoint;
|
||||||
|
import hudson.model.Describable;
|
||||||
|
import hudson.tasks.BuildStep;
|
||||||
|
import hudson.tasks.Shell;
|
||||||
|
|
||||||
|
|
||||||
|
public abstract class BuildStepDetailsProvider<T extends BuildStep> implements ExtensionPoint {
|
||||||
|
|
||||||
|
protected static String defaultName(BuildStep bs) {
|
||||||
|
return bs instanceof Describable<?> ? ((Describable<?>) bs).getDescriptor().getDisplayName()
|
||||||
|
: null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param bs A given {@link BuildStep}.
|
||||||
|
* @return the details of the build step.
|
||||||
|
*/
|
||||||
|
public abstract String getDetails(T bs);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link BuildStepDetailsProvider} for {@link Shell}.
|
||||||
|
*/
|
||||||
|
@Extension
|
||||||
|
public static class ShellBuildStepDetailsProvider extends BuildStepDetailsProvider<Shell> {
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String getDetails(Shell shell) {
|
||||||
|
return shell.getCommand();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,77 @@
|
|||||||
|
package org.openstack.murano.jenkins_plugins.muranoci.deploy;
|
||||||
|
|
||||||
|
import hudson.DescriptorExtensionList;
|
||||||
|
import hudson.ExtensionPoint;
|
||||||
|
import hudson.model.Describable;
|
||||||
|
import hudson.model.Descriptor;
|
||||||
|
import jenkins.model.Jenkins;
|
||||||
|
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static java.util.Objects.requireNonNull;
|
||||||
|
|
||||||
|
public abstract class MuranoDeployment
|
||||||
|
implements Describable<MuranoDeployment>, ExtensionPoint {
|
||||||
|
/**
|
||||||
|
* Json data that describes Murano Environment applications
|
||||||
|
*/
|
||||||
|
private String objectModel;
|
||||||
|
|
||||||
|
|
||||||
|
public MuranoDeployment() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Contains data that describes Environment within Openstack Cloud
|
||||||
|
* and connection credentials.
|
||||||
|
*
|
||||||
|
* @param objectModel description of environment to be deployed
|
||||||
|
*/
|
||||||
|
public MuranoDeployment(String objectModel) {
|
||||||
|
|
||||||
|
this.objectModel = requireNonNull(objectModel, "Object Model should not be Null");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Boilerplate, see:
|
||||||
|
* https://wiki.jenkins-ci.org/display/JENKINS/Defining+a+new+extension+point
|
||||||
|
*
|
||||||
|
* @return all registered {@link MuranoDeployment}s
|
||||||
|
*/
|
||||||
|
public static DescriptorExtensionList<MuranoDeployment, AbstractMuranoDeploymentDescriptor> all() {
|
||||||
|
return Jenkins.getInstance().getDescriptorList(MuranoDeployment.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<AbstractMuranoDeploymentDescriptor> getCompatibleDeployments(Descriptor descriptor) {
|
||||||
|
LinkedList<AbstractMuranoDeploymentDescriptor> cloudDeployments =
|
||||||
|
new LinkedList<>();
|
||||||
|
|
||||||
|
for (AbstractMuranoDeploymentDescriptor deployment : all()) {
|
||||||
|
if (!deployment.isApplicable(descriptor)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
cloudDeployments.add(deployment);
|
||||||
|
}
|
||||||
|
|
||||||
|
return cloudDeployments;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getObjectModel() {
|
||||||
|
return objectModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setObjectModel(String objectModel) {
|
||||||
|
this.objectModel = objectModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Boilerplate, see: https://wiki.jenkins-ci.org/display/JENKINS/Defining+a+new+extension+point
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Descriptor<MuranoDeployment> getDescriptor() {
|
||||||
|
return (Descriptor<MuranoDeployment>) Jenkins.getInstance().getDescriptor(getClass());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,363 @@
|
|||||||
|
package org.openstack.murano.jenkins_plugins.muranoci.deploy;
|
||||||
|
|
||||||
|
|
||||||
|
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||||
|
import org.json.simple.JSONArray;
|
||||||
|
import org.json.simple.JSONObject;
|
||||||
|
import org.json.simple.parser.JSONParser;
|
||||||
|
import org.json.simple.parser.ParseException;
|
||||||
|
import org.kohsuke.stapler.DataBoundConstructor;
|
||||||
|
import org.openstack4j.api.OSClient;
|
||||||
|
import org.openstack4j.api.exceptions.AuthenticationException;
|
||||||
|
import org.openstack4j.connectors.httpclient.HttpCommand;
|
||||||
|
import org.openstack4j.core.transport.HttpMethod;
|
||||||
|
import org.openstack4j.core.transport.HttpRequest;
|
||||||
|
import org.openstack4j.openstack.OSFactory;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.util.concurrent.TimeoutException;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.LogRecord;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
public class MuranoHelper {
|
||||||
|
public static final int MURANO_DEFAULT_PORT = 8082;
|
||||||
|
|
||||||
|
private final static Logger LOG = Logger.getLogger(MuranoHelper.class.getName());
|
||||||
|
|
||||||
|
private OSClient.OSClientV2 os = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Suppose this is keystone Url
|
||||||
|
*/
|
||||||
|
private String serverUrl;
|
||||||
|
private String username;
|
||||||
|
private String password;
|
||||||
|
private String tenantName;
|
||||||
|
/**
|
||||||
|
* Default timeout for waiting deployment success
|
||||||
|
*/
|
||||||
|
private int timeout = 3600*1000;
|
||||||
|
|
||||||
|
@DataBoundConstructor
|
||||||
|
public MuranoHelper(String serverUrl,
|
||||||
|
String username,
|
||||||
|
String password,
|
||||||
|
String tenantName) {
|
||||||
|
this.serverUrl = serverUrl;
|
||||||
|
this.username = username;
|
||||||
|
this.password = password;
|
||||||
|
this.tenantName = tenantName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getServerUrl() {
|
||||||
|
return serverUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUsername() {
|
||||||
|
return username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPassword() {
|
||||||
|
return password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTenantName() {
|
||||||
|
return tenantName;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param name New environment name
|
||||||
|
* @param objectModel object model describing new environment
|
||||||
|
* @return new environment id
|
||||||
|
* @throws AuthenticationException in case credentials
|
||||||
|
*/
|
||||||
|
public String deployNewFromObjectModel(String name, String objectModel)
|
||||||
|
throws AuthenticationException {
|
||||||
|
|
||||||
|
this.authenticate();
|
||||||
|
|
||||||
|
String token = getOSClient().getAccess().getToken().getId();
|
||||||
|
|
||||||
|
String envId = checkIfDeploymentExists(token, name);
|
||||||
|
if (envId == null) {
|
||||||
|
// Create Env
|
||||||
|
envId = this.createEnvironment(token, name);
|
||||||
|
|
||||||
|
// Create Session
|
||||||
|
String sessionId = this.createEnvironmentSession(token, envId);
|
||||||
|
|
||||||
|
// Add App to Environment
|
||||||
|
addApplicationToEnvironment(token, envId, sessionId, objectModel);
|
||||||
|
|
||||||
|
// Deploy
|
||||||
|
deployEnvironment(token, envId, sessionId);
|
||||||
|
}
|
||||||
|
|
||||||
|
return envId;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loop around to see if the deployment is a success. This waits for about 10 secs 300 times hoping that
|
||||||
|
* it finishes. This all depends on teh number of nodes and the speed of the boxes. But seems sufficient.
|
||||||
|
*
|
||||||
|
* @param envId Environemnt Id
|
||||||
|
* @return whether the deployment is a success
|
||||||
|
* @throws TimeoutException if deployment process still in progress after deadline
|
||||||
|
*/
|
||||||
|
public boolean waitDeploymentResult(String envId) throws TimeoutException {
|
||||||
|
String token = getOSClient().getAccess().getToken().getId();
|
||||||
|
|
||||||
|
boolean status = false;
|
||||||
|
Instant deadline = Instant.now().plusMillis(timeout);
|
||||||
|
|
||||||
|
while(true) {
|
||||||
|
try {
|
||||||
|
Thread.sleep(10000);
|
||||||
|
String payload = getResponseForJson(
|
||||||
|
getMuranoEnpoint(),
|
||||||
|
MURANO_DEFAULT_PORT,
|
||||||
|
"/v1/environments/" + envId + "/deployments",
|
||||||
|
HttpMethod.GET,
|
||||||
|
token,
|
||||||
|
null,
|
||||||
|
null);
|
||||||
|
JSONParser parser = new JSONParser();
|
||||||
|
try {
|
||||||
|
JSONObject deployments = (JSONObject) parser.parse(payload);
|
||||||
|
JSONArray deploymentList = (JSONArray) deployments.get("deployments");
|
||||||
|
JSONObject thisDeployment = (JSONObject) deploymentList.get(0);
|
||||||
|
if ("success".equals(thisDeployment.get("state"))) {
|
||||||
|
status = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} catch (ParseException pe) {
|
||||||
|
}
|
||||||
|
} catch (Exception ex) {
|
||||||
|
status = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (Instant.now().isAfter(deadline)){
|
||||||
|
throw new TimeoutException("Environment was not ready in time.");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the Environment id if it exists
|
||||||
|
*
|
||||||
|
* @param token
|
||||||
|
* @param name
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private String checkIfDeploymentExists(String token, String name) {
|
||||||
|
// TODO: remove string manipulation
|
||||||
|
String payload = getResponseForJson(
|
||||||
|
getMuranoEnpoint(),
|
||||||
|
MURANO_DEFAULT_PORT,
|
||||||
|
"/v1/environments",
|
||||||
|
HttpMethod.GET,
|
||||||
|
token,
|
||||||
|
null,
|
||||||
|
null);
|
||||||
|
String envId = null;
|
||||||
|
JSONParser parser = new JSONParser();
|
||||||
|
try{
|
||||||
|
Object obj = parser.parse(payload);
|
||||||
|
JSONObject response = (JSONObject)obj;
|
||||||
|
JSONArray environmentArray = (JSONArray) response.get("environments");
|
||||||
|
for (Object env: environmentArray) {
|
||||||
|
JSONObject thisEnv = (JSONObject) env;
|
||||||
|
String envName = (String) thisEnv.get("name");
|
||||||
|
if (envName.equals(name)) {
|
||||||
|
envId = (String) thisEnv.get("id");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}catch(ParseException pe){
|
||||||
|
LogRecord logRecord = new LogRecord(Level.WARNING, "Parse exception: position: " + pe.getPosition());
|
||||||
|
logRecord.setThrown(pe);
|
||||||
|
LOG.log(logRecord);
|
||||||
|
}
|
||||||
|
return envId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deploy the environment given the environment id and Session Token
|
||||||
|
*/
|
||||||
|
private void deployEnvironment(String token, String envId, String sessionId) {
|
||||||
|
String response = getResponseForJson(
|
||||||
|
getMuranoEnpoint(),
|
||||||
|
MURANO_DEFAULT_PORT,
|
||||||
|
"/v1/environments/" + envId + "/sessions/" + sessionId + "/deploy",
|
||||||
|
HttpMethod.POST,
|
||||||
|
token,
|
||||||
|
null,
|
||||||
|
null);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public String getMuranoEnpoint() {
|
||||||
|
/*
|
||||||
|
* TODO: This is temporary decision. Murano URL should be obtained from Keystone
|
||||||
|
*/
|
||||||
|
String string[] = this.serverUrl.split(":");
|
||||||
|
|
||||||
|
return string[0] + ":" + string[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the app(K8S) to the environment
|
||||||
|
* @param token
|
||||||
|
* @param envId
|
||||||
|
* @param sessionId
|
||||||
|
* @param jsonReq
|
||||||
|
*/
|
||||||
|
private void addApplicationToEnvironment(String token, String envId, String sessionId, String jsonReq) {
|
||||||
|
String response = getResponseForJson(this.getMuranoEnpoint(),
|
||||||
|
MURANO_DEFAULT_PORT,
|
||||||
|
"/v1/environments/" + envId + "/services",
|
||||||
|
HttpMethod.POST,
|
||||||
|
token,
|
||||||
|
jsonReq,
|
||||||
|
sessionId);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String createEnvironmentSession(String token, String envId) {
|
||||||
|
String payload = getResponseForJson(this.getMuranoEnpoint(),
|
||||||
|
MURANO_DEFAULT_PORT,
|
||||||
|
"/v1/environments/" + envId + "/configure",
|
||||||
|
HttpMethod.POST,
|
||||||
|
token,
|
||||||
|
null,
|
||||||
|
null);
|
||||||
|
|
||||||
|
String sessionId = "";
|
||||||
|
JSONParser parser = new JSONParser();
|
||||||
|
try{
|
||||||
|
Object obj = parser.parse(payload);
|
||||||
|
JSONObject response = (JSONObject)obj;
|
||||||
|
sessionId = (String)response.get("id");
|
||||||
|
}catch(ParseException pe){
|
||||||
|
System.out.println("position: " + pe.getPosition());
|
||||||
|
System.out.println(pe);
|
||||||
|
}
|
||||||
|
return sessionId;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String createEnvironment(String token, String envname) {
|
||||||
|
String reqPayload = "{\"name\":\"" + envname + "\"}";
|
||||||
|
String payload = getResponseForJson(
|
||||||
|
getMuranoEnpoint(),
|
||||||
|
MURANO_DEFAULT_PORT,
|
||||||
|
"/v1/environments",
|
||||||
|
HttpMethod.POST, token, reqPayload, null);
|
||||||
|
|
||||||
|
String envId = "";
|
||||||
|
JSONParser parser = new JSONParser();
|
||||||
|
try{
|
||||||
|
Object obj = parser.parse(payload);
|
||||||
|
JSONObject response = (JSONObject)obj;
|
||||||
|
envId = (String)response.get("id");
|
||||||
|
}catch(ParseException pe){
|
||||||
|
System.out.println("position: " + pe.getPosition());
|
||||||
|
System.out.println(pe);
|
||||||
|
}
|
||||||
|
|
||||||
|
return envId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Main helper method to call the Murano API and return the response. Accepts both GET and POST.
|
||||||
|
*
|
||||||
|
* @param url Base URL to connect
|
||||||
|
* @param port Which port is murano listening on
|
||||||
|
* @param requestPath Path on Murano URL
|
||||||
|
* @param method GET or POST
|
||||||
|
* @param token Auth Token
|
||||||
|
* @param jsonPayload Payload for the message
|
||||||
|
* @param muranoSessionId Optional Session Id
|
||||||
|
* @return Response from the Call
|
||||||
|
*/
|
||||||
|
private String getResponseForJson(String url,
|
||||||
|
int port,
|
||||||
|
String requestPath,
|
||||||
|
HttpMethod method,
|
||||||
|
String token,
|
||||||
|
String jsonPayload,
|
||||||
|
String muranoSessionId) {
|
||||||
|
HttpRequest request = HttpRequest.builder().method(method)
|
||||||
|
.endpoint(url + ":" + port)
|
||||||
|
.path(requestPath)
|
||||||
|
.header("X-Auth-Token", token)
|
||||||
|
.json(jsonPayload)
|
||||||
|
.build();
|
||||||
|
if (muranoSessionId != null) {
|
||||||
|
request.getHeaders().put("X-Configuration-Session", muranoSessionId);
|
||||||
|
}
|
||||||
|
if (jsonPayload != null) {
|
||||||
|
request = request.toBuilder().json(jsonPayload).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
HttpCommand command = HttpCommand.create(request);
|
||||||
|
CloseableHttpResponse response = null;
|
||||||
|
try {
|
||||||
|
response = command.execute();
|
||||||
|
} catch(Exception ex) {
|
||||||
|
ex.printStackTrace();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
StringBuffer jsonString = new StringBuffer();
|
||||||
|
try {
|
||||||
|
BufferedReader br = new BufferedReader(new InputStreamReader(
|
||||||
|
response.getEntity().getContent()));
|
||||||
|
|
||||||
|
//Print the raw output of murano api from the server
|
||||||
|
String output;
|
||||||
|
|
||||||
|
while ((output = br.readLine()) != null) {
|
||||||
|
jsonString.append(output + "\n");
|
||||||
|
}
|
||||||
|
} catch(Exception ex) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return jsonString.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Authenticate to the Openstack instance given the credentials in constructor
|
||||||
|
*
|
||||||
|
* @throws AuthenticationException in case of authentication failure.
|
||||||
|
*/
|
||||||
|
public void authenticate() throws AuthenticationException {
|
||||||
|
this.os = OSFactory.builderV2()
|
||||||
|
.endpoint(this.serverUrl)
|
||||||
|
.credentials(this.username, this.password)
|
||||||
|
.tenantName(this.tenantName)
|
||||||
|
.authenticate();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper object to return the OSClient
|
||||||
|
* @return OSClient V2
|
||||||
|
*/
|
||||||
|
public OSClient.OSClientV2 getOSClient() {
|
||||||
|
return this.os;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTimeout(int timeout) {
|
||||||
|
this.timeout = timeout;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,211 @@
|
|||||||
|
package org.openstack.murano.jenkins_plugins.muranoci.deploy;
|
||||||
|
|
||||||
|
import com.cloudbees.plugins.credentials.CredentialsMatchers;
|
||||||
|
import com.cloudbees.plugins.credentials.CredentialsProvider;
|
||||||
|
import com.cloudbees.plugins.credentials.common.StandardCredentials;
|
||||||
|
import com.cloudbees.plugins.credentials.common.StandardListBoxModel;
|
||||||
|
import com.cloudbees.plugins.credentials.domains.DomainRequirement;
|
||||||
|
import com.fasterxml.jackson.core.JsonParser;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
|
||||||
|
import com.fasterxml.jackson.dataformat.yaml.YAMLParser;
|
||||||
|
import hudson.EnvVars;
|
||||||
|
import hudson.Extension;
|
||||||
|
import hudson.FilePath;
|
||||||
|
import hudson.Launcher;
|
||||||
|
import hudson.model.*;
|
||||||
|
import hudson.security.ACL;
|
||||||
|
import hudson.tasks.BuildWrapper;
|
||||||
|
import hudson.tasks.BuildWrapperDescriptor;
|
||||||
|
import hudson.util.ListBoxModel;
|
||||||
|
import jenkins.model.Jenkins;
|
||||||
|
import org.apache.http.impl.client.SystemDefaultCredentialsProvider;
|
||||||
|
import org.kohsuke.stapler.AncestorInPath;
|
||||||
|
import org.kohsuke.stapler.DataBoundConstructor;
|
||||||
|
import org.kohsuke.stapler.QueryParameter;
|
||||||
|
import org.kohsuke.stapler.export.Exported;
|
||||||
|
import org.openstack.murano.jenkins_plugins.muranoci.deploy.credentials.OpenstackCredentials;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.security.SecureRandom;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static com.google.common.collect.Lists.newArrayList;
|
||||||
|
import static java.util.Objects.requireNonNull;
|
||||||
|
|
||||||
|
|
||||||
|
public class MuranoManagerBuildWrapper extends BuildWrapper implements Serializable {
|
||||||
|
private static String MURANO_ENV_NAME = "MuranoCI-";
|
||||||
|
|
||||||
|
|
||||||
|
private final MuranoDeployment deployment;
|
||||||
|
private String credentialsId;
|
||||||
|
|
||||||
|
@DataBoundConstructor
|
||||||
|
public MuranoManagerBuildWrapper(MuranoDeployment deployment,
|
||||||
|
String credentialsId) {
|
||||||
|
|
||||||
|
this.deployment = requireNonNull(deployment);
|
||||||
|
this.credentialsId = requireNonNull(credentialsId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCredentialsId() {
|
||||||
|
return credentialsId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public BuildWrapper.Environment setUp(AbstractBuild build, Launcher launcher, BuildListener listener)
|
||||||
|
throws IOException, InterruptedException {
|
||||||
|
EnvVars env = build.getEnvironment(listener);
|
||||||
|
OpenstackCredentials credentials = getOpenstackCredentials(getCredentialsId());
|
||||||
|
|
||||||
|
try {
|
||||||
|
MuranoHelper helper = new MuranoHelper(
|
||||||
|
credentials.getIdentityServiceEndpoint(),
|
||||||
|
credentials.getUsername(),
|
||||||
|
credentials.getPassword().getPlainText(),
|
||||||
|
credentials.getTenant()
|
||||||
|
);
|
||||||
|
if (env.containsKey("BUILD_ENVIRONMENT_TIMEOUT")) {
|
||||||
|
int timeout = Integer.parseInt(env.get("BUILD_ENVIRONMENT_TIMEOUT"));
|
||||||
|
helper.setTimeout(timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO: Remove
|
||||||
|
try {
|
||||||
|
((RepositoryTemplatedDeployment) deployment).readObjectModel(build.getWorkspace());
|
||||||
|
} catch (Exception io) {
|
||||||
|
}
|
||||||
|
|
||||||
|
String name = generateEnvName();
|
||||||
|
|
||||||
|
String envId = helper.deployNewFromObjectModel(
|
||||||
|
name, deployment.getObjectModel());
|
||||||
|
|
||||||
|
boolean result = helper.waitDeploymentResult(envId);
|
||||||
|
if (!result) {
|
||||||
|
build.setResult(Result.FAILURE);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
build.setResult(Result.FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new JenkinsEnvironmentImpl(env);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String generateEnvName() {
|
||||||
|
return MURANO_ENV_NAME + new BigInteger(
|
||||||
|
32,
|
||||||
|
new SecureRandom())
|
||||||
|
.toString(16);
|
||||||
|
}
|
||||||
|
|
||||||
|
private OpenstackCredentials getOpenstackCredentials(String credentialsId) {
|
||||||
|
List<OpenstackCredentials> openstackCredentialsList =
|
||||||
|
CredentialsProvider.lookupCredentials(
|
||||||
|
OpenstackCredentials.class,
|
||||||
|
Jenkins.getInstance(),
|
||||||
|
ACL.SYSTEM);
|
||||||
|
OpenstackCredentials openstackCredentials = CredentialsMatchers.firstOrNull(
|
||||||
|
openstackCredentialsList,
|
||||||
|
CredentialsMatchers.allOf(
|
||||||
|
CredentialsMatchers.withId(credentialsId)));
|
||||||
|
|
||||||
|
return openstackCredentials;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Exported
|
||||||
|
public MuranoDeployment getDeployment() {
|
||||||
|
return deployment;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public DescriptorImpl getDescriptor() {
|
||||||
|
return (DescriptorImpl) super.getDescriptor();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The descriptor for our {@code MuranoManagerBuildWrapper} plugin.
|
||||||
|
*/
|
||||||
|
@Extension
|
||||||
|
public static final class DescriptorImpl extends BuildWrapperDescriptor {
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean isApplicable(AbstractProject<?, ?> project) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String getDisplayName() {
|
||||||
|
return Messages.MuranoManagerBuildWrapper_DisplayName();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@SuppressWarnings("unused") // used by stapler
|
||||||
|
public ListBoxModel doFillCredentialsIdItems(@AncestorInPath Jenkins context,
|
||||||
|
@QueryParameter String remoteBase) {
|
||||||
|
if (context == null || !context.hasPermission(Item.CONFIGURE)) {
|
||||||
|
return new StandardListBoxModel();
|
||||||
|
}
|
||||||
|
|
||||||
|
List<DomainRequirement> domainRequirements = newArrayList();
|
||||||
|
return new StandardListBoxModel()
|
||||||
|
.withEmptySelection()
|
||||||
|
.withMatching(
|
||||||
|
CredentialsMatchers.anyOf(
|
||||||
|
CredentialsMatchers.instanceOf(OpenstackCredentials.class)),
|
||||||
|
CredentialsProvider.lookupCredentials(
|
||||||
|
StandardCredentials.class,
|
||||||
|
context,
|
||||||
|
ACL.SYSTEM,
|
||||||
|
domainRequirements));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private final class JenkinsEnvironmentImpl extends Environment {
|
||||||
|
private final EnvVars envVars;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct the instance with a snapshot of the environment within which it was created in case
|
||||||
|
* values that were used to configure it at the start of the build change before the end.
|
||||||
|
*
|
||||||
|
* @param envVars The set of environment variables used to spin up the ephemeral deployment, so
|
||||||
|
* we can tear it down with the same.
|
||||||
|
*/
|
||||||
|
public JenkinsEnvironmentImpl(EnvVars envVars) {
|
||||||
|
this.envVars = requireNonNull(envVars);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void buildEnvVars(Map<String, String> env) {
|
||||||
|
super.buildEnvVars(env);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean tearDown(AbstractBuild build, BuildListener listener)
|
||||||
|
throws IOException, InterruptedException {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,92 @@
|
|||||||
|
package org.openstack.murano.jenkins_plugins.muranoci.deploy;
|
||||||
|
|
||||||
|
import hudson.EnvVars;
|
||||||
|
import hudson.Extension;
|
||||||
|
import hudson.Launcher;
|
||||||
|
import hudson.model.AbstractBuild;
|
||||||
|
import hudson.model.AbstractProject;
|
||||||
|
import hudson.model.BuildListener;
|
||||||
|
import hudson.model.Result;
|
||||||
|
import hudson.tasks.BuildStepDescriptor;
|
||||||
|
import hudson.tasks.BuildStepMonitor;
|
||||||
|
import hudson.tasks.Publisher;
|
||||||
|
import hudson.tasks.Recorder;
|
||||||
|
import org.kohsuke.stapler.DataBoundConstructor;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* After a successful build, this plugin deploys to Murano Environment via the
|
||||||
|
* Deployment Manager API.
|
||||||
|
*/
|
||||||
|
public class MuranoManagerDeployer extends Recorder {
|
||||||
|
|
||||||
|
@DataBoundConstructor
|
||||||
|
public MuranoManagerDeployer() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean perform(AbstractBuild build, Launcher launcher, BuildListener listener)
|
||||||
|
throws IOException, InterruptedException {
|
||||||
|
if (build.getResult() != Result.SUCCESS) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
build.getEnvironment(listener);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace(listener.error(Messages.MuranoManagerDeployer_EnvironmentException()));
|
||||||
|
build.setResult(Result.FAILURE);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public BuildStepMonitor getRequiredMonitorService() {
|
||||||
|
return BuildStepMonitor.NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Extension
|
||||||
|
public static class DescriptorImpl extends BuildStepDescriptor<Publisher> {
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean isApplicable(Class<? extends AbstractProject> aClass) {
|
||||||
|
// Indicates that this builder can be used with all kinds of project types
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String getDisplayName() {
|
||||||
|
return Messages.MuranoManagerDeployer_DisplayName();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link BuildStepDetailsProvider} for the Cloud Manager Deployer.
|
||||||
|
*/
|
||||||
|
@Extension
|
||||||
|
public static class DetailsProvider extends BuildStepDetailsProvider<MuranoManagerDeployer> {
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String getDetails(MuranoManagerDeployer deployer) {
|
||||||
|
return "MuranoManagerDeployer";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,101 @@
|
|||||||
|
package org.openstack.murano.jenkins_plugins.muranoci.deploy;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.core.JsonFactory;
|
||||||
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
|
import com.fasterxml.jackson.core.type.TypeReference;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
|
||||||
|
import com.fasterxml.jackson.dataformat.yaml.YAMLParser;
|
||||||
|
import hudson.Extension;
|
||||||
|
import hudson.FilePath;
|
||||||
|
import hudson.model.Descriptor;
|
||||||
|
import org.kohsuke.stapler.DataBoundConstructor;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class RepositoryTemplatedDeployment extends MuranoDeployment {
|
||||||
|
/**
|
||||||
|
* The file in the repository that contains muranoci configuration.
|
||||||
|
*/
|
||||||
|
public static final String CI_CONFG_FILENAME = ".murano.yml";
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private final String environment;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The specific Implemenation of <code>MuranoDeployment</code> that
|
||||||
|
* gets object model from the file within the repo.
|
||||||
|
*
|
||||||
|
* @param environment The name of the environment within the .murano.yml config
|
||||||
|
*/
|
||||||
|
@DataBoundConstructor
|
||||||
|
public RepositoryTemplatedDeployment(
|
||||||
|
String environment) {
|
||||||
|
|
||||||
|
this.environment = environment;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getEnvironment() {
|
||||||
|
return environment;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Denotes that this is a cloud deployment plugin.
|
||||||
|
*/
|
||||||
|
@Extension
|
||||||
|
public static class DescriptorImpl extends AbstractMuranoDeploymentDescriptor {
|
||||||
|
public DescriptorImpl() {
|
||||||
|
this(RepositoryTemplatedDeployment.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public DescriptorImpl(Class<? extends RepositoryTemplatedDeployment> clazz) {
|
||||||
|
super(clazz);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String getDisplayName() {
|
||||||
|
return Messages.RepositoryTemplatedMuranoDeployment_DisplayName();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean isApplicable(Descriptor descriptor) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void readObjectModel(FilePath workspace) throws IOException {
|
||||||
|
String config = null;
|
||||||
|
try {
|
||||||
|
config = new FilePath(workspace, ".murano.yml").readToString();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
YAMLFactory factory = new YAMLFactory();
|
||||||
|
ObjectMapper mapper = new ObjectMapper(factory);
|
||||||
|
HashMap<String, Object> map = mapper.readValue(config, HashMap.class);
|
||||||
|
Object model = ((Map<String,Object>)((Map<String,Object>)map).get("environments")).get(this.environment);
|
||||||
|
|
||||||
|
JsonFactory jsonFactory = new JsonFactory();
|
||||||
|
ObjectMapper mapperModel = new ObjectMapper(jsonFactory);
|
||||||
|
String string = mapperModel.writeValueAsString(model);
|
||||||
|
System.out.println(string);
|
||||||
|
this.setObjectModel(string);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,60 @@
|
|||||||
|
package org.openstack.murano.jenkins_plugins.muranoci.deploy;
|
||||||
|
|
||||||
|
import hudson.Extension;
|
||||||
|
import hudson.model.Descriptor;
|
||||||
|
|
||||||
|
import hudson.util.FormValidation;
|
||||||
|
import org.kohsuke.stapler.DataBoundConstructor;
|
||||||
|
import org.kohsuke.stapler.QueryParameter;
|
||||||
|
import org.openstack4j.api.exceptions.AuthenticationException;
|
||||||
|
|
||||||
|
import javax.servlet.ServletException;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import static java.util.Objects.requireNonNull;
|
||||||
|
|
||||||
|
public class TemplatedDeployment extends MuranoDeployment {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The specific Implemenation of <code>MuranoDeployment</code> that
|
||||||
|
* gets object model from the contructor parameter
|
||||||
|
* (the direct textarea on Jenkins form)
|
||||||
|
*
|
||||||
|
* @param objectModel Object model for Murano environment to be deployed
|
||||||
|
*/
|
||||||
|
@DataBoundConstructor
|
||||||
|
public TemplatedDeployment(
|
||||||
|
String objectModel) {
|
||||||
|
super(requireNonNull(objectModel));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Denotes that this is a cloud deployment plugin.
|
||||||
|
*/
|
||||||
|
@Extension
|
||||||
|
public static class DescriptorImpl extends AbstractMuranoDeploymentDescriptor {
|
||||||
|
public DescriptorImpl() {
|
||||||
|
this(TemplatedDeployment.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public DescriptorImpl(Class<? extends TemplatedDeployment> clazz) {
|
||||||
|
super(clazz);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String getDisplayName() {
|
||||||
|
return Messages.TemplatedMuranoDeployment_DisplayName();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean isApplicable(Descriptor descriptor) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
package org.openstack.murano.jenkins_plugins.muranoci.deploy.credentials;
|
||||||
|
|
||||||
|
|
||||||
|
import com.cloudbees.plugins.credentials.Credentials;
|
||||||
|
import hudson.util.Secret;
|
||||||
|
|
||||||
|
public interface OpenstackCredentials extends Credentials {
|
||||||
|
String getName();
|
||||||
|
String getDescription();
|
||||||
|
String getUsername();
|
||||||
|
Secret getPassword();
|
||||||
|
String getTenant();
|
||||||
|
String getIdentityServiceEndpoint();
|
||||||
|
}
|
@ -0,0 +1,109 @@
|
|||||||
|
package org.openstack.murano.jenkins_plugins.muranoci.deploy.credentials;
|
||||||
|
|
||||||
|
|
||||||
|
import com.cloudbees.plugins.credentials.CredentialsDescriptor;
|
||||||
|
import com.cloudbees.plugins.credentials.NameWith;
|
||||||
|
import com.cloudbees.plugins.credentials.impl.BaseStandardCredentials;
|
||||||
|
import com.cloudbees.plugins.credentials.impl.Messages;
|
||||||
|
import hudson.Extension;
|
||||||
|
import hudson.util.FormValidation;
|
||||||
|
import hudson.util.Secret;
|
||||||
|
import org.kohsuke.stapler.DataBoundConstructor;
|
||||||
|
import org.kohsuke.stapler.QueryParameter;
|
||||||
|
import org.openstack.murano.jenkins_plugins.muranoci.deploy.MuranoHelper;
|
||||||
|
import org.openstack4j.api.exceptions.AuthenticationException;
|
||||||
|
|
||||||
|
import javax.servlet.ServletException;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import static java.util.Objects.requireNonNull;
|
||||||
|
|
||||||
|
@NameWith(value = OpenstackCredentialsNameProvider.class, priority = 50)
|
||||||
|
public class OpenstackCredentialsImpl extends BaseStandardCredentials implements OpenstackCredentials {
|
||||||
|
private final String name;
|
||||||
|
|
||||||
|
private final String identityServiceEndpoint;
|
||||||
|
private final String username;
|
||||||
|
private final Secret password;
|
||||||
|
private final String tenant;
|
||||||
|
|
||||||
|
@DataBoundConstructor
|
||||||
|
public OpenstackCredentialsImpl(
|
||||||
|
String id,
|
||||||
|
String name,
|
||||||
|
String description,
|
||||||
|
String identityServiceEndpoint,
|
||||||
|
String tenant,
|
||||||
|
String username,
|
||||||
|
String password) {
|
||||||
|
super(id, description);
|
||||||
|
|
||||||
|
this.name = name;
|
||||||
|
this.identityServiceEndpoint = identityServiceEndpoint;
|
||||||
|
this.username = username;
|
||||||
|
this.password = Secret.fromString(requireNonNull(password));
|
||||||
|
this.tenant = tenant;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return this.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getUsername() {
|
||||||
|
return this.username;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Secret getPassword() {
|
||||||
|
return this.password;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getTenant() {
|
||||||
|
return this.tenant;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getIdentityServiceEndpoint() {
|
||||||
|
return this.identityServiceEndpoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Extension
|
||||||
|
public static class Descriptor
|
||||||
|
extends CredentialsDescriptor {
|
||||||
|
|
||||||
|
public FormValidation doTestConnection(@QueryParameter("identityServiceEndpoint") final String identityServiceEndpoint,
|
||||||
|
@QueryParameter("tenant") final String tenant,
|
||||||
|
@QueryParameter("username") final String username,
|
||||||
|
@QueryParameter("password") final String password)
|
||||||
|
throws IOException, ServletException {
|
||||||
|
|
||||||
|
MuranoHelper client = new MuranoHelper(
|
||||||
|
identityServiceEndpoint,
|
||||||
|
username,
|
||||||
|
password,
|
||||||
|
tenant);
|
||||||
|
|
||||||
|
try {
|
||||||
|
client.authenticate();
|
||||||
|
} catch (AuthenticationException ae) {
|
||||||
|
return FormValidation.error(
|
||||||
|
"Unable to connect to server. Please check credentials");
|
||||||
|
} catch (Exception e) {
|
||||||
|
return FormValidation.error("Error: " + e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
return FormValidation.ok("Success");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String getDisplayName() {
|
||||||
|
// return Messages.CertificateCredentialsImpl_DisplayName();
|
||||||
|
return "Openstack Cloud";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
package org.openstack.murano.jenkins_plugins.muranoci.deploy.credentials;
|
||||||
|
|
||||||
|
|
||||||
|
import com.cloudbees.plugins.credentials.CredentialsNameProvider;
|
||||||
|
|
||||||
|
public class OpenstackCredentialsNameProvider extends CredentialsNameProvider<OpenstackCredentialsImpl> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName(OpenstackCredentialsImpl openstackCredentials) {
|
||||||
|
return openstackCredentials.getName();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,26 @@
|
|||||||
|
MuranoDeployment.InvalidDeploySpec=Invalid deployment specification.
|
||||||
|
MuranoDeployment.DeployComplete=Deployment complete!
|
||||||
|
MuranoDeployment.InsertRollback=Failure deploying, attempting rollback.
|
||||||
|
MuranoDeployment.RollbackSuccess=Rollback successful.
|
||||||
|
MuranoDeployment.DeleteComplete=Deletion complete!
|
||||||
|
MuranoDeployment.CreatedDeploy=Created new deployment: {0}
|
||||||
|
MuranoDeployment.CreatedDeployVerbose=Created new deployment: {0} with spec: {1}
|
||||||
|
MuranoDeployment.DeletedDeploy=Deleted deployment: {0}
|
||||||
|
MuranoDeployment.CreateDeployException=Exception creating deployment
|
||||||
|
MuranoDeployment.GetDeployException=Exception getting deployment
|
||||||
|
MuranoDeployment.DeleteDeployException=Exception deleting deployment
|
||||||
|
MuranoDeployment.WaitDeploy=Waiting for deployment...
|
||||||
|
MuranoDeployment.WaitDelete=Waiting for deletion...
|
||||||
|
MuranoDeployment.WaitTimeoutDeploy=Timed out waiting for deployment.
|
||||||
|
MuranoDeployment.WaitTimeoutDelete=Timed out waiting for deletion.
|
||||||
|
MuranoDeployment.DeployFailed=Deployment failed for: {0}
|
||||||
|
MuranoDeployment.ExecutorExceptionWhileDeploying=Bad state: RPC execution exception while deploying.
|
||||||
|
MuranoDeployment.IOExceptionWhileDeploying=IO exception while deploying.
|
||||||
|
MuranoDeployment.LogInsert=Inserting deployment: {0}
|
||||||
|
MuranoDeployment.LogDelete=Deleting deployment: {0}
|
||||||
|
MuranoDeploymentDescriptor.BadComponent=Components must match: {0}
|
||||||
|
MuranoDeploymentDescriptor.NotEmpty=Components cannot be empty
|
||||||
|
MuranoDeploymentDescriptor.SampleResolution={0}\nSample variable resolution: {1}
|
||||||
|
MuranoDeploymentModule.AppName=Jenkins Cloud Deployer
|
||||||
|
MuranoDeploymentModule.ConnectionError=Exception connecting to Deployment Manager
|
||||||
|
MuranoEnvironmentDeleter_DisplayName=Deployment Turndown
|
@ -0,0 +1,6 @@
|
|||||||
|
MuranoManagerDeployer.DisplayName=Openstack Murano Deployer
|
||||||
|
MuranoManagerDeployer.EnvironmentException=Exception accessing build environment
|
||||||
|
MuranoManagerBuildWrapper.DisplayName=Murano Deployer
|
||||||
|
BuildStepDetailsProvider.MavenName=Maven
|
||||||
|
TemplatedMuranoDeployment.DisplayName=Deploy using ready-made template
|
||||||
|
RepositoryTemplatedMuranoDeployment.DisplayName=Deploy using configuration from project repository
|
@ -0,0 +1,21 @@
|
|||||||
|
<?jelly escape-by-default='true'?>
|
||||||
|
<j:jelly xmlns:j="jelly:core"
|
||||||
|
xmlns:f="/lib/form"
|
||||||
|
xmlns:c="/lib/credentials">
|
||||||
|
|
||||||
|
<f:entry title="${%Openstack Credentials}" field="credentialsId">
|
||||||
|
<c:select/>
|
||||||
|
</f:entry>
|
||||||
|
|
||||||
|
<j:invokeStatic var="descriptors"
|
||||||
|
method="getCompatibleDeployments"
|
||||||
|
className="org.openstack.murano.jenkins_plugins.muranoci.deploy.MuranoDeployment">
|
||||||
|
|
||||||
|
<j:arg type="hudson.model.Descriptor" value="${descriptor}"/>
|
||||||
|
|
||||||
|
</j:invokeStatic>
|
||||||
|
|
||||||
|
<f:dropdownDescriptorSelector field="deployment"
|
||||||
|
title="${%Deployment Form}"
|
||||||
|
descriptors="${descriptors}"/>
|
||||||
|
</j:jelly>
|
@ -0,0 +1,17 @@
|
|||||||
|
<?jelly escape-by-default='true'?>
|
||||||
|
<j:jelly xmlns:j="jelly:core"
|
||||||
|
xmlns:st="jelly:stapler"
|
||||||
|
xmlns:d="jelly:define"
|
||||||
|
xmlns:l="/lib/layout"
|
||||||
|
xmlns:t="/lib/hudson"
|
||||||
|
xmlns:f="/lib/form"
|
||||||
|
xmlns:a="/lib/auth">
|
||||||
|
|
||||||
|
<f:entry name="action" title="${%Action}" field="action">
|
||||||
|
<select name="action">
|
||||||
|
<option value="teardownAction">${%Tear Down}</option>
|
||||||
|
<option value="doNothingAction">${%Do Nothing}</option>
|
||||||
|
</select>
|
||||||
|
</f:entry>
|
||||||
|
|
||||||
|
</j:jelly>
|
@ -0,0 +1,14 @@
|
|||||||
|
<?jelly escape-by-default='true'?>
|
||||||
|
<j:jelly xmlns:j="jelly:core"
|
||||||
|
xmlns:st="jelly:stapler"
|
||||||
|
xmlns:d="jelly:define"
|
||||||
|
xmlns:l="/lib/layout"
|
||||||
|
xmlns:t="/lib/hudson"
|
||||||
|
xmlns:f="/lib/form"
|
||||||
|
xmlns:a="/lib/auth">
|
||||||
|
|
||||||
|
<f:entry title="${%Environment name}" field="environment" >
|
||||||
|
<f:textbox />
|
||||||
|
</f:entry>
|
||||||
|
|
||||||
|
</j:jelly>
|
@ -0,0 +1,15 @@
|
|||||||
|
<?jelly escape-by-default='true'?>
|
||||||
|
<j:jelly xmlns:j="jelly:core"
|
||||||
|
xmlns:st="jelly:stapler"
|
||||||
|
xmlns:d="jelly:define"
|
||||||
|
xmlns:l="/lib/layout"
|
||||||
|
xmlns:t="/lib/hudson"
|
||||||
|
xmlns:f="/lib/form"
|
||||||
|
xmlns:a="/lib/auth">
|
||||||
|
|
||||||
|
<f:entry title="${%Application Object Model}" field="objectModel">
|
||||||
|
<f:textarea>
|
||||||
|
</f:textarea>
|
||||||
|
</f:entry>
|
||||||
|
|
||||||
|
</j:jelly>
|
@ -0,0 +1,12 @@
|
|||||||
|
<?jelly escape-by-default='true'?>
|
||||||
|
<j:jelly xmlns:j="jelly:core"
|
||||||
|
xmlns:st="jelly:stapler"
|
||||||
|
xmlns:d="jelly:define"
|
||||||
|
xmlns:l="/lib/layout"
|
||||||
|
xmlns:t="/lib/hudson"
|
||||||
|
xmlns:f="/lib/form"
|
||||||
|
xmlns:a="/lib/auth">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</j:jelly>
|
@ -0,0 +1,4 @@
|
|||||||
|
<?jelly escape-by-default='true'?>
|
||||||
|
<div>
|
||||||
|
This plugin integrates Openstack Murano to Jenkins.
|
||||||
|
</div>
|
Loading…
Reference in New Issue
Block a user