~ibmcharmers/ibm-websphere-liberty

Owner: shilkaul
Status: Needs Review
Vote: +0 (+2 needed for approval)

CPP?: No
OIL?: No

Charm for IBM WebSphere Liberty (Support for Ubuntu Z is added and layered approach is used).

The source code can be found here :
https://code.launchpad.net/~iibmcharmers/ibmlayers/layer-ibm-websphere-liberty

Below two issues which were raised in the merge request have been addressed.
- remove unnecessary ./deps directory from layer source
- update repo link in layer.yaml

For the third issue, ie use http instead of https interface (https is not available from http://interfaces.juju.solutions/), we have come up with the below alternative to test this charm.
The IBM Websphere liberty charm needs both http and https port. But the existing HTTP interface supports http port only. We had raised the issue some time back to incorporate https as well. Below is the issue number for reference:
https://github.com/juju-solutions/interface-http/issues/5
So we have created one more interface called HTTPS and pushed it into juju interfaces. In case in future, one single interface handle this, either HTTP or HTTPS, we can change to that one. Till that, we are using the newly created HTTPS interface for liberty charm.


Tests

Substrate Status Results Last Updated
lxc RETRY 19 days ago
aws RETRY 19 days ago
gce RETRY 19 days ago

Add Comment

Login to comment/vote on this review.


Policy Checklist

Description Unreviewed Pass Fail

General

Must verify that any software installed or utilized is verified as coming from the intended source.
  • Any software installed from the Ubuntu or CentOS default archives satisfies this due to the apt and yum sources including cryptographic signing information.
  • Third party repositories must be listed as a configuration option that can be overridden by the user and not hard coded in the charm itself.
  • Launchpad PPAs are acceptable as the add-apt-repository command retrieves the keys securely.
  • Other third party repositories are acceptable if the signing key is embedded in the charm.
Must provide a means to protect users from known security vulnerabilities in a way consistent with best practices as defined by either operating system policies or upstream documentation.
Basically, this means there must be instructions on how to apply updates if you use software not from distribution channels.
Must have hooks that are idempotent.
Should be built using charm layers.
Should use Juju Resources to deliver required payloads.

Testing and Quality

charm proof must pass without errors or warnings.
Must include passing unit, functional, or integration tests.
Tests must exercise all relations.
Tests must exercise config.
set-config, unset-config, and re-set must be tested as a minimum
Must not use anything infrastructure-provider specific (i.e. querying EC2 metadata service).
Must be self contained unless the charm is a proxy for an existing cloud service, e.g. ec2-elb charm.
Must not use symlinks.
Bundles must only use promulgated charms, they cannot reference charms in personal namespaces.
Must call Juju hook tools (relation-*, unit-*, config-*, etc) without a hard coded path.
Should include a tests.yaml for all integration tests.

Metadata

Must include a full description of what the software does.
Must include a maintainer email address for a team or individual who will be responsive to contact.
Must include a license. Call the file 'copyright' and make sure all files' licenses are specified clearly.
Must be under a Free license.
Must have a well documented and valid README.md.
Must describe the service.
Must describe how it interacts with other services, if applicable.
Must document the interfaces.
Must show how to deploy the charm.
Must define external dependencies, if applicable.
Should link to a recommend production usage bundle and recommended configuration if this differs from the default.
Should reference and link to upstream documentation and best practices.

Security

Must not run any network services using default passwords.
Must verify and validate any external payload
  • Known and understood packaging systems that verify packages like apt, pip, and yum are ok.
  • wget | sh style is not ok.
Should make use of whatever Mandatory Access Control system is provided by the distribution.
Should avoid running services as root.

Source Diff

Inline diff comments 0

No comments yet.

Back to file index

Makefile

 1
--- 
 2
+++ Makefile
 3
@@ -0,0 +1,24 @@
 4
+#!/usr/bin/make
 5
+
 6
+all: lint unit_test
 7
+
 8
+
 9
+.PHONY: clean
10
+clean:
11
+	@rm -rf .tox
12
+
13
+.PHONY: apt_prereqs
14
+apt_prereqs:
15
+	@# Need tox, but don't install the apt version unless we have to (don't want to conflict with pip)
16
+	@which tox >/dev/null || (sudo apt-get install -y python-pip && sudo pip install tox)
17
+
18
+.PHONY: lint
19
+lint: apt_prereqs
20
+	@tox --notest
21
+	@PATH=.tox/py34/bin:.tox/py35/bin flake8 $(wildcard hooks reactive lib unit_tests tests)
22
+	@charm proof
23
+
24
+.PHONY: unit_test
25
+unit_test: apt_prereqs
26
+	@echo Starting tests...
27
+	tox
Back to file index

README.md

 1
--- 
 2
+++ README.md
 3
@@ -0,0 +1,72 @@
 4
+# Overview
 5
+
 6
+WebSphere Application Server Liberty Profile
 7
+
 8
+Liberty Profile is a dynamic profile of IBM WebSphere Application Server (WAS) 
 9
+that enables the WAS server to provision **only the required** features of an 
10
+application (or set of applications) deployed to the server.
11
+
12
+If an application only requires a servlet engine, then all that starts is the 
13
+WAS kernel, the HTTP transport and the web container. Which is fast to bring 
14
+up and has an small footprint.
15
+
16
+The WAS Liberty profile provides a development-centric approach to configuring 
17
+the server. Configuration is through a simple XML file which is easy to author,
18
+maintain in a version control system, share across and between development 
19
+team, and diff for changes. 
20
+
21
+# Usage
22
+To use this charm, you must agree to the Terms of Use. You can view the full license for ibm WebsphereLiberty by visiting [here](https://public.dhe.ibm.com/ibmdl/export/pub/software/websphere/wasdev/downloads/wlp/16.0.0.3/lafiles/runtime/en.html) and click on Download to view the license for version 16.0.0.3.
23
+Please check for the license associated with the Websphere Liberty version that you use.
24
+
25
+The charm downloads the 16.0.0.3 version of the Websphere Liberty runtime from IBM.
26
+
27
+# Deploy
28
+
29
+Run the following commands to deploy this charm:
30
+
31
+    juju deploy ibm-websphere-liberty 
32
+
33
+Note: This charm requires acceptance of Terms of Use. When deploying from
34
+the Charm Store, these terms will be presented to you for your consideration.
35
+To accept the terms:
36
+
37
+    juju agree ibm-wlp/0
38
+
39
+By default the charm will deploy the 16.0.0.3 version of websphere liberty. To install a specific version of WebSphere Liberty, run the following command:
40
+
41
+    juju config ibm-websphere-liberty ibm-liberty-version="8.5.5.8" 
42
+
43
+Note: This charm supports only the versions under "16.0.0.3".
44
+Please proide the Checksum value of the file which you want to install:
45
+
46
+    juju config ibm-websphere-liberty sha_wlp="a0497da259cf6ad972500ceedbb1227c0ac72de4adc50a0fa6edc60ea044ab3a32d4f390533c98dee72ad1f36fa54d09591bb0d0ec6e6245b602e091bf7ea3de"
47
+
48
+# Verification
49
+After installing IBM WebSphere Liberty, use your web browser to see the WebSphere Liberty console. The URL for Websphere Liberty console is:
50
+    
51
+    http://websphere-liberty-host:9080 
52
+    
53
+Here websphere-liberty-host represents the public ip address of your machine, where Websphere Liberty is installed.
54
+
55
+
56
+# Configuration
57
+`install-petstore`  
58
+Petstore is a web application written in Java used to test that 
59
+WebSphere Liberty Profile is working.  The default value is True, but 
60
+set this to False if you do not want the test application installed.
61
+
62
+`ibm-liberty-version`
63
+The version of WLP which has to be installed. If nothing is mentioned it would install the 16.0.0.3 version.
64
+
65
+`sha_wlp`
66
+The checksum value of WLP file which has to be installed. If nothing is mentioned it would take the default checksum value of 16.0.0.3 version.    
67
+
68
+
69
+## WebSphere Liberty Profile Links and Information
70
+- [Getting Started](https://www.ibmdw.net/wasdev/docs/category/getting-started/)
71
+- [Introducing the Liberty Profile](https://www.ibmdw.net/wasdev/docs/introducing_the_liberty_profile/)
72
+- [WebSphere Application Server Version 8.5 Information Center](http://pic.dhe.ibm.com/infocenter/wasinfo/v8r5/index.jsp?topic=%2Fcom.ibm.websphere.home.doc_wasinfo_v8r5%2Fwelcome_ic_home.html)
73
+- [Using the Liberty profile](http://pic.dhe.ibm.com/infocenter/wasinfo/v8r5/index.jsp?topic=/com.ibm.websphere.wlp.nd.multiplatform.doc/ae/thread_twlp_devenv.html)
74
+- [WebSphere Application Server Liberty Profile Redbook](http://www.redbooks.ibm.com/redbooks/pdfs/sg248076.pdf)
75
+- [Liberty Repository](https://www.ibmdw.net/wasdev/downloads/)
Back to file index

bin/layer_option

 1
--- 
 2
+++ bin/layer_option
 3
@@ -0,0 +1,24 @@
 4
+#!/usr/bin/env python3
 5
+
 6
+import sys
 7
+sys.path.append('lib')
 8
+
 9
+import argparse
10
+from charms.layer import options
11
+
12
+
13
+parser = argparse.ArgumentParser(description='Access layer options.')
14
+parser.add_argument('section',
15
+                    help='the section, or layer, the option is from')
16
+parser.add_argument('option',
17
+                    help='the option to access')
18
+
19
+args = parser.parse_args()
20
+value = options(args.section).get(args.option, '')
21
+if isinstance(value, bool):
22
+    sys.exit(0 if value else 1)
23
+elif isinstance(value, list):
24
+    for val in value:
25
+        print(val)
26
+else:
27
+    print(value)
Back to file index

config.yaml

 1
--- 
 2
+++ config.yaml
 3
@@ -0,0 +1,26 @@
 4
+"options":
 5
+  "ibm-liberty-url":
 6
+    "type": "string"
 7
+    "default": "http://public.dhe.ibm.com/ibmdl/export/pub/software/websphere/wasdev/downloads/wlp/index.yml"
 8
+    "description": |
 9
+      The URL to the file that has the link to latest IBM Liberty package and license.
10
+      Modification of this value would not be required.
11
+  "install-petstore":
12
+    "type": "boolean"
13
+    "default": !!bool "true"
14
+    "description": "Petstore is a web application written in Java used to test that\
15
+      \ \nWebSphere Liberty Profile is working.  Set this to False if you do \nnot\
16
+      \ want the test application installed.\n"
17
+  "ibm-liberty-version":
18
+    "type": "string"
19
+    "default": "16.0.0.3"
20
+    "description": "The version of WLP which has to be installed. If nothing is mentioned\
21
+      \ \nit would install the latest version.\n"
22
+  "sha_wlp":
23
+    "type": "string"
24
+    "default": "9544919c6056e918ed5bbce5e8667f98dfe8e135bd387a521647b56e7368591d85ec54e9e23aed26736a57d1667de73378cb246cc682275e0240da1a71cbca80"
25
+    "description": |
26
+      Checksum value to check integrity of IBM WLP package. The Charm
27
+      uses sha1sum to check the integrity. If empty, it does not carry out
28
+      the integrity check. Refer README file to find out Checksum value for
29
+      downloaded package.
Back to file index

copyright

 1
--- 
 2
+++ copyright
 3
@@ -0,0 +1,13 @@
 4
+Copyright 2016 IBM Corporation
 5
+
 6
+This Charm is licensed under the Apache License, Version 2.0 (the "License");
 7
+you may not use this file except in compliance with the License.
 8
+You may obtain a copy of the License at
 9
+
10
+    http://www.apache.org/licenses/LICENSE-2.0
11
+
12
+Unless required by applicable law or agreed to in writing, software
13
+distributed under the License is distributed on an "AS IS" BASIS,
14
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+See the License for the specific language governing permissions and
16
+limitations under the License.
Back to file index

files/DBPopulator.java

  1
--- 
  2
+++ files/DBPopulator.java
  3
@@ -0,0 +1,231 @@
  4
+package org.agoncal.application.petstore.service;
  5
+
  6
+import org.agoncal.application.petstore.domain.*;
  7
+import org.agoncal.application.petstore.util.Loggable;
  8
+
  9
+import javax.annotation.PostConstruct;
 10
+import javax.annotation.PreDestroy;
 11
+import javax.annotation.sql.DataSourceDefinition;
 12
+import javax.annotation.sql.DataSourceDefinitions;
 13
+import javax.ejb.Singleton;
 14
+import javax.ejb.Startup;
 15
+import javax.inject.Inject;
 16
+
 17
+/**
 18
+ * @author Antonio Goncalves
 19
+ *         http://www.antoniogoncalves.org
 20
+ *         --
 21
+ */
 22
+
 23
+@Singleton
 24
+@Startup
 25
+@Loggable
 26
+@DataSourceDefinitions({
 27
+    @DataSourceDefinition(
 28
+        className = "org.apache.derby.jdbc.EmbeddedDataSource",
 29
+        name = "java:global/jdbc/applicationPetstoreDS",
 30
+        user = "app",
 31
+        password = "app",
 32
+        databaseName = "applicationPetstoreDB",
 33
+        properties = {"connectionAttributes=;create=true"}
 34
+    ),
 35
+    @DataSourceDefinition(
 36
+        className = "org.apache.derby.jdbc.EmbeddedDataSource",
 37
+        name = "java:global/jdbc/applicationPetstoreNJTADS",
 38
+        user = "app",
 39
+        password = "app",
 40
+        databaseName = "applicationPetstoreDB",
 41
+        transactional = false,
 42
+        properties = {"connectionAttributes=;create=true"}
 43
+    ),
 44
+})  
 45
+public class DBPopulator {
 46
+
 47
+    // ======================================
 48
+    // =             Attributes             =
 49
+    // ======================================
 50
+
 51
+    private Category fish;
 52
+    private Category dog;
 53
+    private Category reptile;
 54
+    private Category cat;
 55
+    private Category bird;
 56
+    private Customer marc;
 57
+    private Customer bill;
 58
+    private Customer steve;
 59
+    private Customer user;
 60
+    private Customer admin;
 61
+
 62
+    @Inject
 63
+    private CatalogService catalogService;
 64
+
 65
+    @Inject
 66
+    private CustomerService customerService;
 67
+
 68
+    // ======================================
 69
+    // =          Lifecycle Methods         =
 70
+    // ======================================
 71
+
 72
+    @PostConstruct
 73
+    private void populateDB() {
 74
+        initCatalog();
 75
+        initCustomers();
 76
+    }
 77
+
 78
+    @PreDestroy
 79
+    private void clearDB() {
 80
+        catalogService.removeCategory(fish);
 81
+        catalogService.removeCategory(dog);
 82
+        catalogService.removeCategory(reptile);
 83
+        catalogService.removeCategory(cat);
 84
+        catalogService.removeCategory(bird);
 85
+        customerService.removeCustomer(marc);
 86
+        customerService.removeCustomer(bill);
 87
+        customerService.removeCustomer(steve);
 88
+        customerService.removeCustomer(user);
 89
+        customerService.removeCustomer(admin);
 90
+    }
 91
+
 92
+    // ======================================
 93
+    // =           Private Methods          =
 94
+    // ======================================
 95
+
 96
+    private void initCatalog() {
 97
+
 98
+        // Categories
 99
+        fish = new Category("Fish", "Any of numerous cold-blooded aquatic vertebrates characteristically having fins, gills, and a streamlined body");
100
+        dog = new Category("Dogs", "A domesticated carnivorous mammal related to the foxes and wolves and raised in a wide variety of breeds");
101
+        reptile = new Category("Reptiles", "Any of various cold-blooded, usually egg-laying vertebrates, such as a snake, lizard, crocodile, turtle");
102
+        cat = new Category("Cats", " Small carnivorous mammal domesticated since early times as a catcher of rats and mice and as a pet and existing in several distinctive breeds and varieties");
103
+        bird = new Category("Birds", "Any of the class Aves of warm-blooded, egg-laying, feathered vertebrates with forelimbs modified to form wings");
104
+
105
+        // Products
106
+        Product angelfish = new Product("Angelfish", "Saltwater fish from Australia", fish);
107
+        Product tigerShark = new Product("Tiger Shark", "Saltwater fish from Australia", fish);
108
+        Product koi = new Product("Koi", "Freshwater fish from Japan", fish);
109
+        Product goldfish = new Product("Goldfish", "Freshwater fish from China", fish);
110
+        fish.addProduct(angelfish);
111
+        fish.addProduct(tigerShark);
112
+        fish.addProduct(koi);
113
+        fish.addProduct(goldfish);
114
+
115
+        Product bulldog = new Product("Bulldog", "Friendly dog from England", dog);
116
+        Product poodle = new Product("Poodle", "Cute dog from France", dog);
117
+        Product dalmation = new Product("Dalmation", "Great dog for a fire station", dog);
118
+        Product goldenRetriever = new Product("Golden Retriever", "Great family dog", dog);
119
+        Product labradorRetriever = new Product("Labrador Retriever", "Great hunting dog", dog);
120
+        Product chihuahua = new Product("Chihuahua", "Great companion dog", dog);
121
+        dog.addProduct(bulldog);
122
+        dog.addProduct(poodle);
123
+        dog.addProduct(dalmation);
124
+        dog.addProduct(goldenRetriever);
125
+        dog.addProduct(labradorRetriever);
126
+        dog.addProduct(chihuahua);
127
+
128
+        Product rattlesnake = new Product("Rattlesnake", "Doubles as a watch dog", reptile);
129
+        Product iguana = new Product("Iguana", "Friendly green friend", reptile);
130
+        reptile.addProduct(rattlesnake);
131
+        reptile.addProduct(iguana);
132
+
133
+        Product manx = new Product("Manx", "Great for reducing mouse populations", cat);
134
+        Product persian = new Product("Persian", "Friendly house cat, doubles as a princess", cat);
135
+        cat.addProduct(manx);
136
+        cat.addProduct(persian);
137
+
138
+        Product amazonParrot = new Product("Amazon Parrot", "Great companion for up to 75 years", bird);
139
+        Product finch = new Product("Finch", "Great stress reliever", bird);
140
+        bird.addProduct(amazonParrot);
141
+        bird.addProduct(finch);
142
+
143
+        // Items
144
+        Item largeAngelfish = new Item("Large", 10.00f, "fish1.jpg", angelfish, "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum velit ante, malesuada porta condimentum eget, tristique id magna. Donec ac justo velit. Suspendisse potenti. Donec vulputate vulputate molestie. Quisque vitae arcu massa, dictum sodales leo. Sed feugiat elit vitae ante auctor ultrices. Duis auctor consectetur arcu id faucibus. Curabitur gravida.");
145
+        Item thootlessAngelfish = new Item("Thootless", 10.00f, "fish1.jpg", angelfish, "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur fringilla pharetra dignissim. In imperdiet, lacus a vehicula dignissim, ante ligula euismod leo, non lobortis orci quam a nisl. Aliquam risus eros, molestie sit amet interdum nec, convallis malesuada leo. Quisque bibendum facilisis erat eget tincidunt. Phasellus pharetra gravida purus. Maecenas.");
146
+        angelfish.addItem(largeAngelfish);
147
+        angelfish.addItem(thootlessAngelfish);
148
+        Item spottedTigerShark = new Item("Spotted", 12.00f, "fish4.jpg", tigerShark, "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque dictum iaculis sapien, eu fermentum eros feugiat a. Pellentesque ultricies mauris orci. Mauris interdum hendrerit felis vel dignissim. Phasellus ac sem sit amet ante laoreet volutpat. Sed sagittis venenatis ullamcorper. Vivamus non mollis nunc. Etiam mauris odio, tristique sed porta in.");
149
+        Item spotlessTigerShark = new Item("Spotless", 12.00f, "fish4.jpg", tigerShark, "Lorem ipsum dolor sit amet, consectetur adipiscing elit. In hendrerit ultricies bibendum. Vestibulum vitae dui porttitor nibh dignissim pretium eu at odio. Proin ac nibh eget erat ullamcorper consequat ac cursus est. Donec sollicitudin interdum elit sed gravida. Integer lacus lacus, gravida eget vehicula ac, sagittis et dui. In et.");
150
+        tigerShark.addItem(spottedTigerShark);
151
+        tigerShark.addItem(spotlessTigerShark);
152
+        Item maleKoi = new Item("Male Adult", 12.00f, "fish3.jpg", koi, "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi consectetur, ligula eu malesuada tempus, risus tellus varius ligula, id auctor magna tellus quis dui. Integer ut neque ut libero aliquet hendrerit. Maecenas bibendum, magna sed vulputate tempor, tortor neque consequat nunc, id consectetur neque odio eget augue. Ut consectetur, nisl.");
153
+        Item femaleKoi = new Item("Female Adult", 12.00f, "fish3.jpg", koi, "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec et porta eros. Aliquam neque arcu, sodales eget rutrum a, luctus sit amet sem. Vestibulum ultricies dictum mi, eu sagittis lacus ultrices sit amet. Mauris nec interdum ipsum. Maecenas semper, magna sit amet commodo tempus, purus lectus pretium dui, sit amet.");
154
+        koi.addItem(maleKoi);
155
+        koi.addItem(femaleKoi);
156
+        Item maleGoldfish = new Item("Male Puppy", 12.00f, "fish2.jpg", goldfish, "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean ac nunc mauris. Proin augue sem, imperdiet quis imperdiet vitae, egestas vitae quam. Nam id lectus nisi. In hac habitasse platea dictumst. Proin ullamcorper eros non diam accumsan ornare. Fusce posuere, nulla vel tempor molestie, lectus dui aliquet orci, in volutpat.");
157
+        Item femaleGoldfish = new Item("Female Puppy", 12.00f, "fish2.jpg", goldfish, "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc pretium ornare est ullamcorper porta. Nullam eleifend tincidunt justo nec ultrices. In vehicula pharetra turpis, nec consequat sapien tempus sit amet. Donec quis urna in odio luctus rhoncus. In metus lorem, ultricies vel vestibulum non, laoreet ac neque. Duis posuere, tortor.");
158
+        goldfish.addItem(maleGoldfish);
159
+        goldfish.addItem(femaleGoldfish);
160
+
161
+        Item maleBulldog = new Item("Spotless Male Puppy", 22.00f, "dog1.jpg", bulldog, "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce et lorem vel tellus aliquet pretium ut nec libero. Cras euismod tincidunt rutrum. Suspendisse nisl justo, vestibulum et commodo vel, ultricies placerat quam. Sed nisi orci, rhoncus ac accumsan eget, pretium ac purus. Nam et scelerisque mi. Vivamus luctus, massa eget.");
162
+        Item femaleBulldog = new Item("Spotless Female Puppy", 22.00f, "dog1.jpg", bulldog, "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam rhoncus arcu sed sapien interdum porttitor. Nulla nunc magna, egestas sed laoreet nec, congue et felis. Donec rhoncus, est vitae tincidunt posuere, dolor nunc fermentum orci, ut varius velit ipsum a massa. Pellentesque habitant morbi tristique senectus et netus et malesuada.");
163
+        bulldog.addItem(maleBulldog);
164
+        bulldog.addItem(femaleBulldog);
165
+        Item malePoodle = new Item("Spotted Male Puppy", 32.00f, "dog2.jpg", poodle, "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis ipsum erat, tincidunt sit amet lacinia non, vestibulum elementum odio. Donec id lacus ante, id bibendum est. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Etiam eu suscipit mauris. Vivamus dolor diam, pulvinar a consectetur at.");
166
+        Item femalePoodle = new Item("Spotted Female Puppy", 32.00f, "dog2.jpg", poodle, "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi nec justo orci, in faucibus lectus. Proin feugiat faucibus pellentesque. Etiam nec dolor justo, non egestas nisl. Etiam convallis orci nec felis pretium malesuada. Maecenas nec tortor erat. Cras accumsan eros sit amet nibh fringilla molestie. Suspendisse potenti. Nulla vulputate neque.");
167
+        poodle.addItem(malePoodle);
168
+        poodle.addItem(femalePoodle);
169
+        Item tailedDalmation = new Item("Tailed", 62.00f, "dog3.jpg", dalmation, "Lorem ipsum dolor sit amet, consectetur adipiscing elit. In ante massa, semper non tempor at, faucibus nec est. Aliquam aliquet, tortor ut egestas blandit, nisi urna elementum lectus, a porta dolor leo quis massa. Aliquam erat volutpat. Fusce sed eros et enim varius consequat. Nam molestie, neque quis commodo rhoncus.");
170
+        Item tailessDalmation = new Item("Tailless", 62.00f, "dog3.jpg", dalmation, "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus ac adipiscing nulla. Proin risus lectus, convallis eu sagittis scelerisque, fringilla ut odio. Suspendisse ultrices ullamcorper adipiscing. Proin ac suscipit tellus. Vivamus tempus nibh interdum ipsum ullamcorper at suscipit nibh mattis. Vivamus elementum volutpat ipsum eu tempus. Proin velit ligula, fringilla.");
171
+        dalmation.addItem(tailedDalmation);
172
+        dalmation.addItem(tailessDalmation);
173
+        Item tailedGoldenRetriever = new Item("Tailed", 82.00f, "dog4.jpg", goldenRetriever, "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin sit amet velit id augue pellentesque tempor suscipit eu nisi. Nulla facilisi. Sed ultrices lectus in ligula viverra lacinia. Quisque et leo nisl. Suspendisse potenti. Donec semper malesuada ullamcorper. Vivamus fringilla nunc eget tellus condimentum ut dictum nisi euismod. Pellentesque habitant.");
174
+        Item tailessGoldenRetriever = new Item("Tailless", 82.00f, "dog4.jpg", goldenRetriever, "Lorem ipsum dolor sit amet, consectetur adipiscing elit. In eget justo odio. Phasellus suscipit auctor lectus eget luctus. Nam ultricies auctor augue vel feugiat. Nulla odio lectus, volutpat sit amet vestibulum id, convallis sit amet tellus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Quisque.");
175
+        goldenRetriever.addItem(tailedGoldenRetriever);
176
+        goldenRetriever.addItem(tailessGoldenRetriever);
177
+        Item tailedLabradorRetriever = new Item("Tailed", 100.00f, "dog5.jpg", labradorRetriever, "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent lobortis volutpat nunc, in sodales felis condimentum a. Quisque quis neque commodo elit consequat porttitor. Integer nec scelerisque nisi. Aliquam velit lorem, egestas sit amet sodales sit amet, gravida ut lorem. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices.");
178
+        Item tailessLabradorRetriever = new Item("Tailless", 100.00f, "dog5.jpg", labradorRetriever, "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin tortor mauris, sodales sodales pretium vitae, egestas eget mi. Ut hendrerit, libero et feugiat tristique, ligula nunc varius sem, non tristique mi ante a turpis. Suspendisse potenti. Nunc fringilla imperdiet nibh, eu sodales nisl pellentesque eu. Curabitur dictum vestibulum elit ut.");
179
+        labradorRetriever.addItem(tailedLabradorRetriever);
180
+        labradorRetriever.addItem(tailessLabradorRetriever);
181
+        Item maleChihuahua = new Item("Male Adult", 100.00f, "dog6.jpg", chihuahua, "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer posuere porta risus, a bibendum enim pellentesque sit amet. Mauris imperdiet suscipit lectus, sed molestie orci posuere a. Fusce eleifend interdum nisi, nec vulputate velit rutrum ut. Nulla turpis ligula, fermentum ac tincidunt at, porttitor sit amet sem. Curabitur eget eros.");
182
+        Item femaleChihuahua = new Item("Female Adult", 100.00f, "dog6.jpg", chihuahua, "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras in diam sapien. Etiam sed dapibus velit. Phasellus gravida egestas congue. Etiam nec nunc non arcu facilisis ultrices. Curabitur et diam sed neque facilisis dignissim. Vestibulum accumsan viverra nunc, ac tincidunt nisi placerat sit amet. Nulla ac pellentesque justo. Aliquam pellentesque.");
183
+        chihuahua.addItem(maleChihuahua);
184
+        chihuahua.addItem(femaleChihuahua);
185
+
186
+        Item femaleRattlesnake = new Item("Female Adult", 20.00f, "reptile1.jpg", rattlesnake, "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent lobortis ante et nunc scelerisque aliquet. Phasellus sed auctor purus. Cras tempus lacus eget felis viverra scelerisque. Sed ac tellus vitae nisl vehicula feugiat ac vitae dolor. Duis interdum lorem quis risus ullamcorper id cursus magna pharetra. Sed et nisi odio.");
187
+        Item maleRattlesnake = new Item("Male Adult", 20.00f, "reptile1.jpg", rattlesnake, "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris pharetra tempus vulputate. Proin at nibh at felis feugiat fringilla. Fusce suscipit malesuada urna posuere suscipit. Integer non quam orci, vel adipiscing odio. Aenean at turpis nisi, a ullamcorper massa. Integer consectetur libero a lorem blandit pretium. Curabitur a sodales justo.");
188
+        rattlesnake.addItem(femaleRattlesnake);
189
+        rattlesnake.addItem(maleRattlesnake);
190
+        Item femaleIguana = new Item("Female Adult", 150.00f, "lizard1.jpg", iguana, "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin dictum, nisi vitae fringilla ultrices, est ipsum faucibus ipsum, sit amet dapibus erat ipsum et arcu. Sed euismod, mauris suscipit placerat semper, tortor magna cursus nulla, id elementum dui dolor sit amet nunc. Pellentesque a interdum lectus. Mauris in augue eu.");
191
+        Item maleIguana = new Item("Male Adult", 160.00f, "lizard1.jpg", iguana, "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus at dapibus arcu. Nunc at dui sem, in fringilla velit. Suspendisse mauris felis, molestie scelerisque viverra sit amet, dapibus eu diam. Curabitur egestas lectus et ligula pharetra in sollicitudin neque tristique. Nunc suscipit scelerisque nunc, vitae consectetur justo sodales ullamcorper. Nulla.");
192
+        iguana.addItem(femaleIguana);
193
+        iguana.addItem(maleIguana);
194
+
195
+        Item maleManx = new Item("Male Adult", 120.00f, "cat1.jpg", manx, "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed convallis scelerisque urna. Sed id nunc quis nisl scelerisque scelerisque sit amet id lorem. Sed rutrum arcu sed sem semper id eleifend nulla feugiat. Praesent faucibus dignissim lectus tincidunt lacinia. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per.");
196
+        Item femaleManx = new Item("Female Adult", 120.00f, "cat1.jpg", manx, "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus viverra nunc vitae libero ultricies lobortis. Duis magna nunc, tincidunt sit amet sagittis et, lobortis volutpat risus. Sed gravida turpis sit amet arcu tincidunt convallis. Nunc vulputate commodo mi non blandit. Etiam eu libero id libero aliquet pretium. Lorem ipsum dolor.");
197
+        manx.addItem(maleManx);
198
+        manx.addItem(femaleManx);
199
+        Item malePersian = new Item("Male Adult", 70.00f, "cat2.jpg", persian, "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut sed est in tortor pharetra fermentum. Pellentesque nulla augue, venenatis ut viverra vel, dignissim sit amet ante. Aliquam erat volutpat. Aenean lectus odio, blandit aliquam sollicitudin a, pulvinar a felis. Phasellus vitae libero et lacus volutpat tristique. Aliquam tortor lacus, pulvinar.");
200
+        Item femalePersian = new Item("Female Adult", 90.00f, "cat2.jpg", persian, "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam fringilla iaculis nunc et hendrerit. Curabitur malesuada felis non velit ultrices lacinia. Vivamus hendrerit tortor et tortor faucibus vehicula. Pellentesque pellentesque, quam at viverra tristique, lacus nibh euismod erat, vel vestibulum purus turpis eget nisi. Donec suscipit ligula tortor, a suscipit.");
201
+        persian.addItem(malePersian);
202
+        persian.addItem(femalePersian);
203
+
204
+        Item maleAmazonParrot = new Item("Male Adult", 120.00f, "bird2.jpg", amazonParrot, "Lorem ipsum dolor sit amet, consectetur adipiscing elit. In justo ligula, volutpat ut adipiscing sed, lobortis vel lacus. Etiam commodo aliquet libero, sit amet pretium risus scelerisque luctus. Suspendisse sit amet nulla nibh, in mollis risus. Curabitur convallis mattis felis, non malesuada justo pretium sed. Nam vestibulum, urna in consequat.");
205
+        Item femaleAmazonParrot = new Item("Female Adult", 120.00f, "bird2.jpg", amazonParrot, "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse vitae turpis ut erat hendrerit sollicitudin. Curabitur auctor neque a enim scelerisque mattis. Mauris in mi nibh, et placerat lorem. Nunc semper, quam vitae semper condimentum, odio arcu sagittis ligula, eu posuere arcu nibh a quam. Aliquam porta dictum eros auctor.");
206
+        amazonParrot.addItem(maleAmazonParrot);
207
+        amazonParrot.addItem(femaleAmazonParrot);
208
+        Item maleFinch = new Item("Male Adult", 75.00f, "bird1.jpg", finch, "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum quis lectus sit amet augue mattis malesuada. Maecenas justo justo, auctor sed consectetur et, pulvinar et diam. Nam felis mi, auctor ornare accumsan sed, pharetra nec arcu. Aliquam tincidunt nisi feugiat dui commodo dapibus. Nullam eget augue odio. Duis mauris nibh.");
209
+        Item femaleFinch = new Item("Female Adult", 80.00f, "bird1.jpg", finch, "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus dignissim vehicula tellus. Vestibulum id diam eros. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Nam sit amet sem at ligula pretium fermentum. Suspendisse potenti. Phasellus rhoncus consequat augue, ac feugiat felis gravida nec. Aliquam at.");
210
+        finch.addItem(maleFinch);
211
+        finch.addItem(femaleFinch);
212
+
213
+        catalogService.createCategory(fish);
214
+        catalogService.createCategory(dog);
215
+        catalogService.createCategory(reptile);
216
+        catalogService.createCategory(cat);
217
+        catalogService.createCategory(bird);
218
+    }
219
+
220
+    private void initCustomers() {
221
+        marc = new Customer("Marc", "Fleury", "marc", "marc", "marc@jboss.org", new Address("65 Ritherdon Road", "Los Angeles", "56421", "USA"));
222
+        bill = new Customer("Bill", "Gates", "bill", "bill", "bill.gates@microsoft.com", new Address("27 West Side", "Alhabama", "8401", "USA"));
223
+        steve = new Customer("Steve", "Jobs", "jobs", "jobs", "steve.jobs@apple.com", new Address("154 Star Boulevard", "San Francisco", "5455", "USA"));
224
+        user = new Customer("User", "User", "user", "user", "user@petstore.org", new Address("Petstore", "Land", "666", "Nowhere"));
225
+        admin = new Customer("Admin", "Admin", "admin", "admin", "admin@petstore.org", new Address("Petstore", "Land", "666", "Nowhere"));
226
+
227
+        customerService.createCustomer(marc);
228
+        customerService.createCustomer(bill);
229
+        customerService.createCustomer(steve);
230
+        customerService.createCustomer(user);
231
+        customerService.createCustomer(admin);
232
+    }
233
+
234
+}
Back to file index

files/ExceptionInterceptor.java

 1
--- 
 2
+++ files/ExceptionInterceptor.java
 3
@@ -0,0 +1,42 @@
 4
+package org.agoncal.application.petstore.web;
 5
+
 6
+import javax.faces.application.FacesMessage;
 7
+import javax.faces.context.FacesContext;
 8
+import javax.inject.Inject;
 9
+import javax.interceptor.AroundInvoke;
10
+import javax.interceptor.Interceptor;
11
+import javax.interceptor.InvocationContext;
12
+import java.io.Serializable;
13
+import java.util.logging.Logger;
14
+
15
+/**
16
+ * @author Antonio Goncalves
17
+ *         http://www.antoniogoncalves.org
18
+ *         --
19
+ *         This interceptor catches exception and displayes them in a JSF page
20
+ */
21
+@Interceptor
22
+@CatchException
23
+public class ExceptionInterceptor implements Serializable {
24
+
25
+    @Inject
26
+    private transient Logger log;
27
+
28
+    @AroundInvoke
29
+    public Object catchException(InvocationContext ic) throws Exception {
30
+        try {
31
+            return ic.proceed();
32
+        } catch (Exception e) {
33
+            addErrorMessage(e.getMessage());
34
+            log.severe("/!\\ " + ic.getTarget().getClass().getName() + " - " + ic.getMethod().getName() + " - " + e.getMessage());
35
+            e.printStackTrace();
36
+        }
37
+        return null;
38
+    }
39
+
40
+    // TODO to refactor with Controller methods
41
+    protected void addErrorMessage(String message) {
42
+        FacesContext context = FacesContext.getCurrentInstance();
43
+        context.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, message, null));
44
+    }
45
+}
Back to file index

files/persistence.xml

 1
--- 
 2
+++ files/persistence.xml
 3
@@ -0,0 +1,29 @@
 4
+<?xml version="1.0" encoding="UTF-8"?>
 5
+<persistence xmlns="http://java.sun.com/xml/ns/persistence"
 6
+             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 7
+             xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
 8
+             version="2.0">
 9
+
10
+    <persistence-unit name="applicationPetstorePU" transaction-type="JTA">
11
+        <jta-data-source>java:global/jdbc/applicationPetstoreDS</jta-data-source>
12
+        <non-jta-data-source>java:global/jdbc/applicationPetstoreNJTADS</non-jta-data-source>
13
+        <properties>
14
+            <!-- Properties for EclipseLink -->
15
+            <property name="eclipselink.target-database" value="DERBY"/>
16
+            <property name="eclipselink.ddl-generation" value="drop-and-create-tables"/>
17
+            <property name="eclipselink.logging.level" value="INFO"/>
18
+
19
+            <!-- Properties for Hibernate -->
20
+            <property name="hibernate.hbm2ddl.auto" value="create-drop"/>
21
+            <property name="hibernate.show_sql" value="true"/>
22
+            <property name="hibernate.format_sql" value="true"/>
23
+            <property name="hibernate.dialect" value="org.hibernate.dialect.DerbyTenSevenDialect"/>
24
+
25
+            <!-- openjpa -->
26
+            <property name="openjpa.jdbc.SynchronizeMappings" value="buildSchema(ForeignKeys=true)"/>
27
+            <property name="openjpa.Log" value="SQL=TRACE"/>
28
+            <property name="openjpa.ConnectionFactoryProperties" value="printParameters=true"/>
29
+
30
+        </properties>
31
+    </persistence-unit>
32
+</persistence>
Back to file index

files/server.xml

 1
--- 
 2
+++ files/server.xml
 3
@@ -0,0 +1,29 @@
 4
+<server description="new server">
 5
+
 6
+    <!-- Enable features -->
 7
+    <featureManager>
 8
+        <feature>jsp-2.2</feature>
 9
+        <feature>webProfile-6.0</feature>
10
+        <feature>jaxrs-1.1</feature>
11
+        <feature>jdbc-4.0</feature>
12
+    </featureManager>
13
+
14
+    <logging traceSpecification="JPA=all:openjpa=all"/>
15
+
16
+    <httpEndpoint id="defaultHttpEndpoint"
17
+                  host="*"
18
+                  httpPort="9080"
19
+                  httpsPort="9443">
20
+      <!-- Allow reuse of local addresses with SO_REUSEADDR -->
21
+      <tcpOptions soReuseAddr="true" />
22
+    </httpEndpoint>
23
+
24
+    <application name="petstore" location="petstore.war">
25
+      <classloader commonLibraryRef="DerbyLib"/>
26
+    </application>
27
+
28
+    <library id="DerbyLib">
29
+      <fileset dir="${shared.resource.dir}/derby" includes="derby.jar"/>
30
+    </library>
31
+</server>
32
+
Back to file index

hooks/config-changed

 1
--- 
 2
+++ hooks/config-changed
 3
@@ -0,0 +1,19 @@
 4
+#!/usr/bin/env python3
 5
+
 6
+# Load modules from $CHARM_DIR/lib
 7
+import sys
 8
+sys.path.append('lib')
 9
+
10
+from charms.layer import basic
11
+basic.bootstrap_charm_deps()
12
+basic.init_config_states()
13
+
14
+
15
+# This will load and run the appropriate @hook and other decorated
16
+# handlers from $CHARM_DIR/reactive, $CHARM_DIR/hooks/reactive,
17
+# and $CHARM_DIR/hooks/relations.
18
+#
19
+# See https://jujucharms.com/docs/stable/authors-charm-building
20
+# for more information on this pattern.
21
+from charms.reactive import main
22
+main()
Back to file index

hooks/hook.template

 1
--- 
 2
+++ hooks/hook.template
 3
@@ -0,0 +1,19 @@
 4
+#!/usr/bin/env python3
 5
+
 6
+# Load modules from $CHARM_DIR/lib
 7
+import sys
 8
+sys.path.append('lib')
 9
+
10
+from charms.layer import basic
11
+basic.bootstrap_charm_deps()
12
+basic.init_config_states()
13
+
14
+
15
+# This will load and run the appropriate @hook and other decorated
16
+# handlers from $CHARM_DIR/reactive, $CHARM_DIR/hooks/reactive,
17
+# and $CHARM_DIR/hooks/relations.
18
+#
19
+# See https://jujucharms.com/docs/stable/authors-charm-building
20
+# for more information on this pattern.
21
+from charms.reactive import main
22
+main()
Back to file index

hooks/install

 1
--- 
 2
+++ hooks/install
 3
@@ -0,0 +1,19 @@
 4
+#!/usr/bin/env python3
 5
+
 6
+# Load modules from $CHARM_DIR/lib
 7
+import sys
 8
+sys.path.append('lib')
 9
+
10
+from charms.layer import basic
11
+basic.bootstrap_charm_deps()
12
+basic.init_config_states()
13
+
14
+
15
+# This will load and run the appropriate @hook and other decorated
16
+# handlers from $CHARM_DIR/reactive, $CHARM_DIR/hooks/reactive,
17
+# and $CHARM_DIR/hooks/relations.
18
+#
19
+# See https://jujucharms.com/docs/stable/authors-charm-building
20
+# for more information on this pattern.
21
+from charms.reactive import main
22
+main()
Back to file index

hooks/leader-elected

 1
--- 
 2
+++ hooks/leader-elected
 3
@@ -0,0 +1,19 @@
 4
+#!/usr/bin/env python3
 5
+
 6
+# Load modules from $CHARM_DIR/lib
 7
+import sys
 8
+sys.path.append('lib')
 9
+
10
+from charms.layer import basic
11
+basic.bootstrap_charm_deps()
12
+basic.init_config_states()
13
+
14
+
15
+# This will load and run the appropriate @hook and other decorated
16
+# handlers from $CHARM_DIR/reactive, $CHARM_DIR/hooks/reactive,
17
+# and $CHARM_DIR/hooks/relations.
18
+#
19
+# See https://jujucharms.com/docs/stable/authors-charm-building
20
+# for more information on this pattern.
21
+from charms.reactive import main
22
+main()
Back to file index

hooks/leader-settings-changed

 1
--- 
 2
+++ hooks/leader-settings-changed
 3
@@ -0,0 +1,19 @@
 4
+#!/usr/bin/env python3
 5
+
 6
+# Load modules from $CHARM_DIR/lib
 7
+import sys
 8
+sys.path.append('lib')
 9
+
10
+from charms.layer import basic
11
+basic.bootstrap_charm_deps()
12
+basic.init_config_states()
13
+
14
+
15
+# This will load and run the appropriate @hook and other decorated
16
+# handlers from $CHARM_DIR/reactive, $CHARM_DIR/hooks/reactive,
17
+# and $CHARM_DIR/hooks/relations.
18
+#
19
+# See https://jujucharms.com/docs/stable/authors-charm-building
20
+# for more information on this pattern.
21
+from charms.reactive import main
22
+main()
Back to file index

hooks/relations/https/README.md

 1
--- 
 2
+++ hooks/relations/https/README.md
 3
@@ -0,0 +1,72 @@
 4
+verview
 5
+
 6
+This interface layer implements the basic form of the `https` interface protocol,
 7
+which is used for things such as reverse-proxies, load-balanced servers, REST
 8
+service discovery, et cetera.
 9
+
10
+# Usage
11
+
12
+## Provides
13
+
14
+By providing the `https` interface, your charm is providing an HTTP server that
15
+can be load-balanced, reverse-proxied, used as a REST endpoint, etc.
16
+
17
+Your charm need only provide the port on which it is serving its content, as
18
+soon as the `{relation_name}.available` state is set:
19
+
20
+```python
21
+@when('website.available')
22
+def configure_website(website):
23
+    website.configure(port=hookenv.config('port'), httpsport=hookenv.config('httpsport'))
24
+```
25
+
26
+## Requires
27
+
28
+By requiring the `https` interface, your charm is consuming one or more HTTP
29
+servers, as a REST endpoint, to load-balance a set of servers, etc.
30
+
31
+Your charm should respond to the `{relation_name}.available` state, which
32
+indicates that there is at least one HTTP server connected.
33
+
34
+The `services()` method returns a list of available HTTP services and their
35
+associated hosts and ports.
36
+
37
+The return value is a list of dicts of the following form:
38
+
39
+```python
40
+[
41
+    {
42
+        'service_name': name_of_service,
43
+        'hosts': [
44
+            {
45
+                'hostname': address_of_host,
46
+                'port': port_for_host,
47
+                'httpsport': httpsport_for_host,
48
+            },
49
+            # ...
50
+        ],
51
+    },
52
+    # ...
53
+]
54
+```
55
+
56
+A trivial example of handling this interface would be:
57
+
58
+```python
59
+from charms.reactive.helpers import data_changed
60
+
61
+@when('reverseproxy.available')
62
+def update_reverse_proxy_config(reverseproxy):
63
+    services = reverseproxy.services()
64
+    if not data_changed('reverseproxy.services', services):
65
+        return
66
+    for service in services:
67
+        for host in service['hosts']:
68
+            hookenv.log('{} has a unit {}:{}'.format(
69
+                services['service_name'],
70
+                host['hostname'],
71
+                host['port'],
72
+                host['httpsport']))
73
+```
74
+
75
+
Back to file index

hooks/relations/https/interface.yaml

1
--- 
2
+++ hooks/relations/https/interface.yaml
3
@@ -0,0 +1,5 @@
4
+name: https
5
+summary: Basic HTTPS interface
6
+version: 1
7
+maintainer: "IBM Juju Support Team <jujusupp@us.ibm.com>"
8
+
Back to file index

hooks/relations/https/provides.py

 1
--- 
 2
+++ hooks/relations/https/provides.py
 3
@@ -0,0 +1,24 @@
 4
+from charmhelpers.core import hookenv
 5
+from charms.reactive import hook
 6
+from charms.reactive import RelationBase
 7
+from charms.reactive import scopes
 8
+
 9
+
10
+class HttpProvides(RelationBase):
11
+    scope = scopes.GLOBAL
12
+
13
+    @hook('{provides:https}-relation-{joined,changed}')
14
+    def changed(self):
15
+        self.set_state('{relation_name}.available')
16
+
17
+    @hook('{provides:https}-relation-{broken,departed}')
18
+    def broken(self):
19
+        self.remove_state('{relation_name}.available')
20
+
21
+    def configure(self, port, httpsport):
22
+        relation_info = {
23
+            'hostname': hookenv.unit_get('private-address'),
24
+            'port': port,
25
+            'httpsport': httpsport,
26
+        }
27
+        self.set_remote(**relation_info)
Back to file index

hooks/relations/https/requires.py

 1
--- 
 2
+++ hooks/relations/https/requires.py
 3
@@ -0,0 +1,45 @@
 4
+
 5
+from charms.reactive import hook
 6
+from charms.reactive import RelationBase
 7
+from charms.reactive import scopes
 8
+
 9
+
10
+class HttpRequires(RelationBase):
11
+    scope = scopes.UNIT
12
+
13
+    @hook('{requires:https}-relation-{joined,changed}')
14
+    def changed(self):
15
+        conv = self.conversation()
16
+        if conv.get_remote('port'):
17
+            # this unit's conversation has a port, so
18
+            # it is part of the set of available units
19
+            conv.set_state('{relation_name}.available')
20
+        if conv.get_remote('httpsport'):
21
+            # this unit's conversation has a port, so
22
+            # it is part of the set of available units
23
+            conv.set_state('{relation_name}.available')
24
+
25
+    @hook('{requires:https}-relation-{departed,broken}')
26
+    def broken(self):
27
+        conv = self.conversation()
28
+        conv.remove_state('{relation_name}.available')
29
+
30
+    def services(self):
31
+        services = {}
32
+        for conv in self.conversations():
33
+            service_name = conv.scope.split('/')[0]
34
+            service = services.setdefault(service_name, {
35
+                'service_name': service_name,
36
+                'hosts': [],
37
+            })
38
+            host = conv.get_remote('hostname') or \
39
+                conv.get_remote('private-address')
40
+            port = conv.get_remote('port')
41
+            httpsport = conv.get_remote('httpsport')
42
+            if host and port:
43
+                service['hosts'].append({
44
+                    'hostname': host,
45
+                    'port': port,
46
+                    'httpsport': httpsport,
47
+                })
48
+        return [s for s in services.values() if s['hosts']]
Back to file index

hooks/start

 1
--- 
 2
+++ hooks/start
 3
@@ -0,0 +1,19 @@
 4
+#!/usr/bin/env python3
 5
+
 6
+# Load modules from $CHARM_DIR/lib
 7
+import sys
 8
+sys.path.append('lib')
 9
+
10
+from charms.layer import basic
11
+basic.bootstrap_charm_deps()
12
+basic.init_config_states()
13
+
14
+
15
+# This will load and run the appropriate @hook and other decorated
16
+# handlers from $CHARM_DIR/reactive, $CHARM_DIR/hooks/reactive,
17
+# and $CHARM_DIR/hooks/relations.
18
+#
19
+# See https://jujucharms.com/docs/stable/authors-charm-building
20
+# for more information on this pattern.
21
+from charms.reactive import main
22
+main()
Back to file index

hooks/stop

 1
--- 
 2
+++ hooks/stop
 3
@@ -0,0 +1,19 @@
 4
+#!/usr/bin/env python3
 5
+
 6
+# Load modules from $CHARM_DIR/lib
 7
+import sys
 8
+sys.path.append('lib')
 9
+
10
+from charms.layer import basic
11
+basic.bootstrap_charm_deps()
12
+basic.init_config_states()
13
+
14
+
15
+# This will load and run the appropriate @hook and other decorated
16
+# handlers from $CHARM_DIR/reactive, $CHARM_DIR/hooks/reactive,
17
+# and $CHARM_DIR/hooks/relations.
18
+#
19
+# See https://jujucharms.com/docs/stable/authors-charm-building
20
+# for more information on this pattern.
21
+from charms.reactive import main
22
+main()
Back to file index

hooks/update-status

 1
--- 
 2
+++ hooks/update-status
 3
@@ -0,0 +1,19 @@
 4
+#!/usr/bin/env python3
 5
+
 6
+# Load modules from $CHARM_DIR/lib
 7
+import sys
 8
+sys.path.append('lib')
 9
+
10
+from charms.layer import basic
11
+basic.bootstrap_charm_deps()
12
+basic.init_config_states()
13
+
14
+
15
+# This will load and run the appropriate @hook and other decorated
16
+# handlers from $CHARM_DIR/reactive, $CHARM_DIR/hooks/reactive,
17
+# and $CHARM_DIR/hooks/relations.
18
+#
19
+# See https://jujucharms.com/docs/stable/authors-charm-building
20
+# for more information on this pattern.
21
+from charms.reactive import main
22
+main()
Back to file index

hooks/upgrade-charm

 1
--- 
 2
+++ hooks/upgrade-charm
 3
@@ -0,0 +1,28 @@
 4
+#!/usr/bin/env python3
 5
+
 6
+# Load modules from $CHARM_DIR/lib
 7
+import os
 8
+import sys
 9
+sys.path.append('lib')
10
+
11
+# This is an upgrade-charm context, make sure we install latest deps
12
+if not os.path.exists('wheelhouse/.upgrade'):
13
+    open('wheelhouse/.upgrade', 'w').close()
14
+    if os.path.exists('wheelhouse/.bootstrapped'):
15
+        os.unlink('wheelhouse/.bootstrapped')
16
+else:
17
+    os.unlink('wheelhouse/.upgrade')
18
+
19
+from charms.layer import basic
20
+basic.bootstrap_charm_deps()
21
+basic.init_config_states()
22
+
23
+
24
+# This will load and run the appropriate @hook and other decorated
25
+# handlers from $CHARM_DIR/reactive, $CHARM_DIR/hooks/reactive,
26
+# and $CHARM_DIR/hooks/relations.
27
+#
28
+# See https://jujucharms.com/docs/stable/authors-charm-building
29
+# for more information on this pattern.
30
+from charms.reactive import main
31
+main()
Back to file index

hooks/website-relation-broken

 1
--- 
 2
+++ hooks/website-relation-broken
 3
@@ -0,0 +1,19 @@
 4
+#!/usr/bin/env python3
 5
+
 6
+# Load modules from $CHARM_DIR/lib
 7
+import sys
 8
+sys.path.append('lib')
 9
+
10
+from charms.layer import basic
11
+basic.bootstrap_charm_deps()
12
+basic.init_config_states()
13
+
14
+
15
+# This will load and run the appropriate @hook and other decorated
16
+# handlers from $CHARM_DIR/reactive, $CHARM_DIR/hooks/reactive,
17
+# and $CHARM_DIR/hooks/relations.
18
+#
19
+# See https://jujucharms.com/docs/stable/authors-charm-building
20
+# for more information on this pattern.
21
+from charms.reactive import main
22
+main()
Back to file index

hooks/website-relation-changed

 1
--- 
 2
+++ hooks/website-relation-changed
 3
@@ -0,0 +1,19 @@
 4
+#!/usr/bin/env python3
 5
+
 6
+# Load modules from $CHARM_DIR/lib
 7
+import sys
 8
+sys.path.append('lib')
 9
+
10
+from charms.layer import basic
11
+basic.bootstrap_charm_deps()
12
+basic.init_config_states()
13
+
14
+
15
+# This will load and run the appropriate @hook and other decorated
16
+# handlers from $CHARM_DIR/reactive, $CHARM_DIR/hooks/reactive,
17
+# and $CHARM_DIR/hooks/relations.
18
+#
19
+# See https://jujucharms.com/docs/stable/authors-charm-building
20
+# for more information on this pattern.
21
+from charms.reactive import main
22
+main()
Back to file index

hooks/website-relation-departed

 1
--- 
 2
+++ hooks/website-relation-departed
 3
@@ -0,0 +1,19 @@
 4
+#!/usr/bin/env python3
 5
+
 6
+# Load modules from $CHARM_DIR/lib
 7
+import sys
 8
+sys.path.append('lib')
 9
+
10
+from charms.layer import basic
11
+basic.bootstrap_charm_deps()
12
+basic.init_config_states()
13
+
14
+
15
+# This will load and run the appropriate @hook and other decorated
16
+# handlers from $CHARM_DIR/reactive, $CHARM_DIR/hooks/reactive,
17
+# and $CHARM_DIR/hooks/relations.
18
+#
19
+# See https://jujucharms.com/docs/stable/authors-charm-building
20
+# for more information on this pattern.
21
+from charms.reactive import main
22
+main()
Back to file index

hooks/website-relation-joined

 1
--- 
 2
+++ hooks/website-relation-joined
 3
@@ -0,0 +1,19 @@
 4
+#!/usr/bin/env python3
 5
+
 6
+# Load modules from $CHARM_DIR/lib
 7
+import sys
 8
+sys.path.append('lib')
 9
+
10
+from charms.layer import basic
11
+basic.bootstrap_charm_deps()
12
+basic.init_config_states()
13
+
14
+
15
+# This will load and run the appropriate @hook and other decorated
16
+# handlers from $CHARM_DIR/reactive, $CHARM_DIR/hooks/reactive,
17
+# and $CHARM_DIR/hooks/relations.
18
+#
19
+# See https://jujucharms.com/docs/stable/authors-charm-building
20
+# for more information on this pattern.
21
+from charms.reactive import main
22
+main()
Back to file index

icon.svg

  1
--- 
  2
+++ icon.svg
  3
@@ -0,0 +1,685 @@
  4
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
  5
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
  6
+
  7
+<svg
  8
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
  9
+   xmlns:cc="http://creativecommons.org/ns#"
 10
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
 11
+   xmlns:svg="http://www.w3.org/2000/svg"
 12
+   xmlns="http://www.w3.org/2000/svg"
 13
+   xmlns:xlink="http://www.w3.org/1999/xlink"
 14
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
 15
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
 16
+   width="96"
 17
+   height="96"
 18
+   id="svg6517"
 19
+   version="1.1"
 20
+   inkscape:version="0.48.4 r9939"
 21
+   sodipodi:docname="websphere-liberty-icon.svg">
 22
+  <defs
 23
+     id="defs6519">
 24
+    <linearGradient
 25
+       inkscape:collect="always"
 26
+       id="linearGradient3886">
 27
+      <stop
 28
+         style="stop-color:#000000;stop-opacity:1;"
 29
+         offset="0"
 30
+         id="stop3888" />
 31
+      <stop
 32
+         style="stop-color:#000000;stop-opacity:0;"
 33
+         offset="1"
 34
+         id="stop3890" />
 35
+    </linearGradient>
 36
+    <linearGradient
 37
+       inkscape:collect="always"
 38
+       xlink:href="#Background"
 39
+       id="linearGradient6461"
 40
+       gradientUnits="userSpaceOnUse"
 41
+       x1="0"
 42
+       y1="970.29498"
 43
+       x2="144"
 44
+       y2="970.29498"
 45
+       gradientTransform="matrix(0,-0.66666669,0.6660448,0,-866.25992,731.29077)" />
 46
+    <linearGradient
 47
+       id="Background">
 48
+      <stop
 49
+         id="stop4178"
 50
+         offset="0"
 51
+         style="stop-color:#466bb0;stop-opacity:1;" />
 52
+      <stop
 53
+         id="stop4180"
 54
+         offset="1"
 55
+         style="stop-color:#c9c9c9;stop-opacity:1" />
 56
+    </linearGradient>
 57
+    <filter
 58
+       style="color-interpolation-filters:sRGB;"
 59
+       inkscape:label="Inner Shadow"
 60
+       id="filter1121">
 61
+      <feFlood
 62
+         flood-opacity="0.59999999999999998"
 63
+         flood-color="rgb(0,0,0)"
 64
+         result="flood"
 65
+         id="feFlood1123" />
 66
+      <feComposite
 67
+         in="flood"
 68
+         in2="SourceGraphic"
 69
+         operator="out"
 70
+         result="composite1"
 71
+         id="feComposite1125" />
 72
+      <feGaussianBlur
 73
+         in="composite1"
 74
+         stdDeviation="1"
 75
+         result="blur"
 76
+         id="feGaussianBlur1127" />
 77
+      <feOffset
 78
+         dx="0"
 79
+         dy="2"
 80
+         result="offset"
 81
+         id="feOffset1129" />
 82
+      <feComposite
 83
+         in="offset"
 84
+         in2="SourceGraphic"
 85
+         operator="atop"
 86
+         result="composite2"
 87
+         id="feComposite1131" />
 88
+    </filter>
 89
+    <filter
 90
+       style="color-interpolation-filters:sRGB;"
 91
+       inkscape:label="Drop Shadow"
 92
+       id="filter950">
 93
+      <feFlood
 94
+         flood-opacity="0.25"
 95
+         flood-color="rgb(0,0,0)"
 96
+         result="flood"
 97
+         id="feFlood952" />
 98
+      <feComposite
 99
+         in="flood"
100
+         in2="SourceGraphic"
101
+         operator="in"
102
+         result="composite1"
103
+         id="feComposite954" />
104
+      <feGaussianBlur
105
+         in="composite1"
106
+         stdDeviation="1"
107
+         result="blur"
108
+         id="feGaussianBlur956" />
109
+      <feOffset
110
+         dx="0"
111
+         dy="1"
112
+         result="offset"
113
+         id="feOffset958" />
114
+      <feComposite
115
+         in="SourceGraphic"
116
+         in2="offset"
117
+         operator="over"
118
+         result="composite2"
119
+         id="feComposite960" />
120
+    </filter>
121
+    <clipPath
122
+       clipPathUnits="userSpaceOnUse"
123
+       id="clipPath873">
124
+      <g
125
+         transform="matrix(0,-0.66666667,0.66604479,0,-258.25992,677.00001)"
126
+         id="g875"
127
+         inkscape:label="Layer 1"
128
+         style="fill:#ff00ff;fill-opacity:1;stroke:none;display:inline">
129
+        <path
130
+           style="fill:#ff00ff;fill-opacity:1;stroke:none;display:inline"
131
+           d="m 46.702703,898.22775 50.594594,0 C 138.16216,898.22775 144,904.06497 144,944.92583 l 0,50.73846 c 0,40.86071 -5.83784,46.69791 -46.702703,46.69791 l -50.594594,0 C 5.8378378,1042.3622 0,1036.525 0,995.66429 L 0,944.92583 C 0,904.06497 5.8378378,898.22775 46.702703,898.22775 Z"
132
+           id="path877"
133
+           inkscape:connector-curvature="0"
134
+           sodipodi:nodetypes="sssssssss" />
135
+      </g>
136
+    </clipPath>
137
+    <filter
138
+       inkscape:collect="always"
139
+       id="filter891"
140
+       inkscape:label="Badge Shadow">
141
+      <feGaussianBlur
142
+         inkscape:collect="always"
143
+         stdDeviation="0.71999962"
144
+         id="feGaussianBlur893" />
145
+    </filter>
146
+    <linearGradient
147
+       inkscape:collect="always"
148
+       xlink:href="#linearGradient3886"
149
+       id="linearGradient3892"
150
+       x1="-410.30341"
151
+       y1="624.94247"
152
+       x2="-343.00002"
153
+       y2="624.94247"
154
+       gradientUnits="userSpaceOnUse" />
155
+    <linearGradient
156
+       inkscape:collect="always"
157
+       xlink:href="#Background"
158
+       id="linearGradient3900"
159
+       x1="-410.30341"
160
+       y1="624.94244"
161
+       x2="-343.00003"
162
+       y2="624.94244"
163
+       gradientUnits="userSpaceOnUse" />
164
+  </defs>
165
+  <sodipodi:namedview
166
+     id="base"
167
+     pagecolor="#ffffff"
168
+     bordercolor="#666666"
169
+     borderopacity="1.0"
170
+     inkscape:pageopacity="0.0"
171
+     inkscape:pageshadow="2"
172
+     inkscape:zoom="4.0745362"
173
+     inkscape:cx="-16.612701"
174
+     inkscape:cy="49.018169"
175
+     inkscape:document-units="px"
176
+     inkscape:current-layer="layer1"
177
+     showgrid="true"
178
+     fit-margin-top="0"
179
+     fit-margin-left="0"
180
+     fit-margin-right="0"
181
+     fit-margin-bottom="0"
182
+     inkscape:window-width="1565"
183
+     inkscape:window-height="1223"
184
+     inkscape:window-x="1167"
185
+     inkscape:window-y="244"
186
+     inkscape:window-maximized="0"
187
+     showborder="true"
188
+     showguides="true"
189
+     inkscape:guide-bbox="true"
190
+     inkscape:showpageshadow="false">
191
+    <inkscape:grid
192
+       type="xygrid"
193
+       id="grid821" />
194
+    <sodipodi:guide
195
+       orientation="1,0"
196
+       position="16,48"
197
+       id="guide823" />
198
+    <sodipodi:guide
199
+       orientation="0,1"
200
+       position="64,80"
201
+       id="guide825" />
202
+    <sodipodi:guide
203
+       orientation="1,0"
204
+       position="80,40"
205
+       id="guide827" />
206
+    <sodipodi:guide
207
+       orientation="0,1"
208
+       position="64,16"
209
+       id="guide829" />
210
+  </sodipodi:namedview>
211
+  <metadata
212
+     id="metadata6522">
213
+    <rdf:RDF>
214
+      <cc:Work
215
+         rdf:about="">
216
+        <dc:format>image/svg+xml</dc:format>
217
+        <dc:type
218
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
219
+        <dc:title></dc:title>
220
+      </cc:Work>
221
+    </rdf:RDF>
222
+  </metadata>
223
+  <g
224
+     inkscape:label="BACKGROUND"
225
+     inkscape:groupmode="layer"
226
+     id="layer1"
227
+     transform="translate(268,-635.29076)"
228
+     style="display:inline">
229
+    <path
230
+       style="fill:url(#linearGradient6461);fill-opacity:1;stroke:none;display:inline;filter:url(#filter1121)"
231
+       d="m -268,700.15563 0,-33.72973 c 0,-27.24324 3.88785,-31.13513 31.10302,-31.13513 l 33.79408,0 c 27.21507,0 31.1029,3.89189 31.1029,31.13513 l 0,33.72973 c 0,27.24325 -3.88783,31.13514 -31.1029,31.13514 l -33.79408,0 C -264.11215,731.29077 -268,727.39888 -268,700.15563 Z"
232
+       id="path6455"
233
+       inkscape:connector-curvature="0"
234
+       sodipodi:nodetypes="sssssssss" />
235
+    <image
236
+       y="651.29077"
237
+       x="-253"
238
+       id="image3115"
239
+       xlink:href="data:image/png;base64,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
606
+TkSuQmCC
607
+"
608
+       height="67.303391"
609
+       width="67.303391"
610
+       style="fill:url(#linearGradient3900);fill-opacity:1;stroke:url(#linearGradient3892)" />
611
+  </g>
612
+  <g
613
+     inkscape:groupmode="layer"
614
+     id="layer3"
615
+     inkscape:label="PLACE YOUR PICTOGRAM HERE"
616
+     style="display:inline" />
617
+  <g
618
+     inkscape:groupmode="layer"
619
+     id="layer2"
620
+     inkscape:label="BADGE"
621
+     style="display:none"
622
+     sodipodi:insensitive="true">
623
+    <g
624
+       style="display:inline"
625
+       transform="translate(-340.00001,-581)"
626
+       id="g4394"
627
+       clip-path="none">
628
+      <g
629
+         id="g855">
630
+        <g
631
+           inkscape:groupmode="maskhelper"
632
+           id="g870"
633
+           clip-path="url(#clipPath873)"
634
+           style="opacity:0.6;filter:url(#filter891)">
635
+          <path
636
+             transform="matrix(1.4999992,0,0,1.4999992,-29.999795,-237.54282)"
637
+             d="m 264,552.36218 c 0,6.62742 -5.37258,12 -12,12 -6.62742,0 -12,-5.37258 -12,-12 0,-6.62741 5.37258,-12 12,-12 6.62742,0 12,5.37259 12,12 z"
638
+             sodipodi:ry="12"
639
+             sodipodi:rx="12"
640
+             sodipodi:cy="552.36218"
641
+             sodipodi:cx="252"
642
+             id="path844"
643
+             style="color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:4;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
644
+             sodipodi:type="arc" />
645
+        </g>
646
+        <g
647
+           id="g862">
648
+          <path
649
+             sodipodi:type="arc"
650
+             style="color:#000000;fill:#f5f5f5;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:4;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
651
+             id="path4398"
652
+             sodipodi:cx="252"
653
+             sodipodi:cy="552.36218"
654
+             sodipodi:rx="12"
655
+             sodipodi:ry="12"
656
+             d="m 264,552.36218 c 0,6.62742 -5.37258,12 -12,12 -6.62742,0 -12,-5.37258 -12,-12 0,-6.62741 5.37258,-12 12,-12 6.62742,0 12,5.37259 12,12 z"
657
+             transform="matrix(1.4999992,0,0,1.4999992,-29.999795,-238.54282)" />
658
+          <path
659
+             transform="matrix(1.25,0,0,1.25,33,-100.45273)"
660
+             d="m 264,552.36218 c 0,6.62742 -5.37258,12 -12,12 -6.62742,0 -12,-5.37258 -12,-12 0,-6.62741 5.37258,-12 12,-12 6.62742,0 12,5.37259 12,12 z"
661
+             sodipodi:ry="12"
662
+             sodipodi:rx="12"
663
+             sodipodi:cy="552.36218"
664
+             sodipodi:cx="252"
665
+             id="path4400"
666
+             style="color:#000000;fill:#dd4814;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:4;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
667
+             sodipodi:type="arc" />
668
+          <path
669
+             sodipodi:type="star"
670
+             style="color:#000000;fill:#f5f5f5;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
671
+             id="path4459"
672
+             sodipodi:sides="5"
673
+             sodipodi:cx="666.19574"
674
+             sodipodi:cy="589.50385"
675
+             sodipodi:r1="7.2431178"
676
+             sodipodi:r2="4.3458705"
677
+             sodipodi:arg1="1.0471976"
678
+             sodipodi:arg2="1.6755161"
679
+             inkscape:flatsided="false"
680
+             inkscape:rounded="0.1"
681
+             inkscape:randomized="0"
682
+             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"
683
+             transform="matrix(1.511423,-0.16366377,0.16366377,1.511423,-755.37346,-191.93651)" />
684
+        </g>
685
+      </g>
686
+    </g>
687
+  </g>
688
+</svg>
Back to file index

layer.yaml

 1
--- 
 2
+++ layer.yaml
 3
@@ -0,0 +1,16 @@
 4
+"options":
 5
+  "basic":
 6
+    "packages":
 7
+    - "unzip"
 8
+    - "git-core"
 9
+    - "default-jdk"
10
+    - "maven"
11
+    - "libderby-java"
12
+    "use_venv": !!bool "false"
13
+    "include_system_packages": !!bool "false"
14
+  "ibm-websphere-liberty": {}
15
+"repo": "bzr+ssh://bazaar.launchpad.net/~ibmcharmers/ibmlayers/layer-ibm-websphere-liberty"
16
+"includes":
17
+- "layer:basic"
18
+- "interface:https"
19
+"is": "ibm-websphere-liberty"
Back to file index

lib/charms/layer/__init__.py

 1
--- 
 2
+++ lib/charms/layer/__init__.py
 3
@@ -0,0 +1,21 @@
 4
+import os
 5
+
 6
+
 7
+class LayerOptions(dict):
 8
+    def __init__(self, layer_file, section=None):
 9
+        import yaml  # defer, might not be available until bootstrap
10
+        with open(layer_file) as f:
11
+            layer = yaml.safe_load(f.read())
12
+        opts = layer.get('options', {})
13
+        if section and section in opts:
14
+            super(LayerOptions, self).__init__(opts.get(section))
15
+        else:
16
+            super(LayerOptions, self).__init__(opts)
17
+
18
+
19
+def options(section=None, layer_file=None):
20
+    if not layer_file:
21
+        base_dir = os.environ.get('CHARM_DIR', os.getcwd())
22
+        layer_file = os.path.join(base_dir, 'layer.yaml')
23
+
24
+    return LayerOptions(layer_file, section)
Back to file index

lib/charms/layer/basic.py

  1
--- 
  2
+++ lib/charms/layer/basic.py
  3
@@ -0,0 +1,205 @@
  4
+import os
  5
+import sys
  6
+import shutil
  7
+from glob import glob
  8
+from subprocess import check_call, CalledProcessError
  9
+from time import sleep
 10
+
 11
+from charms.layer.execd import execd_preinstall
 12
+
 13
+
 14
+def lsb_release():
 15
+    """Return /etc/lsb-release in a dict"""
 16
+    d = {}
 17
+    with open('/etc/lsb-release', 'r') as lsb:
 18
+        for l in lsb:
 19
+            k, v = l.split('=')
 20
+            d[k.strip()] = v.strip()
 21
+    return d
 22
+
 23
+
 24
+def bootstrap_charm_deps():
 25
+    """
 26
+    Set up the base charm dependencies so that the reactive system can run.
 27
+    """
 28
+    # execd must happen first, before any attempt to install packages or
 29
+    # access the network, because sites use this hook to do bespoke
 30
+    # configuration and install secrets so the rest of this bootstrap
 31
+    # and the charm itself can actually succeed. This call does nothing
 32
+    # unless the operator has created and populated $CHARM_DIR/exec.d.
 33
+    execd_preinstall()
 34
+    # ensure that $CHARM_DIR/bin is on the path, for helper scripts
 35
+    os.environ['PATH'] += ':%s' % os.path.join(os.environ['CHARM_DIR'], 'bin')
 36
+    venv = os.path.abspath('../.venv')
 37
+    vbin = os.path.join(venv, 'bin')
 38
+    vpip = os.path.join(vbin, 'pip')
 39
+    vpy = os.path.join(vbin, 'python')
 40
+    if os.path.exists('wheelhouse/.bootstrapped'):
 41
+        activate_venv()
 42
+        return
 43
+    # bootstrap wheelhouse
 44
+    if os.path.exists('wheelhouse'):
 45
+        with open('/root/.pydistutils.cfg', 'w') as fp:
 46
+            # make sure that easy_install also only uses the wheelhouse
 47
+            # (see https://github.com/pypa/pip/issues/410)
 48
+            charm_dir = os.environ['CHARM_DIR']
 49
+            fp.writelines([
 50
+                "[easy_install]\n",
 51
+                "allow_hosts = ''\n",
 52
+                "find_links = file://{}/wheelhouse/\n".format(charm_dir),
 53
+            ])
 54
+        apt_install([
 55
+            'python3-pip',
 56
+            'python3-setuptools',
 57
+            'python3-yaml',
 58
+            'python3-dev',
 59
+        ])
 60
+        from charms import layer
 61
+        cfg = layer.options('basic')
 62
+        # include packages defined in layer.yaml
 63
+        apt_install(cfg.get('packages', []))
 64
+        # if we're using a venv, set it up
 65
+        if cfg.get('use_venv'):
 66
+            if not os.path.exists(venv):
 67
+                series = lsb_release()['DISTRIB_CODENAME']
 68
+                if series in ('precise', 'trusty'):
 69
+                    apt_install(['python-virtualenv'])
 70
+                else:
 71
+                    apt_install(['virtualenv'])
 72
+                cmd = ['virtualenv', '-ppython3', '--never-download', venv]
 73
+                if cfg.get('include_system_packages'):
 74
+                    cmd.append('--system-site-packages')
 75
+                check_call(cmd)
 76
+            os.environ['PATH'] = ':'.join([vbin, os.environ['PATH']])
 77
+            pip = vpip
 78
+        else:
 79
+            pip = 'pip3'
 80
+            # save a copy of system pip to prevent `pip3 install -U pip`
 81
+            # from changing it
 82
+            if os.path.exists('/usr/bin/pip'):
 83
+                shutil.copy2('/usr/bin/pip', '/usr/bin/pip.save')
 84
+        # need newer pip, to fix spurious Double Requirement error:
 85
+        # https://github.com/pypa/pip/issues/56
 86
+        check_call([pip, 'install', '-U', '--no-index', '-f', 'wheelhouse',
 87
+                    'pip'])
 88
+        # install the rest of the wheelhouse deps
 89
+        check_call([pip, 'install', '-U', '--no-index', '-f', 'wheelhouse'] +
 90
+                   glob('wheelhouse/*'))
 91
+        if not cfg.get('use_venv'):
 92
+            # restore system pip to prevent `pip3 install -U pip`
 93
+            # from changing it
 94
+            if os.path.exists('/usr/bin/pip.save'):
 95
+                shutil.copy2('/usr/bin/pip.save', '/usr/bin/pip')
 96
+                os.remove('/usr/bin/pip.save')
 97
+        os.remove('/root/.pydistutils.cfg')
 98
+        # flag us as having already bootstrapped so we don't do it again
 99
+        open('wheelhouse/.bootstrapped', 'w').close()
100
+        # Ensure that the newly bootstrapped libs are available.
101
+        # Note: this only seems to be an issue with namespace packages.
102
+        # Non-namespace-package libs (e.g., charmhelpers) are available
103
+        # without having to reload the interpreter. :/
104
+        reload_interpreter(vpy if cfg.get('use_venv') else sys.argv[0])
105
+
106
+
107
+def activate_venv():
108
+    """
109
+    Activate the venv if enabled in ``layer.yaml``.
110
+
111
+    This is handled automatically for normal hooks, but actions might
112
+    need to invoke this manually, using something like:
113
+
114
+        # Load modules from $CHARM_DIR/lib
115
+        import sys
116
+        sys.path.append('lib')
117
+
118
+        from charms.layer.basic import activate_venv
119
+        activate_venv()
120
+
121
+    This will ensure that modules installed in the charm's
122
+    virtual environment are available to the action.
123
+    """
124
+    venv = os.path.abspath('../.venv')
125
+    vbin = os.path.join(venv, 'bin')
126
+    vpy = os.path.join(vbin, 'python')
127
+    from charms import layer
128
+    cfg = layer.options('basic')
129
+    if cfg.get('use_venv') and '.venv' not in sys.executable:
130
+        # activate the venv
131
+        os.environ['PATH'] = ':'.join([vbin, os.environ['PATH']])
132
+        reload_interpreter(vpy)
133
+
134
+
135
+def reload_interpreter(python):
136
+    """
137
+    Reload the python interpreter to ensure that all deps are available.
138
+
139
+    Newly installed modules in namespace packages sometimes seemt to
140
+    not be picked up by Python 3.
141
+    """
142
+    os.execve(python, [python] + list(sys.argv), os.environ)
143
+
144
+
145
+def apt_install(packages):
146
+    """
147
+    Install apt packages.
148
+
149
+    This ensures a consistent set of options that are often missed but
150
+    should really be set.
151
+    """
152
+    if isinstance(packages, (str, bytes)):
153
+        packages = [packages]
154
+
155
+    env = os.environ.copy()
156
+
157
+    if 'DEBIAN_FRONTEND' not in env:
158
+        env['DEBIAN_FRONTEND'] = 'noninteractive'
159
+
160
+    cmd = ['apt-get',
161
+           '--option=Dpkg::Options::=--force-confold',
162
+           '--assume-yes',
163
+           'install']
164
+    for attempt in range(3):
165
+        try:
166
+            check_call(cmd + packages, env=env)
167
+        except CalledProcessError:
168
+            if attempt == 2:  # third attempt
169
+                raise
170
+            sleep(5)
171
+        else:
172
+            break
173
+
174
+
175
+def init_config_states():
176
+    import yaml
177
+    from charmhelpers.core import hookenv
178
+    from charms.reactive import set_state
179
+    from charms.reactive import toggle_state
180
+    config = hookenv.config()
181
+    config_defaults = {}
182
+    config_defs = {}
183
+    config_yaml = os.path.join(hookenv.charm_dir(), 'config.yaml')
184
+    if os.path.exists(config_yaml):
185
+        with open(config_yaml) as fp:
186
+            config_defs = yaml.safe_load(fp).get('options', {})
187
+            config_defaults = {key: value.get('default')
188
+                               for key, value in config_defs.items()}
189
+    for opt in config_defs.keys():
190
+        if config.changed(opt):
191
+            set_state('config.changed')
192
+            set_state('config.changed.{}'.format(opt))
193
+        toggle_state('config.set.{}'.format(opt), config.get(opt))
194
+        toggle_state('config.default.{}'.format(opt),
195
+                     config.get(opt) == config_defaults[opt])
196
+    hookenv.atexit(clear_config_states)
197
+
198
+
199
+def clear_config_states():
200
+    from charmhelpers.core import hookenv, unitdata
201
+    from charms.reactive import remove_state
202
+    config = hookenv.config()
203
+    remove_state('config.changed')
204
+    for opt in config.keys():
205
+        remove_state('config.changed.{}'.format(opt))
206
+        remove_state('config.set.{}'.format(opt))
207
+        remove_state('config.default.{}'.format(opt))
208
+    unitdata.kv().flush()
Back to file index

lib/charms/layer/execd.py

  1
--- 
  2
+++ lib/charms/layer/execd.py
  3
@@ -0,0 +1,138 @@
  4
+# Copyright 2014-2016 Canonical Limited.
  5
+#
  6
+# This file is part of layer-basic, the reactive base layer for Juju.
  7
+#
  8
+# charm-helpers is free software: you can redistribute it and/or modify
  9
+# it under the terms of the GNU Lesser General Public License version 3 as
 10
+# published by the Free Software Foundation.
 11
+#
 12
+# charm-helpers is distributed in the hope that it will be useful,
 13
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
 14
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 15
+# GNU Lesser General Public License for more details.
 16
+#
 17
+# You should have received a copy of the GNU Lesser General Public License
 18
+# along with charm-helpers.  If not, see <http://www.gnu.org/licenses/>.
 19
+
 20
+# This module may only import from the Python standard library.
 21
+import os
 22
+import sys
 23
+import subprocess
 24
+import time
 25
+
 26
+'''
 27
+execd/preinstall
 28
+
 29
+It is often necessary to configure and reconfigure machines
 30
+after provisioning, but before attempting to run the charm.
 31
+Common examples are specialized network configuration, enabling
 32
+of custom hardware, non-standard disk partitioning and filesystems,
 33
+adding secrets and keys required for using a secured network.
 34
+
 35
+The reactive framework's base layer invokes this mechanism as
 36
+early as possible, before any network access is made or dependencies
 37
+unpacked or non-standard modules imported (including the charms.reactive
 38
+framework itself).
 39
+
 40
+Operators needing to use this functionality may branch a charm and
 41
+create an exec.d directory in it. The exec.d directory in turn contains
 42
+one or more subdirectories, each of which contains an executable called
 43
+charm-pre-install and any other required resources. The charm-pre-install
 44
+executables are run, and if successful, state saved so they will not be
 45
+run again.
 46
+
 47
+    $CHARM_DIR/exec.d/mynamespace/charm-pre-install
 48
+
 49
+An alternative to branching a charm is to compose a new charm that contains
 50
+the exec.d directory, using the original charm as a layer,
 51
+
 52
+A charm author could also abuse this mechanism to modify the charm
 53
+environment in unusual ways, but for most purposes it is saner to use
 54
+charmhelpers.core.hookenv.atstart().
 55
+'''
 56
+
 57
+
 58
+def default_execd_dir():
 59
+    return os.path.join(os.environ['CHARM_DIR'], 'exec.d')
 60
+
 61
+
 62
+def execd_module_paths(execd_dir=None):
 63
+    """Generate a list of full paths to modules within execd_dir."""
 64
+    if not execd_dir:
 65
+        execd_dir = default_execd_dir()
 66
+
 67
+    if not os.path.exists(execd_dir):
 68
+        return
 69
+
 70
+    for subpath in os.listdir(execd_dir):
 71
+        module = os.path.join(execd_dir, subpath)
 72
+        if os.path.isdir(module):
 73
+            yield module
 74
+
 75
+
 76
+def execd_submodule_paths(command, execd_dir=None):
 77
+    """Generate a list of full paths to the specified command within exec_dir.
 78
+    """
 79
+    for module_path in execd_module_paths(execd_dir):
 80
+        path = os.path.join(module_path, command)
 81
+        if os.access(path, os.X_OK) and os.path.isfile(path):
 82
+            yield path
 83
+
 84
+
 85
+def execd_sentinel_path(submodule_path):
 86
+    module_path = os.path.dirname(submodule_path)
 87
+    execd_path = os.path.dirname(module_path)
 88
+    module_name = os.path.basename(module_path)
 89
+    submodule_name = os.path.basename(submodule_path)
 90
+    return os.path.join(execd_path,
 91
+                        '.{}_{}.done'.format(module_name, submodule_name))
 92
+
 93
+
 94
+def execd_run(command, execd_dir=None, stop_on_error=True, stderr=None):
 95
+    """Run command for each module within execd_dir which defines it."""
 96
+    if stderr is None:
 97
+        stderr = sys.stdout
 98
+    for submodule_path in execd_submodule_paths(command, execd_dir):
 99
+        # Only run each execd once. We cannot simply run them in the
100
+        # install hook, as potentially storage hooks are run before that.
101
+        # We cannot rely on them being idempotent.
102
+        sentinel = execd_sentinel_path(submodule_path)
103
+        if os.path.exists(sentinel):
104
+            continue
105
+
106
+        try:
107
+            subprocess.check_call([submodule_path], stderr=stderr,
108
+                                  universal_newlines=True)
109
+            with open(sentinel, 'w') as f:
110
+                f.write('{} ran successfully {}\n'.format(submodule_path,
111
+                                                          time.ctime()))
112
+                f.write('Removing this file will cause it to be run again\n')
113
+        except subprocess.CalledProcessError as e:
114
+            # Logs get the details. We can't use juju-log, as the
115
+            # output may be substantial and exceed command line
116
+            # length limits.
117
+            print("ERROR ({}) running {}".format(e.returncode, e.cmd),
118
+                  file=stderr)
119
+            print("STDOUT<<EOM", file=stderr)
120
+            print(e.output, file=stderr)
121
+            print("EOM", file=stderr)
122
+
123
+            # Unit workload status gets a shorter fail message.
124
+            short_path = os.path.relpath(submodule_path)
125
+            block_msg = "Error ({}) running {}".format(e.returncode,
126
+                                                       short_path)
127
+            try:
128
+                subprocess.check_call(['status-set', 'blocked', block_msg],
129
+                                      universal_newlines=True)
130
+                if stop_on_error:
131
+                    sys.exit(0)  # Leave unit in blocked state.
132
+            except Exception:
133
+                pass  # We care about the exec.d/* failure, not status-set.
134
+
135
+            if stop_on_error:
136
+                sys.exit(e.returncode or 1)  # Error state for pre-1.24 Juju
137
+
138
+
139
+def execd_preinstall(execd_dir=None):
140
+    """Run charm-pre-install for each module within execd_dir."""
141
+    execd_run('charm-pre-install', execd_dir=execd_dir)
Back to file index

metadata.yaml

 1
--- 
 2
+++ metadata.yaml
 3
@@ -0,0 +1,22 @@
 4
+"name": "ibm-websphere-liberty"
 5
+"summary": "IBM WebSphere Application Server Liberty Profile"
 6
+"maintainer": "IBM Juju Support Team <jujusupp@us.ibm.com>"
 7
+"description": |
 8
+  Liberty profile is a dynamic profile of IBM WebSphere Application Server (WAS)
 9
+  that enables the WAS server to provision only the features required by the
10
+  application (or set of applications) deployed to the server.
11
+"tags":
12
+- "misc"
13
+- "ibm"
14
+- "ibm-z"
15
+- "application"
16
+"provides":
17
+  "website":
18
+    "interface": "https"
19
+"series":
20
+- "xenial"
21
+- "trusty"
22
+
23
+"subordinate": !!bool "false"
24
+"terms":
25
+- "ibm-wlp/0"
Back to file index

reactive/ibm-wlp.py

  1
--- 
  2
+++ reactive/ibm-wlp.py
  3
@@ -0,0 +1,416 @@
  4
+#!/usr/bin/env python
  5
+
  6
+import os
  7
+import grp
  8
+import pwd
  9
+import subprocess
 10
+import shutil
 11
+import urllib
 12
+import urllib.request
 13
+
 14
+from charmhelpers.core import hookenv
 15
+from charms.reactive import when, when_not, set_state
 16
+# Import charmhelpers python libraries.
 17
+from charmhelpers.core.hookenv import (
 18
+    charm_dir,
 19
+    log,
 20
+    config,
 21
+    unit_private_ip,
 22
+    open_port,
 23
+)
 24
+from charmhelpers.core.host import (
 25
+    mkdir,
 26
+)
 27
+
 28
+private_address = unit_private_ip()
 29
+
 30
+# Install directory constants.
 31
+ibm_install_prefix = '/opt/ibm'
 32
+wlp_directory = os.path.join(ibm_install_prefix, 'wlp')
 33
+
 34
+# The url of the petstore source code.
 35
+petstore_url = 'https://github.com/agoncal/agoncal-application-petstore-ee6'
 36
+
 37
+
 38
+@when_not('ibm-wlp.installed')
 39
+def install_ibm_wlp():
 40
+    # Get all the configuration values here.
 41
+    mkdir('/opt/ibm', 'ubuntu', 'ubuntu', 0o755)
 42
+
 43
+    # Checking the version
 44
+    wlp_version = config().get('ibm-liberty-version')
 45
+    a, b, c, d = wlp_version.split(".")
 46
+    wlp_version = (str(a)+str(b)+str(c)+str(d))
 47
+    version = "16.0.0.3"
 48
+    a1, b1, c1, d1 = version.split(".")
 49
+    version_sup = (str(a1)+str(b1)+str(c1)+str(d1))
 50
+    if (int(wlp_version) > int(version_sup)):
 51
+        log('Charm supports under 16.0.0.3 version only')
 52
+        hookenv.status_set('maintenance', 'Charm supports under'
 53
+                           ' V16.0.0.3 only')
 54
+    else:
 55
+        install_wlp()
 56
+
 57
+
 58
+@when('ibm-wlp.installed')
 59
+@when_not('ibm-wlp.started')
 60
+def start_wlp(server='defaultServer'):
 61
+    """ Start the WebSphere Liberty Profile server if it exists. """
 62
+    wlp_server = os.path.join('/opt', 'ibm', 'wlp', 'bin', 'server')
 63
+    output = '{} does not exist unable to start {}'.format(wlp_server, server)
 64
+    if os.path.exists(wlp_server):
 65
+        start_wlp_server = [wlp_server, 'start', server]
 66
+        # Use a callback method to temporarily run process as different user.
 67
+        p = subprocess.Popen(start_wlp_server,
 68
+                             preexec_fn=run_as('ubuntu', 'ubuntu'),
 69
+                             stdout=subprocess.PIPE,
 70
+                             stderr=subprocess.PIPE)
 71
+        output, err = p.communicate()
 72
+        p.stdout.close()
 73
+        p.stderr.close()
 74
+        if err:
 75
+            print(err)
 76
+            hookenv.status_set('maintenance', "Error while starting  wlp")
 77
+        else:
 78
+            # Open the ports that wlp uses.
 79
+            open_port(9080)
 80
+            open_port(9443)
 81
+            log('WebSphere Liberty Profile start complete. ')
 82
+            set_state('ibm-wlp.started')
 83
+            hookenv.status_set('active', 'WebSphere Liberty is started')
 84
+            # Installing Petstore application
 85
+            petstore = config().get('install-petstore')
 86
+            if petstore:
 87
+                install_petstore()
 88
+            else:
 89
+                remove_petstore()
 90
+
 91
+
 92
+@when('ibm-wlp.started')
 93
+@when('website.available')
 94
+def configure_website(website):
 95
+    log('Configuring website for Liberty Profile server.')
 96
+    httpport = "9080"
 97
+    wlphttpsport = "9443"
 98
+    website.configure(port=httpport, httpsport=wlphttpsport)
 99
+    hookenv.status_set('active', 'Configured website for Liberty Profile.')
100
+
101
+
102
+def run_as(user=None, group=None):
103
+    """ Pass the function 'set_ids' to preexec_fn, rather than just calling
104
+    setuid and setgid. This will change the ids for that subprocess only. """
105
+    if group:
106
+        gid = grp.getgrnam(user).gr_gid
107
+    else:
108
+        gid = 0
109
+    if user:
110
+        uid = pwd.getpwnam(group).pw_uid
111
+    else:
112
+        uid = 0
113
+
114
+    def set_ids():
115
+        """ Change the uid and gid for the subproccess only. """
116
+        os.setgid(gid)
117
+        os.setuid(uid)
118
+    return set_ids
119
+
120
+
121
+def download_url_details(to_path):
122
+    """ Download the URL file that contains the location for Websphere Liberty
123
+        Runtime and license. """
124
+
125
+    log("Retrieving Liberty URL information file.")
126
+
127
+    # The path where the downloaded file is to be stored should not be empty
128
+    if to_path == "":
129
+        log("Provide a path to download the URL information file")
130
+        return 0
131
+
132
+    # The web url for the file that is to be downloaded
133
+    wlp_file_url = config().get('ibm-liberty-url')
134
+    print(wlp_file_url)
135
+    # Set to default if null
136
+    if (wlp_file_url == ""):
137
+        wlp_file_url = ('http://public.dhe.ibm.com/ibmdl/export/pub/software'
138
+                        '/websphere/wasdev/downloads/wlp/index.yml')
139
+
140
+    # Full path to where it will be downloaded
141
+    to_file = os.path.join(to_path, 'index.yml')
142
+    # Download it
143
+    print(to_path)
144
+    try:
145
+        urllib.request.urlretrieve(wlp_file_url, to_file)
146
+        log("Retrieved Liberty URL information file.")
147
+        return to_file
148
+    except subprocess.CalledProcessError as e:
149
+        print(e.output)
150
+        log("Unable to retrieve WebSphere Liberty URL information file.")
151
+        return 0
152
+
153
+
154
+def download_wlp(to_path):
155
+    """ Download Liberty runtime file,similar to download of license file """
156
+
157
+    log("Downloading Liberty Runtime ..")
158
+
159
+    index_file = download_url_details(to_path)
160
+    grep_out = subprocess.Popen(('grep', '-m',  '1',  'uri:', index_file),
161
+                                stdout=subprocess.PIPE)
162
+    wlp_file_url = subprocess.check_output(('sed',  's/uri://'),
163
+                                           stdin=grep_out.stdout)
164
+    grep_out.wait()
165
+    grep_out.stdout.close()
166
+    wlp_file_url = wlp_file_url.decode("utf-8")
167
+    wlp_version = config().get('ibm-liberty-version')
168
+    wlp_file_url = ('http://public.dhe.ibm.com/ibmdl/export/pub/software'
169
+                    '/websphere/wasdev/downloads/wlp/' + wlp_version +
170
+                    '/wlp-runtime-' + wlp_version + '.jar')
171
+    print(wlp_file_url)
172
+    try:
173
+        index = os.path.basename(wlp_file_url)
174
+    except subprocess.CalledProcessError as e:
175
+        print(e.output)
176
+        log("Unable to parse WebSphere Liberty download URL")
177
+        return 0
178
+
179
+    jar_file = index
180
+    wlp_file = os.path.join(to_path, jar_file)
181
+    # Do not download if it is downloaded earlier
182
+    if os.path.isfile(wlp_file):
183
+        log("Liberty Runtime is already downloaded")
184
+        return jar_file
185
+
186
+    try:
187
+        urllib.request.urlretrieve(wlp_file_url, wlp_file)
188
+        log("Downloaded WebSphere Liberty Runtime.")
189
+        return jar_file
190
+    except subprocess.CalledProcessError as e:
191
+        print(e.output)
192
+        log("Unable to retrieve WebSphere Liberty Runtime."
193
+            "Exiting config-changed")
194
+        return 0
195
+
196
+
197
+def install_wlp():
198
+    """ Install and configure the WebSphere Liberty Profile software. """
199
+
200
+    if os.path.exists(wlp_directory):
201
+        log('Removing previous installation to achieve idempotency.')
202
+        shutil.rmtree(wlp_directory)
203
+
204
+    wlp_file_name = download_wlp(os.path.join(charm_dir(), 'files',
205
+                                              'archives'))
206
+
207
+    log('Installing WebSphere Liberty Profile to ' + wlp_directory)
208
+    # Get the wlp runtime file from the charm archives directory.
209
+    wlp_file = os.path.join(charm_dir(), 'files', 'archives',
210
+                            wlp_file_name)
211
+    # Checking check_sum value
212
+    command = ["sha512sum", wlp_file]
213
+    p1 = subprocess.Popen(command, stdout=subprocess.PIPE,
214
+                          stderr=subprocess.PIPE, shell=False)
215
+    output1, err = p1.communicate()
216
+    msg = str(output1)
217
+    var = msg.split(" ")
218
+    var1 = var[0]
219
+    value = var1[2:]
220
+    check_sum = config().get('sha_wlp')
221
+    if (value != check_sum):
222
+        log('Checksum didnot match')
223
+        hookenv.status_set('maintenance', "Please provide the checksum value")
224
+        return 1
225
+    if not os.path.isfile(wlp_file):
226
+        log('The IBM Liberty runtime file does not exist: ' + wlp_file_name)
227
+        log('Ensure that the file name is correct and is present in files or'
228
+            'archives directory')
229
+        return 1
230
+
231
+    # Create the command that unpacks the jar file to the install directory.
232
+    java_command = ['java', '-jar', wlp_file, '--acceptLicense',
233
+                    ibm_install_prefix]
234
+    log(subprocess.check_output(java_command))
235
+
236
+    # Change the files in the wlp directory to be owned by ubuntu.
237
+    chown_command = ['chown', '-R', 'ubuntu:ubuntu', wlp_directory]
238
+    subprocess.check_output(chown_command)
239
+
240
+    # The defaultServer directory.
241
+    default_server_directory = os.path.join(wlp_directory, 'usr', 'servers',
242
+                                            'defaultServer')
243
+    if (os.path.exists(default_server_directory)):
244
+        log('Removing the previous defaultServer directory.')
245
+        shutil.rmtree(default_server_directory)
246
+
247
+    wlp_server = os.path.join(wlp_directory, 'bin', 'server')
248
+    create_default_server = [wlp_server, 'create', 'defaultServer']
249
+    log('Creating defaultServer profile.')
250
+    # Create the defaultServer definition.
251
+    log(subprocess.check_output(create_default_server,
252
+                                preexec_fn=run_as('ubuntu', 'ubuntu')))
253
+
254
+    # The derby directory is in the shared resources directory.
255
+    wlp_derby_directory = os.path.join(wlp_directory, 'usr', 'shared',
256
+                                       'resources', 'derby')
257
+    wlp_derby = os.path.join(wlp_derby_directory, 'derby.jar')
258
+    wlp_derby_log = os.path.join(default_server_directory, 'derby.log')
259
+
260
+    # Remove the previous derby jar file to be idempotent.
261
+    if os.path.exists(wlp_derby):
262
+        os.remove(wlp_derby)
263
+    # Remove the previous derby log file to be idempotent.
264
+    if os.path.exists(wlp_derby_log):
265
+        os.remove(wlp_derby_log)
266
+
267
+    # Create the derby directory if it does not exist.
268
+    mkdir(wlp_derby_directory, 'ubuntu', 'ubuntu', 0o755)
269
+
270
+    # Create the path to the system derby.jar file.
271
+    system_derby = os.path.join('/usr', 'share', 'java', 'derby.jar')
272
+    if os.path.isfile(system_derby):
273
+        log('Copying derby.jar file from ' + system_derby)
274
+        # Copy the derby jar to the wlp ${shared.resource.dir}
275
+        shutil.copy2(system_derby, wlp_derby)
276
+    else:
277
+        log('The derby.jar file does not exist at {0}'.format(system_derby))
278
+        log(' Is libderby-java installed?')
279
+        return 1
280
+
281
+    # Change the files in the wlp directory to be owned by ubuntu.
282
+    chown_command = ['chown', '-R', 'ubuntu:ubuntu', wlp_directory]
283
+    subprocess.check_output(chown_command)
284
+    hookenv.status_set('active', 'WebSphere Liberty is installed')
285
+    set_state('ibm-wlp.installed')
286
+
287
+
288
+def install_petstore():
289
+    """ Install the petstore web application to test Liberty Profile. """
290
+
291
+    log('Installing the petstore application.')
292
+
293
+    default_server_directory = os.path.join(wlp_directory, 'usr', 'servers',
294
+                                            'defaultServer')
295
+    petstore_directory = os.path.join(default_server_directory, 'apps',
296
+                                      'petstore.war')
297
+
298
+    # Remove the old petstore code for idempotency.
299
+    remove_petstore()
300
+
301
+    mkdir(petstore_directory, 'ubuntu', 'ubuntu', 0o755)
302
+
303
+    petstore_war_file = os.path.join(charm_dir(), 'files', 'archives',
304
+                                     'petstore.war')
305
+    if os.path.isfile(petstore_war_file):
306
+        log('Copying the petstore application from the charm directory.')
307
+        shutil.copy2(petstore_war_file, petstore_directory)
308
+    else:
309
+        log('The charm does not contain petstore.war, need to build petstore.')
310
+
311
+        liberty_directory = os.path.join(charm_dir(), 'Liberty')
312
+
313
+        # Remove the Liberty directory to stay idempotent.
314
+        if os.path.exists(liberty_directory):
315
+            shutil.rmtree(liberty_directory)
316
+
317
+        mkdir(liberty_directory, 'ubuntu', 'ubuntu', 0o755)
318
+
319
+        os.chdir(liberty_directory)
320
+        # Create the command to git the petstore code.
321
+        get_petstore = ['git', 'clone', petstore_url]
322
+        log('Downloading {} to {}'.format(petstore_url, liberty_directory))
323
+        subprocess.check_output(get_petstore)
324
+
325
+        build_directory = os.path.join(liberty_directory,
326
+                                       'agoncal-application-petstore-ee6')
327
+
328
+        petstore_source = os.path.join(build_directory, 'src', 'main', 'java',
329
+                                       'org', 'agoncal', 'application',
330
+                                       'petstore')
331
+
332
+        log('Coping over source files from charm...')
333
+
334
+        # Copy the DB populator to the proper location.
335
+        db_populator = os.path.join(charm_dir(), 'files', 'DBPopulator.java')
336
+        service_directory = os.path.join(petstore_source, 'service')
337
+        shutil.copy2(db_populator, service_directory)
338
+        # Copy the ExceptionInterceptor to the proper location.
339
+        interceptor = os.path.join(charm_dir(), 'files',
340
+                                   'ExceptionInterceptor.java')
341
+        web_directory = os.path.join(petstore_source, 'web')
342
+        shutil.copy2(interceptor, web_directory)
343
+
344
+        # Copy the persistence.xml file to the proper location.
345
+        persistence_xml = os.path.join(charm_dir(), 'files', 'persistence.xml')
346
+        meta_inf = os.path.join(build_directory, 'src', 'main', 'resources',
347
+                                'META-INF')
348
+        shutil.copy2(persistence_xml, meta_inf)
349
+
350
+        # Change to the build directory.
351
+        os.chdir(build_directory)
352
+
353
+        maven_command = ['mvn', 'clean', 'compile', 'package']
354
+        log('Building the petstore application...')
355
+        # Build and package the petstore WAR file.
356
+        subprocess.check_output(maven_command)
357
+
358
+        build_jar = os.path.join(build_directory, 'target',
359
+                                 'applicationPetstore.war')
360
+        # Create the destination directory and name.
361
+        petstore_war_file = os.path.join(petstore_directory, 'petstore.war')
362
+        # Copy the WAR file to the defaultServer directory.
363
+        shutil.copy2(build_jar, petstore_war_file)
364
+
365
+    default_server_xml = os.path.join(default_server_directory, 'server.xml')
366
+    original_server_xml = os.path.join(default_server_directory,
367
+                                       'server.xml.original')
368
+    if not os.path.exists(original_server_xml):
369
+        os.rename(default_server_xml, original_server_xml)
370
+
371
+    petstore_server_xml = os.path.join(charm_dir(), 'files', 'server.xml')
372
+    # Copy over the petstore server.xml file from the charm directory.
373
+    shutil.copy2(petstore_server_xml, default_server_xml)
374
+
375
+    # Change to the petstore directory.
376
+    os.chdir(petstore_directory)
377
+
378
+    log('Unpacking the petstore.war file to: ' + petstore_directory)
379
+    unjar_command = ['jar', '-xvf', 'petstore.war']
380
+    # Expand the war file in this directory.
381
+    log(subprocess.check_output(unjar_command,
382
+                                preexec_fn=run_as('ubuntu', 'ubuntu')))
383
+
384
+    # Remove the war file.
385
+    os.remove(os.path.join(petstore_directory, 'petstore.war'))
386
+
387
+    log('Changing ownership of petstore files...')
388
+    # Change the files in the pestore directory to be owned by the ubuntu user.
389
+    chown_command = ['chown', '-R', 'ubuntu:ubuntu', petstore_directory]
390
+    subprocess.check_output(chown_command)
391
+
392
+
393
+def remove_petstore():
394
+    """ Remove the petstore web application. """
395
+
396
+    log('Removing the previous petstore web application.')
397
+
398
+    default_server_directory = os.path.join(wlp_directory, 'usr', 'servers',
399
+                                            'defaultServer')
400
+    petstore_directory = os.path.join(default_server_directory, 'apps',
401
+                                      'petstore.war')
402
+    petstore_db = os.path.join(default_server_directory,
403
+                               'applicationPetstoreDB')
404
+
405
+    # Check for the existance of a directory named petstore.war and delete it.
406
+    if os.path.isdir(petstore_directory):
407
+        log('Removing the previous petstore directory ' + petstore_directory)
408
+        shutil.rmtree(petstore_directory)
409
+
410
+    # Check for the existance of the petstore database directory.
411
+    if os.path.isdir(petstore_db):
412
+        log('Removing the previous petstore database: ' + petstore_db)
413
+        shutil.rmtree(petstore_db)
414
+
415
+    default_server_xml = os.path.join(default_server_directory, 'server.xml')
416
+    original_server_xml = os.path.join(default_server_directory,
417
+                                       'server.xml.original')
418
+    if os.path.isfile(original_server_xml):
419
+        os.rename(original_server_xml, default_server_xml)
Back to file index

requirements.txt

1
--- 
2
+++ requirements.txt
3
@@ -0,0 +1,2 @@
4
+flake8
5
+pytest
Back to file index

revision

1
--- 
2
+++ revision
3
@@ -0,0 +1 @@
4
+0
Back to file index

tests/01-deploy.py

 1
--- 
 2
+++ tests/01-deploy.py
 3
@@ -0,0 +1,30 @@
 4
+#!/usr/bin/env python3
 5
+
 6
+import amulet
 7
+import requests
 8
+import unittest
 9
+
10
+
11
+class TestDeploy(unittest.TestCase):
12
+    """
13
+    Deployment test for the IBM Websphere Liberty charm.
14
+
15
+    """
16
+    def setUp(self):
17
+        self.d = amulet.Deployment(series='xenial')
18
+        self.d.add('ibm-websphere-liberty',
19
+                   'cs:~ibmcharmers/ibm-websphere-liberty')
20
+        self.d.setup(timeout=900)
21
+        self.d.sentry.wait(timeout=1800)
22
+
23
+    def test_wlp_deployed(self):
24
+        self.assertTrue(self.d.deployed)
25
+        unit = self.d.sentry['ibm-websphere-liberty'][0]
26
+        url = 'http://%s:9080' % unit.info['public-address']
27
+        response = requests.get(url, verify=False)
28
+        # Raise an exception if the url was not a valid web page.
29
+        response.raise_for_status()
30
+
31
+
32
+if __name__ == '__main__':
33
+    unittest.main()
Back to file index

tests/tests.yaml

1
--- 
2
+++ tests/tests.yaml
3
@@ -0,0 +1,4 @@
4
+packages:
5
+  - amulet
6
+  - python3
7
+  - unzip
Back to file index

tox.ini

 1
--- 
 2
+++ tox.ini
 3
@@ -0,0 +1,12 @@
 4
+[tox]
 5
+skipsdist=True
 6
+envlist = py34, py35
 7
+skip_missing_interpreters = True
 8
+
 9
+[testenv]
10
+commands = py.test -v
11
+deps =
12
+    -r{toxinidir}/requirements.txt
13
+
14
+[flake8]
15
+exclude=docs