[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