summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorvnathan <viswesn@gmail.com>2016-10-23 10:30:53 +0530
committervnathan <viswesn@gmail.com>2016-10-23 10:30:53 +0530
commitd2829d40251c93ff643b70f05eb155324b8f2004 (patch)
tree56575e1e7a12b98b17f6c534e35537289fbe36f0
downloadcharm-murano-d2829d40251c93ff643b70f05eb155324b8f2004.zip
charm-murano-d2829d40251c93ff643b70f05eb155324b8f2004.tar.gz
charm-murano-d2829d40251c93ff643b70f05eb155324b8f2004.tar.bz2
Initial commit
-rw-r--r--LICENSE202
-rw-r--r--README.md22
-rw-r--r--requirements.txt12
-rw-r--r--src/README.md22
-rw-r--r--src/config.yaml29
-rw-r--r--src/copyright16
-rw-r--r--src/icon.svg450
-rw-r--r--src/layer.yaml5
-rw-r--r--src/lib/charm/openstack/__init__.py0
-rw-r--r--src/lib/charm/openstack/murano.py148
-rw-r--r--src/metadata.yaml13
-rw-r--r--src/novarc19
-rw-r--r--src/reactive/murano_handlers.py47
-rw-r--r--src/templates/liberty/.keep0
-rw-r--r--src/templates/mitaka/.keep0
-rw-r--r--src/templates/mitaka/murano.conf37
-rw-r--r--src/tests/README.md9
-rw-r--r--src/tests/basic_deployment.py181
-rwxr-xr-xsrc/tests/gate-basic-trusty-icehouse23
-rwxr-xr-xsrc/tests/gate-basic-trusty-liberty25
-rwxr-xr-xsrc/tests/gate-basic-trusty-mitaka25
-rwxr-xr-xsrc/tests/gate-basic-xenial-mitaka23
-rw-r--r--src/tests/tests.yaml17
-rw-r--r--src/tox.ini47
-rw-r--r--test-requirements.txt7
-rw-r--r--tox.ini47
-rw-r--r--unit_tests/__init__.py46
-rw-r--r--unit_tests/test_lib_charm_openstack_openvswitch_odl.py47
-rw-r--r--unit_tests/test_openvswitch_odl_handlers.py43
29 files changed, 1562 insertions, 0 deletions
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..7a4a3ea
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,202 @@
+
+ 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. \ No newline at end of file
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..b30ff03
--- /dev/null
+++ b/README.md
@@ -0,0 +1,22 @@
+# Overview
+
+Murano charm provides a catalog of applications deployable on Openstack cloud.
+
+# Usage
+
+Murano relies on services from the mysql/percona, rabbitmq-server and keystone charms:
+
+ juju deploy murano
+ juju deploy keystone
+ juju deploy mysql
+ juju deploy rabbitmq-server
+ juju add-relation murano rabbitmq-server
+ juju add-relation murano mysql
+ juju add-relation murano keystone
+
+
+# Bugs
+
+Please report bugs on [Launchpad](https://bugs.launchpad.net/charm-murano/+filebug).
+
+For general questions please refer to the OpenStack [Charm Guide](https://github.com/openstack/charm-guide).
diff --git a/requirements.txt b/requirements.txt
new file mode 100644
index 0000000..8d3d204
--- /dev/null
+++ b/requirements.txt
@@ -0,0 +1,12 @@
+# The order of packages is significant, because pip processes them in the order
+# of appearance. Changing the order has an impact on the overall integration
+# process, which may cause wedges in the gate later.
+pbr>=1.8.0,<1.9.0
+PyYAML>=3.1.0
+simplejson>=2.2.0
+netifaces>=0.10.4
+netaddr>=0.7.12,!=0.7.16
+Jinja2>=2.6 # BSD License (3 clause)
+six>=1.9.0
+dnspython>=1.12.0
+psutil>=1.1.1,<2.0.0 \ No newline at end of file
diff --git a/src/README.md b/src/README.md
new file mode 100644
index 0000000..b30ff03
--- /dev/null
+++ b/src/README.md
@@ -0,0 +1,22 @@
+# Overview
+
+Murano charm provides a catalog of applications deployable on Openstack cloud.
+
+# Usage
+
+Murano relies on services from the mysql/percona, rabbitmq-server and keystone charms:
+
+ juju deploy murano
+ juju deploy keystone
+ juju deploy mysql
+ juju deploy rabbitmq-server
+ juju add-relation murano rabbitmq-server
+ juju add-relation murano mysql
+ juju add-relation murano keystone
+
+
+# Bugs
+
+Please report bugs on [Launchpad](https://bugs.launchpad.net/charm-murano/+filebug).
+
+For general questions please refer to the OpenStack [Charm Guide](https://github.com/openstack/charm-guide).
diff --git a/src/config.yaml b/src/config.yaml
new file mode 100644
index 0000000..ae22d70
--- /dev/null
+++ b/src/config.yaml
@@ -0,0 +1,29 @@
+options:
+ rabbit-user:
+ default: murano
+ type: string
+ description: Username used to access rabbitmq queue.
+ rabbit-vhost:
+ default: openstack
+ type: string
+ description: RabbitMQ virtual host to request access on rabbitmq-server.
+ database-user:
+ default: murano
+ type: string
+ description: Database username.
+ database:
+ default: murano
+ type: string
+ description: Murano database name.
+ debug:
+ default: False
+ type: boolean
+ description: Enable debug logging
+ verbose:
+ default: False
+ type: boolean
+ description: Enable verbose logging
+ region:
+ default: RegionOne
+ type: string
+ description: OpenStack Region
diff --git a/src/copyright b/src/copyright
new file mode 100644
index 0000000..6f8a25f
--- /dev/null
+++ b/src/copyright
@@ -0,0 +1,16 @@
+Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0
+
+Files: *
+Copyright: 2015, Canonical Ltd.
+License: Apache-2.0
+ 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. \ No newline at end of file
diff --git a/src/icon.svg b/src/icon.svg
new file mode 100644
index 0000000..c90ecfc
--- /dev/null
+++ b/src/icon.svg
@@ -0,0 +1,450 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="96"
+ height="96"
+ id="svg6517"
+ version="1.1"
+ inkscape:version="0.91+devel r"
+ sodipodi:docname="openvswitch01.svg"
+ viewBox="0 0 96 96">
+ <defs
+ id="defs6519">
+ <linearGradient
+ id="Background">
+ <stop
+ id="stop4178"
+ offset="0"
+ style="stop-color:#22779e;stop-opacity:1" />
+ <stop
+ id="stop4180"
+ offset="1"
+ style="stop-color:#2991c0;stop-opacity:1" />
+ </linearGradient>
+ <filter
+ style="color-interpolation-filters:sRGB"
+ inkscape:label="Inner Shadow"
+ id="filter1121">
+ <feFlood
+ flood-opacity="0.59999999999999998"
+ flood-color="rgb(0,0,0)"
+ result="flood"
+ id="feFlood1123" />
+ <feComposite
+ in="flood"
+ in2="SourceGraphic"
+ operator="out"
+ result="composite1"
+ id="feComposite1125" />
+ <feGaussianBlur
+ in="composite1"
+ stdDeviation="1"
+ result="blur"
+ id="feGaussianBlur1127" />
+ <feOffset
+ dx="0"
+ dy="2"
+ result="offset"
+ id="feOffset1129" />
+ <feComposite
+ in="offset"
+ in2="SourceGraphic"
+ operator="atop"
+ result="composite2"
+ id="feComposite1131" />
+ </filter>
+ <filter
+ style="color-interpolation-filters:sRGB"
+ inkscape:label="Drop Shadow"
+ id="filter950">
+ <feFlood
+ flood-opacity="0.25"
+ flood-color="rgb(0,0,0)"
+ result="flood"
+ id="feFlood952" />
+ <feComposite
+ in="flood"
+ in2="SourceGraphic"
+ operator="in"
+ result="composite1"
+ id="feComposite954" />
+ <feGaussianBlur
+ in="composite1"
+ stdDeviation="1"
+ result="blur"
+ id="feGaussianBlur956" />
+ <feOffset
+ dx="0"
+ dy="1"
+ result="offset"
+ id="feOffset958" />
+ <feComposite
+ in="SourceGraphic"
+ in2="offset"
+ operator="over"
+ result="composite2"
+ id="feComposite960" />
+ </filter>
+ <clipPath
+ clipPathUnits="userSpaceOnUse"
+ id="clipPath873">
+ <g
+ transform="matrix(0,-0.66666667,0.66604479,0,-258.25992,677.00001)"
+ id="g875"
+ inkscape:label="Layer 1"
+ style="display:inline;fill:#ff00ff;fill-opacity:1;stroke:none">
+ <path
+ style="display:inline;fill:#ff00ff;fill-opacity:1;stroke:none"
+ d="M 46.702703,898.22775 H 97.297297 C 138.16216,898.22775 144,904.06497 144,944.92583 v 50.73846 c 0,40.86071 -5.83784,46.69791 -46.702703,46.69791 H 46.702703 C 5.8378378,1042.3622 0,1036.525 0,995.66429 v -50.73846 c 0,-40.86086 5.8378378,-46.69808 46.702703,-46.69808 z"
+ id="path877"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="sssssssss" />
+ </g>
+ </clipPath>
+ <filter
+ inkscape:collect="always"
+ id="filter891"
+ inkscape:label="Badge Shadow">
+ <feGaussianBlur
+ inkscape:collect="always"
+ stdDeviation="0.71999962"
+ id="feGaussianBlur893" />
+ </filter>
+ <style
+ id="style867"
+ type="text/css"><![CDATA[
+ .fil0 {fill:#1F1A17}
+ ]]></style>
+ <clipPath
+ id="clipPath16">
+ <path
+ id="path18"
+ d="M -9,-9 H 605 V 222 H -9 Z"
+ inkscape:connector-curvature="0" />
+ </clipPath>
+ <clipPath
+ id="clipPath116">
+ <path
+ id="path118"
+ d="m 91.7368,146.3253 -9.7039,-1.577 -8.8548,-3.8814 -7.5206,-4.7308 -7.1566,-8.7335 -4.0431,-4.282 -3.9093,-1.4409 -1.034,2.5271 1.8079,2.6096 0.4062,3.6802 1.211,-0.0488 1.3232,-1.2069 -0.3569,3.7488 -1.4667,0.9839 0.0445,1.4286 -3.4744,-1.9655 -3.1462,-3.712 -0.6559,-3.3176 1.3453,-2.6567 1.2549,-4.5133 2.5521,-1.2084 2.6847,0.1318 2.5455,1.4791 -1.698,-8.6122 1.698,-9.5825 -1.8692,-4.4246 -6.1223,-6.5965 1.0885,-3.941 2.9002,-4.5669 5.4688,-3.8486 2.9007,-0.3969 3.225,-0.1094 -2.012,-8.2601 7.3993,-3.0326 9.2188,-1.2129 3.1535,2.0619 0.2427,5.5797 3.5178,5.8224 0.2426,4.6094 8.4909,-0.6066 7.8843,0.7279 -7.8843,-4.7307 1.3343,-5.701 4.9731,-7.763 4.8521,-2.0622 3.8814,1.5769 1.577,3.1538 8.1269,6.1861 1.5769,-1.3343 12.7363,-0.485 2.5473,2.0619 0.2426,3.6391 -0.849,1.5767 -0.6066,9.8251 -4.2454,8.4909 0.7276,3.7605 2.5475,-1.3343 7.1566,-6.6716 3.5175,-0.2424 3.8815,1.5769 3.8818,2.9109 1.9406,6.3077 11.4021,-0.7277 6.914,2.6686 5.5797,5.2157 4.0028,7.5206 0.9706,8.8546 -0.8493,10.3105 -2.1832,9.2185 -2.1836,2.9112 -3.0322,0.9706 -5.3373,-5.8224 -4.8518,-1.6982 -4.2455,7.0353 -4.2454,3.8815 -2.3049,1.4556 -9.2185,7.6419 -7.3993,4.0028 -7.3993,0.6066 -8.6119,-1.4556 -7.5206,-2.7899 -5.2158,-4.2454 -4.1241,-4.9734 -4.2454,-1.2129"
+ inkscape:connector-curvature="0" />
+ </clipPath>
+ <clipPath
+ id="clipPath128">
+ <path
+ id="path130"
+ d="m 91.7368,146.3253 -9.7039,-1.577 -8.8548,-3.8814 -7.5206,-4.7308 -7.1566,-8.7335 -4.0431,-4.282 -3.9093,-1.4409 -1.034,2.5271 1.8079,2.6096 0.4062,3.6802 1.211,-0.0488 1.3232,-1.2069 -0.3569,3.7488 -1.4667,0.9839 0.0445,1.4286 -3.4744,-1.9655 -3.1462,-3.712 -0.6559,-3.3176 1.3453,-2.6567 1.2549,-4.5133 2.5521,-1.2084 2.6847,0.1318 2.5455,1.4791 -1.698,-8.6122 1.698,-9.5825 -1.8692,-4.4246 -6.1223,-6.5965 1.0885,-3.941 2.9002,-4.5669 5.4688,-3.8486 2.9007,-0.3969 3.225,-0.1094 -2.012,-8.2601 7.3993,-3.0326 9.2188,-1.2129 3.1535,2.0619 0.2427,5.5797 3.5178,5.8224 0.2426,4.6094 8.4909,-0.6066 7.8843,0.7279 -7.8843,-4.7307 1.3343,-5.701 4.9731,-7.763 4.8521,-2.0622 3.8814,1.5769 1.577,3.1538 8.1269,6.1861 1.5769,-1.3343 12.7363,-0.485 2.5473,2.0619 0.2426,3.6391 -0.849,1.5767 -0.6066,9.8251 -4.2454,8.4909 0.7276,3.7605 2.5475,-1.3343 7.1566,-6.6716 3.5175,-0.2424 3.8815,1.5769 3.8818,2.9109 1.9406,6.3077 11.4021,-0.7277 6.914,2.6686 5.5797,5.2157 4.0028,7.5206 0.9706,8.8546 -0.8493,10.3105 -2.1832,9.2185 -2.1836,2.9112 -3.0322,0.9706 -5.3373,-5.8224 -4.8518,-1.6982 -4.2455,7.0353 -4.2454,3.8815 -2.3049,1.4556 -9.2185,7.6419 -7.3993,4.0028 -7.3993,0.6066 -8.6119,-1.4556 -7.5206,-2.7899 -5.2158,-4.2454 -4.1241,-4.9734 -4.2454,-1.2129"
+ inkscape:connector-curvature="0" />
+ </clipPath>
+ <linearGradient
+ id="linearGradient3850"
+ inkscape:collect="always">
+ <stop
+ id="stop3852"
+ offset="0"
+ style="stop-color:#000000;stop-opacity:1;" />
+ <stop
+ id="stop3854"
+ offset="1"
+ style="stop-color:#000000;stop-opacity:0;" />
+ </linearGradient>
+ <clipPath
+ clipPathUnits="userSpaceOnUse"
+ id="clipPath3095">
+ <path
+ d="M 976.648,389.551 H 134.246 V 1229.55 H 976.648 V 389.551"
+ id="path3097"
+ inkscape:connector-curvature="0" />
+ </clipPath>
+ <clipPath
+ clipPathUnits="userSpaceOnUse"
+ id="clipPath3195">
+ <path
+ d="m 611.836,756.738 -106.34,105.207 c -8.473,8.289 -13.617,20.102 -13.598,33.379 L 598.301,790.207 c -0.031,-13.418 5.094,-25.031 13.535,-33.469"
+ id="path3197"
+ inkscape:connector-curvature="0" />
+ </clipPath>
+ <clipPath
+ clipPathUnits="userSpaceOnUse"
+ id="clipPath3235">
+ <path
+ d="m 1095.64,1501.81 c 35.46,-35.07 70.89,-70.11 106.35,-105.17 4.4,-4.38 7.11,-10.53 7.11,-17.55 l -106.37,105.21 c 0,7 -2.71,13.11 -7.09,17.51"
+ id="path3237"
+ inkscape:connector-curvature="0" />
+ </clipPath>
+ <clipPath
+ id="clipPath4591"
+ clipPathUnits="userSpaceOnUse">
+ <path
+ inkscape:connector-curvature="0"
+ d="m 1106.6009,730.43734 -0.036,21.648 c -0.01,3.50825 -2.8675,6.61375 -6.4037,6.92525 l -83.6503,7.33162 c -3.5205,0.30763 -6.3812,-2.29987 -6.3671,-5.8145 l 0.036,-21.6475 20.1171,-1.76662 -0.011,4.63775 c 0,1.83937 1.4844,3.19925 3.3262,3.0395 l 49.5274,-4.33975 c 1.8425,-0.166 3.3425,-1.78125 3.3538,-3.626 l 0.01,-4.63025 20.1,-1.7575"
+ style="fill:#ff00ff;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ id="path4593" />
+ </clipPath>
+ <radialGradient
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(-1.4333926,-2.2742838,1.1731823,-0.73941125,-174.08025,98.374394)"
+ r="20.40658"
+ fy="93.399292"
+ fx="-26.508606"
+ cy="93.399292"
+ cx="-26.508606"
+ id="radialGradient3856"
+ xlink:href="#linearGradient3850"
+ inkscape:collect="always" />
+ <linearGradient
+ gradientTransform="translate(-318.48033,212.32022)"
+ gradientUnits="userSpaceOnUse"
+ y2="993.19702"
+ x2="-51.879555"
+ y1="593.11615"
+ x1="348.20132"
+ id="linearGradient3895"
+ xlink:href="#linearGradient3850"
+ inkscape:collect="always" />
+ <clipPath
+ id="clipPath3906"
+ clipPathUnits="userSpaceOnUse">
+ <rect
+ transform="scale(1,-1)"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:0.8;fill:#ff00ff;stroke:none;stroke-width:4;marker:none;enable-background:accumulate"
+ id="rect3908"
+ width="1019.1371"
+ height="1019.1371"
+ x="357.9816"
+ y="-1725.8152" />
+ </clipPath>
+ <linearGradient
+ gradientTransform="translate(0,-1.111e-5)"
+ inkscape:collect="always"
+ xlink:href="#linearGradient4439-7"
+ id="linearGradient908-9"
+ x1="-220"
+ y1="731.29077"
+ x2="-220"
+ y2="635.29077"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ id="linearGradient4439-7"
+ inkscape:collect="always">
+ <stop
+ id="stop4441-6"
+ offset="0"
+ style="stop-color:#f2f2f2;stop-opacity:1" />
+ <stop
+ id="stop4443-2"
+ offset="1"
+ style="stop-color:#f9f9f9;stop-opacity:1" />
+ </linearGradient>
+ <filter
+ style="color-interpolation-filters:sRGB"
+ inkscape:label="Inner Shadow"
+ id="filter1121-2">
+ <feFlood
+ flood-opacity="0.59999999999999998"
+ flood-color="rgb(0,0,0)"
+ result="flood"
+ id="feFlood1123-6" />
+ <feComposite
+ in="flood"
+ in2="SourceGraphic"
+ operator="out"
+ result="composite1"
+ id="feComposite1125-4" />
+ <feGaussianBlur
+ in="composite1"
+ stdDeviation="1"
+ result="blur"
+ id="feGaussianBlur1127-0" />
+ <feOffset
+ dx="0"
+ dy="2"
+ result="offset"
+ id="feOffset1129-2" />
+ <feComposite
+ in="offset"
+ in2="SourceGraphic"
+ operator="atop"
+ result="composite2"
+ id="feComposite1131-1" />
+ </filter>
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="7.9580784"
+ inkscape:cx="28.893746"
+ inkscape:cy="26.083721"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer3"
+ showgrid="false"
+ fit-margin-top="0"
+ fit-margin-left="0"
+ fit-margin-right="0"
+ fit-margin-bottom="0"
+ inkscape:window-width="1920"
+ inkscape:window-height="1029"
+ inkscape:window-x="0"
+ inkscape:window-y="24"
+ inkscape:window-maximized="1"
+ showborder="true"
+ showguides="false"
+ inkscape:guide-bbox="true"
+ inkscape:showpageshadow="false"
+ inkscape:snap-global="false"
+ inkscape:snap-bbox="true"
+ inkscape:bbox-paths="true"
+ inkscape:bbox-nodes="true"
+ inkscape:snap-bbox-edge-midpoints="true"
+ inkscape:snap-bbox-midpoints="true"
+ inkscape:object-paths="true"
+ inkscape:snap-intersection-paths="true"
+ inkscape:object-nodes="true"
+ inkscape:snap-smooth-nodes="true"
+ inkscape:snap-midpoints="true"
+ inkscape:snap-object-midpoints="true"
+ inkscape:snap-center="true"
+ inkscape:snap-page="true">
+ <inkscape:grid
+ type="xygrid"
+ id="grid821" />
+ <sodipodi:guide
+ orientation="1,0"
+ position="16,48"
+ id="guide823" />
+ <sodipodi:guide
+ orientation="0,1"
+ position="64,80"
+ id="guide825" />
+ <sodipodi:guide
+ orientation="1,0"
+ position="80,40"
+ id="guide827" />
+ <sodipodi:guide
+ orientation="0,1"
+ position="64,16"
+ id="guide829" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata6522">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="BACKGROUND"
+ inkscape:groupmode="layer"
+ id="layer1"
+ transform="translate(268,-635.29076)"
+ style="display:inline"
+ sodipodi:insensitive="true">
+ <path
+ style="display:inline;fill:url(#linearGradient908-9);fill-opacity:1;stroke:none;filter:url(#filter1121-2)"
+ d="m -268,700.15562 v -33.72973 c 0,-27.24324 3.88785,-31.13513 31.10302,-31.13513 h 33.79408 c 27.21507,0 31.1029,3.89189 31.1029,31.13513 v 33.72973 c 0,27.24325 -3.88783,31.13514 -31.1029,31.13514 h -33.79408 c -27.21517,0 -31.10302,-3.89189 -31.10302,-31.13514 z"
+ id="path6455-8"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="sssssssss" />
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer4"
+ inkscape:label="FOLDS"
+ sodipodi:insensitive="true" />
+ <g
+ inkscape:groupmode="layer"
+ id="layer3"
+ inkscape:label="PLACE YOUR PICTOGRAM HERE"
+ style="display:inline">
+ <path
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:#201f1f;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ d="M 48.000977,13.601563 A 34.399006,34.399006 0 0 0 13.600586,48 34.399006,34.399006 0 0 0 48.000977,82.398437 34.399006,34.399006 0 0 0 82.399414,48 34.399006,34.399006 0 0 0 48.000977,13.601563 Z m 0,11.623046 A 22.775597,22.775597 0 0 1 70.776368,48 22.775597,22.775597 0 0 1 48.000977,70.77539 22.775597,22.775597 0 0 1 25.225586,48 22.775597,22.775597 0 0 1 48.000977,25.224609 Z"
+ id="path4319"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:#4f8a49;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ d="m 57.626953,34.075195 v 5.279297 H 40.791016 v 6.835938 h 16.835937 v 5.279297 L 68.398437,42.772461 Z M 38.373047,44.530274 27.601562,53.227539 38.373047,61.924805 V 56.645508 H 55.208984 V 49.809571 H 38.373047 Z"
+ id="rect4326"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer2"
+ inkscape:label="BADGE"
+ style="display:none"
+ sodipodi:insensitive="true">
+ <g
+ style="display:inline"
+ transform="translate(-340.00001,-581)"
+ id="g4394"
+ clip-path="none">
+ <g
+ id="g855">
+ <g
+ inkscape:groupmode="maskhelper"
+ id="g870"
+ clip-path="url(#clipPath873)"
+ style="opacity:0.6;filter:url(#filter891)">
+ <circle
+ transform="matrix(1.4999992,0,0,1.4999992,-29.999795,-237.54282)"
+ id="path844"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:4;marker:none;enable-background:accumulate"
+ cx="252"
+ cy="552.36218"
+ r="12" />
+ </g>
+ <g
+ id="g862">
+ <circle
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#f5f5f5;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:4;marker:none;enable-background:accumulate"
+ id="path4398"
+ transform="matrix(1.4999992,0,0,1.4999992,-29.999795,-238.54282)"
+ cx="252"
+ cy="552.36218"
+ r="12" />
+ <circle
+ transform="matrix(1.25,0,0,1.25,33,-100.45273)"
+ id="path4400"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#dd4814;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:4;marker:none;enable-background:accumulate"
+ cx="252"
+ cy="552.36218"
+ r="12" />
+ <path
+ sodipodi:type="star"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#f5f5f5;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;marker:none;enable-background:accumulate"
+ id="path4459"
+ sodipodi:sides="5"
+ sodipodi:cx="666.19574"
+ sodipodi:cy="589.50385"
+ sodipodi:r1="7.2431178"
+ sodipodi:r2="4.3458705"
+ sodipodi:arg1="1.0471976"
+ sodipodi:arg2="1.6755161"
+ inkscape:flatsided="false"
+ inkscape:rounded="0.1"
+ inkscape:randomized="0"
+ d="m 669.8173,595.77657 c -0.39132,0.22593 -3.62645,-1.90343 -4.07583,-1.95066 -0.44938,-0.0472 -4.05653,1.36297 -4.39232,1.06062 -0.3358,-0.30235 0.68963,-4.03715 0.59569,-4.47913 -0.0939,-0.44198 -2.5498,-3.43681 -2.36602,-3.8496 0.18379,-0.41279 4.05267,-0.59166 4.44398,-0.81759 0.39132,-0.22593 2.48067,-3.48704 2.93005,-3.4398 0.44938,0.0472 1.81505,3.67147 2.15084,3.97382 0.3358,0.30236 4.08294,1.2817 4.17689,1.72369 0.0939,0.44198 -2.9309,2.86076 -3.11469,3.27355 -0.18379,0.41279 0.0427,4.27917 -0.34859,4.5051 z"
+ transform="matrix(1.511423,-0.16366377,0.16366377,1.511423,-755.37346,-191.93651)" />
+ </g>
+ </g>
+ </g>
+ </g>
+</svg> \ No newline at end of file
diff --git a/src/layer.yaml b/src/layer.yaml
new file mode 100644
index 0000000..7777bf1
--- /dev/null
+++ b/src/layer.yaml
@@ -0,0 +1,5 @@
+includes: ['layer:openstack-api']
+options:
+ basic:
+ use_venv: True
+ include_system_packages: True
diff --git a/src/lib/charm/openstack/__init__.py b/src/lib/charm/openstack/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/lib/charm/openstack/__init__.py
diff --git a/src/lib/charm/openstack/murano.py b/src/lib/charm/openstack/murano.py
new file mode 100644
index 0000000..60a5360
--- /dev/null
+++ b/src/lib/charm/openstack/murano.py
@@ -0,0 +1,148 @@
+import socket
+import subprocess
+
+import charmhelpers.contrib.openstack.utils as ch_utils
+import charmhelpers.core.hookenv as hookenv
+import charms_openstack.charm
+import charms_openstack.ip as os_ip
+
+# import charms_openstack.sdn.odl as odl
+# import charms_openstack.sdn.ovs as ovs
+
+def register_endpoints(keystone):
+ """When the keystone interface connects, register this unit in the keystone
+ catalogue.
+
+ @param keystone: KeystoneRequires() interface class
+ @returns: None
+ """
+ charm = MuranoCharm.singleton
+ keystone.register_endpoints(charm.service_type,
+ charm.region,
+ charm.public_url,
+ charm.internal_url,
+ charm.admin_url)
+
+def configure_ha_resources(hacluster):
+ """Use the singleton from the MuranoCharm to run configure ha resources
+
+ @param hacluster: OpenstackHAPeers() interface class
+ @returns: None
+ """
+ MuranoCharm.singleton.configure_ha_resources(hacluster)
+
+
+def restart_all():
+ """Use the singleton from the MuranoCharm to restart all registered
+ services
+
+ @returns: None
+ """
+ MuranoCharm.singleton.restart_all()
+
+
+def configure_ssl(keystone=None):
+ """Use the singleton from the MuranoCharm to configure ssl
+
+ @param keystone: KeystoneRequires() interface class
+ @returns: None
+ """
+ MuranoCharm.singleton.configure_ssl(keystone)
+
+def update_peers(hacluster):
+ """Use the singleton from the MuranoCharm to update peers with detials
+ of this unit
+
+ @param hacluster: OpenstackHAPeers() interface class
+ @returns: None
+ """
+ MuranoCharm.singleton.update_peers(hacluster)
+
+def assess_status():
+ """Just call the MuranoCharm.singleton.assess_status() command to update
+ status on the unit.
+
+ @returns: None
+ """
+ MuranoCharm.singleton.assess_status()
+
+
+class MuranoCharm(charms_openstack.charm.HAOpenStackCharm):
+
+ # Internal name of charm
+ service_name = name = 'murano'
+
+ # First release supported
+ release = 'mitaka'
+
+ # List of packages to install for this charm
+ packages = ['murano-api', 'murano-engine', 'python-pymysql']
+
+ # Init services the charm manages
+ services = ['haproxy', 'murano-api', 'murano-engine']
+
+ # Ports that need exposing.
+ default_service = 'murano-api'
+ api_ports = {
+ 'murano-api': {
+ os_ip.PUBLIC: 8082,
+ os_ip.ADMIN: 8082,
+ os_ip.INTERNAL: 8082,
+ }
+ }
+
+ service_type = 'murano'
+ # Note that the hsm interface is optional - defined in config.yaml
+ required_relations = ['shared-db', 'amqp', 'identity-service']
+
+ restart_map = {'/etc/murano/murano.conf': services}
+
+ ha_resources = ['vips', 'haproxy']
+
+
+ sync_cmd = ['murano-db-manage', '--config-file', '/etc/murano/murano.conf', 'upgrade']
+
+ def __init__(self, release=None, **kwargs):
+ """Custom initialiser for class
+ If no release is passed, then the charm determines the release from the
+ ch_utils.os_release() function.
+ """
+ if release is None:
+ release = ch_utils.os_release('python-keystonemiddleware')
+ super(MuranoCharm, self).__init__(release=release, **kwargs)
+
+ def install(self):
+ """Customise the installation, configure the source and then call the
+ parent install() method to install the packages
+ """
+ self.configure_source()
+ super(MuranoCharm, self).install()
+
+ def get_amqp_credentials(self):
+ """Provide the default amqp username and vhost as a tuple.
+
+ :returns (username, host): two strings to send to the amqp provider.
+ """
+ return (self.config['rabbit-user'], self.config['rabbit-vhost'])
+
+ def get_database_setup(self):
+ """Provide the default database credentials as a list of 3-tuples
+
+ returns a structure of:
+ [
+ {'database': <database>,
+ 'username': <username>,
+ 'hostname': <hostname of this unit>
+ 'prefix': <the optional prefix for the database>, },
+ ]
+
+ :returns [{'database': ...}, ...]: credentials for multiple databases
+ """
+ return [
+ dict(
+ database=self.config['database'],
+ username=self.config['database-user'],
+ hostname=hookenv.unit_private_ip(), )
+ ]
+
+
diff --git a/src/metadata.yaml b/src/metadata.yaml
new file mode 100644
index 0000000..2e59f33
--- /dev/null
+++ b/src/metadata.yaml
@@ -0,0 +1,13 @@
+name: murano
+maintainer: OpenStack Charmers <openstack-charmers@list.ubuntu.com>
+summary: OpenStack Application Catalog Service
+description: |
+ The Murano Project introduces an application catalog to OpenStack,
+ enabling application developers and cloud administrators to publish
+ various cloud-ready applications in a browsable categorized catalog
+tags:
+ - openstack
+series:
+ - xenial
+ - trusty
+ - yakkety
diff --git a/src/novarc b/src/novarc
new file mode 100644
index 0000000..06512e5
--- /dev/null
+++ b/src/novarc
@@ -0,0 +1,19 @@
+{% if identity_service.api_version == '3' -%}
+export OS_AUTH_URL={{ identity_service.auth_protocol }}://{{ identity_service.auth_host }}:{{ identity_service.auth_port }}/v3
+export OS_USERNAME={{ identity_service.service_username }}
+export OS_PASSWORD={{ identity_service.service_password }}
+export OS_USER_DOMAIN_NAME=default
+export OS_PROJECT_DOMAIN_NAME=default
+export OS_PROJECT_NAME={{ identity_service.service_tenant }}
+export OS_REGION_NAME={{ options.region }}
+export OS_IDENTITY_API_VERSION=3
+export OS_DNS_ENDPOINT={{ options.service_listen_info.designate_api.url }}
+export OS_AUTH_VERSION=3
+{% else -%}
+export OS_AUTH_URL={{ identity_service.auth_protocol }}://{{ identity_service.auth_host }}:{{ identity_service.auth_port }}/v2.0
+export OS_TENANT_NAME={{ identity_service.service_tenant }}
+export OS_USERNAME={{ identity_service.service_username }}
+export OS_PASSWORD={{ identity_service.service_password }}
+export OS_REGION_NAME={{ options.region }}
+export OS_DNS_ENDPOINT={{ options.service_listen_info.designate_api.url }}
+{% endif -%}
diff --git a/src/reactive/murano_handlers.py b/src/reactive/murano_handlers.py
new file mode 100644
index 0000000..192018e
--- /dev/null
+++ b/src/reactive/murano_handlers.py
@@ -0,0 +1,47 @@
+# Copyright 2016 Canonical Ltd
+#
+# 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.
+
+import charms_openstack.charm as charm
+import charms.reactive as reactive
+
+# This charm's library contains all of the handler code associated with
+# sdn_charm
+import charm.openstack.murano as murano # noqa
+
+charm.use_defaults(
+ 'charm.installed',
+ 'amqp.connected',
+ 'shared-db.connected',
+ 'identity-service.connected',
+ 'identity-service.available', # enables SSL support
+ 'config.changed',
+ 'update-status')
+
+@reactive.when('shared-db.available')
+@reactive.when('identity-service.available')
+@reactive.when('amqp.available')
+def render_config(*args):
+ """Render the configuration for charm when all the interfaces are
+ available.
+ """
+ with charm.provide_charm_instance() as charm_class:
+ charm_class.render_with_interfaces(args)
+ charm_class.assess_status()
+ reactive.set_state('config.rendered')
+
+# db_sync checks if sync has been done so rerunning is a noop
+@reactive.when('config.rendered')
+def init_db():
+ with charm.provide_charm_instance() as charm_class:
+ charm_class.db_sync()
diff --git a/src/templates/liberty/.keep b/src/templates/liberty/.keep
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/templates/liberty/.keep
diff --git a/src/templates/mitaka/.keep b/src/templates/mitaka/.keep
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/templates/mitaka/.keep
diff --git a/src/templates/mitaka/murano.conf b/src/templates/mitaka/murano.conf
new file mode 100644
index 0000000..2ab471a
--- /dev/null
+++ b/src/templates/mitaka/murano.conf
@@ -0,0 +1,37 @@
+[DEFAULT]
+debug = {{ options.debug }}
+
+bind_host = {{ options.service_listen_info.murano_api.ip }}
+bind_port = {{ options.service_listen_info.murano_api.port }}
+
+[database]
+connection = {{ shared_db.uri }}
+
+{% include "parts/section-keystone-authtoken" %}
+
+{% if identity_service.auth_host -%}
+admin_user = {{ identity_service.service_username }}
+admin_password = {{ identity_service.service_password }}
+admin_tenant_name = {{ identity_service.service_tenant }}
+{% endif -%}
+
+[service_credentials]
+{% if identity_service.auth_host -%}
+auth_type = password
+region_name = {{ options.region }}
+auth_url = {{ identity_service.auth_protocol }}://{{ identity_service.auth_host }}:{{ identity_service.auth_port }}
+project_name = {{ identity_service.service_tenant }}
+username = {{ identity_service.service_username }}
+password = {{ identity_service.service_password }}
+{%- endif %}
+
+{% include "parts/section-rabbitmq-oslo" %}
+
+[murano]
+url = {{ options.external_endpoints.murano_api.url }}
+
+[networking]
+
+external_network = ext_net
+router_name = murano_default_router
+create_router = true
diff --git a/src/tests/README.md b/src/tests/README.md
new file mode 100644
index 0000000..a8d9e14
--- /dev/null
+++ b/src/tests/README.md
@@ -0,0 +1,9 @@
+# Overview
+
+This directory provides Amulet tests to verify basic deployment functionality
+from the perspective of this charm, its requirements and its features, as
+exercised in a subset of the full OpenStack deployment test bundle topology.
+
+For full details on functional testing of OpenStack charms please refer to
+the [functional testing](http://docs.openstack.org/developer/charm-guide/testing.html#functional-testing)
+section of the OpenStack Charm Guide. \ No newline at end of file
diff --git a/src/tests/basic_deployment.py b/src/tests/basic_deployment.py
new file mode 100644
index 0000000..4e3d967
--- /dev/null
+++ b/src/tests/basic_deployment.py
@@ -0,0 +1,181 @@
+# Copyright 2016 Canonical Ltd
+#
+# 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.
+
+
+import amulet
+import json
+import subprocess
+import time
+
+
+import charmhelpers.contrib.openstack.amulet.deployment as amulet_deployment
+import charmhelpers.contrib.openstack.amulet.utils as os_amulet_utils
+
+# Use DEBUG to turn on debug logging
+u = os_amulet_utils.OpenStackAmuletUtils(os_amulet_utils.DEBUG)
+
+
+class SDNCharmDeployment(amulet_deployment.OpenStackAmuletDeployment):
+ """Amulet tests on a basic sdn_charm deployment."""
+
+ def __init__(self, series, openstack=None, source=None, stable=False):
+ """Deploy the entire test environment."""
+ super(SDNCharmDeployment, self).__init__(series, openstack,
+ source, stable)
+ self._add_services()
+ self._add_relations()
+ self._configure_services()
+ self._deploy()
+
+ u.log.info('Waiting on extended status checks...')
+ exclude_services = ['mysql', 'mongodb']
+ self._auto_wait_for_status(exclude_services=exclude_services)
+
+ self._initialize_tests()
+
+ def _add_services(self):
+ """Add services
+
+ Add the services that we're testing, where sdn_charm is local,
+ and the rest of the service are from lp branches that are
+ compatible with the local charm (e.g. stable or next).
+ """
+ this_service = {'name': 'sdn_charm'}
+ other_services = [
+ {
+ 'name': 'nova-compute',
+ 'constraints': {'mem': '4G'},
+ },
+ {
+ 'name': 'neutron-api',
+ },
+ {
+ 'name': 'neutron-gateway',
+ },
+ {'name': 'mysql'},
+ {'name': 'rabbitmq-server'},
+ {'name': 'keystone'},
+ {'name': 'nova-cloud-controller'},
+ {'name': 'glance'},
+ ]
+ super(SDNCharmDeployment, self)._add_services(this_service,
+ other_services)
+
+ def _add_relations(self):
+ """Add all of the relations for the services."""
+ relations = {
+ 'nova-compute:neutron-plugin': 'sdn_charm:neutron-plugin',
+ 'keystone:shared-db': 'mysql:shared-db',
+ 'nova-cloud-controller:shared-db': 'mysql:shared-db',
+ 'nova-cloud-controller:amqp': 'rabbitmq-server:amqp',
+ 'nova-cloud-controller:image-service': 'glance:image-service',
+ 'nova-cloud-controller:identity-service':
+ 'keystone:identity-service',
+ 'nova-compute:cloud-compute':
+ 'nova-cloud-controller:cloud-compute',
+ 'nova-compute:amqp': 'rabbitmq-server:amqp',
+ 'nova-compute:image-service': 'glance:image-service',
+ 'glance:shared-db': 'mysql:shared-db',
+ 'glance:identity-service': 'keystone:identity-service',
+ 'glance:amqp': 'rabbitmq-server:amqp',
+ 'neutron-api:shared-db': 'mysql:shared-db',
+ 'neutron-api:amqp': 'rabbitmq-server:amqp',
+ 'neutron-api:neutron-api': 'nova-cloud-controller:neutron-api',
+ 'neutron-api:identity-service': 'keystone:identity-service',
+ 'neutron-gateway:amqp': 'rabbitmq-server:amqp',
+ 'neutron-gateway:neutron-plugin-api':
+ 'neutron-api:neutron-plugin-api',
+ 'neutron-gateway:quantum-network-service':
+ 'nova-cloud-controller:quantum-network-service',
+ 'neutron-gateway:juju-info': 'sdn_charm:container',
+ }
+ super(SDNCharmDeployment, self)._add_relations(relations)
+
+ def _configure_services(self):
+ """Configure all of the services."""
+ keystone_config = {'admin-password': 'openstack',
+ 'admin-token': 'ubuntutesting'}
+ configs = {'keystone': keystone_config}
+ super(SDNCharmDeployment, self)._configure_services(configs)
+
+ def _get_token(self):
+ return self.keystone.service_catalog.catalog['token']['id']
+
+ def _initialize_tests(self):
+ """Perform final initialization before tests get run."""
+ # Access the sentries for inspecting service units
+ self.sdn_charm_sentry = self.d.sentry['sdn_charm'][0]
+ self.mysql_sentry = self.d.sentry['mysql'][0]
+ self.keystone_sentry = self.d.sentry['keystone'][0]
+ self.rabbitmq_sentry = self.d.sentry['rabbitmq-server'][0]
+ self.sdn_charm_svcs = [
+ 'sdn_charm-agent', 'sdn_charm-api']
+
+ # Authenticate admin with keystone endpoint
+ self.keystone = u.authenticate_keystone_admin(self.keystone_sentry,
+ user='admin',
+ password='openstack',
+ tenant='admin')
+
+ def check_and_wait(self, check_command, interval=2, max_wait=200,
+ desc=None):
+ waited = 0
+ while not check_command() or waited > max_wait:
+ if desc:
+ u.log.debug(desc)
+ time.sleep(interval)
+ waited = waited + interval
+ if waited > max_wait:
+ raise Exception('cmd failed {}'.format(check_command))
+
+ def _run_action(self, unit_id, action, *args):
+ command = ["juju", "action", "do", "--format=json", unit_id, action]
+ command.extend(args)
+ print("Running command: %s\n" % " ".join(command))
+ output = subprocess.check_output(command)
+ output_json = output.decode(encoding="UTF-8")
+ data = json.loads(output_json)
+ action_id = data[u'Action queued with id']
+ return action_id
+
+ def _wait_on_action(self, action_id):
+ command = ["juju", "action", "fetch", "--format=json", action_id]
+ while True:
+ try:
+ output = subprocess.check_output(command)
+ except Exception as e:
+ print(e)
+ return False
+ output_json = output.decode(encoding="UTF-8")
+ data = json.loads(output_json)
+ if data[u"status"] == "completed":
+ return True
+ elif data[u"status"] == "failed":
+ return False
+ time.sleep(2)
+
+ def test_100_services(self):
+ """Verify the expected services are running on the corresponding
+ service units."""
+ u.log.debug('Checking system services on units...')
+
+ service_names = {
+ self.sdn_charm_sentry: self.sdn_charm_svcs,
+ }
+
+ ret = u.validate_services_by_name(service_names)
+ if ret:
+ amulet.raise_status(amulet.FAIL, msg=ret)
+
+ u.log.debug('OK') \ No newline at end of file
diff --git a/src/tests/gate-basic-trusty-icehouse b/src/tests/gate-basic-trusty-icehouse
new file mode 100755
index 0000000..bc30915
--- /dev/null
+++ b/src/tests/gate-basic-trusty-icehouse
@@ -0,0 +1,23 @@
+#!/usr/bin/env python
+#
+# Copyright 2016 Canonical Ltd
+#
+# 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.
+
+"""Amulet tests on a basic SDN Charm deployment on trusty-icehouse."""
+
+from basic_deployment import SDNCharmDeployment
+
+if __name__ == '__main__':
+ deployment = SDNCharmDeployment(series='trusty')
+ deployment.run_tests() \ No newline at end of file
diff --git a/src/tests/gate-basic-trusty-liberty b/src/tests/gate-basic-trusty-liberty
new file mode 100755
index 0000000..f4fe1ff
--- /dev/null
+++ b/src/tests/gate-basic-trusty-liberty
@@ -0,0 +1,25 @@
+#!/usr/bin/env python
+#
+# Copyright 2016 Canonical Ltd
+#
+# 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.
+
+"""Amulet tests on a basic SDN Charm deployment on trusty-liberty."""
+
+from basic_deployment import SDNCharmDeployment
+
+if __name__ == '__main__':
+ deployment = SDNCharmDeployment(series='trusty',
+ openstack='cloud:trusty-liberty',
+ source='cloud:trusty-updates/liberty')
+ deployment.run_tests() \ No newline at end of file
diff --git a/src/tests/gate-basic-trusty-mitaka b/src/tests/gate-basic-trusty-mitaka
new file mode 100755
index 0000000..9142a10
--- /dev/null
+++ b/src/tests/gate-basic-trusty-mitaka
@@ -0,0 +1,25 @@
+#!/usr/bin/env python
+#
+# Copyright 2016 Canonical Ltd
+#
+# 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.
+
+"""Amulet tests on a basic SDN Charm deployment on trusty-mitaka."""
+
+from basic_deployment import SDNCharmDeployment
+
+if __name__ == '__main__':
+ deployment = SDNCharmDeployment(series='trusty',
+ openstack='cloud:trusty-mitaka',
+ source='cloud:trusty-updates/mitaka')
+ deployment.run_tests() \ No newline at end of file
diff --git a/src/tests/gate-basic-xenial-mitaka b/src/tests/gate-basic-xenial-mitaka
new file mode 100755
index 0000000..37725c2
--- /dev/null
+++ b/src/tests/gate-basic-xenial-mitaka
@@ -0,0 +1,23 @@
+#!/usr/bin/env python
+#
+# Copyright 2016 Canonical Ltd
+#
+# 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.
+
+"""Amulet tests on a basic SDN Charm deployment on xenial-mitaka."""
+
+from basic_deployment import SDNCharmDeployment
+
+if __name__ == '__main__':
+ deployment = SDNCharmDeployment(series='xenial')
+ deployment.run_tests() \ No newline at end of file
diff --git a/src/tests/tests.yaml b/src/tests/tests.yaml
new file mode 100644
index 0000000..8ba143b
--- /dev/null
+++ b/src/tests/tests.yaml
@@ -0,0 +1,17 @@
+# Bootstrap the model if necessary.
+bootstrap: True
+# Re-use bootstrap node instead of destroying/re-bootstrapping.
+reset: True
+# Use tox/requirements to drive the venv instead of bundletester's venv feature.
+virtualenv: False
+# Leave makefile empty, otherwise unit/lint tests will rerun ahead of amulet.
+makefile: []
+# Do not specify juju PPA sources. Juju is presumed to be pre-installed
+# and configured in all test runner environments.
+#sources:
+# Do not specify or rely on system packages.
+#packages:
+# Do not specify python packages here. Use test-requirements.txt
+# and tox instead. ie. The venv is constructed before bundletester
+# is invoked.
+#python-packages: \ No newline at end of file
diff --git a/src/tox.ini b/src/tox.ini
new file mode 100644
index 0000000..8b9f734
--- /dev/null
+++ b/src/tox.ini
@@ -0,0 +1,47 @@
+# Source charm: ./tox.ini
+# This file is managed centrally by release-tools and should not be modified
+# within individual charm repos.
+[tox]
+skipsdist = True
+envlist = pep8,py34,py35
+skip_missing_interpreters = True
+
+[testenv]
+setenv = VIRTUAL_ENV={envdir}
+ PYTHONHASHSEED=0
+ TERM=linux
+ LAYER_PATH={toxinidir}/layers
+ INTERFACE_PATH={toxinidir}/interfaces
+ JUJU_REPOSITORY={toxinidir}/build
+passenv = http_proxy https_proxy
+install_command =
+ pip install {opts} {packages}
+deps =
+ -r{toxinidir}/requirements.txt
+
+[testenv:build]
+basepython = python2.7
+commands =
+ charm-build --log-level DEBUG -o {toxinidir}/build src {posargs}
+
+[testenv:py34]
+basepython = python3.4
+deps = -r{toxinidir}/test-requirements.txt
+commands = ostestr {posargs}
+
+[testenv:py35]
+basepython = python3.5
+deps = -r{toxinidir}/test-requirements.txt
+commands = ostestr {posargs}
+
+[testenv:pep8]
+basepython = python2.7
+deps = -r{toxinidir}/test-requirements.txt
+commands = flake8 {posargs} src unit_tests
+
+[testenv:venv]
+commands = {posargs}
+
+[flake8]
+# E402 ignore necessary for path append before sys module import in actions
+ignore = E402 \ No newline at end of file
diff --git a/test-requirements.txt b/test-requirements.txt
new file mode 100644
index 0000000..4c9c8dd
--- /dev/null
+++ b/test-requirements.txt
@@ -0,0 +1,7 @@
+# Lint and unit test requirements
+flake8
+os-testr>=0.4.1
+charms.reactive
+mock>=1.2
+coverage>=3.6
+git+https://github.com/openstack/charms.openstack.git#egg=charms-openstack \ No newline at end of file
diff --git a/tox.ini b/tox.ini
new file mode 100644
index 0000000..8b9f734
--- /dev/null
+++ b/tox.ini
@@ -0,0 +1,47 @@
+# Source charm: ./tox.ini
+# This file is managed centrally by release-tools and should not be modified
+# within individual charm repos.
+[tox]
+skipsdist = True
+envlist = pep8,py34,py35
+skip_missing_interpreters = True
+
+[testenv]
+setenv = VIRTUAL_ENV={envdir}
+ PYTHONHASHSEED=0
+ TERM=linux
+ LAYER_PATH={toxinidir}/layers
+ INTERFACE_PATH={toxinidir}/interfaces
+ JUJU_REPOSITORY={toxinidir}/build
+passenv = http_proxy https_proxy
+install_command =
+ pip install {opts} {packages}
+deps =
+ -r{toxinidir}/requirements.txt
+
+[testenv:build]
+basepython = python2.7
+commands =
+ charm-build --log-level DEBUG -o {toxinidir}/build src {posargs}
+
+[testenv:py34]
+basepython = python3.4
+deps = -r{toxinidir}/test-requirements.txt
+commands = ostestr {posargs}
+
+[testenv:py35]
+basepython = python3.5
+deps = -r{toxinidir}/test-requirements.txt
+commands = ostestr {posargs}
+
+[testenv:pep8]
+basepython = python2.7
+deps = -r{toxinidir}/test-requirements.txt
+commands = flake8 {posargs} src unit_tests
+
+[testenv:venv]
+commands = {posargs}
+
+[flake8]
+# E402 ignore necessary for path append before sys module import in actions
+ignore = E402 \ No newline at end of file
diff --git a/unit_tests/__init__.py b/unit_tests/__init__.py
new file mode 100644
index 0000000..1ca5eb6
--- /dev/null
+++ b/unit_tests/__init__.py
@@ -0,0 +1,46 @@
+# Copyright 2016 Canonical Ltd
+#
+# 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.
+
+import sys
+import mock
+
+sys.path.append('src')
+sys.path.append('src/lib')
+
+# Mock out charmhelpers so that we can test without it.
+# also stops sideeffects from occuring.
+charmhelpers = mock.MagicMock()
+apt_pkg = mock.MagicMock()
+sys.modules['apt_pkg'] = apt_pkg
+sys.modules['charmhelpers'] = charmhelpers
+sys.modules['charmhelpers.core'] = charmhelpers.core
+sys.modules['charmhelpers.core.decorators'] = charmhelpers.core.decorators
+sys.modules['charmhelpers.core.hookenv'] = charmhelpers.core.hookenv
+sys.modules['charmhelpers.core.host'] = charmhelpers.core.host
+sys.modules['charmhelpers.core.unitdata'] = charmhelpers.core.unitdata
+sys.modules['charmhelpers.core.templating'] = charmhelpers.core.templating
+sys.modules['charmhelpers.contrib'] = charmhelpers.contrib
+sys.modules['charmhelpers.contrib.openstack'] = charmhelpers.contrib.openstack
+sys.modules['charmhelpers.contrib.openstack.utils'] = (
+ charmhelpers.contrib.openstack.utils)
+sys.modules['charmhelpers.contrib.openstack.templating'] = (
+ charmhelpers.contrib.openstack.templating)
+sys.modules['charmhelpers.contrib.network'] = charmhelpers.contrib.network
+sys.modules['charmhelpers.contrib.network.ip'] = (
+ charmhelpers.contrib.network.ip)
+sys.modules['charmhelpers.fetch'] = charmhelpers.fetch
+sys.modules['charmhelpers.cli'] = charmhelpers.cli
+sys.modules['charmhelpers.contrib.hahelpers'] = charmhelpers.contrib.hahelpers
+sys.modules['charmhelpers.contrib.hahelpers.cluster'] = (
+ charmhelpers.contrib.hahelpers.cluster) \ No newline at end of file
diff --git a/unit_tests/test_lib_charm_openstack_openvswitch_odl.py b/unit_tests/test_lib_charm_openstack_openvswitch_odl.py
new file mode 100644
index 0000000..7c4385b
--- /dev/null
+++ b/unit_tests/test_lib_charm_openstack_openvswitch_odl.py
@@ -0,0 +1,47 @@
+# Copyright 2016 Canonical Ltd
+#
+# 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.
+
+from __future__ import absolute_import
+from __future__ import print_function
+
+import unittest
+
+import mock
+
+import charm.openstack.sdn_charm as sdn_charm
+
+
+class Helper(unittest.TestCase):
+
+ def setUp(self):
+ self._patches = {}
+ self._patches_start = {}
+
+ def tearDown(self):
+ for k, v in self._patches.items():
+ v.stop()
+ setattr(self, k, None)
+ self._patches = None
+ self._patches_start = None
+
+ def patch(self, obj, attr, return_value=None, **kwargs):
+ mocked = mock.patch.object(obj, attr, **kwargs)
+ self._patches[attr] = mocked
+ started = mocked.start()
+ started.return_value = return_value
+ self._patches_start[attr] = started
+ setattr(self, attr, started)
+
+
+class TestSDNCharm(Helper): \ No newline at end of file
diff --git a/unit_tests/test_openvswitch_odl_handlers.py b/unit_tests/test_openvswitch_odl_handlers.py
new file mode 100644
index 0000000..f107ee6
--- /dev/null
+++ b/unit_tests/test_openvswitch_odl_handlers.py
@@ -0,0 +1,43 @@
+# Copyright 2016 Canonical Ltd
+#
+# 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.
+
+from __future__ import absolute_import
+from __future__ import print_function
+
+import mock
+
+import reactive.sdn_charm_handlers as handlers
+
+import charms_openstack.test_utils as test_utils
+
+
+class TestRegisteredHooks(test_utils.TestRegisteredHooks):
+
+ def test_hooks(self):
+ defaults = [
+ 'charm.installed',
+ 'config.changed',
+ 'update-status']
+ hook_set = {
+ 'when': {
+ },
+ 'when_not': {
+ }
+ }
+ # test that the hooks were registered via the
+ # reactive.barbican_handlers
+ self.registered_hooks_test_helper(handlers, hook_set, defaults)
+
+
+class TestSDNCharmHandles(test_utils.PatchHelper): \ No newline at end of file

This mirror site include all the OpenStack related repositories under: openstack, openstack-dev and openstack-infra.

NOTE: All repositories are updated every one hour.

Usage

For Git Clone
 git clone http://git.trystack.cn/openstack/nova.git 
For DevStack

Add GIT_BASE, NOVNC_REPO and SPICE_REPO variables to local.conf file.

[[local|localrc]]

# use TryStack git mirror
GIT_BASE=http://git.trystack.cn
NOVNC_REPO=http://git.trystack.cn/kanaka/noVNC.git
SPICE_REPO=http://git.trystack.cn/git/spice/spice-html5.git