~ibmcharmers/trusty/ibm-wxs-container

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

CPP?: No
OIL?: No

IBM WXS Container Charm for Trusty Series. IBM WXS Charm comprises of three charms, This is one of the charm.


Tests

Substrate Status Results Last Updated
aws RETRY 19 days ago
gce RETRY 19 days ago
lxc 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

Files changed 95

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,160 @@
  4
+Charm for IBM WebSphere eXtreme Scale (IBM WXS) 8.6.1 for Container Service
  5
+
  6
+## Overview
  7
+
  8
+The WebSphere eXtreme Scale licensed program is an elastic, scalable, in-memory data grid. The data grid dynamically caches, partitions, replicates, and manages application data and business logic across multiple servers. WebSphere eXtreme Scale performs massive volumes of transaction processing with high efficiency and linear scalability. With WebSphere eXtreme Scale, you can also get qualities of service such as transactional integrity, high availability, and predictable response times.
  9
+For details on IBM WebSphere eXtreme Scale, as well as information on purchasing, please visit: [Product Page] [wxs-product-page] and at the [Passport Advantage Site] [Passport]. More information available at the [IBM Knowledge Center] [IBM-WXS-Infocenter]
 10
+
 11
+`IBM WebSphere eXtreme Scale Container Service`
 12
+
 13
+This charm is using IBM Installation Manager to install IBM WebSphere eXtreme Scale Software. This charm is using ibm-im charm as base layer to install Installation Manager tool.
 14
+
 15
+## Prerequisites
 16
+
 17
+This charm makes use of resources, a feature only available in Juju 2.0. During deploy or upgrade, you will need to specify the installable package(s)
 18
+required by this charm. Download your licensed IBM WebSphere eXtreme Scale packages from the [Product Page] [WXS-8.6.1-download].
 19
+
 20
+### Packages for Ubuntu on AMD64 (x86_64):
 21
+
 22
+IBM Installation Manager 1.8 (`agent.installer.linux.gtk.x86_64_1.8.3000.20150606_0047.zip`)
 23
+
 24
+IBM WXS 8.6.1 (`WS_XSCALE_V8.6_MP_ML.zip`)
 25
+
 26
+### Packages for Ubuntu on Power (ppc64le):
 27
+
 28
+IBM WXS 8.6.1 (`WS_XSCALE_V8.6_MP_ML.zip`)
 29
+
 30
+## Usage
 31
+
 32
+To use this charm, you must agree to the Terms of Use. You can view the full license for `IBM Installation Manager` and `IBM WebSphere eXtreme Scale` products by visiting the [im-license-info](http://www-03.ibm.com/software/sla/sladb.nsf/displaylis/39AFC1C1D485C4E085257E7300548B05?OpenDocument) and [wxs-license-info] [license-info] page.
 33
+
 34
+Search for "IBM WebSphere eXtreme Scale" and choose the license that applies to the version you are using.
 35
+
 36
+
 37
+## Memory and Disk Requirements
 38
+
 39
+Space requirements
 40
+
 41
+    Approximately 1.1 GB of disk space to store the required downloadable parts
 42
+    Approximately 1.1 GB of disk space to unpack the parts
 43
+    Approximately 400 MB of disk space to install the product
 44
+    Approximately 100 MB of space in the tmp directory to run the installation program
 45
+
 46
+WebSphere eXtreme Scale Container Service Charm requires 15 GB of root disk to download packages and install the IBM WebSphere eXtreme Scale Container Service Software. By default available root disk space is 8GB.
 47
+
 48
+To request a larger root disk, run the following command:
 49
+
 50
+	juju set-constraints root-disk=15G
 51
+
 52
+### Deploy
 53
+
 54
+1. Run the following commands to deploy this charm:
 55
+
 56
+	On x86_64, ppc64le or s390x :
 57
+	
 58
+	    juju deploy ibm-wxs-container --resource ibm_im_installer=</path/to/ibm_im_installer.zip> --resource ibm_wxs_base_installer=</path/to/ibm_wxs_base_installer.zip> 
 59
+		
 60
+    **Note**: This charm requires acceptance of Terms of Use. When deploying from the Charm Store, these terms will be presented to you for your consideration.  
 61
+         To accept the terms:
 62
+    
 63
+        juju agree ibm-im/1 ibm-wxs/1
 64
+        juju deploy ibm-wxs-container
 65
+
 66
+
 67
+2. To Expose the IBM WXS Container Service to public, run the following command:
 68
+
 69
+		juju expose ibm-wxs-container
 70
+
 71
+
 72
+### Upgrade
 73
+
 74
+Once deployed, user can upgrade the existing installation by installing fixpacks:
 75
+
 76
+If user wants to upgrade existing installation of Installtion Manger, run the following command:
 77
+
 78
+	juju attach ibm-wxs-container ibm_im_fixpack=</path/to/fixpack.zip>
 79
+
 80
+To upgrade WXS Container installation:
 81
+	
 82
+	juju attach ibm-wxs-container ibm_wxs_fixpack_installer=</path/to/ibm_wxs_fixpack_installer.zip>
 83
+	
 84
+
 85
+### Verification
 86
+
 87
+After installing IBM WXS Container Server, The Container server should be Up and Running on the hostname and port of the Catalog Server that it is connected.
 88
+
 89
+
 90
+## Relating with IBM WXS Container
 91
+
 92
+Install IBM WXS Catalog Charm. 
 93
+
 94
+IBM WXS Container charm is related to IBM WXS Catalog. To add a relation, run the following command:
 95
+
 96
+	juju add-relation ibm-wxs-catalog ibm-wxs-container
 97
+		
 98
+In the above relation, it uses `ibm-wxs` interface. IBM WXS Container charm is related to IBM WXS Catalog charm, to make WXS Data Grid available for user to access from IBM WXS Client charm.
 99
+
100
+### Verification
101
+
102
+After establishing relation with IBM WXS Catalog charms, user can check container service running inside the container, by issueing the following command:
103
+
104
+    juju run --machine <id> 'ps -ef | grep [c]atalogServiceEndPoint'
105
+
106
+Container should be running with hostname and port of related Catalog server.
107
+
108
+To remove the relation, run the following command:
109
+
110
+	juju remove-relation ibm-wxs-catalog ibm-wxs-container
111
+		
112
+## IBM Installation Manager(IM) Information
113
+
114
+(1) General Information
115
+Details about IM available at [IBM Knowledge Center][Im-info].
116
+
117
+(2) Download Information
118
+Information on procuring IM product is available at the [Product Page][im-product-page]
119
+and at the [Passport Advantage Site][passport].	
120
+
121
+## IBM IBM WebSphere eXtreme Scale Information
122
+
123
+(1) General Information 
124
+
125
+Details about IBM WXS software available at [IBM Knowledge Center] [IBM-WXS-Infocenter].
126
+
127
+Information on procuring WXS product is available at the [Passport Advantage site] [Passport]
128
+
129
+(2) Download Information
130
+
131
+Details about IBM WXS 8.6.1 download available [here] [WXS-8.6.1-download]
132
+
133
+Information about installation of IBM WXS on 'x86_64', 'ppc64le' and 's390x' based machine available [here] [WXS-Installation]  
134
+
135
+More information about IBM IM Downloadable file and IBM WXS Downloadable files available [here] [IBM-IM-more-info]
136
+
137
+## Contact Information
138
+
139
+For issues with this charm, please contact IBM Juju Support team <jujusupp@us.ibm.com>
140
+
141
+<!-- Links -->
142
+
143
+[IM-info]: http://www-01.ibm.com/support/knowledgecenter/SSDV2W/im_family_welcome.html
144
+
145
+[im-product-page]: http://www-01.ibm.com/support/docview.wss?uid=swg27025142
146
+
147
+[wxs-product-page]: https://www.ibm.com/support/knowledgecenter/SSTVLU_8.6.1/com.ibm.websphere.extremescale.doc/cxsprodoverview.html
148
+
149
+[IBM-WXS-Infocenter]: https://www.ibm.com/support/knowledgecenter/en/SSTVLU_8.6.1/com.ibm.websphere.extremescale.doc/kc_welcome-xs.html
150
+
151
+[WXS-8.6.1-download]: http://www-01.ibm.com/support/docview.wss?uid=swg24033719
152
+
153
+[WXS-Installation]: https://www.ibm.com/support/knowledgecenter/SSTVLU_8.6.1/com.ibm.websphere.extremescale.doc/txsinstalling.html
154
+
155
+[Passport]: http://www-01.ibm.com/software/passportadvantage/
156
+
157
+[IBM-IM-more-info]: http://www-01.ibm.com/support/docview.wss?uid=swg24038380
158
+
159
+[WXS-download-links]: https://www-947.ibm.com/support/entry/myportal/all_download_links/websphere/websphere_extreme_scale?productContext=-966955061
160
+
161
+[WXS-Support-link]: https://support-pilot.podc.sl.edst.ibm.com/support/home/product/P838994E69185S66/WebSphere_eXtreme_Scale?redir=auto_overlay&redirURL=https:%2F%2Fwww-947.ibm.com%2Fsupport%2Fentry%2Fmyportal%2Fproduct%2Fwebsphere%2Fwebsphere_extreme_scale%3FproductContext%3D-966955061%26redir%3Dno
162
+
163
+[license-info]: http://www-01.ibm.com/common/ssi/cgi-bin/ssialias?htmlfid=897/ENUS212-370&infotype=AN&subtype=CA&appname=wwwsearch#h2-tcx
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,55 @@
 4
+"options":
 5
+  "extra_packages":
 6
+    "description": "Space separated list of extra deb packages to install.\n"
 7
+    "type": "string"
 8
+    "default": ""
 9
+  "package_status":
10
+    "default": "install"
11
+    "type": "string"
12
+    "description": "The status of service-affecting packages will be set to this value\
13
+      \ in the dpkg database. Valid values are \"install\" and \"hold\".\n"
14
+  "install_sources":
15
+    "description": "List of extra apt sources, per charm-helpers standard format (a\
16
+      \ yaml list of strings encoded as a string). Each source may be either a line\
17
+      \ that can be added directly to sources.list(5), or in the form ppa:<user>/<ppa-name>\
18
+      \ for adding Personal Package Archives, or a distribution component to enable.\n"
19
+    "type": "string"
20
+    "default": ""
21
+  "install_keys":
22
+    "description": "List of signing keys for install_sources package sources, per\
23
+      \ charmhelpers standard format (a yaml list of strings encoded as a string).\
24
+      \ The keys should be the full ASCII armoured GPG public keys. While GPG key\
25
+      \ ids are also supported and looked up on a keyserver, operators should be aware\
26
+      \ that this mechanism is insecure. null can be used if a standard package signing\
27
+      \ key is used that will already be installed on the machine, and for PPA sources\
28
+      \ where the package signing key is securely retrieved from Launchpad.\n"
29
+    "type": "string"
30
+    "default": ""
31
+  "curl_url":
32
+    "type": "string"
33
+    "default": ""
34
+    "description": |
35
+      Location of the IBM product installation file(s). This should be a URL
36
+      that curl can use to download files. Multiple URLs should be separated
37
+      by a space. NOTE: cryptographic verification is required and must be
38
+      specified as part of the URL query string with the key a valid hash
39
+      algorithms md5, sha256, or sha512, and the the checksum value itself
40
+      (http://<url>?[md5|sha256|sha512]=<checksum>).
41
+      For example:
42
+        'http://example.com/file.tgz?sha256=<sum>'
43
+        'sftp://example.com/file1.tgz?md5=<sum> ftp://example.com/file2.tgz?md5=<sum>'
44
+  "curl_opts":
45
+    "type": "string"
46
+    "default": ""
47
+    "description": |
48
+      The options passed to the 'curl' command when fetching files from
49
+      curl_url. For example:
50
+        '-u <user:password>'
51
+  "license_accepted":
52
+    "type": "boolean"
53
+    "default": !!bool "false"
54
+    "description": |
55
+      Some IBM charms require acceptance of a license before installation
56
+      can proceed. If required, setting this option to True indicates that you
57
+      have read and accepted the IBM terms and conditions found in the license
58
+      file referenced by the charm.
Back to file index

deps/interface/ibm-wxs/README.md

 1
--- 
 2
+++ deps/interface/ibm-wxs/README.md
 3
@@ -0,0 +1,28 @@
 4
+Overview
 5
+-----------
 6
+
 7
+This interface layer handles the communication between `IBM WXS Catalog` and `IBM WXS Container` or `IBM WXS Catalog` and `IBM WXS Client` charms.
 8
+The provider end of this interface provides the WXS Catalog service. The consumer/Requires part will be the IBM WXS Container and IBM WXS Client, which want the IBM WXS Catalog Server Ip Address and Port information to fetch the Data Grid.
 9
+
10
+
11
+Usage
12
+------
13
+
14
+#### Provides
15
+IBM WXS catalog Server product will provide this interface. This interface layer will set the following states, as appropriate:
16
+
17
+ - `{relation_name}.available`: The relation is established, IBM WXS Catalog is ready to send it's Ip Address and Port information. At this point, the charm waits for Provider charm to send IP Address and port.
18
+	- `set_wxs_catalog_details()` : Sets IP Address and Port of the Catalog Server once the Server started successfully.
19
+
20
+#### Requires
21
+
22
+Consumer charms `IBM WXS Container` and `IBM WXS Client` will require this interface to connect to WXS Catalog so that they can connect to Catalog Server. 
23
+This interface layer will set the following states, as appropriate:
24
+
25
+- `{relation_name}.available` : The consumer charm has been related to a IBM WXS Catalog provider charm. 
26
+- `{relation_name}.ready` : IBM WXS Container or IBM WXS Client is now ready to connect to WXS Catalog to fetch Data Grid. 
27
+	The Http Server charm can access the configuration details using the below methods:
28
+
29
+    - `get_wxs_catalog_port()` - returns the port of the Catalog Server that listens.
30
+    - `get_wxs_catalog_ip()` - returns running ip of the Catalog Server.
31
+   
Back to file index

deps/interface/ibm-wxs/interface.yaml

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

deps/interface/ibm-wxs/provides.py

 1
--- 
 2
+++ deps/interface/ibm-wxs/provides.py
 3
@@ -0,0 +1,73 @@
 4
+from charms.reactive import hook
 5
+from charms.reactive import RelationBase
 6
+from charms.reactive import scopes
 7
+
 8
+
 9
+class WXSProvides(RelationBase):
10
+    # Every unit connecting will get the same information
11
+    scope = scopes.SERVICE
12
+    # convenient way to provide accessor methods
13
+    # auto_accessors = ['wxs_catalog_ip', 'wxs_catalog_port']
14
+
15
+    @hook('{provides:ibm-wxs}-relation-joined')
16
+    def joined(self):
17
+        conversation = self.conversation()
18
+        conversation.set_state('{relation_name}.available')
19
+        print("In joined hook in ibm-wxs interface")
20
+
21
+    @hook('{provides:ibm-wxs}-relation-changed')
22
+    def changed(self):
23
+        conversation = self.conversation()
24
+        conversation.set_state('{relation_name}.available')
25
+        print("In changed hook in ibm-wxs interface")
26
+
27
+    @hook('{provides:ibm-wxs}-relation-departed')
28
+    def departed(self):
29
+        conversation = self.conversation()
30
+        conversation.remove_state('{relation_name}.available')
31
+        print("In departed hook in ibm-wxs interface")
32
+
33
+    def dismiss(self, service):
34
+        conversation = self.conversation(service)
35
+        conversation.remove_state('{relation_name}.available')
36
+        print("In dismissed for service", service)
37
+
38
+    def reset_states(self, service):
39
+        conversation = self.conversation(service)
40
+        conversation.remove_state('{relation_name}.available')
41
+
42
+    def set_wxs_catalog_details(self, service, wxs_catalog_ip,
43
+                                wxs_catalog_port):
44
+        conversation = self.conversation(service)
45
+        print("In set_wxs_catalog_details for service", service)
46
+        conversation.set_remote(data={
47
+            'wxs_catalog_ip': wxs_catalog_ip,
48
+            'wxs_catalog_port': wxs_catalog_port
49
+        })
50
+
51
+    #    def wxs_catalog_ip(self):
52
+    #    """
53
+    #    Return a list of services requesting databases.
54
+    #    """
55
+    #    wxs_catalog_ip = []
56
+    #    for conversation in self.conversations():
57
+    #        wxs_catalog_ip.append(conversation.scope)
58
+    #    return wxs_catalog_ip
59
+#
60
+#    def wxs_catalog_port(self):
61
+#        """
62
+#        Return a list of services requesting databases.
63
+#        """
64
+#        wxs_catalog_port = []
65
+#        for conversation in self.conversations():
66
+#            wxs_catalog_port.append(conversation.scope)
67
+#        return wxs_catalog_port
68
+
69
+    def services(self):
70
+        """
71
+        Return a list of services requesting Catalog.
72
+        """
73
+        service = []
74
+        for conversation in self.conversations():
75
+            service.append(conversation.scope)
76
+        return service
Back to file index

deps/interface/ibm-wxs/requires.py

 1
--- 
 2
+++ deps/interface/ibm-wxs/requires.py
 3
@@ -0,0 +1,43 @@
 4
+# Licensed under the Apache License, Version 2.0 (the "License");
 5
+# you may not use this file except in compliance with the License.
 6
+# You may obtain a copy of the License at
 7
+#
 8
+#     http://www.apache.org/licenses/LICENSE-2.0
 9
+#
10
+# Unless required by applicable law or agreed to in writing, software
11
+# distributed under the License is distributed on an "AS IS" BASIS,
12
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+# See the License for the specific language governing permissions and
14
+# limitations under the License.
15
+# from charmhelpers.core import hookenv
16
+from charms.reactive import hook
17
+from charms.reactive import RelationBase
18
+from charms.reactive import scopes
19
+
20
+
21
+class WXSRequires(RelationBase):
22
+    scope = scopes.GLOBAL
23
+
24
+    auto_accessors = ['wxs_catalog_ip', 'wxs_catalog_port']
25
+
26
+    @hook('{requires:ibm-wxs}-relation-joined')
27
+    def joined(self):
28
+        self.set_state('{relation_name}.available')
29
+
30
+    @hook('{requires:ibm-wxs}-relation-changed')
31
+    def changed(self):
32
+        print("Status is ibm-wxs.available in requires")
33
+        if str(self.get_remote('wxs_catalog_port')) != "None":
34
+            self.set_state('{relation_name}.ready')
35
+            print("Status is relation_name.available in requires")
36
+
37
+    @hook('{requires:ibm-wxs}-relation-departed')
38
+    def departed(self):
39
+        self.remove_state('{relation_name}.available')
40
+        self.remove_state('{relation_name}.ready')
41
+
42
+    def get_wxs_catalog_port(self):
43
+        return self.get_remote('wxs_catalog_port')
44
+
45
+    def get_wxs_catalog_ip(self):
46
+        return self.get_remote('wxs_catalog_ip')
Back to file index

deps/layer/basic/.gitignore

1
--- 
2
+++ deps/layer/basic/.gitignore
3
@@ -0,0 +1,5 @@
4
+*.pyc
5
+*~
6
+.ropeproject
7
+.settings
8
+.tox
Back to file index

deps/layer/basic/Makefile

 1
--- 
 2
+++ deps/layer/basic/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

deps/layer/basic/README.md

  1
--- 
  2
+++ deps/layer/basic/README.md
  3
@@ -0,0 +1,238 @@
  4
+# Overview
  5
+[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
  6
+
  7
+This is the base layer for all charms [built using layers][building].  It
  8
+provides all of the standard Juju hooks and runs the
  9
+[charms.reactive.main][charms.reactive] loop for them.  It also bootstraps the
 10
+[charm-helpers][] and [charms.reactive][] libraries and all of their
 11
+dependencies for use by the charm.
 12
+
 13
+# Usage
 14
+
 15
+To create a charm layer using this base layer, you need only include it in
 16
+a `layer.yaml` file:
 17
+
 18
+```yaml
 19
+includes: ['layer:basic']
 20
+```
 21
+
 22
+This will fetch this layer from [interfaces.juju.solutions][] and incorporate
 23
+it into your charm layer.  You can then add handlers under the `reactive/`
 24
+directory.  Note that **any** file under `reactive/` will be expected to
 25
+contain handlers, whether as Python decorated functions or [executables][non-python]
 26
+using the [external handler protocol][].
 27
+
 28
+### Charm Dependencies
 29
+
 30
+Each layer can include a `wheelhouse.txt` file with Python requirement lines.
 31
+For example, this layer's `wheelhouse.txt` includes:
 32
+
 33
+```
 34
+pip>=7.0.0,<8.0.0
 35
+charmhelpers>=0.4.0,<1.0.0
 36
+charms.reactive>=0.1.0,<2.0.0
 37
+```
 38
+
 39
+All of these dependencies from each layer will be fetched (and updated) at build
 40
+time and will be automatically installed by this base layer before any reactive
 41
+handlers are run.
 42
+
 43
+Note that the `wheelhouse.txt` file is intended for **charm** dependencies only.
 44
+That is, for libraries that the charm code itself needs to do its job of deploying
 45
+and configuring the payload.  If the payload itself has Python dependencies, those
 46
+should be handled separately, by the charm.
 47
+
 48
+See [PyPI][pypi charms.X] for packages under the `charms.` namespace which might
 49
+be useful for your charm.
 50
+
 51
+### Layer Namespace
 52
+
 53
+Each layer has a reserved section in the `charms.layer.` Python package namespace,
 54
+which it can populate by including a `lib/charms/layer/<layer-name>.py` file or
 55
+by placing files under `lib/charms/layer/<layer-name>/`.  (If the layer name
 56
+includes hyphens, replace them with underscores.)  These can be helpers that the
 57
+layer uses internally, or it can expose classes or functions to be used by other
 58
+layers to interact with that layer.
 59
+
 60
+For example, a layer named `foo` could include a `lib/charms/layer/foo.py` file
 61
+with some helper functions that other layers could access using:
 62
+
 63
+```python
 64
+from charms.layer.foo import my_helper
 65
+```
 66
+
 67
+### Layer Options
 68
+
 69
+Any layer can define options in its `layer.yaml`.  Those options can then be set
 70
+by other layers to change the behavior of your layer.  The options are defined
 71
+using [jsonschema][], which is the same way that [action paramters][] are defined.
 72
+
 73
+For example, the `foo` layer could include the following option definitons:
 74
+
 75
+```yaml
 76
+includes: ['layer:basic']
 77
+defines:  # define some options for this layer (the layer "foo")
 78
+  enable-bar:  # define an "enable-bar" option for this layer
 79
+    description: If true, enable support for "bar".
 80
+    type: boolean
 81
+    default: false
 82
+```
 83
+
 84
+A layer using `foo` could then set it:
 85
+
 86
+```yaml
 87
+includes: ['layer:foo']
 88
+options:
 89
+  foo:  # setting options for the "foo" layer
 90
+    enable-bar: true  # set the "enable-bar" option to true
 91
+```
 92
+
 93
+The `foo` layer can then use the `charms.layer.options` helper to load the values
 94
+for the options that it defined.  For example:
 95
+
 96
+```python
 97
+from charms import layer
 98
+
 99
+@when('state')
100
+def do_thing():
101
+  layer_opts = layer.options('foo')  # load all of the options for the "foo" layer
102
+  if layer_opts['enable-bar']:  # check the value of the "enable-bar" option
103
+      hookenv.log("Bar is enabled")
104
+```
105
+
106
+You can also access layer options in other handlers, such as Bash, using
107
+the command-line interface:
108
+
109
+```bash
110
+. charms.reactive.sh
111
+
112
+@when 'state'
113
+function do_thing() {
114
+    if layer_option foo enable-bar; then
115
+        juju-log "Bar is enabled"
116
+        juju-log "bar-value is: $(layer_option foo bar-value)"
117
+    fi
118
+}
119
+
120
+reactive_handler_main
121
+```
122
+
123
+Note that options of type `boolean` will set the exit code, while other types
124
+will be printed out.
125
+
126
+# Hooks
127
+
128
+This layer provides hooks that other layers can react to using the decorators
129
+of the [charms.reactive][] library:
130
+
131
+  * `config-changed`
132
+  * `install`
133
+  * `leader-elected`
134
+  * `leader-settings-changed`
135
+  * `start`
136
+  * `stop`
137
+  * `upgrade-charm`
138
+  * `update-status`
139
+
140
+Other hooks are not implemented at this time. A new layer can implement storage
141
+or relation hooks in their own layer by putting them in the `hooks` directory.
142
+
143
+**Note:** Because `update-status` is invoked every 5 minutes, you should take
144
+care to ensure that your reactive handlers only invoke expensive operations
145
+when absolutely necessary.  It is recommended that you use helpers like
146
+[`@only_once`][], [`@when_file_changed`][], and [`data_changed`][] to ensure
147
+that handlers run only when necessary.
148
+
149
+# Layer Configuration
150
+
151
+This layer supports the following options, which can be set in `layer.yaml`:
152
+
153
+  * **packages**  A list of system packages to be installed before the reactive
154
+    handlers are invoked.
155
+
156
+  * **use_venv**  If set to true, the charm dependencies from the various
157
+    layers' `wheelhouse.txt` files will be installed in a Python virtualenv
158
+    located at `$CHARM_DIR/../.venv`.  This keeps charm dependencies from
159
+    conflicting with payload dependencies, but you must take care to preserve
160
+    the environment and interpreter if using `execl` or `subprocess`.
161
+
162
+  * **include_system_packages**  If set to true and using a venv, include
163
+    the `--system-site-packages` options to make system Python libraries
164
+    visible within the venv.
165
+
166
+An example `layer.yaml` using these options might be:
167
+
168
+```yaml
169
+includes: ['layer:basic']
170
+options:
171
+  basic:
172
+    packages: ['git']
173
+    use_venv: true
174
+    include_system_packages: true
175
+```
176
+
177
+
178
+# Reactive States
179
+
180
+This layer will set the following states:
181
+
182
+  * **`config.changed`**  Any config option has changed from its previous value.
183
+    This state is cleared automatically at the end of each hook invocation.
184
+
185
+  * **`config.changed.<option>`** A specific config option has changed.
186
+    **`<option>`** will be replaced by the config option name from `config.yaml`.
187
+    This state is cleared automatically at the end of each hook invocation.
188
+
189
+  * **`config.set.<option>`** A specific config option has a True or non-empty
190
+    value set.  **`<option>`** will be replaced by the config option name from
191
+    `config.yaml`.  This state is cleared automatically at the end of each hook
192
+    invocation.
193
+
194
+  * **`config.default.<option>`** A specific config option is set to its
195
+    default value.  **`<option>`** will be replaced by the config option name
196
+    from `config.yaml`.  This state is cleared automatically at the end of
197
+    each hook invocation.
198
+
199
+An example using the config states would be:
200
+
201
+```python
202
+@when('config.changed.my-opt')
203
+def my_opt_changed():
204
+    update_config()
205
+    restart_service()
206
+```
207
+
208
+
209
+# Actions
210
+
211
+This layer currently does not define any actions.
212
+
213
+# Exec.d Support
214
+
215
+This is a mechanism used to customize provisioned machines so the charms can
216
+actually work. This is useful if there are pre-conditions in your cloud that
217
+you must account for, such as charm pre-requisits (pre-reactive install) or
218
+environment customization.
219
+
220
+The feature implementation documented this as the following:
221
+
222
+> Your apt-get install isn't going to work until your bonded
223
+network has been configured and connected to the right vlan, the beta firmware 
224
+loaded and injected with ipsec keys so it can pull packages from the proxy
225
+discovered by avahi. At which point the charms.reactive framework can be
226
+imported and kicked off.
227
+
228
+
229
+
230
+[building]: https://jujucharms.com/docs/devel/authors-charm-building
231
+[charm-helpers]: https://pythonhosted.org/charmhelpers/
232
+[charms.reactive]: https://pythonhosted.org/charms.reactive/
233
+[interfaces.juju.solutions]: http://interfaces.juju.solutions/
234
+[non-python]: https://pythonhosted.org/charms.reactive/#non-python-reactive-handlers
235
+[external handler protocol]: https://pythonhosted.org/charms.reactive/charms.reactive.bus.html#charms.reactive.bus.ExternalHandler
236
+[jsonschema]: http://json-schema.org/
237
+[action paramters]: https://jujucharms.com/docs/stable/authors-charm-actions
238
+[pypi charms.X]: https://pypi.python.org/pypi?%3Aaction=search&term=charms.&submit=search
239
+[`@only_once`]: https://pythonhosted.org/charms.reactive/charms.reactive.decorators.html#charms.reactive.decorators.only_once
240
+[`@when_file_changed`]: https://pythonhosted.org/charms.reactive/charms.reactive.decorators.html#charms.reactive.decorators.when_file_changed
241
+[`data_changed`]: https://pythonhosted.org/charms.reactive/charms.reactive.helpers.html#charms.reactive.helpers.data_changed
Back to file index

deps/layer/basic/bin/layer_option

 1
--- 
 2
+++ deps/layer/basic/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

deps/layer/basic/copyright

 1
--- 
 2
+++ deps/layer/basic/copyright
 3
@@ -0,0 +1,16 @@
 4
+Format: http://dep.debian.net/deps/dep5/
 5
+
 6
+Files: *
 7
+Copyright: Copyright 2015-2017, Canonical Ltd., All Rights Reserved.
 8
+License: Apache License 2.0
 9
+ Licensed under the Apache License, Version 2.0 (the "License");
10
+ you may not use this file except in compliance with the License.
11
+ You may obtain a copy of the License at
12
+ .
13
+     http://www.apache.org/licenses/LICENSE-2.0
14
+ .
15
+ Unless required by applicable law or agreed to in writing, software
16
+ distributed under the License is distributed on an "AS IS" BASIS,
17
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18
+ See the License for the specific language governing permissions and
19
+ limitations under the License.
Back to file index

deps/layer/basic/hooks/config-changed

 1
--- 
 2
+++ deps/layer/basic/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

deps/layer/basic/hooks/hook.template

 1
--- 
 2
+++ deps/layer/basic/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

deps/layer/basic/hooks/install

 1
--- 
 2
+++ deps/layer/basic/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

deps/layer/basic/hooks/leader-elected

 1
--- 
 2
+++ deps/layer/basic/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

deps/layer/basic/hooks/leader-settings-changed

 1
--- 
 2
+++ deps/layer/basic/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

deps/layer/basic/hooks/start

 1
--- 
 2
+++ deps/layer/basic/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

deps/layer/basic/hooks/stop

 1
--- 
 2
+++ deps/layer/basic/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

deps/layer/basic/hooks/update-status

 1
--- 
 2
+++ deps/layer/basic/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

deps/layer/basic/hooks/upgrade-charm

 1
--- 
 2
+++ deps/layer/basic/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

deps/layer/basic/layer.yaml

 1
--- 
 2
+++ deps/layer/basic/layer.yaml
 3
@@ -0,0 +1,18 @@
 4
+defines:
 5
+  packages:
 6
+    type: array
 7
+    default: []
 8
+    description: Additional packages to be installed at time of bootstrap
 9
+  use_venv:
10
+    type: boolean
11
+    default: false
12
+    description: >
13
+      Install charm dependencies (wheelhouse) into a Python virtual environment
14
+      to help avoid conflicts with other charms or libraries on the machine.
15
+  include_system_packages:
16
+    type: boolean
17
+    default: false
18
+    description: >
19
+      If using a virtual environment, allow the venv to see Python packages
20
+      installed at the system level.  This reduces isolation, but is necessary
21
+      to use Python packages installed via apt-get.
Back to file index

deps/layer/basic/lib/charms/layer/__init__.py

 1
--- 
 2
+++ deps/layer/basic/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

deps/layer/basic/lib/charms/layer/basic.py

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

deps/layer/basic/lib/charms/layer/execd.py

  1
--- 
  2
+++ deps/layer/basic/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

deps/layer/basic/metadata.yaml

1
--- 
2
+++ deps/layer/basic/metadata.yaml
3
@@ -0,0 +1 @@
4
+{}
Back to file index

deps/layer/basic/requirements.txt

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

deps/layer/basic/tox.ini

 1
--- 
 2
+++ deps/layer/basic/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
Back to file index

deps/layer/basic/wheelhouse.txt

1
--- 
2
+++ deps/layer/basic/wheelhouse.txt
3
@@ -0,0 +1,3 @@
4
+pip>=7.0.0,<8.2.0
5
+charmhelpers>=0.4.0,<1.0.0
6
+charms.reactive>=0.1.0,<2.0.0
Back to file index

deps/layer/ibm-im/README.md

  1
--- 
  2
+++ deps/layer/ibm-im/README.md
  3
@@ -0,0 +1,119 @@
  4
+# IBM Installation Manager (IM)
  5
+
  6
+IBM Installation Manager (IM) is a single installation program that uses remote
  7
+or local software repositories to install, modify, or update certain IBM
  8
+products.
  9
+
 10
+User guides and security guides to support this release are available for
 11
+online viewing
 12
+[User Guide](http://www.ibm.com/support/knowledgecenter/SSDV2W/im_family_welcome.html).
 13
+
 14
+
 15
+## Prerequisites
 16
+
 17
+This charm makes use of resources, a feature only available in Juju 2.0. During
 18
+deploy or upgrade, you will need to specify the installable package(s)
 19
+required by this charm. Download your licensed IBM Installation Manager
 20
+packages from the [Product Page](http://www-01.ibm.com/support/docview.wss?uid=swg27025142).
 21
+
 22
+### Package for Ubuntu on Z (s390x):
 23
+
 24
+IBM Installation Manager 1.8.5 (`agent.installer.linux.gtk.s390x_1.8.5000.20160506_1125.zip`)
 25
+
 26
+### Package for Ubuntu on AMD64 (x86_64):
 27
+
 28
+IBM Installation Manager 1.8.5 (`agent.installer.linux.gtk.x86_64_1.8.5000.20160506_1125.zip`)
 29
+
 30
+### Package for Ubuntu on Power (ppc64le):
 31
+
 32
+IBM Installation Manager 1.8.5 (`agent.installer.linux.gtk.ppc64le_1.8.5000.20160506_1125.zip`)
 33
+
 34
+## Usage
 35
+
 36
+To use this charm, you must agree to the Terms of Use. You can view the full license
 37
+for `IBM Installation Manager` by visiting the
 38
+[license-info](http://www-03.ibm.com/software/sla/sladb.nsf/displaylis/39AFC1C1D485C4E085257E7300548B05?OpenDocument)
 39
+page.
 40
+
 41
+Search for "IBM Installation Manager" and choose the license that applies to
 42
+the version you are using.
 43
+
 44
+### Deploy
 45
+
 46
+Run the following commands to deploy this charm:
 47
+
 48
+    juju deploy ibm-im --resource ibm_im_installer=</path/to/installer.zip>
 49
+
 50
+**Note**: This charm requires acceptance of Terms of Use. When deploying from
 51
+the Charm Store, these terms will be presented to you for your consideration.
 52
+To accept the terms:
 53
+
 54
+    juju agree ibmcharmers/ibm-im/1
 55
+
 56
+### Upgrade
 57
+
 58
+Once deployed, users can install fixpacks by upgrading the charm:
 59
+
 60
+    juju attach ibm-im ibm_im_fixpack=</path/to/fixpack.zip>
 61
+
 62
+### Verification
 63
+
 64
+Once deployed, you can use IBM IM to install any IBM products. To verify IM is
 65
+installed, list the contents of the installation directory:
 66
+
 67
+    juju run --application ibm-im 'ls /opt/IBM/InstallationManager'
 68
+
 69
+
 70
+## Additional information
 71
+
 72
+### General
 73
+
 74
+Details about IBM Installation Manager are available
 75
+[here](http://www.ibm.com/support/knowledgecenter/SSDV2W/im_family_welcome.html).
 76
+
 77
+### Download
 78
+
 79
+Information on procuring IBM IM product is available at the
 80
+[Product Page](http://www-01.ibm.com/support/docview.wss?uid=swg27025142).
 81
+
 82
+### License
 83
+
 84
+License information for IBM IM can be viewed
 85
+[here](http://www-03.ibm.com/software/sla/sladb.nsf/searchlis/?searchview&searchorder=4&searchmax=0&query=%28Installation+Manager+1.8.3%29).
 86
+
 87
+### Developers
 88
+
 89
+This layer is intended to be extended by other charms that would benefit from
 90
+having IBM Installation Manager (IBM IM) preinstalled. For example, a WebSphere
 91
+layered charm could include this layer so it could use IBM IM to install
 92
+WebSphere.
 93
+
 94
+To use this layer, include the following in your `layer.yaml`:
 95
+
 96
+```yaml
 97
+includes: ['layer:ibm-im']
 98
+```
 99
+
100
+Then in your charm, watch for the `ibm-im.installed` state, at which point you
101
+will know the IBM IM tools are available:
102
+
103
+```sh
104
+IM_PATH=/opt/IBM/InstallationManager
105
+
106
+@when 'ibm-im.installed'
107
+install_was() {
108
+  WAS_REPO=`config-get was_repo`
109
+  ${IM_PATH}/tools/imutilsc saveCredential -url $WAS_REPO -userName $IBM_ID_NAME -userPassword $IBM_ID_PASS -secureStorageFile "secure.store"
110
+  ${IM_PATH}/installc -input silent-install.xml -acceptlicense -secureStorageFile "secure.store"
111
+  ${IM_PATH}/imcl install $IM_ARGS
112
+}
113
+```
114
+
115
+## Known Limitations
116
+
117
+This charm makes use of Juju features that are only available in version 2.0 or
118
+greater.
119
+
120
+## Contact Information
121
+
122
+For issues with this charm, please contact [IBM Juju Support Team](mailto:jujusupp@us.ibm.com)
Back to file index

deps/layer/ibm-im/copyright

 1
--- 
 2
+++ deps/layer/ibm-im/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

deps/layer/ibm-im/icon.svg

 1
--- 
 2
+++ deps/layer/ibm-im/icon.svg
 3
@@ -0,0 +1,29 @@
 4
+<?xml version="1.0" encoding="UTF-8"?>
 5
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
 6
+<!-- Creator: CorelDRAW X6 -->
 7
+<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" width="1in" height="0.999996in" version="1.1" shape-rendering="geometricPrecision" text-rendering="geometricPrecision" image-rendering="optimizeQuality" fill-rule="evenodd" clip-rule="evenodd"
 8
+viewBox="0 0 1000 1000"
 9
+ xmlns:xlink="http://www.w3.org/1999/xlink">
10
+ <defs>
11
+    <linearGradient id="id0" gradientUnits="userSpaceOnUse" x1="500.002" y1="999.996" x2="500.002" y2="0">
12
+     <stop offset="0" stop-color="#B8471D"/>
13
+     <stop offset="1" stop-color="#DE731E"/>
14
+    </linearGradient>
15
+    <mask id="id1">
16
+      <linearGradient id="id2" gradientUnits="userSpaceOnUse" x1="500.002" y1="58.4805" x2="500.002" y2="307.017">
17
+       <stop offset="0" stop-opacity="1" stop-color="white"/>
18
+       <stop offset="0.141176" stop-opacity="62.7412" stop-color="white"/>
19
+       <stop offset="1" stop-opacity="0" stop-color="white"/>
20
+      </linearGradient>
21
+     <rect fill="url(#id2)" width="1000" height="365"/>
22
+    </mask>
23
+ </defs>
24
+ <g id="Layer_x0020_1">
25
+  <metadata id="CorelCorpID_0Corel-Layer"/>
26
+  <g id="_1038852160">
27
+   <path id="Background" fill="url(#id0)" d="M0 676l0 -352c0,-283 41,-324 324,-324l352 0c284,0 324,41 324,324l0 352c0,283 -40,324 -324,324l-352 0c-283,0 -324,-41 -324,-324z"/>
28
+   <path fill="#999999" mask="url(#id1)" d="M0 365l0 -41c0,-283 41,-324 324,-324l352 0c284,0 324,41 324,324l0 41c0,-283 -40,-324 -324,-324l-352 0c-283,0 -324,41 -324,324z"/>
29
+   <path fill="white" d="M236 434l89 0 0 401 -89 0 0 -401zm-7 -70c33,-12 66,-22 100,-30 56,-12 114,-18 171,-18 57,0 115,6 171,18 34,8 67,18 100,30l-29 34c-26,-9 -53,-16 -80,-22 -53,-12 -107,-18 -162,-18 -55,0 -109,6 -162,18 -27,6 -54,13 -80,22l-29 -34zm-99 -123c54,-23 109,-41 167,-53 67,-15 135,-23 203,-23 68,0 137,8 203,23 58,12 113,30 167,53l-28 35c-48,-20 -97,-36 -148,-47 -63,-14 -128,-21 -194,-21 -66,0 -131,7 -194,21 -51,11 -100,27 -148,47l-28 -35zm49 61c44,-17 88,-31 134,-41 61,-14 124,-20 187,-20 63,0 126,6 187,20 46,10 90,24 134,41l-29 35c-37,-15 -75,-26 -114,-35 -58,-12 -118,-19 -178,-19 -60,0 -120,7 -178,19 -39,9 -77,20 -114,35l-29 -35zm498 132l44 0 45 0 0 401 -89 0 0 -253 -62 84 0 169 -89 0 0 -164 -61 -84 0 248 -89 0 0 -401 44 0 45 0 106 146 106 -146z"/>
30
+  </g>
31
+ </g>
32
+</svg>
Back to file index

deps/layer/ibm-im/layer.yaml

1
--- 
2
+++ deps/layer/ibm-im/layer.yaml
3
@@ -0,0 +1,6 @@
4
+repo: bzr+ssh://bazaar.launchpad.net/~ibmcharmers/ibmlayers/layer-ibm-im
5
+includes: ['layer:basic']
6
+options:
7
+ basic:
8
+  packages:
9
+      - unzip
Back to file index

deps/layer/ibm-im/metadata.yaml

 1
--- 
 2
+++ deps/layer/ibm-im/metadata.yaml
 3
@@ -0,0 +1,24 @@
 4
+name: ibm-im
 5
+summary: IBM Installation Manager
 6
+maintainer: IBM Juju Support Team <jujusupp@us.ibm.com>
 7
+description: |
 8
+  IBM IM is an installation tool that helps install many IBM products.
 9
+tags:
10
+- ibm
11
+- im
12
+- ibm-z
13
+subordinate: false
14
+resources:
15
+  ibm_im_installer:
16
+    type: file
17
+    filename: ibm_im_installer.zip
18
+    description: Installation Manager installer archive
19
+  ibm_im_fixpack:
20
+    type: file
21
+    filename: ibm_im_fixpack.zip
22
+    description: Installation Manager fix pack archive
23
+terms:
24
+  - ibmcharmers/ibm-im/1
25
+series:
26
+  - 'xenial'
27
+  - 'trusty'
Back to file index

deps/layer/ibm-im/reactive/ibm-im.sh

  1
--- 
  2
+++ deps/layer/ibm-im/reactive/ibm-im.sh
  3
@@ -0,0 +1,189 @@
  4
+#!/bin/bash
  5
+set -e
  6
+
  7
+source charms.reactive.sh
  8
+ARCHITECTURE=`uname -m`
  9
+
 10
+# Installation Manager install path
 11
+IM_INSTALL_PATH="/opt/IBM/InstallationManager"
 12
+
 13
+@when_not 'ibm-im.installed'
 14
+function install_ibm_im(){
 15
+      # Fail fast if we're on an unsupported arch
 16
+      if [ "$ARCHITECTURE" != "x86_64" -a  "$ARCHITECTURE" != "ppc64le" -a "$ARCHITECTURE" != "s390x" ]; then
 17
+            juju-log "IBM IM: only supported on x86_64 or ppc64le or s390x platforms"
 18
+            status-set blocked "unsupported architecture"
 19
+            return 1
 20
+      fi
 21
+
 22
+      # Get the installable resource
 23
+      juju-log "IBM IM: fetching the ibm_im_installer resource"
 24
+      status-set maintenance "fetching the ibm_im_installer resource"
 25
+      cfg_im_pkg_name=`resource-get 'ibm_im_installer' || echo unavailable`
 26
+
 27
+      # If we don't have a package, report blocked status; we can't proceed.
 28
+      if [ "$cfg_im_pkg_name" = "unavailable" ]; then
 29
+        juju-log "IBM IM: missing required ibm_im_installer resource"
 30
+        status-set blocked "missing required ibm_im_installer resource"
 31
+        return 0
 32
+      fi
 33
+
 34
+      juju-log "IBM IM: using $cfg_im_pkg_name as the ibm_im_installer resource"
 35
+      ARCHIVE_DIR=`dirname $cfg_im_pkg_name`
 36
+
 37
+      # Extract the installer contents
 38
+      if [ -f  $cfg_im_pkg_name ]; then
 39
+           juju-log "IBM IM: extracting the ibm_im_installer resource"
 40
+           status-set maintenance "extracting the ibm_im_installer resource"
 41
+           if [ -f $ARCHIVE_DIR/userinstc ]; then
 42
+                 juju-log "IBM IM: ibm_im_installer resource already extracted"
 43
+           else
 44
+                 cd $ARCHIVE_DIR
 45
+                 if ! unzip $cfg_im_pkg_name; then
 46
+                      juju-log "IBM IM: Unable to extract the ibm_im_installer resource"
 47
+                      # Remove corrupt archive file
 48
+                      status-set blocked "ibm_im_installer resource is corrupt"
 49
+                      cd -
 50
+                      rm -rf $ARCHIVE_DIR
 51
+                      return 0
 52
+                 else
 53
+                      juju-log "IBM IM: ibm_im_installer resource extracted successfully"
 54
+                 fi
 55
+           fi
 56
+      fi
 57
+
 58
+      # Do the actual IBM IM install
 59
+      if [ -f  $ARCHIVE_DIR/userinstc ]; then
 60
+        juju-log "IBM IM: starting installation."
 61
+        status-set maintenance "installing ibm-im"
 62
+        cp $ARCHIVE_DIR/install.xml $ARCHIVE_DIR/silent_install.xml
 63
+        sed -i "2 a \<profile kind='self' installLocation='$IM_INSTALL_PATH' id='IBM Installation Manager'>\n <data key='eclipseLocation' value='$IM_INSTALL_PATH' />\n</profile>" $ARCHIVE_DIR/silent_install.xml
 64
+        if $ARCHIVE_DIR/userinstc -input $ARCHIVE_DIR/silent_install.xml -acceptlicense; then
 65
+            set_state 'ibm-im.installed'
 66
+            status-set active "ready"
 67
+        else
 68
+            juju-log "IBM IM: error while installing"
 69
+            return 1
 70
+        fi
 71
+      else
 72
+        juju-log "IBM IM: installer was not found."
 73
+        status-set blocked "installation failed"
 74
+        return 1
 75
+      fi
 76
+}
 77
+
 78
+@when 'ibm-im.installed'
 79
+@when_not 'ibm-im.updated'
 80
+function install_ibm_im_fixpack(){
 81
+    # Get the fixpack resource
 82
+    juju-log "IBM IM: fetching the ibm_im_fixpack resource"
 83
+    status-set maintenance "fetching the ibm_im_fixpack resource"
 84
+    ibm_im_fp_package=`resource-get 'ibm_im_fixpack' || echo unavailable`
 85
+
 86
+    # If we don't have a fixpack, just exit successfully; there's nothing to do.
 87
+    if [ "$ibm_im_fp_package" = "unavailable" ]; then
 88
+      juju-log "IBM IM: no ibm_im_fixpack to install"
 89
+      status-set active "ready"
 90
+      return 0
 91
+    fi
 92
+
 93
+    # Currently, there is no way to make a resource optional, so something
 94
+    # must be uploaded to the charm store, even if it's a dummy archive.
 95
+    # If we detect the fixpack is just a placeholder (because we created an
 96
+    # empty placeholder in the store), exit just like we do with a missing
 97
+    # fixpack resource.
 98
+    ibm_im_fp_empty=`file $ibm_im_fp_package | { grep -q empty && echo "True"; } || echo "False"`
 99
+    if [ "$ibm_im_fp_empty" = "True" ]; then
100
+      juju-log "IBM IM: no ibm_im_fixpack to install"
101
+      status-set active "ready"
102
+      return 0
103
+    fi
104
+
105
+    juju-log "IBM IM: using $ibm_im_fp_package as the ibm_im_fixpack resource"
106
+    ARCHIVE_DIR=`dirname $ibm_im_fp_package`
107
+
108
+    # Extract the fixpack contents
109
+    if [ -f $ibm_im_fp_package ]; then
110
+        juju-log "IBM IM: extracting the ibm_im_fixpack resource"
111
+        status-set maintenance "extracting the ibm_im_fixpack resource"
112
+        if [ -f $ARCHIVE_DIR/userinstc ]; then
113
+              juju-log "IBM IM: ibm_im_fixpack resource already extracted"
114
+        else
115
+              cd $ARCHIVE_DIR
116
+              if ! unzip $ibm_im_fp_package; then
117
+                      juju-log "IBM IM: Unable to extract the ibm_im_fixpack resource"
118
+                      # Remove corrupt archive file
119
+                      status-set blocked "ibm_im_fixpack resource is corrupt"
120
+                      cd -
121
+                      rm -rf $ARCHIVE_DIR
122
+                      return 0
123
+              else
124
+                      juju-log "IBM IM: ibm_im_fixpack resource extracted successfully"
125
+              fi
126
+        fi
127
+    fi
128
+
129
+    # Do the actual IBM IM fixpack install
130
+    if [ -f $ARCHIVE_DIR/userinstc ]; then
131
+        juju-log "IBM IM: starting fixpack installation."
132
+        status-set maintenance "installing fixpack"
133
+        cp $ARCHIVE_DIR/install.xml $ARCHIVE_DIR/silent_install.xml
134
+        sed -i "2 a \<profile kind='self' installLocation='$IM_INSTALL_PATH' id='IBM Installation Manager'>\n <data key='eclipseLocation' value='$IM_INSTALL_PATH' />\n</profile>" $ARCHIVE_DIR/silent_install.xml
135
+        if $ARCHIVE_DIR/userinstc -input $ARCHIVE_DIR/silent_install.xml -acceptlicense; then
136
+             set_state 'ibm-im.updated'
137
+             status-set active "ready"
138
+        else
139
+             juju-log "IBM IM: error while installing the fixpack."
140
+             return 1
141
+        fi
142
+    else
143
+        juju-log "IBM_IM: Fix pack installer was not found."
144
+        status-set blocked "fixpack installation failed"
145
+        return 1
146
+   fi
147
+}
148
+
149
+@hook 'upgrade-charm'
150
+function check_fixpack(){
151
+    # The upgrade-charm hook will fire when a new resource is pushed for this
152
+    # charm. This is a good time to determine if we need to deal with a new
153
+    # fixpack.
154
+    if ! charms.reactive is_state 'ibm-im.updated'; then
155
+        # If there is no prior fixpack installed (because ibm-im.updated is not
156
+        # set), do nothing since install-ibm-im-fixpack will handle that case.
157
+        juju-log "IBM IM: no fixpack has been installed; nothing to upgrade."
158
+        return 0
159
+    else
160
+        # If we have a fixpack already (because ibm-im.updated is set),
161
+        # we should fetch the latest fixpack and determine if it is new.
162
+        #  - If it is new, set our states so install-ibm-im-fixpack is called again
163
+        #  - If it is not new, do nothing
164
+        juju-log "IBM IM: scanning for new fixpacks to install"
165
+        ARCHIVE_DIR="$CHARM_DIR/../resources/ibm_im_fixpack"
166
+        CUR_FIXPACK="$ARCHIVE_DIR/ibm_im_fixpack.zip"
167
+
168
+        # Sum any existing fixpack to determine if we have a new one
169
+        if [ -f $CUR_FIXPACK ]; then
170
+            CUR_MD5=`md5sum "$CUR_FIXPACK" | awk '{print $1}'`
171
+            # Calling resource-get here will fetch the fixpack resource.
172
+            NEW_FIXPACK=`resource-get 'ibm_im_fixpack' || echo unavailable`
173
+            if [ "$NEW_FIXPACK" = "unavailable" ]; then
174
+                juju-log "IBM IM: no fixpack to install"
175
+            else
176
+                NEW_MD5=`md5sum "$NEW_FIXPACK" | awk '{print $1}'`
177
+                # If sums don't match, we have a new fp. Configure states so
178
+                # we re-run install-ibm-im-fixpack().
179
+                if [ "$CUR_MD5" != "$NEW_MD5" ]; then
180
+                    juju-log "IBM IM: new fixpack detected ($CUR_FIXPACK with $CUR_MD5 versus $NEW_FIXPACK with $NEW_MD5)"
181
+                    rm -rf $ARCHIVE_DIR
182
+                    remove_state 'ibm-im.updated'
183
+                else
184
+                    juju-log "IBM IM: no new fixpack to install"
185
+                fi
186
+            fi
187
+        fi
188
+    fi
189
+}
190
+
191
+
192
+reactive_handler_main
Back to file index

deps/layer/ibm-im/tests/01-deploy.py

 1
--- 
 2
+++ deps/layer/ibm-im/tests/01-deploy.py
 3
@@ -0,0 +1,30 @@
 4
+#!/usr/bin/env python3
 5
+
 6
+import amulet
 7
+import re
 8
+import unittest
 9
+
10
+
11
+class TestDeploy(unittest.TestCase):
12
+    """
13
+    Deployment test for the IBM IM charm.
14
+
15
+    This charm doesn't do much by itself, so we expect functional
16
+    tests to happen in the charms that use this layer (for example, websphere).
17
+    """
18
+    def setUp(self):
19
+        self.d = amulet.Deployment(series='xenial')
20
+        self.d.add('ibm-im', 'cs:~ibmcharmers/xenial/ibm-im')
21
+        self.d.setup(timeout=900)
22
+        self.d.sentry.wait(timeout=1800)
23
+
24
+    def test_deploy_with_placeholder_resource(self):
25
+        # The status message when using placeholder resources will include the
26
+        # string "ibm_im_installer resource". If we see that, the test is
27
+        # successful.
28
+        sentry_re = re.compile('ibm_im_installer resource')
29
+        self.d.sentry.wait_for_messages({"ibm-im": sentry_re})
30
+
31
+
32
+if __name__ == '__main__':
33
+    unittest.main()
Back to file index

deps/layer/ibm-im/tests/tests.yaml

1
--- 
2
+++ deps/layer/ibm-im/tests/tests.yaml
3
@@ -0,0 +1,4 @@
4
+packages:
5
+  - amulet
6
+  - python3
7
+  - unzip
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/ibm-wxs/README.md

 1
--- 
 2
+++ hooks/relations/ibm-wxs/README.md
 3
@@ -0,0 +1,28 @@
 4
+Overview
 5
+-----------
 6
+
 7
+This interface layer handles the communication between `IBM WXS Catalog` and `IBM WXS Container` or `IBM WXS Catalog` and `IBM WXS Client` charms.
 8
+The provider end of this interface provides the WXS Catalog service. The consumer/Requires part will be the IBM WXS Container and IBM WXS Client, which want the IBM WXS Catalog Server Ip Address and Port information to fetch the Data Grid.
 9
+
10
+
11
+Usage
12
+------
13
+
14
+#### Provides
15
+IBM WXS catalog Server product will provide this interface. This interface layer will set the following states, as appropriate:
16
+
17
+ - `{relation_name}.available`: The relation is established, IBM WXS Catalog is ready to send it's Ip Address and Port information. At this point, the charm waits for Provider charm to send IP Address and port.
18
+	- `set_wxs_catalog_details()` : Sets IP Address and Port of the Catalog Server once the Server started successfully.
19
+
20
+#### Requires
21
+
22
+Consumer charms `IBM WXS Container` and `IBM WXS Client` will require this interface to connect to WXS Catalog so that they can connect to Catalog Server. 
23
+This interface layer will set the following states, as appropriate:
24
+
25
+- `{relation_name}.available` : The consumer charm has been related to a IBM WXS Catalog provider charm. 
26
+- `{relation_name}.ready` : IBM WXS Container or IBM WXS Client is now ready to connect to WXS Catalog to fetch Data Grid. 
27
+	The Http Server charm can access the configuration details using the below methods:
28
+
29
+    - `get_wxs_catalog_port()` - returns the port of the Catalog Server that listens.
30
+    - `get_wxs_catalog_ip()` - returns running ip of the Catalog Server.
31
+   
Back to file index

hooks/relations/ibm-wxs/interface.yaml

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

hooks/relations/ibm-wxs/provides.py

 1
--- 
 2
+++ hooks/relations/ibm-wxs/provides.py
 3
@@ -0,0 +1,73 @@
 4
+from charms.reactive import hook
 5
+from charms.reactive import RelationBase
 6
+from charms.reactive import scopes
 7
+
 8
+
 9
+class WXSProvides(RelationBase):
10
+    # Every unit connecting will get the same information
11
+    scope = scopes.SERVICE
12
+    # convenient way to provide accessor methods
13
+    # auto_accessors = ['wxs_catalog_ip', 'wxs_catalog_port']
14
+
15
+    @hook('{provides:ibm-wxs}-relation-joined')
16
+    def joined(self):
17
+        conversation = self.conversation()
18
+        conversation.set_state('{relation_name}.available')
19
+        print("In joined hook in ibm-wxs interface")
20
+
21
+    @hook('{provides:ibm-wxs}-relation-changed')
22
+    def changed(self):
23
+        conversation = self.conversation()
24
+        conversation.set_state('{relation_name}.available')
25
+        print("In changed hook in ibm-wxs interface")
26
+
27
+    @hook('{provides:ibm-wxs}-relation-departed')
28
+    def departed(self):
29
+        conversation = self.conversation()
30
+        conversation.remove_state('{relation_name}.available')
31
+        print("In departed hook in ibm-wxs interface")
32
+
33
+    def dismiss(self, service):
34
+        conversation = self.conversation(service)
35
+        conversation.remove_state('{relation_name}.available')
36
+        print("In dismissed for service", service)
37
+
38
+    def reset_states(self, service):
39
+        conversation = self.conversation(service)
40
+        conversation.remove_state('{relation_name}.available')
41
+
42
+    def set_wxs_catalog_details(self, service, wxs_catalog_ip,
43
+                                wxs_catalog_port):
44
+        conversation = self.conversation(service)
45
+        print("In set_wxs_catalog_details for service", service)
46
+        conversation.set_remote(data={
47
+            'wxs_catalog_ip': wxs_catalog_ip,
48
+            'wxs_catalog_port': wxs_catalog_port
49
+        })
50
+
51
+    #    def wxs_catalog_ip(self):
52
+    #    """
53
+    #    Return a list of services requesting databases.
54
+    #    """
55
+    #    wxs_catalog_ip = []
56
+    #    for conversation in self.conversations():
57
+    #        wxs_catalog_ip.append(conversation.scope)
58
+    #    return wxs_catalog_ip
59
+#
60
+#    def wxs_catalog_port(self):
61
+#        """
62
+#        Return a list of services requesting databases.
63
+#        """
64
+#        wxs_catalog_port = []
65
+#        for conversation in self.conversations():
66
+#            wxs_catalog_port.append(conversation.scope)
67
+#        return wxs_catalog_port
68
+
69
+    def services(self):
70
+        """
71
+        Return a list of services requesting Catalog.
72
+        """
73
+        service = []
74
+        for conversation in self.conversations():
75
+            service.append(conversation.scope)
76
+        return service
Back to file index

hooks/relations/ibm-wxs/requires.py

 1
--- 
 2
+++ hooks/relations/ibm-wxs/requires.py
 3
@@ -0,0 +1,43 @@
 4
+# Licensed under the Apache License, Version 2.0 (the "License");
 5
+# you may not use this file except in compliance with the License.
 6
+# You may obtain a copy of the License at
 7
+#
 8
+#     http://www.apache.org/licenses/LICENSE-2.0
 9
+#
10
+# Unless required by applicable law or agreed to in writing, software
11
+# distributed under the License is distributed on an "AS IS" BASIS,
12
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+# See the License for the specific language governing permissions and
14
+# limitations under the License.
15
+# from charmhelpers.core import hookenv
16
+from charms.reactive import hook
17
+from charms.reactive import RelationBase
18
+from charms.reactive import scopes
19
+
20
+
21
+class WXSRequires(RelationBase):
22
+    scope = scopes.GLOBAL
23
+
24
+    auto_accessors = ['wxs_catalog_ip', 'wxs_catalog_port']
25
+
26
+    @hook('{requires:ibm-wxs}-relation-joined')
27
+    def joined(self):
28
+        self.set_state('{relation_name}.available')
29
+
30
+    @hook('{requires:ibm-wxs}-relation-changed')
31
+    def changed(self):
32
+        print("Status is ibm-wxs.available in requires")
33
+        if str(self.get_remote('wxs_catalog_port')) != "None":
34
+            self.set_state('{relation_name}.ready')
35
+            print("Status is relation_name.available in requires")
36
+
37
+    @hook('{requires:ibm-wxs}-relation-departed')
38
+    def departed(self):
39
+        self.remove_state('{relation_name}.available')
40
+        self.remove_state('{relation_name}.ready')
41
+
42
+    def get_wxs_catalog_port(self):
43
+        return self.get_remote('wxs_catalog_port')
44
+
45
+    def get_wxs_catalog_ip(self):
46
+        return self.get_remote('wxs_catalog_ip')
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/wxsgrid-relation-broken

 1
--- 
 2
+++ hooks/wxsgrid-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/wxsgrid-relation-changed

 1
--- 
 2
+++ hooks/wxsgrid-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/wxsgrid-relation-departed

 1
--- 
 2
+++ hooks/wxsgrid-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/wxsgrid-relation-joined

 1
--- 
 2
+++ hooks/wxsgrid-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,40 @@
 4
+<?xml version="1.0" encoding="UTF-8"?>
 5
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
 6
+<!-- Creator: CorelDRAW X6 -->
 7
+<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" width="1in" height="0.999996in" version="1.1" shape-rendering="geometricPrecision" text-rendering="geometricPrecision" image-rendering="optimizeQuality" fill-rule="evenodd" clip-rule="evenodd"
 8
+viewBox="0 0 1000 1000"
 9
+ xmlns:xlink="http://www.w3.org/1999/xlink">
10
+ <defs>
11
+    <linearGradient id="id0" gradientUnits="userSpaceOnUse" x1="500.002" y1="999.996" x2="500.002" y2="0">
12
+     <stop offset="0" stop-color="#0465B2"/>
13
+     <stop offset="1" stop-color="#7ED3F7"/>
14
+    </linearGradient>
15
+    <mask id="id1">
16
+      <linearGradient id="id2" gradientUnits="userSpaceOnUse" x1="500.002" y1="58.4805" x2="500.002" y2="307.017">
17
+       <stop offset="0" stop-opacity="1" stop-color="white"/>
18
+       <stop offset="0.141176" stop-opacity="48.6863" stop-color="white"/>
19
+       <stop offset="1" stop-opacity="0" stop-color="white"/>
20
+      </linearGradient>
21
+     <rect fill="url(#id2)" width="1000" height="365"/>
22
+    </mask>
23
+    <radialGradient id="id3" gradientUnits="userSpaceOnUse" cx="613.782" cy="372.832" r="261.194" fx="613.782" fy="372.832">
24
+     <stop offset="0" stop-color="#7ED3F7"/>
25
+     <stop offset="1" stop-color="#0465B2"/>
26
+    </radialGradient>
27
+    <radialGradient id="id4" gradientUnits="userSpaceOnUse" cx="613.782" cy="372.832" r="261.194" fx="613.782" fy="372.832">
28
+     <stop offset="0" stop-color="#0465B2"/>
29
+     <stop offset="1" stop-color="#07425A"/>
30
+    </radialGradient>
31
+ </defs>
32
+ <g id="Layer_x0020_1">
33
+  <metadata id="CorelCorpID_0Corel-Layer"/>
34
+  <g id="_927323728">
35
+   <path id="Background" fill="url(#id0)" d="M0 676l0 -352c0,-283 41,-324 324,-324l352 0c284,0 324,41 324,324l0 352c0,283 -40,324 -324,324l-352 0c-283,0 -324,-41 -324,-324z"/>
36
+   <path fill="#999999" mask="url(#id1)" d="M0 365l0 -41c0,-283 41,-324 324,-324l352 0c284,0 324,41 324,324l0 41c0,-283 -40,-324 -324,-324l-352 0c-283,0 -324,41 -324,324z"/>
37
+   <path fill="#7ED3F7" fill-rule="nonzero" d="M500 126c103,0 197,42 264,110 68,67 110,161 110,264 0,103 -42,197 -110,264 -67,68 -161,110 -264,110 -103,0 -197,-42 -264,-110 -68,-67 -110,-161 -110,-264 0,-103 42,-197 110,-264 67,-68 161,-110 264,-110zm237 137c-61,-60 -145,-98 -237,-98 -92,0 -176,38 -237,98 -60,61 -98,145 -98,237 0,92 38,176 98,237 61,60 145,98 237,98 92,0 176,-38 237,-98 60,-61 98,-145 98,-237 0,-92 -38,-176 -98,-237z"/>
38
+   <circle fill="url(#id3)" cx="500" cy="500" r="335"/>
39
+   <circle fill="url(#id4)" cx="500" cy="500" r="335"/>
40
+   <polygon fill="#C9EFFF" fill-rule="nonzero" points="616,687 559,687 500,479 442,687 386,687 311,422 279,422 279,372 407,372 407,422 373,422 418,588 474,372 525,372 586,586 628,422 593,422 593,372 721,372 721,422 686,422 "/>
41
+  </g>
42
+ </g>
43
+</svg>
Back to file index

layer.yaml

 1
--- 
 2
+++ layer.yaml
 3
@@ -0,0 +1,24 @@
 4
+"options":
 5
+  "basic":
 6
+    "packages":
 7
+    - "curl"
 8
+    - "unzip"
 9
+    "use_venv": !!bool "false"
10
+    "include_system_packages": !!bool "false"
11
+  "ibm-im":
12
+    "silent": !!bool "true"
13
+  "ibm-wxs-container": {}
14
+  "apt":
15
+    "version_package": ""
16
+    "packages": []
17
+    "full_version": !!bool "false"
18
+  "leadership": {}
19
+  "ibm-base": {}
20
+"includes":
21
+- "layer:basic"
22
+- "layer:apt"
23
+- "layer:leadership"
24
+- "layer:ibm-base"
25
+- "layer:ibm-im"
26
+- "interface:ibm-wxs"
27
+"is": "ibm-wxs-container"
Back to file index

lib/charms/__init__.py

1
--- 
2
+++ lib/charms/__init__.py
3
@@ -0,0 +1,2 @@
4
+from pkgutil import extend_path
5
+__path__ = extend_path(__path__, __name__)
Back to file index

lib/charms/apt.py

  1
--- 
  2
+++ lib/charms/apt.py
  3
@@ -0,0 +1,217 @@
  4
+# Copyright 2015-2016 Canonical Ltd.
  5
+#
  6
+# This file is part of the Apt layer for Juju.
  7
+#
  8
+# This program is free software: you can redistribute it and/or modify
  9
+# it under the terms of the GNU General Public License version 3, as
 10
+# published by the Free Software Foundation.
 11
+#
 12
+# This program is distributed in the hope that it will be useful, but
 13
+# WITHOUT ANY WARRANTY; without even the implied warranties of
 14
+# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
 15
+# PURPOSE.  See the GNU General Public License for more details.
 16
+#
 17
+# You should have received a copy of the GNU General Public License
 18
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 19
+
 20
+'''
 21
+charms.reactive helpers for dealing with deb packages.
 22
+
 23
+Add apt package sources using add_source(). Queue deb packages for
 24
+installation with install(). Configure and work with your software
 25
+once the apt.installed.{packagename} state is set.
 26
+'''
 27
+import itertools
 28
+import re
 29
+import subprocess
 30
+
 31
+from charmhelpers import fetch
 32
+from charmhelpers.core import hookenv, unitdata
 33
+from charms import layer, reactive
 34
+
 35
+
 36
+__all__ = ['add_source', 'update', 'queue_install', 'install_queued',
 37
+           'installed', 'purge', 'ensure_package_status']
 38
+
 39
+
 40
+def add_source(source, key=None):
 41
+    '''Add an apt source.
 42
+
 43
+    Sets the apt.needs_update state.
 44
+
 45
+    A source may be either a line that can be added directly to
 46
+    sources.list(5), or in the form ppa:<user>/<ppa-name> for adding
 47
+    Personal Package Archives, or a distribution component to enable.
 48
+
 49
+    The package signing key should be an ASCII armoured GPG key. While
 50
+    GPG key ids are also supported, the retrieval mechanism is insecure.
 51
+    There is no need to specify the package signing key for PPAs or for
 52
+    the main Ubuntu archives.
 53
+    '''
 54
+    # Maybe we should remember which sources have been added already
 55
+    # so we don't waste time re-adding them. Is this time significant?
 56
+    fetch.add_source(source, key)
 57
+    reactive.set_state('apt.needs_update')
 58
+
 59
+
 60
+def queue_install(packages, options=None):
 61
+    """Queue one or more deb packages for install.
 62
+
 63
+    The `apt.installed.{name}` state is set once the package is installed.
 64
+
 65
+    If a package has already been installed it will not be reinstalled.
 66
+
 67
+    If a package has already been queued it will not be requeued, and
 68
+    the install options will not be changed.
 69
+
 70
+    Sets the apt.queued_installs state.
 71
+    """
 72
+    if isinstance(packages, str):
 73
+        packages = [packages]
 74
+    # Filter installed packages.
 75
+    store = unitdata.kv()
 76
+    queued_packages = store.getrange('apt.install_queue.', strip=True)
 77
+    packages = {package: options for package in packages
 78
+                if not (package in queued_packages or
 79
+                        reactive.helpers.is_state('apt.installed.' + package))}
 80
+    if packages:
 81
+        unitdata.kv().update(packages, prefix='apt.install_queue.')
 82
+        reactive.set_state('apt.queued_installs')
 83
+
 84
+
 85
+def installed():
 86
+    '''Return the set of deb packages completed install'''
 87
+    return set(state.split('.', 2)[2] for state in reactive.bus.get_states()
 88
+               if state.startswith('apt.installed.'))
 89
+
 90
+
 91
+def purge(packages):
 92
+    """Purge one or more deb packages from the system"""
 93
+    fetch.apt_purge(packages, fatal=True)
 94
+    store = unitdata.kv()
 95
+    store.unsetrange(packages, prefix='apt.install_queue.')
 96
+    for package in packages:
 97
+        reactive.remove_state('apt.installed.{}'.format(package))
 98
+
 99
+
100
+def update():
101
+    """Update the apt cache.
102
+
103
+    Removes the apt.needs_update state.
104
+    """
105
+    status_set(None, 'Updating apt cache')
106
+    fetch.apt_update(fatal=True)  # Friends don't let friends set fatal=False
107
+    reactive.remove_state('apt.needs_update')
108
+
109
+
110
+def install_queued():
111
+    '''Installs queued deb packages.
112
+
113
+    Removes the apt.queued_installs state and sets the apt.installed state.
114
+
115
+    On failure, sets the unit's workload state to 'blocked' and returns
116
+    False. Package installs remain queued.
117
+
118
+    On success, sets the apt.installed.{packagename} state for each
119
+    installed package and returns True.
120
+    '''
121
+    store = unitdata.kv()
122
+    queue = sorted((options, package)
123
+                   for package, options in store.getrange('apt.install_queue.',
124
+                                                          strip=True).items())
125
+
126
+    installed = set()
127
+    for options, batch in itertools.groupby(queue, lambda x: x[0]):
128
+        packages = [b[1] for b in batch]
129
+        try:
130
+            status_set(None, 'Installing {}'.format(','.join(packages)))
131
+            fetch.apt_install(packages, options, fatal=True)
132
+            store.unsetrange(packages, prefix='apt.install_queue.')
133
+            installed.update(packages)
134
+        except subprocess.CalledProcessError:
135
+            status_set('blocked',
136
+                       'Unable to install packages {}'
137
+                       .format(','.join(packages)))
138
+            return False  # Without setting reactive state.
139
+
140
+    for package in installed:
141
+        reactive.set_state('apt.installed.{}'.format(package))
142
+    reactive.remove_state('apt.queued_installs')
143
+
144
+    reset_application_version()
145
+
146
+    return True
147
+
148
+
149
+def get_package_version(package, full_version=False):
150
+    '''Return the version of an installed package.
151
+
152
+    If `full_version` is True, returns the full Debian package version.
153
+    Otherwise, returns the shorter 'upstream' version number.
154
+    '''
155
+    # Don't use fetch.get_upstream_version, as it depends on python-apt
156
+    # and not available if the basic layer's use_site_packages option is off.
157
+    cmd = ['dpkg-query', '--show', r'--showformat=${Version}\n', package]
158
+    full = subprocess.check_output(cmd, universal_newlines=True).strip()
159
+    if not full_version:
160
+        # Attempt to strip off Debian style metadata from the end of the
161
+        # version number.
162
+        m = re.search('^([\d.a-z]+)', full, re.I)
163
+        if m is not None:
164
+            return m.group(1)
165
+    return full
166
+
167
+
168
+def reset_application_version():
169
+    '''Set the Juju application version, per settings in layer.yaml'''
170
+    # Reset the application version. We call this after installing
171
+    # packages to initialize the version. We also call this every
172
+    # hook, incase the version has changed (eg. Landscape upgraded
173
+    # the package).
174
+    opts = layer.options().get('apt', {})
175
+    pkg = opts.get('version_package')
176
+    if pkg and pkg in installed():
177
+        ver = get_package_version(pkg, opts.get('full_version', False))
178
+        hookenv.application_version_set(ver)
179
+
180
+
181
+def ensure_package_status():
182
+    '''Hold or unhold packages per the package_status configuration option.
183
+
184
+    All packages installed using this module and handlers are affected.
185
+
186
+    An mechanism may be added in the future to override this for a
187
+    subset of installed packages.
188
+    '''
189
+    packages = installed()
190
+    if not packages:
191
+        return
192
+    config = hookenv.config()
193
+    package_status = config.get('package_status') or ''
194
+    changed = reactive.helpers.data_changed('apt.package_status',
195
+                                            (package_status, sorted(packages)))
196
+    if changed:
197
+        if package_status == 'hold':
198
+            hookenv.log('Holding packages {}'.format(','.join(packages)))
199
+            fetch.apt_hold(packages)
200
+        else:
201
+            hookenv.log('Unholding packages {}'.format(','.join(packages)))
202
+            fetch.apt_unhold(packages)
203
+    reactive.remove_state('apt.needs_hold')
204
+
205
+
206
+def status_set(state, message):
207
+    '''Set the unit's workload status.
208
+
209
+    Set state == None to keep the same state and just change the message.
210
+    '''
211
+    if state is None:
212
+        state = hookenv.status_get()[0]
213
+        if state == 'unknown':
214
+            state = 'maintenance'  # Guess
215
+    if state in ('error', 'blocked'):
216
+        lvl = hookenv.WARNING
217
+    else:
218
+        lvl = hookenv.INFO
219
+    hookenv.status_set(state, message)
220
+    hookenv.log('{}: {}'.format(state, message), lvl)
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,196 @@
  4
+import os
  5
+import sys
  6
+import shutil
  7
+from glob import glob
  8
+from subprocess import check_call
  9
+
 10
+from charms.layer.execd import execd_preinstall
 11
+
 12
+
 13
+def lsb_release():
 14
+    """Return /etc/lsb-release in a dict"""
 15
+    d = {}
 16
+    with open('/etc/lsb-release', 'r') as lsb:
 17
+        for l in lsb:
 18
+            k, v = l.split('=')
 19
+            d[k.strip()] = v.strip()
 20
+    return d
 21
+
 22
+
 23
+def bootstrap_charm_deps():
 24
+    """
 25
+    Set up the base charm dependencies so that the reactive system can run.
 26
+    """
 27
+    # execd must happen first, before any attempt to install packages or
 28
+    # access the network, because sites use this hook to do bespoke
 29
+    # configuration and install secrets so the rest of this bootstrap
 30
+    # and the charm itself can actually succeed. This call does nothing
 31
+    # unless the operator has created and populated $CHARM_DIR/exec.d.
 32
+    execd_preinstall()
 33
+    # ensure that $CHARM_DIR/bin is on the path, for helper scripts
 34
+    os.environ['PATH'] += ':%s' % os.path.join(os.environ['CHARM_DIR'], 'bin')
 35
+    venv = os.path.abspath('../.venv')
 36
+    vbin = os.path.join(venv, 'bin')
 37
+    vpip = os.path.join(vbin, 'pip')
 38
+    vpy = os.path.join(vbin, 'python')
 39
+    if os.path.exists('wheelhouse/.bootstrapped'):
 40
+        activate_venv()
 41
+        return
 42
+    # bootstrap wheelhouse
 43
+    if os.path.exists('wheelhouse'):
 44
+        with open('/root/.pydistutils.cfg', 'w') as fp:
 45
+            # make sure that easy_install also only uses the wheelhouse
 46
+            # (see https://github.com/pypa/pip/issues/410)
 47
+            charm_dir = os.environ['CHARM_DIR']
 48
+            fp.writelines([
 49
+                "[easy_install]\n",
 50
+                "allow_hosts = ''\n",
 51
+                "find_links = file://{}/wheelhouse/\n".format(charm_dir),
 52
+            ])
 53
+        apt_install([
 54
+            'python3-pip',
 55
+            'python3-setuptools',
 56
+            'python3-yaml',
 57
+            'python3-dev',
 58
+        ])
 59
+        from charms import layer
 60
+        cfg = layer.options('basic')
 61
+        # include packages defined in layer.yaml
 62
+        apt_install(cfg.get('packages', []))
 63
+        # if we're using a venv, set it up
 64
+        if cfg.get('use_venv'):
 65
+            if not os.path.exists(venv):
 66
+                series = lsb_release()['DISTRIB_CODENAME']
 67
+                if series in ('precise', 'trusty'):
 68
+                    apt_install(['python-virtualenv'])
 69
+                else:
 70
+                    apt_install(['virtualenv'])
 71
+                cmd = ['virtualenv', '-ppython3', '--never-download', venv]
 72
+                if cfg.get('include_system_packages'):
 73
+                    cmd.append('--system-site-packages')
 74
+                check_call(cmd)
 75
+            os.environ['PATH'] = ':'.join([vbin, os.environ['PATH']])
 76
+            pip = vpip
 77
+        else:
 78
+            pip = 'pip3'
 79
+            # save a copy of system pip to prevent `pip3 install -U pip`
 80
+            # from changing it
 81
+            if os.path.exists('/usr/bin/pip'):
 82
+                shutil.copy2('/usr/bin/pip', '/usr/bin/pip.save')
 83
+        # need newer pip, to fix spurious Double Requirement error:
 84
+        # https://github.com/pypa/pip/issues/56
 85
+        check_call([pip, 'install', '-U', '--no-index', '-f', 'wheelhouse',
 86
+                    'pip'])
 87
+        # install the rest of the wheelhouse deps
 88
+        check_call([pip, 'install', '-U', '--no-index', '-f', 'wheelhouse'] +
 89
+                   glob('wheelhouse/*'))
 90
+        if not cfg.get('use_venv'):
 91
+            # restore system pip to prevent `pip3 install -U pip`
 92
+            # from changing it
 93
+            if os.path.exists('/usr/bin/pip.save'):
 94
+                shutil.copy2('/usr/bin/pip.save', '/usr/bin/pip')
 95
+                os.remove('/usr/bin/pip.save')
 96
+        os.remove('/root/.pydistutils.cfg')
 97
+        # flag us as having already bootstrapped so we don't do it again
 98
+        open('wheelhouse/.bootstrapped', 'w').close()
 99
+        # Ensure that the newly bootstrapped libs are available.
100
+        # Note: this only seems to be an issue with namespace packages.
101
+        # Non-namespace-package libs (e.g., charmhelpers) are available
102
+        # without having to reload the interpreter. :/
103
+        reload_interpreter(vpy if cfg.get('use_venv') else sys.argv[0])
104
+
105
+
106
+def activate_venv():
107
+    """
108
+    Activate the venv if enabled in ``layer.yaml``.
109
+
110
+    This is handled automatically for normal hooks, but actions might
111
+    need to invoke this manually, using something like:
112
+
113
+        # Load modules from $CHARM_DIR/lib
114
+        import sys
115
+        sys.path.append('lib')
116
+
117
+        from charms.layer.basic import activate_venv
118
+        activate_venv()
119
+
120
+    This will ensure that modules installed in the charm's
121
+    virtual environment are available to the action.
122
+    """
123
+    venv = os.path.abspath('../.venv')
124
+    vbin = os.path.join(venv, 'bin')
125
+    vpy = os.path.join(vbin, 'python')
126
+    from charms import layer
127
+    cfg = layer.options('basic')
128
+    if cfg.get('use_venv') and '.venv' not in sys.executable:
129
+        # activate the venv
130
+        os.environ['PATH'] = ':'.join([vbin, os.environ['PATH']])
131
+        reload_interpreter(vpy)
132
+
133
+
134
+def reload_interpreter(python):
135
+    """
136
+    Reload the python interpreter to ensure that all deps are available.
137
+
138
+    Newly installed modules in namespace packages sometimes seemt to
139
+    not be picked up by Python 3.
140
+    """
141
+    os.execle(python, python, sys.argv[0], os.environ)
142
+
143
+
144
+def apt_install(packages):
145
+    """
146
+    Install apt packages.
147
+
148
+    This ensures a consistent set of options that are often missed but
149
+    should really be set.
150
+    """
151
+    if isinstance(packages, (str, bytes)):
152
+        packages = [packages]
153
+
154
+    env = os.environ.copy()
155
+
156
+    if 'DEBIAN_FRONTEND' not in env:
157
+        env['DEBIAN_FRONTEND'] = 'noninteractive'
158
+
159
+    cmd = ['apt-get',
160
+           '--option=Dpkg::Options::=--force-confold',
161
+           '--assume-yes',
162
+           'install']
163
+    check_call(cmd + packages, env=env)
164
+
165
+
166
+def init_config_states():
167
+    import yaml
168
+    from charmhelpers.core import hookenv
169
+    from charms.reactive import set_state
170
+    from charms.reactive import toggle_state
171
+    config = hookenv.config()
172
+    config_defaults = {}
173
+    config_defs = {}
174
+    config_yaml = os.path.join(hookenv.charm_dir(), 'config.yaml')
175
+    if os.path.exists(config_yaml):
176
+        with open(config_yaml) as fp:
177
+            config_defs = yaml.safe_load(fp).get('options', {})
178
+            config_defaults = {key: value.get('default')
179
+                               for key, value in config_defs.items()}
180
+    for opt in config_defs.keys():
181
+        if config.changed(opt):
182
+            set_state('config.changed')
183
+            set_state('config.changed.{}'.format(opt))
184
+        toggle_state('config.set.{}'.format(opt), config.get(opt))
185
+        toggle_state('config.default.{}'.format(opt),
186
+                     config.get(opt) == config_defaults[opt])
187
+    hookenv.atexit(clear_config_states)
188
+
189
+
190
+def clear_config_states():
191
+    from charmhelpers.core import hookenv, unitdata
192
+    from charms.reactive import remove_state
193
+    config = hookenv.config()
194
+    remove_state('config.changed')
195
+    for opt in config.keys():
196
+        remove_state('config.changed.{}'.format(opt))
197
+        remove_state('config.set.{}'.format(opt))
198
+        remove_state('config.default.{}'.format(opt))
199
+    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

lib/charms/leadership.py

 1
--- 
 2
+++ lib/charms/leadership.py
 3
@@ -0,0 +1,58 @@
 4
+# Copyright 2015-2016 Canonical Ltd.
 5
+#
 6
+# This file is part of the Leadership Layer for Juju.
 7
+#
 8
+# This program is free software: you can redistribute it and/or modify
 9
+# it under the terms of the GNU General Public License version 3, as
10
+# published by the Free Software Foundation.
11
+#
12
+# This program is distributed in the hope that it will be useful, but
13
+# WITHOUT ANY WARRANTY; without even the implied warranties of
14
+# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
15
+# PURPOSE.  See the GNU General Public License for more details.
16
+#
17
+# You should have received a copy of the GNU General Public License
18
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
19
+
20
+from charmhelpers.core import hookenv
21
+from charmhelpers.core import unitdata
22
+
23
+from charms import reactive
24
+from charms.reactive import not_unless
25
+
26
+
27
+__all__ = ['leader_get', 'leader_set']
28
+
29
+
30
+@not_unless('leadership.is_leader')
31
+def leader_set(settings=None, **kw):
32
+    '''Change leadership settings, per charmhelpers.core.hookenv.leader_set.
33
+
34
+    The leadership.set.{key} reactive state will be set while the
35
+    leadership hook environment setting remains set.
36
+
37
+    Changed leadership settings will set the leadership.changed.{key}
38
+    and leadership.changed states. These states will remain set until
39
+    the following hook.
40
+
41
+    These state changes take effect immediately on the leader, and
42
+    in future hooks run on non-leaders. In this way both leaders and
43
+    non-leaders can share handlers, waiting on these states.
44
+    '''
45
+    settings = settings or {}
46
+    settings.update(kw)
47
+    previous = unitdata.kv().getrange('leadership.settings.', strip=True)
48
+
49
+    for key, value in settings.items():
50
+        if value != previous.get(key):
51
+            reactive.set_state('leadership.changed.{}'.format(key))
52
+            reactive.set_state('leadership.changed')
53
+        reactive.helpers.toggle_state('leadership.set.{}'.format(key),
54
+                                      value is not None)
55
+    hookenv.leader_set(settings)
56
+    unitdata.kv().update(settings, prefix='leadership.settings.')
57
+
58
+
59
+def leader_get(attribute=None):
60
+    '''Return leadership settings, per charmhelpers.core.hookenv.leader_get.'''
61
+    return hookenv.leader_get(attribute)
Back to file index

metadata.yaml

 1
--- 
 2
+++ metadata.yaml
 3
@@ -0,0 +1,41 @@
 4
+"name": "ibm-wxs-container"
 5
+"summary": "IBM WebSphere eXtreme Scale"
 6
+"maintainer": "IBM Juju Support Team <jujusupp@us.ibm.com>"
 7
+"description": "IBM WebSphere eXtreme Scale is an elastic, scalable, in-memory data\
 8
+  \ grid (IMDG). It is designed to help you handle exponential growth of transactions.\
 9
+  \ With WebSphere eXtreme Scale, you can expect an enhanced quality of service in\
10
+  \ high-performance computing environments."
11
+"tags":
12
+- "ibm"
13
+- "im"
14
+- "ibm-z"
15
+- "wxs-container"
16
+- "in-memory data grid"
17
+- "workload_management"
18
+"series":
19
+- "trusty"
20
+"requires":
21
+  "wxsgrid":
22
+    "interface": "ibm-wxs"
23
+"min-juju-version": "2.0-beta1"
24
+"resources":
25
+  "ibm_im_installer":
26
+    "type": "file"
27
+    "filename": "ibm_im_installer.zip"
28
+    "description": "Installation Manager installer archive"
29
+  "ibm_im_fixpack":
30
+    "type": "file"
31
+    "filename": "ibm_im_fixpack.zip"
32
+    "description": "Installation Manager fix pack archive"
33
+  "ibm_wxs_base_installer":
34
+    "type": "file"
35
+    "filename": "ibm_wxs_base_installer.zip"
36
+    "description": "WXS  Base installer archive"
37
+  "ibm_wxs_fixpack_installer":
38
+    "type": "file"
39
+    "filename": "ibm_wxs_fixpack_installer.zip"
40
+    "description": "WXS Fixpack installer archive"
41
+"subordinate": !!bool "false"
42
+"terms":
43
+- "ibm-im/1"
44
+- "ibm-wxs/1"
Back to file index

reactive/apt.py

  1
--- 
  2
+++ reactive/apt.py
  3
@@ -0,0 +1,132 @@
  4
+# Copyright 2015-2016 Canonical Ltd.
  5
+#
  6
+# This file is part of the Apt layer for Juju.
  7
+#
  8
+# This program is free software: you can redistribute it and/or modify
  9
+# it under the terms of the GNU General Public License version 3, as
 10
+# published by the Free Software Foundation.
 11
+#
 12
+# This program is distributed in the hope that it will be useful, but
 13
+# WITHOUT ANY WARRANTY; without even the implied warranties of
 14
+# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
 15
+# PURPOSE.  See the GNU General Public License for more details.
 16
+#
 17
+# You should have received a copy of the GNU General Public License
 18
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 19
+
 20
+'''
 21
+charms.reactive helpers for dealing with deb packages.
 22
+
 23
+Add apt package sources using add_source(). Queue deb packages for
 24
+installation with install(). Configure and work with your software
 25
+once the apt.installed.{packagename} state is set.
 26
+'''
 27
+import subprocess
 28
+
 29
+from charmhelpers import fetch
 30
+from charmhelpers.core import hookenv
 31
+from charmhelpers.core.hookenv import WARNING
 32
+from charms import layer
 33
+from charms import reactive
 34
+from charms.reactive import when, when_not
 35
+
 36
+import charms.apt
 37
+
 38
+
 39
+@when('apt.needs_update')
 40
+def update():
 41
+    charms.apt.update()
 42
+
 43
+
 44
+@when('apt.queued_installs')
 45
+@when_not('apt.needs_update')
 46
+def install_queued():
 47
+    charms.apt.install_queued()
 48
+
 49
+
 50
+@when_not('apt.queued_installs')
 51
+def ensure_package_status():
 52
+    charms.apt.ensure_package_status()
 53
+
 54
+
 55
+def filter_installed_packages(packages):
 56
+    # Don't use fetch.filter_installed_packages, as it depends on python-apt
 57
+    # and not available if the basic layer's use_site_packages option is off
 58
+    cmd = ['dpkg-query', '--show', r'--showformat=${Package}\n']
 59
+    installed = set(subprocess.check_output(cmd,
 60
+                                            universal_newlines=True).split())
 61
+    return set(packages) - installed
 62
+
 63
+
 64
+def clear_removed_package_states():
 65
+    """On hook startup, clear install states for removed packages."""
 66
+    removed = filter_installed_packages(charms.apt.installed())
 67
+    if removed:
 68
+        hookenv.log('{} missing packages ({})'.format(len(removed),
 69
+                                                      ','.join(removed)),
 70
+                    WARNING)
 71
+        for package in removed:
 72
+            reactive.remove_state('apt.installed.{}'.format(package))
 73
+
 74
+
 75
+def configure_sources():
 76
+    """Add user specified package sources from the service configuration.
 77
+
 78
+    See charmhelpers.fetch.configure_sources for details.
 79
+    """
 80
+    config = hookenv.config()
 81
+
 82
+    # We don't have enums, so we need to validate this ourselves.
 83
+    package_status = config.get('package_status') or ''
 84
+    if package_status not in ('hold', 'install'):
 85
+        charms.apt.status_set('blocked',
 86
+                              'Unknown package_status {}'
 87
+                              ''.format(package_status))
 88
+        # Die before further hooks are run. This isn't very nice, but
 89
+        # there is no other way to inform the operator that they have
 90
+        # invalid configuration.
 91
+        raise SystemExit(0)
 92
+
 93
+    sources = config.get('install_sources') or ''
 94
+    keys = config.get('install_keys') or ''
 95
+    if reactive.helpers.data_changed('apt.configure_sources', (sources, keys)):
 96
+        fetch.configure_sources(update=False,
 97
+                                sources_var='install_sources',
 98
+                                keys_var='install_keys')
 99
+        reactive.set_state('apt.needs_update')
100
+
101
+    # Clumsy 'config.get() or' per Bug #1641362
102
+    extra_packages = sorted((config.get('extra_packages') or '').split())
103
+    if extra_packages:
104
+        charms.apt.queue_install(extra_packages)
105
+
106
+
107
+def queue_layer_packages():
108
+    """Add packages listed in build-time layer options."""
109
+    # Both basic and apt layer. basic layer will have already installed
110
+    # its defined packages, but rescheduling it here gets the apt layer
111
+    # state set and they will pinned as any other apt layer installed
112
+    # package.
113
+    opts = layer.options()
114
+    for section in ['basic', 'apt']:
115
+        if section in opts and 'packages' in opts[section]:
116
+            charms.apt.queue_install(opts[section]['packages'])
117
+
118
+
119
+# Per https://github.com/juju-solutions/charms.reactive/issues/33,
120
+# this module may be imported multiple times so ensure the
121
+# initialization hook is only registered once. I have to piggy back
122
+# onto the namespace of a module imported before reactive discovery
123
+# to do this.
124
+if not hasattr(reactive, '_apt_registered'):
125
+    # We need to register this to run every hook, not just during install
126
+    # and config-changed, to protect against race conditions. If we don't
127
+    # do this, then the config in the hook environment may show updates
128
+    # to running hooks well before the config-changed hook has been invoked
129
+    # and the intialization provided an opertunity to be run.
130
+    hookenv.atstart(hookenv.log, 'Initializing Apt Layer')
131
+    hookenv.atstart(clear_removed_package_states)
132
+    hookenv.atstart(configure_sources)
133
+    hookenv.atstart(queue_layer_packages)
134
+    hookenv.atstart(charms.apt.reset_application_version)
135
+    reactive._apt_registered = True
Back to file index

reactive/ibm-base.sh

  1
--- 
  2
+++ reactive/ibm-base.sh
  3
@@ -0,0 +1,107 @@
  4
+#!/bin/bash
  5
+source charms.reactive.sh
  6
+set -e
  7
+
  8
+
  9
+# Utility function to verify a downloaded resource
 10
+# :param: file name
 11
+# :param: checksum type
 12
+# :param: checksum value
 13
+function verify_curl_resource() {
 14
+  local FILE=$1
 15
+  local TYPE=$2
 16
+  local EXPECTED_SUM=$3
 17
+  local CALCULATED_SUM=""
 18
+  local PROG=""
 19
+
 20
+  if [ ! -r ${FILE} ]; then
 21
+    status-set blocked "ibm-base: could not read ${FILE}"
 22
+    juju-log "Could not verify the downloaded resource. File could not be read: ${FILE}"
 23
+  fi
 24
+
 25
+  # Set our checksum utility based on the requested type
 26
+  case "${TYPE}" in
 27
+    md5)
 28
+      PROG='md5sum'
 29
+      ;;
 30
+    sha256)
 31
+      PROG='sha256sum'
 32
+      ;;
 33
+    sha512)
 34
+      PROG='sha512sum'
 35
+      ;;
 36
+    *)
 37
+      status-set blocked "ibm-base: checksum type must be md5, sha215, or sha512"
 38
+      juju-log "Could not verify the downloaded resource ${FILE}. Unknown checksum type: ${TYPE}"
 39
+      return 1
 40
+  esac
 41
+
 42
+  CALCULATED_SUM=`${PROG} ${FILE} | awk '{print $1}'`
 43
+  if [ "${CALCULATED_SUM}" = "${EXPECTED_SUM}" ]; then
 44
+    juju-log "Checksum verified for ${FILE}."
 45
+    return 0
 46
+  else
 47
+    status-set blocked "ibm-base: checksums did not match"
 48
+    juju-log "Checksum mismatch for ${FILE}. Expected ${EXPECTED_SUM}, got ${CALCULATED_SUM}"
 49
+    return 1
 50
+  fi
 51
+}
 52
+
 53
+
 54
+# Fetch curl resources if a URL is configured
 55
+@when 'config.set.curl_url'
 56
+@when_any 'config.new.curl_url' 'config.changed.curl_url' 'config.new.curl_opts' 'config.changed.curl_opts'
 57
+function fetch_curl_resource() {
 58
+  local ARCHIVE_DIR="${CHARM_DIR}/files/archives"
 59
+  local CURL_URL=$(config-get 'curl_url')
 60
+  local CURL_OPTS=$(config-get 'curl_opts')
 61
+
 62
+  status-set maintenance "ibm-base: fetching resource(s)"
 63
+
 64
+  mkdir -p ${ARCHIVE_DIR}
 65
+  cd ${ARCHIVE_DIR}
 66
+  # Multiple URLs may be separated by a space, so loop.
 67
+  for URL_STRING in ${CURL_URL}
 68
+  do
 69
+    # For each URL_STRING, set the url, checksum type, and checksum value.
 70
+    local URL=${URL_STRING%%\?*}        # string before the first '?'
 71
+    local FILE_NAME=${URL##*\/}         # string after the last '/'
 72
+    local SUM_STRING=${URL_STRING#*\?}  # string after the first '?'
 73
+    local SUM_TYPE=${SUM_STRING%%\=*}   # string before the first '='
 74
+    local SUM_VALUE=${SUM_STRING#*\=}   # string after the first '='
 75
+
 76
+    if [ -z ${FILE_NAME} ]; then
 77
+      FILE_NAME="juju-${RANDOM}"
 78
+    fi
 79
+    curl --silent --show-error ${CURL_OPTS} -o ${FILE_NAME} ${URL}
 80
+
 81
+    # Verify our resource checksum. If this fails, let verify_resource log
 82
+    # the reason and exit successfully. Exiting non-zero would fail the hook,
 83
+    # so return 0 and simply inform the user that verification failed.
 84
+    verify_curl_resource ${FILE_NAME} ${SUM_TYPE} ${SUM_VALUE} || return 0
 85
+  done
 86
+  cd -
 87
+
 88
+  set_state 'ibm-base.curl.resource.fetched'
 89
+  status-set active "ibm-base: curl resource(s) fetched"
 90
+  juju-log 'Curl resource fetched'
 91
+}
 92
+
 93
+
 94
+# Handle license acceptance
 95
+@when 'config.changed.license_accepted'
 96
+function check_license_acceptance() {
 97
+  local LIC_ACCEPTED=$(config-get 'license_accepted')
 98
+
 99
+  # compare lowercase LIC_ACCEPTED (requires bash > 4)
100
+  if [ "${LIC_ACCEPTED,,}" = "true" ]; then
101
+    set_state 'ibm-base.license.accepted'
102
+    juju-log 'License accepted'
103
+  else
104
+    remove_state 'ibm-base.license.accepted'
105
+    juju-log 'License NOT accepted'
106
+  fi
107
+}
108
+
109
+# Main reactive entry point
110
+reactive_handler_main
Back to file index

reactive/ibm-im.sh

  1
--- 
  2
+++ reactive/ibm-im.sh
  3
@@ -0,0 +1,187 @@
  4
+#!/bin/bash
  5
+set -e
  6
+
  7
+source charms.reactive.sh
  8
+ARCHITECTURE=`uname -m`
  9
+
 10
+# Installation Manager install path
 11
+IM_INSTALL_PATH="/opt/IBM/InstallationManager"
 12
+
 13
+@when_not 'ibm-im.installed'
 14
+function install_ibm_im(){
 15
+      # Fail fast if we're on an unsupported arch
 16
+      if [ "$ARCHITECTURE" != "x86_64" -a  "$ARCHITECTURE" != "ppc64le" -a "$ARCHITECTURE" != "s390x" ]; then
 17
+            juju-log "IBM IM: only supported on x86_64 or ppc64le platforms"
 18
+            status-set blocked "unsupported architecture"
 19
+            exit 1
 20
+      fi
 21
+
 22
+      # Get the installable resource
 23
+      juju-log "IBM IM: fetching the ibm_im_installer resource"
 24
+      status-set maintenance "fetching the ibm_im_installer resource"
 25
+      cfg_im_pkg_name=`resource-get 'ibm_im_installer' || echo unavailable`
 26
+
 27
+      # If we don't have a package, report blocked status; we can't proceed.
 28
+      if [ "$cfg_im_pkg_name" = "unavailable" ]; then
 29
+        juju-log "IBM IM: missing required ibm_im_installer resource"
 30
+        status-set blocked "missing required ibm_im_installer resource"
 31
+        exit 0
 32
+      fi
 33
+
 34
+      juju-log "IBM IM: using $cfg_im_pkg_name as the ibm_im_installer resource"
 35
+      ARCHIVE_DIR=`dirname $cfg_im_pkg_name`
 36
+
 37
+      # Extract the installer contents
 38
+      if [ -f  $cfg_im_pkg_name ]; then
 39
+           juju-log "IBM IM: extracting the ibm_im_installer resource"
 40
+           status-set maintenance "extracting the ibm_im_installer resource"
 41
+           if [ -f $ARCHIVE_DIR/userinstc ]; then
 42
+                 juju-log "IBM IM: ibm_im_installer resource already extracted"
 43
+           else
 44
+                 cd $ARCHIVE_DIR
 45
+                 if ! unzip $cfg_im_pkg_name; then
 46
+                      juju-log "IBM IM: Unable to extract the ibm_im_installer resource"
 47
+                      # Remove corrupt archive file
 48
+                      status-set blocked "ibm_im_installer resource is corrupt"
 49
+                      rm -rf $ARCHIVE_DIR
 50
+                      exit 0
 51
+                 else
 52
+                      juju-log "IBM IM: ibm_im_installer resource extracted successfully"
 53
+                 fi
 54
+           fi
 55
+      fi
 56
+
 57
+      # Do the actual IBM IM install
 58
+      if [ -f  $ARCHIVE_DIR/userinstc ]; then
 59
+        juju-log "IBM IM: starting installation."
 60
+        status-set maintenance "installing ibm-im"
 61
+        cp $ARCHIVE_DIR/install.xml $ARCHIVE_DIR/silent_install.xml
 62
+        sed -i "2 a \<profile kind='self' installLocation='$IM_INSTALL_PATH' id='IBM Installation Manager'>\n <data key='eclipseLocation' value='$IM_INSTALL_PATH' />\n</profile>" $ARCHIVE_DIR/silent_install.xml
 63
+        if $ARCHIVE_DIR/userinstc -input $ARCHIVE_DIR/silent_install.xml -acceptlicense; then
 64
+            set_state 'ibm-im.installed'
 65
+            status-set active "ready"
 66
+        else
 67
+            juju-log "IBM IM: error while installing"
 68
+            exit 1
 69
+        fi
 70
+      else
 71
+        juju-log "IBM IM: installer was not found."
 72
+        status-set blocked "installation failed"
 73
+        exit 1
 74
+      fi
 75
+}
 76
+
 77
+@when 'ibm-im.installed'
 78
+@when_not 'ibm-im.updated'
 79
+function install_ibm_im_fixpack(){
 80
+    # Get the fixpack resource
 81
+    juju-log "IBM IM: fetching the ibm_im_fixpack resource"
 82
+    status-set maintenance "fetching the ibm_im_fixpack resource"
 83
+    ibm_im_fp_package=`resource-get 'ibm_im_fixpack' || echo unavailable`
 84
+
 85
+    # If we don't have a fixpack, just exit successfully; there's nothing to do.
 86
+    if [ "$ibm_im_fp_package" = "unavailable" ]; then
 87
+      juju-log "IBM IM: no ibm_im_fixpack to install"
 88
+      status-set active "ready"
 89
+      exit 0
 90
+    fi
 91
+
 92
+    # Currently, there is no way to make a resource optional, so something
 93
+    # must be uploaded to the charm store, even if it's a dummy archive.
 94
+    # If we detect the fixpack is just a placeholder (because we created an
 95
+    # empty placeholder in the store), exit just like we do with a missing
 96
+    # fixpack resource.
 97
+    ibm_im_fp_empty=`file $ibm_im_fp_package | { grep -q empty && echo "True"; } || echo "False"`
 98
+    if [ "$ibm_im_fp_empty" = "True" ]; then
 99
+      juju-log "IBM IM: no ibm_im_fixpack to install"
100
+      status-set active "ready"
101
+      exit 0
102
+    fi
103
+
104
+    juju-log "IBM IM: using $ibm_im_fp_package as the ibm_im_fixpack resource"
105
+    ARCHIVE_DIR=`dirname $ibm_im_fp_package`
106
+
107
+    # Extract the fixpack contents
108
+    if [ -f $ibm_im_fp_package ]; then
109
+        juju-log "IBM IM: extracting the ibm_im_fixpack resource"
110
+        status-set maintenance "extracting the ibm_im_fixpack resource"
111
+        if [ -f $ARCHIVE_DIR/userinstc ]; then
112
+              juju-log "IBM IM: ibm_im_fixpack resource already extracted"
113
+        else
114
+              cd $ARCHIVE_DIR
115
+              if ! unzip $ibm_im_fp_package; then
116
+                      juju-log "IBM IM: Unable to extract the ibm_im_fixpack resource"
117
+                      # Remove corrupt archive file
118
+                      status-set blocked "ibm_im_fixpack resource is corrupt"
119
+                      rm  -rf $ARCHIVE_DIR
120
+                      exit 0
121
+              else
122
+                      juju-log "IBM IM: ibm_im_fixpack resource extracted successfully"
123
+              fi
124
+        fi
125
+    fi
126
+
127
+    # Do the actual IBM IM fixpack install
128
+    if [ -f $ARCHIVE_DIR/userinstc ]; then
129
+        juju-log "IBM IM: starting fixpack installation."
130
+        status-set maintenance "installing fixpack"
131
+        cp $ARCHIVE_DIR/install.xml $ARCHIVE_DIR/silent_install.xml
132
+        sed -i "2 a \<profile kind='self' installLocation='$IM_INSTALL_PATH' id='IBM Installation Manager'>\n <data key='eclipseLocation' value='$IM_INSTALL_PATH' />\n</profile>" $ARCHIVE_DIR/silent_install.xml
133
+        if $ARCHIVE_DIR/userinstc -input $ARCHIVE_DIR/silent_install.xml -acceptlicense; then
134
+             set_state 'ibm-im.updated'
135
+             status-set active "ready"
136
+        else
137
+             juju-log "IBM IM: error while installing the fixpack."
138
+             exit 1
139
+        fi
140
+    else
141
+        juju-log "IBM_IM: Fix pack installer was not found."
142
+        status-set blocked "fixpack installation failed"
143
+        exit 1
144
+   fi
145
+}
146
+
147
+@hook 'upgrade-charm'
148
+function check_fixpack(){
149
+    # The upgrade-charm hook will fire when a new resource is pushed for this
150
+    # charm. This is a good time to determine if we need to deal with a new
151
+    # fixpack.
152
+    if ! charms.reactive is_state 'ibm-im.updated'; then
153
+        # If there is no prior fixpack installed (because ibm-im.updated is not
154
+        # set), do nothing since install-ibm-im-fixpack will handle that case.
155
+        juju-log "IBM IM: no fixpack has been installed; nothing to upgrade."
156
+        exit 0
157
+    else
158
+        # If we have a fixpack already (because ibm-im.updated is set),
159
+        # we should fetch the latest fixpack and determine if it is new.
160
+        #  - If it is new, set our states so install-ibm-im-fixpack is called again
161
+        #  - If it is not new, do nothing
162
+        juju-log "IBM IM: scanning for new fixpacks to install"
163
+        ARCHIVE_DIR="$CHARM_DIR/../resources/ibm_im_fixpack"
164
+        CUR_FIXPACK="$ARCHIVE_DIR/ibm_im_fixpack.zip"
165
+
166
+        # Sum any existing fixpack to determine if we have a new one
167
+        if [ -f $CUR_FIXPACK ]; then
168
+            CUR_MD5=`md5sum "$CUR_FIXPACK" | awk '{print $1}'`
169
+            # Calling resource-get here will fetch the fixpack resource.
170
+            NEW_FIXPACK=`resource-get 'ibm_im_fixpack' || echo unavailable`
171
+            if [ "$NEW_FIXPACK" = "unavailable" ]; then
172
+                juju-log "IBM IM: no fixpack to install"
173
+            else
174
+                NEW_MD5=`md5sum "$NEW_FIXPACK" | awk '{print $1}'`
175
+                # If sums don't match, we have a new fp. Configure states so
176
+                # we re-run install-ibm-im-fixpack().
177
+                if [ "$CUR_MD5" != "$NEW_MD5" ]; then
178
+                    juju-log "IBM IM: new fixpack detected ($CUR_FIXPACK with $CUR_MD5 versus $NEW_FIXPACK with $NEW_MD5)"
179
+                    rm -rf $ARCHIVE_DIR
180
+                    remove_state 'ibm-im.updated'
181
+                else
182
+                    juju-log "IBM IM: no new fixpack to install"
183
+                fi
184
+            fi
185
+        fi
186
+    fi
187
+}
188
+
189
+
190
+reactive_handler_main
Back to file index

reactive/ibm-wxs-container.sh

  1
--- 
  2
+++ reactive/ibm-wxs-container.sh
  3
@@ -0,0 +1,331 @@
  4
+#!/bin/bash
  5
+set -ex
  6
+
  7
+source charms.reactive.sh
  8
+
  9
+ARCHITECTURE=`uname -m`
 10
+IM_INSTALL_PATH=/opt/IBM/InstallationManager
 11
+WXS_INSTALL_PATH=/opt/ibm/WXS
 12
+private_address=`unit-get private-address`
 13
+
 14
+#Check the System Arch
 15
+function check_arch() {
 16
+	#Check the architecture before installing the product
 17
+	if [ "$ARCHITECTURE" != "x86_64" -a "$ARCHITECTURE" != "ppc64le" ]; then
 18
+		juju-log "check_arch: Unsupported platform. IBM WXS installed with this Charm supports only on x86_64 or ppc64le platform."
 19
+		status-set blocked "IBM WXS Container: Platform not supported"
 20
+	 	exit 1
 21
+	fi
 22
+}
 23
+
 24
+#start wxs container service
 25
+function start_wxs_container(){ 
 26
+	#start wxs container service
 27
+	if [ -d $WXS_INSTALL_PATH/ObjectGrid/bin/ ]; then
 28
+	set +e
 29
+		containerstarted=`ps -ef | grep "[c]atalogServiceEndPoints" | grep -v grep`
 30
+	set -e
 31
+	wxs_catalog_ip=$(relation_call --state=wxsgrid.available get_wxs_catalog_ip )|| true
 32
+	wxs_catalog_port=$(relation_call --state=wxsgrid.available get_wxs_catalog_port) || true
 33
+	echo "wxs_catalog_ip:" $wxs_catalog_ip
 34
+	echo "wxs_catalog_port:" $wxs_catalog_port
 35
+		if [ -z "$containerstarted" ]; then
 36
+			juju-log "start_wxs_container: Start container service"
 37
+			echo "serverName=$private_address-cs" | sudo tee -a $WXS_INSTALL_PATH/ObjectGrid/gettingstarted/server/config/catalogServer.props
 38
+			echo "catalogServiceEndPoints=$private_address:2809" | sudo tee -a $WXS_INSTALL_PATH/ObjectGrid/gettingstarted/server/config/containerServer.props
 39
+			if ! $WXS_INSTALL_PATH/ObjectGrid/bin/startXsServer.sh "$private_address-c" -objectGridFile $WXS_INSTALL_PATH/ObjectGrid/gettingstarted/server/config/objectgrid.xml -deploymentPolicyFile $WXS_INSTALL_PATH/ObjectGrid/gettingstarted/server/config/deployment.xml -catalogServiceEndPoints "$wxs_catalog_ip":"$wxs_catalog_port"
 40
+			then
 41
+				juju-log "start_wxs_container: while starting Container"
 42
+				status-set blocked "IBM WXS Container: Error while starting Container"
 43
+				return 1
 44
+			else
 45
+				juju-log "start_wxs_container: Container started successfully"
 46
+				set_state 'ibm-wxs-container-service.started'
 47
+				status-set maintenance "IBM WXS Container: WXS Container service started successfully"
 48
+				return 0
 49
+			fi
 50
+		fi
 51
+	else
 52
+	
 53
+		status-set blocked "IBM WXS Container: No Container to start, exiting."	
 54
+		retun 1
 55
+	fi
 56
+}
 57
+
 58
+#stop wxs container service 
 59
+function stop_wxs_container() {
 60
+set +e
 61
+containerstarted=`ps -aux | grep '[c]atalogServiceEndPoints' | grep -v grep`
 62
+set -e
 63
+if [ ! -z "$containerstarted" ]; then
 64
+	echo "inside stop_wxs_container $wxs_catalog_ip"
 65
+	echo "inside stop_wxs_container $wxs_catalog_port"
 66
+	wxs_catalog_ip=`ps -aux | grep "[c]atalogServiceEndPoints" | grep -v grep | awk -F" " '{print $NF}' | awk -F":" '{print $1}'`
 67
+	wxs_catalog_port=`ps -aux | grep "[c]atalogServiceEndPoints" | grep -v grep | awk -F" " '{print $NF}' | awk -F":" '{print $2}'`
 68
+	if ! $WXS_INSTALL_PATH/ObjectGrid/bin/xscmd.sh -c teardown -to 60 -sl "$private_address-c" --catalogEndPoints "$wxs_catalog_ip":"$wxs_catalog_port" -f
 69
+	then
 70
+		juju-log "stop_wxs_container: Error while stopping Container"
 71
+		status-set blocked "IBM WXS Container: Error while stopping Container"
 72
+		return 1
 73
+	else
 74
+		juju-log "stop_wxs_container: Container stopped successfully"
 75
+		remove_state 'ibm-wxs-container-service.started'
 76
+		status-set maintenance "IBM WXS Container: WXS Container service stopped successfully"
 77
+		return 0
 78
+	fi
 79
+else
 80
+	juju-log "stop_wxs_container: Container is not running"
 81
+	status-set maintenance "IBM WXS Container: WXS Container service is not running"
 82
+	return 0
 83
+fi
 84
+}
 85
+
 86
+#Install WXS Container base package
 87
+@when 'ibm-im.installed'
 88
+@when_not 'ibm-wxs-container.installed'
 89
+function install-wxs-container(){
 90
+	
 91
+	juju-log "install-wxs-container: Checking etc/hosts file."
 92
+	private_address=`unit-get private-address`
 93
+	juju-log "install-wxs-container: private_address : $private_address"
 94
+	cd /etc
 95
+	if grep -q "$private_address" hosts
 96
+	then
 97
+		juju-log "install-wxs-container: Host file already updated"
 98
+	else
 99
+		juju-log "install-wxs-container: Updating Host file"
100
+		echo "$private_address `hostname`" >> /etc/hosts
101
+	fi
102
+	#check arch supported
103
+	juju-log "install-wxs-container: calling check_arch function"
104
+	check_arch
105
+	#check if downloaded package is present in ${CHARM_DIR}/../resources
106
+	juju-log "install-wxs-container: calling check_wxs_package function"
107
+
108
+	if [ ! -d $CHARM_DIR/../resources/WXS_BASE/ ]; then
109
+		juju-log "install-wxs-container: fetching the ibm_wxs_base_installer resource"
110
+		status-set maintenance "IBM WXS Container: fetching the ibm_wxs_base_installer resource"
111
+		cfg_wxs_base_pkg_name=`resource-get 'ibm_wxs_base_installer' || echo unavailable`
112
+
113
+		ibm_wxs_pkg_isempty=`file $cfg_wxs_base_pkg_name | { grep -q empty && echo "True"; } || echo "False"`
114
+
115
+		if [ "$cfg_wxs_base_pkg_name" = "unavailable" ]; then
116
+			juju-log "install-wxs-container: missing required ibm_wxs_base_installer resource"
117
+			status-set blocked "IBM WXS Container: missing required ibm_wxs_base_installer resource"
118
+			exit 0
119
+		fi
120
+		if [ "$ibm_wxs_pkg_isempty" = "True" ]; then
121
+				juju-log "install-wxs-container: missing required ibm_wxs_base_installer resource, found empty packages"
122
+				status-set blocked "IBM WXS Container: missing required ibm_wxs_base_installer resource, provide actual ibm_wxs_base_installer resources."
123
+				exit 0
124
+		fi
125
+
126
+		if [ -f $cfg_wxs_base_pkg_name ]; then
127
+			ARCHIVE_DIR=`dirname $cfg_wxs_base_pkg_name`
128
+			juju-log "install-wxs-container: extracting the ibm_wxs_base_installer resources"
129
+			status-set maintenance "IBM WXS Container: extracting the ibm_wxs_base_installer resource"
130
+			if [ ! -d $ARCHIVE_DIR/../WXS_BASE ]; then
131
+				mkdir $ARCHIVE_DIR/../WXS_BASE
132
+			fi
133
+			if ! unzip ${cfg_wxs_base_pkg_name} -d ${ARCHIVE_DIR}/../WXS_BASE
134
+			then
135
+				juju-log "install-wxs-container: Unable to extract the WXS package content. Verify whether the package is corrupt."
136
+				status-set blocked "IBM WXS Container: IBM WXS package is corrupt"
137
+				rm -rf $ARCHIVE_DIR/../WXS_BASE 
138
+				exit 0
139
+			else
140
+				juju-log "install-wxs-container: Extracted package"
141
+				status-set maintenance "IBM WXS Container: Extracted wxs package"
142
+				WXS_Install_dir="`basename ${ARCHIVE_DIR}/../WXS_BASE/WXS_*`"
143
+                                juju-log "install-wxs-catalog: WXS_Install_dir is $WXS_Install_dir"
144
+
145
+			fi
146
+		fi
147
+	else
148
+                juju-log "install-wxs-container: Base Package Extracted already"
149
+                status-set maintenance "IBM WXS Container: Base Package Extracted already"
150
+                WXS_Install_dir="`basename ${CHARM_DIR}/../resources/WXS_BASE/WXS_*`"
151
+                juju-log "install-wxs-container: WXS_Install_dir is $WXS_Install_dir"
152
+	fi
153
+	#Install WXS package
154
+	juju-log "install-wxs-container: WXS Base Installation started"
155
+	if ! $IM_INSTALL_PATH/eclipse/tools/imcl install com.ibm.websphere.WXS.v86 -acceptLicense -installationDirectory $WXS_INSTALL_PATH -repositories ${CHARM_DIR}/../resources/WXS_BASE/${WXS_Install_dir}
156
+	then
157
+		juju-log "install-wxs-container: Error while installing WXS Base"
158
+		status-set blocked "IBM WXS Container: Error while installing WXS Base"
159
+		exit 1
160
+	else
161
+		juju-log "install-wxs-container: WXS Base installed successfully"
162
+		status-set maintenance "IBM WXS Container: WXS Base installed successfully"
163
+		set_state 'ibm-wxs-container.installed'
164
+	fi	
165
+}
166
+
167
+
168
+#Install WXS Container fixpack package
169
+@when_any 'ibm-wxs-container.installed'
170
+@when_not 'ibm-wxs-container.updated'
171
+function install-wxs-container-fixpack(){
172
+	#check if downloaded package is present in ${CHARM_DIR}/files/archives
173
+	juju-log "install-wxs-container-fixpack: calling check_wxs_fixpack function"
174
+	juju-log "install-wxs-container-fixpack: fetching the ibm_wxs_fixpack_installer resource"
175
+	status-set maintenance "IBM WXS Container: fetching the ibm_wxs_fixpack_installer resource"
176
+	cfg_wxs_fixpack_pkg_name=`resource-get 'ibm_wxs_fixpack_installer' || echo unavailable`
177
+
178
+	ibm_wxs_fixpack_isempty=`file $cfg_wxs_fixpack_pkg_name | { grep -q empty && echo "True"; } || echo "False"`
179
+
180
+	if [ "$cfg_wxs_fixpack_pkg_name" = "unavailable" ]; then
181
+		if [ "$ARCHITECTURE" == "ppc64le" ]; then
182
+			juju-log "install-wxs-container-fixpack: missing required ibm_wxs_fixpack_installer resource"
183
+			status-set blocked "IBM WXS Container: missing required ibm_wxs_fixpack_installer resource for ppc64le platform"
184
+			exit 0	
185
+		elif [ "$ARCHITECTURE" == "x86_64" -o "$ARCHITECTURE" == "s390x" ]; then
186
+			juju-log "install-wxs-container-fixpack: no ibm_wxs_fixpack_installer packages to install"
187
+			status-set active "IBM WXS Container: IBM WXS Container is Ready"
188
+			return 0
189
+		fi
190
+	fi
191
+			
192
+	if [ "$ibm_wxs_fixpack_isempty" = "True" ]; then
193
+		if [ "$ARCHITECTURE" == "ppc64le" ]; then
194
+			juju-log "install-wxs-container-fixpack: missing required ibm_wxs_fixpack_installer resource, found empty packages"
195
+			status-set blocked "IBM WXS Conatiner: missing required ibm_wxs_fixpack_installer resource, provide actual ibm_wxs_fixpack_installer resources."
196
+			exit 0	
197
+		elif [ "$ARCHITECTURE" == "x86_64" -o "$ARCHITECTURE" == "s390x" ]; then
198
+			juju-log "install-wxs-container-fixpack: no ibm_wxs_container_fixpack packages to install"
199
+			status-set active "IBM WXS Conatiner: IBM WXS Container is Ready"
200
+			return 0
201
+		fi
202
+		
203
+	fi
204
+        if [ -f ${cfg_wxs_fixpack_pkg_name} ]; then
205
+		if charms.reactive is_state 'wxsgrid.available'; then
206
+			juju-log "install-wxs-container-fixpack: Has relation with other service"
207
+			status-set blocked "IBM WXS Container: Has relation with other service. Remove Relation before applying Fixpack"
208
+			exit 0
209
+		fi
210
+		juju-log "install-wxs-container-fixpack: extracting WXS fixpack packages"
211
+		ARCHIVE_DIR=`dirname $cfg_wxs_fixpack_pkg_name`
212
+		juju-log "install-wxs-container-fixpack: extracting the ibm_wxs_fixpack_installer resource"
213
+		status-set maintenance "IBM WXS Container: extracting the ibm_wxs_fixpack_installer resources"
214
+
215
+		if [ ! -d $ARCHIVE_DIR/../WXS_FP ]; then
216
+                	mkdir $ARCHIVE_DIR/../WXS_FP
217
+		fi
218
+		if ! unzip ${cfg_wxs_fixpack_pkg_name} -d ${ARCHIVE_DIR}/../WXS_FP
219
+		then
220
+			juju-log "install-wxs-container-fixpack: Unable to extract the WXS fixpack package content. Verify whether the package is corrupt."
221
+			status-set blocked "IBM WXS Container: IBM WXS fixpack package is corrupt"
222
+			rm -rf $ARCHIVE_DIR/../WXS_FP
223
+			exit 0
224
+		else
225
+			juju-log "install-wxs-container-fixpack: Extracted WXS fixpack package"
226
+			status-set maintenance "IBM WXS Container: Extracted wxs fixpack package"
227
+			WXS_Install_dir="`basename ${ARCHIVE_DIR}/../WXS_BASE/WXS_*`"
228
+                        juju-log "install-wxs-catalog: WXS_Install_dir is $WXS_Install_dir"
229
+		fi
230
+	fi
231
+
232
+	#Stop wxs container service
233
+	if [ -d $WXS_INSTALL_PATH ]; then
234
+		juju-log "install-wxs-container-fixpack: calling check_arch function"
235
+		if charms.reactive is_state 'ibm-wxs-container-server.started'; then
236
+			set +e
237
+			stop_wxs_container
238
+			set -e
239
+			if [ $? -eq 1 ]; then
240
+				juju-log "install-wxs-container-fixpack: Can not proceed for fixpack Installation, as server is running"
241
+				status-set blocked "IBM WXS Container: Can not proceed for fixpack Installation, container server is running.Stop Container server"
242
+				exit 0
243
+			fi
244
+		fi
245
+	fi
246
+
247
+	#Install WXS fixpack package
248
+	juju-log "install-wxs-container-fixpack: WXS Fix Pack Installation started"
249
+	status-set maintenance "IBM WXS Container: WXS Fix Pack Installation started"
250
+	if ! $IM_INSTALL_PATH/eclipse/tools/imcl install com.ibm.websphere.WXS.v86 -acceptLicense -installationDirectory $WXS_INSTALL_PATH -repositories ${CHARM_DIR}/../resources/WXS_FP/8611 
251
+	then
252
+		juju-log "install-wxs-container-fixpack: Error while installing WXS Fix Pack"
253
+		status-set blocked "IBM WXS Container: Error while upgrading WXS Fix Pack"
254
+		exit 1
255
+	else
256
+		juju-log "install-wxs-container-fixpack: WXS Fix Pack is installed successfully"
257
+		status-set active "IBM WXS Container: WXS Fix Pack is installed successfully"
258
+		set_state 'ibm-wxs-container.updated'
259
+	fi
260
+}
261
+
262
+@hook 'upgrade-charm'
263
+function check_fixpack(){
264
+	# The upgrade-charm hook will fire when a new resource is pushed for this
265
+	# charm. This is a good time to determine if we need to deal with a new
266
+	# fixpack.
267
+	if ! charms.reactive is_state 'ibm-wxs-container.updated'; then
268
+		# If there is no prior fixpack installed (because ibm-wxs-container.updated is not
269
+		# set), do nothing since install_wxs_catalog_fixpack will handle that case.
270
+		juju-log "check_fixpack: no fixpack has been installed; nothing to upgrade."
271
+		return 0
272
+	else
273
+	# If we have a fixpack packges already (because ibm-wxs-catalog.updated is set),
274
+	# we should fetch the latest fixpack packages and determine if it is new.
275
+	#  - If it is new, set our states so install_wxs_catalog_fixpack is called again
276
+	#  - If it is not new, do nothing
277
+		juju-log "check_fixpack: scanning for new fixpacks to install"
278
+		WXS_FP_DIR="$CHARM_DIR/../resources/ibm_wxs_fixpack_installer"
279
+       
280
+		CUR_FP="$WXS_FP_DIR/ibm_wxs_fixpack_installer.zip"
281
+       
282
+		if [ -f $CUR_FP ]; then
283
+			CUR_FP_MD5=`md5sum "$CUR_FP" | awk '{print $1}'`
284
+		fi
285
+       
286
+		NEW_FP=`resource-get 'ibm_wxs_fixpack_installer' || echo unavailable`
287
+	
288
+
289
+		if [ "$NEW_FP" = "unavailable" ]; then
290
+			juju-log "check_fixpack: no fixpack to install"
291
+			return 0
292
+		elif [ -f $NEW_FP ]; then
293
+			NEW_FP_MD5=`md5sum "$NEW_FP" | awk '{print $1}'`
294
+		fi
295
+
296
+		if [ "$CUR_FP_MD5" != "$NEW_FP_MD5" ]; then
297
+			juju-log "check_fixpack: new fixpack detected ($CUR_FP with $CUR_FP_MD5 versus $NEW_FP with $NEW_FP_MD5)"
298
+			rm -rf $CHARM_DIR/../resources/WXS_FP
299
+			remove_state 'ibm-wxs-container.updated'
300
+		else
301
+			juju-log "check_fixpack: no new fixpack to install"
302
+		fi
303
+	fi
304
+}
305
+
306
+
307
+@when 'wxsgrid.available' 'wxsgrid.ready'
308
+@when_any 'ibm-wxs-container.installed' 'ibm-wxs-container.updated'
309
+@when_not 'ibm-wxs-container-service.started'
310
+function start_ibm_wxs_container() {
311
+	#Start wxs container service
312
+	juju-log "start_ibm_wxs_container: calling start_wxs_container function"
313
+	set +e
314
+	start_wxs_container
315
+	set -e
316
+	if [ $? -eq 1 ]; then
317
+		juju-log "start_ibm_wxs_container: Could not start Container"
318
+	fi
319
+}
320
+
321
+@when_not 'wxsgrid.available'
322
+function depart_relation(){
323
+	if [ -d $WXS_INSTALL_PATH ]; then
324
+		set +e
325
+		stop_wxs_container
326
+		set -e
327
+		if [ $? -eq 1 ]; then
328
+			juju-log "depart_relation: Could not stop Container when relation broken from Catalog"
329
+			exit 1
330
+		fi
331
+	fi
332
+}
333
+
334
+reactive_handler_main
Back to file index

reactive/leadership.py

 1
--- 
 2
+++ reactive/leadership.py
 3
@@ -0,0 +1,68 @@
 4
+# Copyright 2015-2016 Canonical Ltd.
 5
+#
 6
+# This file is part of the Leadership Layer for Juju.
 7
+#
 8
+# This program is free software: you can redistribute it and/or modify
 9
+# it under the terms of the GNU General Public License version 3, as
10
+# published by the Free Software Foundation.
11
+#
12
+# This program is distributed in the hope that it will be useful, but
13
+# WITHOUT ANY WARRANTY; without even the implied warranties of
14
+# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
15
+# PURPOSE.  See the GNU General Public License for more details.
16
+#
17
+# You should have received a copy of the GNU General Public License
18
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
19
+
20
+from charmhelpers.core import hookenv
21
+from charmhelpers.core import unitdata
22
+
23
+from charms import reactive
24
+from charms.leadership import leader_get, leader_set
25
+
26
+
27
+__all__ = ['leader_get', 'leader_set']  # Backwards compatibility
28
+
29
+
30
+def initialize_leadership_state():
31
+    '''Initialize leadership.* states from the hook environment.
32
+
33
+    Invoked by hookenv.atstart() so states are available in
34
+    @hook decorated handlers.
35
+    '''
36
+    is_leader = hookenv.is_leader()
37
+    if is_leader:
38
+        hookenv.log('Initializing Leadership Layer (is leader)')
39
+    else:
40
+        hookenv.log('Initializing Leadership Layer (is follower)')
41
+
42
+    reactive.helpers.toggle_state('leadership.is_leader', is_leader)
43
+
44
+    previous = unitdata.kv().getrange('leadership.settings.', strip=True)
45
+    current = hookenv.leader_get()
46
+
47
+    # Handle deletions.
48
+    for key in set(previous.keys()) - set(current.keys()):
49
+        current[key] = None
50
+
51
+    any_changed = False
52
+    for key, value in current.items():
53
+        reactive.helpers.toggle_state('leadership.changed.{}'.format(key),
54
+                                      value != previous.get(key))
55
+        if value != previous.get(key):
56
+            any_changed = True
57
+        reactive.helpers.toggle_state('leadership.set.{}'.format(key),
58
+                                      value is not None)
59
+    reactive.helpers.toggle_state('leadership.changed', any_changed)
60
+
61
+    unitdata.kv().update(current, prefix='leadership.settings.')
62
+
63
+
64
+# Per https://github.com/juju-solutions/charms.reactive/issues/33,
65
+# this module may be imported multiple times so ensure the
66
+# initialization hook is only registered once. I have to piggy back
67
+# onto the namespace of a module imported before reactive discovery
68
+# to do this.
69
+if not hasattr(reactive, '_leadership_registered'):
70
+    hookenv.atstart(initialize_leadership_state)
71
+    reactive._leadership_registered = True
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,68 @@
 4
+#!/usr/bin/env python3
 5
+
 6
+
 7
+import amulet
 8
+import re
 9
+import unittest
10
+
11
+seconds_to_wait = 20000
12
+
13
+
14
+class TestDeploy(unittest.TestCase):
15
+    """
16
+    Deployment test for the IBM WXS Container charm
17
+    """
18
+    def setUp(self):
19
+        self.d = amulet.Deployment(series='trusty')
20
+        self.d.add('ibm-wxs-container',
21
+                   'cs:~ibmcharmers/trusty/ibm-wxs-container')
22
+        self.d.add('ibm-wxs-catalog', 'cs:~ibmcharmers/trusty/ibm-wxs-catalog')
23
+        self.d.setup(seconds_to_wait)
24
+        self.d.sentry.wait(seconds_to_wait)
25
+        self.d.relate('ibm-wxs-container:ibm-wxs', 'bm-wxs-catalog:ibm-wxs')
26
+
27
+    def test_deploy_with_placeholder_resource(self):
28
+        # The status message when using placeholder resources will include the
29
+        # string "ibm_was_nd_installer resource". If we see that, the test is
30
+        # successful.
31
+        sentry_re = re.compile('ibm_im_installer resource')
32
+        self.d.sentry.wait_for_messages({"ibm-wxs-container": sentry_re})
33
+        sentry_re = re.compile('ibm_wxs_base_installer resource')
34
+        self.d.sentry.wait_for_messages({"ibm-wxs-container": sentry_re})
35
+        sentry_re = re.compile('ibm_im_installer resource')
36
+        self.d.sentry.wait_for_messages({"ibm-wxs-catalog": sentry_re})
37
+        sentry_re = re.compile('ibm_wxs_base_installer resource')
38
+        self.d.sentry.wait_for_messages({"ibm-wxs-catalog": sentry_re})
39
+
40
+    def test_ibm_wxs_container_deployed(self):
41
+        self.assertTrue(self.d.deployed)
42
+        wxs_container_unit = self.d.sentry['ibm-wxs-container'][0]
43
+        state_wxs_container = wxs_container_unit.info['agent-state']
44
+        print('IBM WXS Container is %s' % state_wxs_container)
45
+        output, result_code = wxs_container_unit.run("ps -ef"
46
+                                                     " | grep "
47
+                                                     "catalog"
48
+                                                     "ServiceEndPoints")
49
+        print('Output of grep is %s' % output)
50
+
51
+        if result_code != 0:
52
+            message = ('catalog server is not running')
53
+            amulet.raise_status(amulet.FAIL, msg=message)
54
+
55
+    def test_ibm_wxs_catalog_deployed(self):
56
+        wxs_catalog_unit = self.d.sentry['ibm-wxs-catalog'][0]
57
+        state_wxs_catalog = wxs_catalog_unit.info['agent-state']
58
+        print('IBM WXS Catalog Server is %s' % state_wxs_catalog)
59
+        output, result_code = wxs_catalog_unit.run("ps -ef"
60
+                                                   " | grep "
61
+                                                   "catalog"
62
+                                                   "ServiceEndPoints")
63
+        print('Output of grep is %s' % output)
64
+
65
+        if result_code != 0:
66
+            message = ('catalog server is not running')
67
+            amulet.raise_status(amulet.FAIL, msg=message)
68
+
69
+
70
+if __name__ == '__main__':
71
+    unittest.main()
Back to file index

tests/tests.yaml

1
--- 
2
+++ tests/tests.yaml
3
@@ -0,0 +1,5 @@
4
+packages:
5
+  - amulet
6
+  - python3
7
+  - unzip
8
+  - pwgen
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