~ibmcharmers/ibm-mq-28

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

CPP?: No
OIL?: No

This charm is for IBM MQ. Earlier recommended IBM MQ charm was for Power and x86 Trusty Series. This charm adds the support for Ubuntu on Z as well (Xenial).
Its source code can be found in the below repository:
https://code.launchpad.net/~ibmcharmers/ibmlayers/layer-ibm-mq


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

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,127 @@
  4
+## Charm for IBM MQ 9.0.1
  5
+
  6
+### Overview
  7
+
  8
+IBM MQ
  9
+
 10
+IBM MQ provides messaging services to transport multiple types of data.
 11
+MQ Runtime, Server and Sample components from IBM MQ product can be deployed using this charm.
 12
+
 13
+This charm installs IBM MQ product and configures it's IP Address and default port number. MQ Administrators can setup queue managers and queues. This will allow IBM MQ client application to transmit/receive messages.
 14
+
 15
+More information on IBM MQ available at the [Product Page](http://www-03.ibm.com/software/products/en/ibm-mq) and [IBM Knowledge Center](https://www.ibm.com/support/knowledgecenter/SSFKSJ_9.0.0/com.ibm.mq.pro.doc/q128140_.htm)
 16
+
 17
+### Prerequisites
 18
+
 19
+This charm makes use of resources, a feature only available in Juju 2.0. During deploy, you will need to specify the installable package(s) required by this charm. 
 20
+Download your licensed `IBM MQ 9.0.1 Continuous Delivery Release` version for Ubuntu. To acquire and download IBM MQ, follow instructions available at the [Product Page](http://www-03.ibm.com/software/products/en/ibm-mq). 
 21
+
 22
+`Ubuntu for x86_64`, the package and part number is:
 23
+    
 24
+	IBM MQ V9.0.1 Continuous Delivery Release for Linux for System x86 (CNF04ML) 
 25
+
 26
+`Ubuntu for Power LE`, the package and part number is:
 27
+ 
 28
+	IBM MQ V9.0.1 Continuous Delivery Release for Linux for System p LE (CNF02ML)
 29
+ 
 30
+ `Ubuntu for IBM z`, the package and part number is:  
 31
+ 
 32
+   	IBM MQ V9.0.1 Continuous Delivery Release for Linux for System z (CNF03ML)
 33
+
 34
+### Usage
 35
+To use this charm, you must agree to the Terms of Use. You can view the full license for IBM MQ by visiting the [Software license agreements search website](http://www-03.ibm.com/software/sla/sladb.nsf/search).
 36
+Search for `"IBM MQ V9.0.1"` and choose the license that applies to the version you are using.
 37
+
 38
+### Deploy
 39
+
 40
+Run the following commands to deploy this charm:
 41
+           
 42
+    juju deploy ibm-mq --resource ibm_mq_installer=</path/to/installer.tar.gz>
 43
+**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.
 44
+To accept the terms:
 45
+
 46
+    juju agree ibm-mq/1
 47
+Once you have agreed to the Terms, then only the IBM MQ charm will be deployed.
 48
+
 49
+##### Manually update the following system configuration after installing MQ:
 50
+
 51
+In order to create MQ objects like queue, it is required that some of the system configurations be updated. User has to manually update these values incase the limit is less for the required parameters. Details are provided at [IBM Knowledge Center](https://www.ibm.com/support/knowledgecenter/SSFKSJ_9.0.0/com.ibm.mq.pro.doc/q128140_.htm).
 52
+
 53
+  * In `/etc/sysctl.conf`:
 54
+
 55
+        fs.file-max = 524288
 56
+        kernel.shmmax = 268435456
 57
+
 58
+##### The Charm updates the following system configuration:
 59
+
 60
+In order to create MQ objects like queue, it is required that some of the system configurations be updated. Details provided at [IBM Knowledge Center](https://www.ibm.com/support/knowledgecenter/SSFKSJ_9.0.0/com.ibm.mq.pro.doc/q128140_.htm).
 61
+The below configurations will be updated by the charm only after installing MQ.
 62
+  * Adds user `ubuntu` to group `mqm`.
 63
+
 64
+  * In `/etc/security/limits.conf` if hard nofile and soft nofile limit for user `mqm` are  less than 10240:
 65
+
 66
+        mqm              hard    nofile          10240
 67
+        mqm              soft    nofile          10240
 68
+  
 69
+  * Updates `/etc/pam.d/common-session` file to take the above configurations to take effect
 70
+
 71
+Verify these changes have been made successfully if MQ throws up any errors.
 72
+
 73
+
 74
+
 75
+### Verification
 76
+
 77
+Once deployed, you can make use of IBM MQ by creating queues or adding relation with other services like WAS.
 78
+To verify IBM MQ is installed, list the contents of the installation directory:
 79
+
 80
+    juju run --application ibm-mq 'ls /opt/mqm'
 81
+
 82
+
 83
+### Relation with other services:
 84
+
 85
+ibm-mq can have relation with other services to get the service specific queue manager. For example if ibm-mq is related with ibm-was then, ibm-was specific queue manger will be created like 'ibm-wasQM'.
 86
+ 
 87
+    juju add-relation ibm-mq:messaging ibm-was-base:wasmessaging
 88
+ or     
 89
+ 
 90
+    juju add-relation ibm-mq ibm-was-base
 91
+	
 92
+IBM-MQ sets Queue Manager name, Queue Name, IP Address and Port for the connected services. It creates a Queue Manager for the consumer application and a local queue i.e QUEUE1 for above Queue Manager. But as a Queue Name it sets a filename where MQSC Commands can be edited for further operation.
 93
+      
 94
+On removal of relation with the service with which already relation was established, the service specific queue manger will be removed i.e in the above case 'ibm-wasQM' will be removed.
 95
+
 96
+     juju remove-relation ibm-mq:messaging ibm-was-base:wasmessaging
 97
+or  
 98
+    
 99
+     juju remove-relation ibm-mq ibm-was-base
100
+
101
+
102
+
103
+#### Known Limitations:
104
+
105
+Local providers does not allow updates to system configuration using sysctl command. These configurations will need be done manually for MQ to function. The required configurations are provided in the README under the `Deploy` section.
106
+
107
+
108
+### IBM MQ Information
109
+
110
+(1) General Information
111
+Details about MQ available [here](http://www-01.ibm.com/software/integration/wmq/library/).
112
+Details about MQ Version 9.0.1 available at [IBM Knowledge Center](https://www.ibm.com/support/knowledgecenter/SSFKSJ_9.0.0/com.ibm.mq.pro.doc/q128140_.htm)
113
+
114
+(2) Download Information
115
+Information on procuring MQ product is available at the [Product Page](http://www-03.ibm.com/software/products/en/ibm-mq) and at the [Passport Advantage Site](http://www-01.ibm.com/software/passportadvantage/).
116
+A development version for x86_64 is available [here](http://www14.software.ibm.com/cgi-bin/weblap/lap.pl?popup=Y&li_formnum=L-APIG-ABNDJ7&accepted_url=http://public.dhe.ibm.com/ibmdl/export/pub/software/websphere/messaging/mqadv/mqadv_dev901_linux_x86-64.tar.gz). After clicking on the above link and if you agree to the license, click on `'I agree'` link to download the `IBM MQ` package.
117
+
118
+(3) License Information
119
+License information for IBM MQ is available as part of the downloaded product package. The license can be viewed by running the following command after extracting IBM MQ.
120
+`./mqlicense.sh -text_only`
121
+
122
+License for the development version is available [here](http://www14.software.ibm.com/cgi-bin/weblap/lap.pl?popup=Y&li_formnum=L-APIG-ABNDJ7&accepted_url=http://public.dhe.ibm.com/ibmdl/export/pub/software/websphere/messaging/mqadv/mqadv_dev901_linux_x86-64.tar.gz).
123
+
124
+(4) Contact Information
125
+For issues with this charm, please contact IBM Juju Support Team <jujusupp@us.ibm.com>
126
+
127
+(5) Known Limitations
128
+This charm makes use of Juju features that are only available in version `2.0` or greater.
129
+
130
+
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

copyright

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

files/archives/mq_create_queue.mqsc

1
--- 
2
+++ files/archives/mq_create_queue.mqsc
3
@@ -0,0 +1 @@
4
+DEFINE QLOCAL (QUEUE1)
Back to file index

files/archives/mq_delete_queue.mqsc

1
--- 
2
+++ files/archives/mq_delete_queue.mqsc
3
@@ -0,0 +1 @@
4
+DELETE QLOCAL(QUEUE1) PURGE
Back to file index

files/archives/qinput

1
--- 
2
+++ files/archives/qinput
3
@@ -0,0 +1,2 @@
4
+Test Line 1
5
+Test Line 2
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/messaging-relation-broken

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

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

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

 1
--- 
 2
+++ hooks/messaging-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

hooks/relations/ibm-mq/README.md

 1
--- 
 2
+++ hooks/relations/ibm-mq/README.md
 3
@@ -0,0 +1,42 @@
 4
+Overview
 5
+-----------
 6
+
 7
+This interface layer handles the communication between `IBM MQ` and other charms that tries to communicate by sending each other data in messages through IBM-MQ rather than by calling each other directly.
 8
+The provider end of this interface provides the Queue Manager name, Queue Name, IP Address and Port.
 9
+The consumer/requires part will be any other charm and can get all the above values viz. Queue Manager name, Queue Name, IP Address and Port to send or receive messages. Here we are describing consumer charm as `ibm-was-base`
10
+
11
+
12
+Usage
13
+------
14
+
15
+#### Provides 
16
+IBM MQ product will provide this interface. This interface layer will set the following states, as appropriate:
17
+
18
+ - `{relation_name}.connected`: The relation is established, IBM-MQ is ready to send it's information.
19
+ 
20
+	- `get_consumer_hostname()` - returns/gets the consumer hostname to create a channel authentication rule that allows client system to use the channel by entering the MQSC command.
21
+
22
+	- `set_mq_details()` - Sets Queue Manager name, Queue Name, IP Address and Port for the connected services. 
23
+						As a Queue Name it sets a filename where MQSC Commands can be edited for further operation. 
24
+						
25
+	
26
+ - `{relation_name}.departed` : The relation has been removed. Any cleanup related to the consumer charm (e.g IBM WebSphere Server) should happen now on the Consumer charm since the consumer is going away.
27
+
28
+#### Requires
29
+
30
+Consumer charms e.g `IBM WebSphere Application Server` will require this interface to connect to IBM-MQ so that they can get the necessary information about `IBM-MQ` to send/receive messages to other Applications. 
31
+This interface layer will set the following states, as appropriate:
32
+
33
+- `{relation_name}.connected` : The consumer charm has been related to a IBM-MQ provider charm. 
34
+	At this point, the charm waits for Provider charm to send details like Queue Manager name, Queue Name, IP Address and Port.
35
+	
36
+	- `set_hostname()` - sets the `hostname`, so that IBM-MQ can get the consumer/client hostname to allow to send/receive messages.
37
+
38
+- `{relation_name}.ready` : The consumer charm e.g `IBM WebSphere Application Server` is now ready to access the details of IBM-MQ to send/recieve messages. Such as Queue Manager name, Queue Name, IP Address/hostname and Port.
39
+
40
+    - `get_qm_name()` - returns the `QM_Name` that IBM-MQ has created.
41
+	- `get_qname()`  - returns the `QName` that IBM-MQ has created.
42
+	- `get_mq_hostname()` - returns the `hostname` that IBM-MQ has created.
43
+	- `get_mq_port()` - returns the `MQ Port` that IBM-MQ has created.
44
+
45
+- `{relation_name}.departed` : The relation has been removed. Any cleanup related to the provider charm should happen now. 
Back to file index

hooks/relations/ibm-mq/interface.yaml

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

hooks/relations/ibm-mq/provides.py

 1
--- 
 2
+++ hooks/relations/ibm-mq/provides.py
 3
@@ -0,0 +1,50 @@
 4
+from charms.reactive import hook
 5
+from charms.reactive import RelationBase
 6
+from charms.reactive import scopes
 7
+
 8
+
 9
+class mqProvides(RelationBase):
10
+    # Every unit connecting will get the same information
11
+    scope = scopes.SERVICE
12
+
13
+    @hook('{provides:ibm-mq}-relation-joined')
14
+    def joined(self):
15
+        conversation = self.conversation()
16
+        conversation.remove_state('{relation_name}.departed')
17
+        conversation.set_state('{relation_name}.connected')
18
+
19
+    @hook('{provides:ibm-mq}-relation-departed')
20
+    def departed(self):
21
+        conversation = self.conversation()
22
+        conversation.remove_state('{relation_name}.connected')
23
+        conversation.set_state('{relation_name}.departed')
24
+
25
+    def dismiss(self, service):
26
+        conversation = self.conversation(service)
27
+        conversation.remove_state('{relation_name}.departed')
28
+
29
+    def reset_states(self, service):
30
+        conversation = self.conversation(service)
31
+        conversation.remove_state('{relation_name}.connected')
32
+        conversation.remove_state('{relation_name}.departed')
33
+
34
+    def set_mq_details(self, service, QM_Name, Qname, host, port):
35
+        conversation = self.conversation(service)
36
+        conversation.set_remote(data={
37
+            'QM_Name': QM_Name,
38
+            'Qname': Qname,
39
+            'host': host,
40
+            'port': port,
41
+        })
42
+
43
+    def get_consumer_hostname(self):
44
+        return self.get_remote('host')
45
+
46
+    def services(self):
47
+        """
48
+        Return a list of services requesting MQ.
49
+        """
50
+        service = []
51
+        for conversation in self.conversations():
52
+            service.append(conversation.scope)
53
+        return service
Back to file index

hooks/relations/ibm-mq/requires.py

 1
--- 
 2
+++ hooks/relations/ibm-mq/requires.py
 3
@@ -0,0 +1,42 @@
 4
+from charms.reactive import hook
 5
+from charms.reactive import RelationBase
 6
+from charms.reactive import scopes
 7
+
 8
+
 9
+class mq1Requires(RelationBase):
10
+    scope = scopes.GLOBAL
11
+
12
+    @hook('{requires:ibm-mq}-relation-joined')
13
+    def joined(self):
14
+        self.remove_state('{relation_name}.departed')
15
+        self.set_state('{relation_name}.connected')
16
+
17
+    @hook('{requires:ibm-mq}-relation-changed')
18
+    def changed(self):
19
+        if str(self.get_remote('port')) != "None":
20
+            self.set_state('{relation_name}.ready')
21
+            print("Status is relation_name.ready in requires")
22
+
23
+    @hook('{requires:ibm-mq}-relation-departed')
24
+    def departed(self):
25
+        self.remove_state('{relation_name}.connected')
26
+        self.remove_state('{relation_name}.ready')
27
+        self.set_state('{relation_name}.departed')
28
+
29
+    def set_hostname(self, host):
30
+        conversation = self.conversation()
31
+        conversation.set_remote(data={
32
+            'host': host,
33
+        })
34
+
35
+    def get_qm_name(self):
36
+        return self.get_remote('QM_Name')
37
+
38
+    def get_qname(self):
39
+        return self.get_remote('Qname')
40
+
41
+    def get_mq_hostname(self):
42
+        return self.get_remote('host')
43
+
44
+    def get_mq_port(self):
45
+        return self.get_remote('port')
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

icon.svg

  1
--- 
  2
+++ icon.svg
  3
@@ -0,0 +1,524 @@
  4
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
  5
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
  6
+
  7
+<svg
  8
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
  9
+   xmlns:cc="http://creativecommons.org/ns#"
 10
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
 11
+   xmlns:svg="http://www.w3.org/2000/svg"
 12
+   xmlns="http://www.w3.org/2000/svg"
 13
+   xmlns:xlink="http://www.w3.org/1999/xlink"
 14
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
 15
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
 16
+   width="96"
 17
+   height="96"
 18
+   id="svg6517"
 19
+   version="1.1"
 20
+   inkscape:version="0.48.4 r9939"
 21
+   sodipodi:docname="icon.svg">
 22
+  <defs
 23
+     id="defs6519">
 24
+    <linearGradient
 25
+       inkscape:collect="always"
 26
+       id="linearGradient3886">
 27
+      <stop
 28
+         style="stop-color:#000000;stop-opacity:1;"
 29
+         offset="0"
 30
+         id="stop3888" />
 31
+      <stop
 32
+         style="stop-color:#000000;stop-opacity:0;"
 33
+         offset="1"
 34
+         id="stop3890" />
 35
+    </linearGradient>
 36
+    <linearGradient
 37
+       id="Background">
 38
+      <stop
 39
+         id="stop4178"
 40
+         offset="0"
 41
+         style="stop-color:#466bb0;stop-opacity:1;" />
 42
+      <stop
 43
+         id="stop4180"
 44
+         offset="1"
 45
+         style="stop-color:#c9c9c9;stop-opacity:1" />
 46
+    </linearGradient>
 47
+    <filter
 48
+       style="color-interpolation-filters:sRGB;"
 49
+       inkscape:label="Inner Shadow"
 50
+       id="filter1121">
 51
+      <feFlood
 52
+         flood-opacity="0.59999999999999998"
 53
+         flood-color="rgb(0,0,0)"
 54
+         result="flood"
 55
+         id="feFlood1123" />
 56
+      <feComposite
 57
+         in="flood"
 58
+         in2="SourceGraphic"
 59
+         operator="out"
 60
+         result="composite1"
 61
+         id="feComposite1125" />
 62
+      <feGaussianBlur
 63
+         in="composite1"
 64
+         stdDeviation="1"
 65
+         result="blur"
 66
+         id="feGaussianBlur1127" />
 67
+      <feOffset
 68
+         dx="0"
 69
+         dy="2"
 70
+         result="offset"
 71
+         id="feOffset1129" />
 72
+      <feComposite
 73
+         in="offset"
 74
+         in2="SourceGraphic"
 75
+         operator="atop"
 76
+         result="composite2"
 77
+         id="feComposite1131" />
 78
+    </filter>
 79
+    <filter
 80
+       style="color-interpolation-filters:sRGB;"
 81
+       inkscape:label="Drop Shadow"
 82
+       id="filter950">
 83
+      <feFlood
 84
+         flood-opacity="0.25"
 85
+         flood-color="rgb(0,0,0)"
 86
+         result="flood"
 87
+         id="feFlood952" />
 88
+      <feComposite
 89
+         in="flood"
 90
+         in2="SourceGraphic"
 91
+         operator="in"
 92
+         result="composite1"
 93
+         id="feComposite954" />
 94
+      <feGaussianBlur
 95
+         in="composite1"
 96
+         stdDeviation="1"
 97
+         result="blur"
 98
+         id="feGaussianBlur956" />
 99
+      <feOffset
100
+         dx="0"
101
+         dy="1"
102
+         result="offset"
103
+         id="feOffset958" />
104
+      <feComposite
105
+         in="SourceGraphic"
106
+         in2="offset"
107
+         operator="over"
108
+         result="composite2"
109
+         id="feComposite960" />
110
+    </filter>
111
+    <clipPath
112
+       clipPathUnits="userSpaceOnUse"
113
+       id="clipPath873">
114
+      <g
115
+         transform="matrix(0,-0.66666667,0.66604479,0,-258.25992,677.00001)"
116
+         id="g875"
117
+         inkscape:label="Layer 1"
118
+         style="fill:#ff00ff;fill-opacity:1;stroke:none;display:inline">
119
+        <path
120
+           style="fill:#ff00ff;fill-opacity:1;stroke:none;display:inline"
121
+           d="m 46.702703,898.22775 50.594594,0 C 138.16216,898.22775 144,904.06497 144,944.92583 l 0,50.73846 c 0,40.86071 -5.83784,46.69791 -46.702703,46.69791 l -50.594594,0 C 5.8378378,1042.3622 0,1036.525 0,995.66429 L 0,944.92583 C 0,904.06497 5.8378378,898.22775 46.702703,898.22775 Z"
122
+           id="path877"
123
+           inkscape:connector-curvature="0"
124
+           sodipodi:nodetypes="sssssssss" />
125
+      </g>
126
+    </clipPath>
127
+    <filter
128
+       inkscape:collect="always"
129
+       id="filter891"
130
+       inkscape:label="Badge Shadow">
131
+      <feGaussianBlur
132
+         inkscape:collect="always"
133
+         stdDeviation="0.71999962"
134
+         id="feGaussianBlur893" />
135
+    </filter>
136
+    <linearGradient
137
+       inkscape:collect="always"
138
+       xlink:href="#linearGradient3886"
139
+       id="linearGradient3892"
140
+       x1="-410.30341"
141
+       y1="624.94247"
142
+       x2="-343.00002"
143
+       y2="624.94247"
144
+       gradientUnits="userSpaceOnUse" />
145
+    <linearGradient
146
+       inkscape:collect="always"
147
+       xlink:href="#Background"
148
+       id="linearGradient3900"
149
+       x1="-410.30341"
150
+       y1="624.94244"
151
+       x2="-343.00003"
152
+       y2="624.94244"
153
+       gradientUnits="userSpaceOnUse" />
154
+    <linearGradient
155
+       id="id0"
156
+       gradientUnits="userSpaceOnUse"
157
+       x1="558.13898"
158
+       y1="0"
159
+       x2="558.13898"
160
+       y2="1116.27">
161
+      <stop
162
+         offset="0"
163
+         stop-color="#BFA6E6"
164
+         id="stop7" />
165
+      <stop
166
+         offset="1"
167
+         stop-color="#6C5393"
168
+         id="stop9" />
169
+    </linearGradient>
170
+    <mask
171
+       id="id1">
172
+      <linearGradient
173
+         id="id2"
174
+         gradientUnits="userSpaceOnUse"
175
+         x1="558.13898"
176
+         y1="65.280296"
177
+         x2="558.13898"
178
+         y2="342.715">
179
+        <stop
180
+           offset="0"
181
+           stop-opacity="1"
182
+           stop-color="white"
183
+           id="stop13" />
184
+        <stop
185
+           offset="0.141176"
186
+           stop-opacity="98.8824"
187
+           stop-color="white"
188
+           id="stop15" />
189
+        <stop
190
+           offset="1"
191
+           stop-opacity="0"
192
+           stop-color="white"
193
+           id="stop17" />
194
+      </linearGradient>
195
+      <rect
196
+         style="fill:url(#id2)"
197
+         y="0"
198
+         x="0"
199
+         width="1116"
200
+         height="408"
201
+         id="rect19" />
202
+    </mask>
203
+    <linearGradient
204
+       id="linearGradient3161"
205
+       gradientUnits="userSpaceOnUse"
206
+       x1="558.13898"
207
+       y1="65.280296"
208
+       x2="558.13898"
209
+       y2="342.715">
210
+      <stop
211
+         offset="0"
212
+         stop-opacity="1"
213
+         stop-color="white"
214
+         id="stop3163" />
215
+      <stop
216
+         offset="0.141176"
217
+         stop-opacity="98.8824"
218
+         stop-color="white"
219
+         id="stop3165" />
220
+      <stop
221
+         offset="1"
222
+         stop-opacity="0"
223
+         stop-color="white"
224
+         id="stop3167" />
225
+    </linearGradient>
226
+    <linearGradient
227
+       id="id0-2"
228
+       gradientUnits="userSpaceOnUse"
229
+       x1="558.13898"
230
+       y1="0"
231
+       x2="558.13898"
232
+       y2="1116.27">
233
+      <stop
234
+         offset="0"
235
+         stop-color="#BFA6E6"
236
+         id="stop7-4" />
237
+      <stop
238
+         offset="1"
239
+         stop-color="#6C5393"
240
+         id="stop9-8" />
241
+    </linearGradient>
242
+    <mask
243
+       id="id1-4">
244
+      <linearGradient
245
+         id="id2-9"
246
+         gradientUnits="userSpaceOnUse"
247
+         x1="558.13898"
248
+         y1="65.280296"
249
+         x2="558.13898"
250
+         y2="342.715">
251
+        <stop
252
+           offset="0"
253
+           stop-opacity="1"
254
+           stop-color="white"
255
+           id="stop13-0" />
256
+        <stop
257
+           offset="0.141176"
258
+           stop-opacity="98.8824"
259
+           stop-color="white"
260
+           id="stop15-9" />
261
+        <stop
262
+           offset="1"
263
+           stop-opacity="0"
264
+           stop-color="white"
265
+           id="stop17-8" />
266
+      </linearGradient>
267
+      <rect
268
+         style="fill:url(#id2-9)"
269
+         y="0"
270
+         x="0"
271
+         width="1116"
272
+         height="408"
273
+         id="rect19-3" />
274
+    </mask>
275
+    <linearGradient
276
+       id="linearGradient3161-1"
277
+       gradientUnits="userSpaceOnUse"
278
+       x1="558.13898"
279
+       y1="65.280296"
280
+       x2="558.13898"
281
+       y2="342.715">
282
+      <stop
283
+         offset="0"
284
+         stop-opacity="1"
285
+         stop-color="white"
286
+         id="stop3163-2" />
287
+      <stop
288
+         offset="0.141176"
289
+         stop-opacity="98.8824"
290
+         stop-color="white"
291
+         id="stop3165-2" />
292
+      <stop
293
+         offset="1"
294
+         stop-opacity="0"
295
+         stop-color="white"
296
+         id="stop3167-9" />
297
+    </linearGradient>
298
+    <linearGradient
299
+       id="id0-6"
300
+       gradientUnits="userSpaceOnUse"
301
+       x1="558.13898"
302
+       y1="0"
303
+       x2="558.13898"
304
+       y2="1116.27">
305
+      <stop
306
+         offset="0"
307
+         stop-color="#BFA6E6"
308
+         id="stop7-9" />
309
+      <stop
310
+         offset="1"
311
+         stop-color="#6C5393"
312
+         id="stop9-88" />
313
+    </linearGradient>
314
+    <mask
315
+       id="id1-5">
316
+      <linearGradient
317
+         id="id2-95"
318
+         gradientUnits="userSpaceOnUse"
319
+         x1="558.13898"
320
+         y1="65.280296"
321
+         x2="558.13898"
322
+         y2="342.715">
323
+        <stop
324
+           offset="0"
325
+           stop-opacity="1"
326
+           stop-color="white"
327
+           id="stop13-3" />
328
+        <stop
329
+           offset="0.141176"
330
+           stop-opacity="98.8824"
331
+           stop-color="white"
332
+           id="stop15-93" />
333
+        <stop
334
+           offset="1"
335
+           stop-opacity="0"
336
+           stop-color="white"
337
+           id="stop17-9" />
338
+      </linearGradient>
339
+      <rect
340
+         style="fill:url(#id2-95)"
341
+         y="0"
342
+         x="0"
343
+         width="1116"
344
+         height="408"
345
+         id="rect19-4" />
346
+    </mask>
347
+    <linearGradient
348
+       id="linearGradient3161-17"
349
+       gradientUnits="userSpaceOnUse"
350
+       x1="558.13898"
351
+       y1="65.280296"
352
+       x2="558.13898"
353
+       y2="342.715">
354
+      <stop
355
+         offset="0"
356
+         stop-opacity="1"
357
+         stop-color="white"
358
+         id="stop3163-3" />
359
+      <stop
360
+         offset="0.141176"
361
+         stop-opacity="98.8824"
362
+         stop-color="white"
363
+         id="stop3165-8" />
364
+      <stop
365
+         offset="1"
366
+         stop-opacity="0"
367
+         stop-color="white"
368
+         id="stop3167-3" />
369
+    </linearGradient>
370
+  </defs>
371
+  <sodipodi:namedview
372
+     id="base"
373
+     pagecolor="#ffffff"
374
+     bordercolor="#666666"
375
+     borderopacity="1.0"
376
+     inkscape:pageopacity="0.0"
377
+     inkscape:pageshadow="2"
378
+     inkscape:zoom="4.0745362"
379
+     inkscape:cx="-16.612701"
380
+     inkscape:cy="49.018169"
381
+     inkscape:document-units="px"
382
+     inkscape:current-layer="layer3"
383
+     showgrid="true"
384
+     fit-margin-top="0"
385
+     fit-margin-left="0"
386
+     fit-margin-right="0"
387
+     fit-margin-bottom="0"
388
+     inkscape:window-width="1600"
389
+     inkscape:window-height="838"
390
+     inkscape:window-x="0"
391
+     inkscape:window-y="22"
392
+     inkscape:window-maximized="0"
393
+     showborder="true"
394
+     showguides="true"
395
+     inkscape:guide-bbox="true"
396
+     inkscape:showpageshadow="false">
397
+    <inkscape:grid
398
+       type="xygrid"
399
+       id="grid821" />
400
+    <sodipodi:guide
401
+       orientation="1,0"
402
+       position="16,48"
403
+       id="guide823" />
404
+    <sodipodi:guide
405
+       orientation="0,1"
406
+       position="64,80"
407
+       id="guide825" />
408
+    <sodipodi:guide
409
+       orientation="1,0"
410
+       position="80,40"
411
+       id="guide827" />
412
+    <sodipodi:guide
413
+       orientation="0,1"
414
+       position="64,16"
415
+       id="guide829" />
416
+  </sodipodi:namedview>
417
+  <metadata
418
+     id="metadata6522">
419
+    <rdf:RDF>
420
+      <cc:Work
421
+         rdf:about="">
422
+        <dc:format>image/svg+xml</dc:format>
423
+        <dc:type
424
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
425
+        <dc:title></dc:title>
426
+      </cc:Work>
427
+    </rdf:RDF>
428
+  </metadata>
429
+  <g
430
+     inkscape:label="BACKGROUND"
431
+     inkscape:groupmode="layer"
432
+     id="layer1"
433
+     transform="translate(268,-635.29076)"
434
+     style="display:inline">
435
+    <path
436
+       style="fill:#7e65a5;fill-opacity:1;stroke:none;display:inline;filter:url(#filter1121)"
437
+       d="m -268,700.15563 0,-33.72973 c 0,-27.24324 3.88785,-31.13513 31.10302,-31.13513 l 33.79408,0 c 27.21507,0 31.1029,3.89189 31.1029,31.13513 l 0,33.72973 c 0,27.24325 -3.88783,31.13514 -31.1029,31.13514 l -33.79408,0 C -264.11215,731.29077 -268,727.39888 -268,700.15563 Z"
438
+       id="path6455"
439
+       inkscape:connector-curvature="0"
440
+       sodipodi:nodetypes="sssssssss" />
441
+  </g>
442
+  <g
443
+     inkscape:groupmode="layer"
444
+     id="layer3"
445
+     inkscape:label="PLACE YOUR PICTOGRAM HERE"
446
+     style="display:inline">
447
+    <image
448
+       y="16"
449
+       x="16"
450
+       id="image3366"
451
+       xlink:href="data:image/png;base64,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 "
452
+       height="64"
453
+       width="64"
454
+       style="fill:#5072b2;fill-opacity:1" />
455
+  </g>
456
+  <g
457
+     inkscape:groupmode="layer"
458
+     id="layer2"
459
+     inkscape:label="BADGE"
460
+     style="display:none"
461
+     sodipodi:insensitive="true">
462
+    <g
463
+       style="display:inline"
464
+       transform="translate(-340.00001,-581)"
465
+       id="g4394"
466
+       clip-path="none">
467
+      <g
468
+         id="g855">
469
+        <g
470
+           inkscape:groupmode="maskhelper"
471
+           id="g870"
472
+           clip-path="url(#clipPath873)"
473
+           style="opacity:0.6;filter:url(#filter891)">
474
+          <path
475
+             transform="matrix(1.4999992,0,0,1.4999992,-29.999795,-237.54282)"
476
+             d="m 264,552.36218 c 0,6.62742 -5.37258,12 -12,12 -6.62742,0 -12,-5.37258 -12,-12 0,-6.62741 5.37258,-12 12,-12 6.62742,0 12,5.37259 12,12 z"
477
+             sodipodi:ry="12"
478
+             sodipodi:rx="12"
479
+             sodipodi:cy="552.36218"
480
+             sodipodi:cx="252"
481
+             id="path844"
482
+             style="color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:4;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
483
+             sodipodi:type="arc" />
484
+        </g>
485
+        <g
486
+           id="g862">
487
+          <path
488
+             sodipodi:type="arc"
489
+             style="color:#000000;fill:#f5f5f5;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:4;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
490
+             id="path4398"
491
+             sodipodi:cx="252"
492
+             sodipodi:cy="552.36218"
493
+             sodipodi:rx="12"
494
+             sodipodi:ry="12"
495
+             d="m 264,552.36218 c 0,6.62742 -5.37258,12 -12,12 -6.62742,0 -12,-5.37258 -12,-12 0,-6.62741 5.37258,-12 12,-12 6.62742,0 12,5.37259 12,12 z"
496
+             transform="matrix(1.4999992,0,0,1.4999992,-29.999795,-238.54282)" />
497
+          <path
498
+             transform="matrix(1.25,0,0,1.25,33,-100.45273)"
499
+             d="m 264,552.36218 c 0,6.62742 -5.37258,12 -12,12 -6.62742,0 -12,-5.37258 -12,-12 0,-6.62741 5.37258,-12 12,-12 6.62742,0 12,5.37259 12,12 z"
500
+             sodipodi:ry="12"
501
+             sodipodi:rx="12"
502
+             sodipodi:cy="552.36218"
503
+             sodipodi:cx="252"
504
+             id="path4400"
505
+             style="color:#000000;fill:#dd4814;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:4;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
506
+             sodipodi:type="arc" />
507
+          <path
508
+             sodipodi:type="star"
509
+             style="color:#000000;fill:#f5f5f5;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
510
+             id="path4459"
511
+             sodipodi:sides="5"
512
+             sodipodi:cx="666.19574"
513
+             sodipodi:cy="589.50385"
514
+             sodipodi:r1="7.2431178"
515
+             sodipodi:r2="4.3458705"
516
+             sodipodi:arg1="1.0471976"
517
+             sodipodi:arg2="1.6755161"
518
+             inkscape:flatsided="false"
519
+             inkscape:rounded="0.1"
520
+             inkscape:randomized="0"
521
+             d="m 669.8173,595.77657 c -0.39132,0.22593 -3.62645,-1.90343 -4.07583,-1.95066 -0.44938,-0.0472 -4.05653,1.36297 -4.39232,1.06062 -0.3358,-0.30235 0.68963,-4.03715 0.59569,-4.47913 -0.0939,-0.44198 -2.5498,-3.43681 -2.36602,-3.8496 0.18379,-0.41279 4.05267,-0.59166 4.44398,-0.81759 0.39132,-0.22593 2.48067,-3.48704 2.93005,-3.4398 0.44938,0.0472 1.81505,3.67147 2.15084,3.97382 0.3358,0.30236 4.08294,1.2817 4.17689,1.72369 0.0939,0.44198 -2.9309,2.86076 -3.11469,3.27355 -0.18379,0.41279 0.0427,4.27917 -0.34859,4.5051 z"
522
+             transform="matrix(1.511423,-0.16366377,0.16366377,1.511423,-755.37346,-191.93651)" />
523
+        </g>
524
+      </g>
525
+    </g>
526
+  </g>
527
+</svg>
Back to file index

layer.yaml

 1
--- 
 2
+++ layer.yaml
 3
@@ -0,0 +1,13 @@
 4
+"options":
 5
+  "basic":
 6
+    "packages":
 7
+    - "rpm"
 8
+    - "bc"
 9
+    "use_venv": !!bool "false"
10
+    "include_system_packages": !!bool "false"
11
+  "ibm-mq": {}
12
+"repo": "bzr+ssh://bazaar.launchpad.net/~ibmcharmers/ibmlayers/layer-ibm-mq/"
13
+"includes":
14
+- "layer:basic"
15
+- "interface:ibm-mq"
16
+"is": "ibm-mq"
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

metadata.yaml

 1
--- 
 2
+++ metadata.yaml
 3
@@ -0,0 +1,24 @@
 4
+"name": "ibm-mq"
 5
+"summary": "IBM MQ messaging Product"
 6
+"maintainer": "IBM Juju Support Team <jujusupp@us.ibm.com>"
 7
+"description": |
 8
+  IBM MQ provides for messaging services to transport multiple types of data.
 9
+"tags":
10
+- "ibm"
11
+- "mq"
12
+- "ibm-z"
13
+- "messaging"
14
+"provides":
15
+  "messaging":
16
+    "interface": "ibm-mq"
17
+"resources":
18
+  "ibm_mq_installer":
19
+    "type": "file"
20
+    "filename": "ibm_mq_installer.tar.gz"
21
+    "description": "IBM MQ installer archive"
22
+"series":
23
+- "trusty"
24
+- "xenial"
25
+"subordinate": !!bool "false"
26
+"terms":
27
+- "ibmcharmers/ibm-mq/1"
Back to file index

reactive/ibm-mq.sh

  1
--- 
  2
+++ reactive/ibm-mq.sh
  3
@@ -0,0 +1,337 @@
  4
+#!/bin/bash
  5
+
  6
+set -ex
  7
+source charms.reactive.sh
  8
+
  9
+ARCHIVE_DIR=$CHARM_DIR/files/archives
 10
+MQ_INSTALL_PATH=/opt/mqm
 11
+ARCHITECTURE=`uname -m`
 12
+relatedService=""
 13
+QMA=""
 14
+QM_Name=""
 15
+hostname=`unit-get private-address`
 16
+	
 17
+if [ "$ARCHITECTURE" = "ppc64le" ]; then
 18
+	RPM_INSTALL_ARG="-ivh --nodeps --force-debian --ignorearch"
 19
+elif [ "$ARCHITECTURE" = "x86_64" -o "$ARCHITECTURE" = "s390x" ]; then
 20
+	RPM_INSTALL_ARG="-ivh --nodeps --force-debian"
 21
+fi
 22
+
 23
+
 24
+# Update system configuration after installing MQ
 25
+configure_system()
 26
+{
 27
+	juju-log "IBM MQ: Updating system configuration."
 28
+	# Some containers do not allow system updates.
 29
+	# Prevent the script from failing in such cases
 30
+	set +e
 31
+
 32
+	# Add user ubuntu to mqm group
 33
+	adduser ubuntu mqm
 34
+
 35
+	# Update mqm file limits
 36
+
 37
+	hard_nf=`su - mqm -c "ulimit -Hn"`
 38
+	soft_nf=`su - mqm -c "ulimit -Sn"`
 39
+
 40
+	if [ $hard_nf -lt 10240 -o $soft_nf -lt 10240 ]; then
 41
+		if [ "`grep mqm  /etc/security/limits.conf`"=="" ]; then
 42
+			sed -i 's/# End of file/@mqm              hard    nofile          10240\n@mqm              soft    nofile          10240\n# End of file/' /etc/security/limits.conf
 43
+		fi
 44
+		#Update /etc/pam.d/common-session file to take effect the above changes
 45
+		result_search=`grep 'session required pam_limits.so' /etc/pam.d/common-session`
 46
+		if [ -z "$result_search" ]; then
 47
+			sed -i 's/# end of pam-auth-update config/session required pam_limits.so\n# end of pam-auth-update config/' /etc/pam.d/common-session
 48
+		fi
 49
+	fi
 50
+
 51
+	set -e
 52
+	juju-log "IBM MQ: Completed system configuration update."
 53
+
 54
+}
 55
+
 56
+# create Queue manager and Queue 
 57
+create_QM_Queue()
 58
+{
 59
+
 60
+	juju-log "IBM MQ: Verifying installation."
 61
+
 62
+	relatedService=$1
 63
+	consumer_hostname=$2
 64
+        QM_create=0
 65
+	QMA="${relatedService//-}.queue.manager"
 66
+
 67
+	# Prevent the script from failing on failure. 
 68
+	# It could because configure_system call failed
 69
+	set +e
 70
+
 71
+	# Run as mqm user as root will not work
 72
+
 73
+	# Create queue manager
 74
+	juju-log "IBM MQ: Create queue manager $QMA."
 75
+	su -l mqm -c "$MQ_INSTALL_PATH/bin/crtmqm $QMA"
 76
+	rc=$?
 77
+	if [ $rc == 0 ]; then
 78
+		juju-log "IBM MQ: queue manager $QMA created."
 79
+		QM_create=1
 80
+	elif [ $rc == 8 ]; then
 81
+		QM_exists=1
 82
+	else
 83
+		juju-log "IBM MQ: Failed to create queue manager $QMA."
 84
+	fi
 85
+
 86
+	# Start queue manager
 87
+	if [ "$QM_create" -eq "1" ]; then
 88
+		juju-log "IBM MQ: Starting queue manager $QMA."
 89
+		su -l mqm -c "$MQ_INSTALL_PATH/bin/strmqm $QMA"
 90
+		if [ $? == 0 ]; then
 91
+			juju-log "IBM MQ: Queue manager $QMA started."
 92
+		else
 93
+			juju-log "IBM MQ: Failed to start queue manager $QMA."
 94
+	
 95
+		fi
 96
+	
 97
+		# set the port to listen queue manager
 98
+		new_port=1414
 99
+		free_port=0
100
+		is_free=0
101
+	
102
+		#Check whether the port number is already in use
103
+		while [ $free_port -eq 0 ]
104
+		do
105
+	
106
+			is_free=`netstat -an | grep $new_port | grep LISTEN`
107
+			if [ -z "$is_free" ]; then
108
+				free_port=1
109
+			else
110
+				new_port=$((new_port+1))
111
+			fi
112
+	
113
+		done
114
+
115
+		juju-log "IBM MQ: Setting port to $new_port"
116
+	
117
+		#start queue manager in listener mode
118
+		juju-log "IBM MQ: Starting queue manager $QMA in listener mode"
119
+		su -l mqm -c "$MQ_INSTALL_PATH/bin/runmqlsr -m $QMA -t tcp -p $new_port" &
120
+		if [ $? == 0 ]; then
121
+			juju-log "IBM MQ: Queue manager $QMA listening on $new_port"
122
+		else
123
+			juju-log "IBM MQ: Queue manager $QMA failed to listen"
124
+		fi
125
+
126
+		# Create queue and setup the queue configuration for consumer service 
127
+		juju-log "IBM MQ: Creating queue."
128
+
129
+		sudo bash -c "cat > $CHARM_DIR/files/archives/${relatedService//-}_mq_create_queue.mqsc << EOF
130
+DEFINE QLOCAL (QUEUE1)
131
+DEFINE CHANNEL ('MDB.SVRCONN') CHLTYPE(SVRCONN) TRPTYPE(TCP)
132
+SET CHLAUTH ('MDB.SVRCONN') TYPE(ADDRESSMAP) ADDRESS($consumer_hostname) MCAUSER('mqm')
133
+SET AUTHREC OBJTYPE(QMGR) PRINCIPAL('mqm') AUTHADD(CONNECT,INQ)
134
+SET AUTHREC PROFILE('QUEUE1') OBJTYPE(QUEUE) PRINCIPAL('mqm') AUTHADD(PUT,GET,INQ,BROWSE)
135
+SET AUTHREC PROFILE('SYSTEM.BASE.TOPIC') OBJTYPE(TOPIC) PRINCIPAL('mqm') AUTHADD(PUB, SUB)
136
+EOF"
137
+		if [ $? == 0 ]; then
138
+			# Create file to delete the above queue when relation breaks
139
+			sudo bash -c "echo 'DELETE QLOCAL(QUEUE1) PURGE' > $CHARM_DIR/files/archives/${relatedService//-}_mq_delete_queue.mqsc"
140
+		fi
141
+
142
+		if [ -f $CHARM_DIR/files/archives/${relatedService//-}_mq_create_queue.mqsc ]; then
143
+
144
+			su -l mqm -c "$MQ_INSTALL_PATH/bin/runmqsc $QMA < $CHARM_DIR/files/archives/${relatedService//-}_mq_create_queue.mqsc"
145
+			if [ $? == 0 ]; then
146
+				juju-log "IBM MQ: Queue created."
147
+			else
148
+				juju-log "IBM MQ: Failed to create queue."
149
+			fi
150
+
151
+			QM_Name=$QMA
152
+			Qname=$CHARM_DIR/files/archives/${relatedService//-}_mq_create_queue.mqsc
153
+			port=$new_port
154
+			open-port $port/TCP
155
+
156
+			juju-log "create_QM_Queue values are QM_name=$QM_Name Qname=$Qname hostname=$hostname port=$port"
157
+		fi
158
+	elif [ $QM_exists -eq 1 ];then
159
+		QM_Name=$QMA
160
+		Qname=$CHARM_DIR/files/archives/${relatedService//-}_mq_create_queue.mqsc
161
+		port=`ps -ef| grep runmqlsr | grep "$QMA" | grep -v grep | grep "su -l mqm" | awk -F"-p " '{print $2}'`
162
+		juju-log "relation with ${relatedService} already exists"
163
+		juju-log "create_QM_Queue values are QM_name=$QM_Name Qname=$Qname hostname=$hostname port=$port"
164
+	fi
165
+
166
+}
167
+
168
+
169
+# IBM MQ: Deleting queue	
170
+delete_QM_Queue()
171
+{
172
+
173
+	relatedService=$1
174
+
175
+	QMA="${relatedService//-}.queue.manager"
176
+	# Delete queue
177
+	juju-log "IBM MQ: Deleting queue."
178
+	su -l mqm -c "$MQ_INSTALL_PATH/bin/runmqsc $QMA < $CHARM_DIR/files/archives/${relatedService//-}_mq_delete_queue.mqsc" || true
179
+	if [ $? == 0 ]; then
180
+		juju-log "IBM MQ: Deleted queue."
181
+	else
182
+		juju-log "IBM IB: Failed to delete queue."
183
+                return
184
+	fi
185
+	
186
+
187
+	port=`ps -ef| grep runmqlsr | grep "$QMA" | grep -v grep | grep "su -l mqm" | awk -F"-p " '{print $2}'`
188
+
189
+	juju-log "IBM MQ: stop Queue manager from listening on port"
190
+	su -l mqm -c "$MQ_INSTALL_PATH/bin/endmqlsr -m $QMA -w" || true
191
+	if [ $? == 0 ]; then
192
+                juju-log "IBM MQ: Stopped queue manager from listening."
193
+        else
194
+                juju-log "IBM IB: Failed to stop queue manager to listen."
195
+        fi
196
+
197
+	#close-port the open-port for the consumer
198
+	if [ ! -z "$port" ]; then
199
+		close-port $port
200
+	fi
201
+	
202
+	# End queue manger
203
+	juju-log "IBM MQ: Stopping queue manager."
204
+	su -l mqm -c "$MQ_INSTALL_PATH/bin/endmqm $QMA" || true
205
+	su -l mqm -c "$MQ_INSTALL_PATH/bin/endmqlsr -w -m  $QMA" || true
206
+	if [ $? -eq 0 ]; then
207
+		juju-log "IBM IB: Queue Manager is stopped."
208
+	else
209
+		juju-log "IBM IB: Queue Manager failed to stop."
210
+                return
211
+	fi
212
+
213
+	sleep 10
214
+
215
+	juju-log "IBM MQ: Deleting queue manager."
216
+	su -l mqm -c "$MQ_INSTALL_PATH/bin/dltmqm $QMA" || true
217
+	if [ $? -eq 0 ]; then
218
+		juju-log "IBM IB: Queue Manager is deleted."
219
+	else
220
+		juju-log "IBM IB: Queue Manager could not be deleted."
221
+                return
222
+	fi
223
+
224
+	#clean up the created MQSC files
225
+	if [ -f $CHARM_DIR/files/archives/${relatedService//-}_mq_create_queue.mqsc ];then
226
+		sudo bash -c "rm $CHARM_DIR/files/archives/${relatedService//-}_mq_create_queue.mqsc"
227
+	fi
228
+	if [ -f $CHARM_DIR/files/archives/${relatedService//-}_mq_delete_queue.mqsc ]; then
229
+		sudo bash -c "rm $CHARM_DIR/files/archives/${relatedService//-}_mq_delete_queue.mqsc"
230
+	fi
231
+
232
+	set -e
233
+	juju-log "IBM MQ: Deleting queue completed."
234
+}
235
+
236
+
237
+@when_not 'ibm-mq.installed'
238
+function mq_install(){
239
+# Fail fast if we're on an unsupported arch
240
+	if [ "$ARCHITECTURE" != "x86_64" -a "$ARCHITECTURE" != "ppc64le"  -a "$ARCHITECTURE" != "s390x" ]; then
241
+		juju-log "IBM MQ: only supported on x86_64 or ppc64le or s390x platforms"
242
+		status-set blocked "unsupported architecture"
243
+		return 1
244
+	fi
245
+	# Get the installable resource
246
+	juju-log "IBM MQ: fetching the ibm_mq_installer resource"
247
+	status-set maintenance "fetching the ibm_mq_installer resource"
248
+	cfg_mq_pkg_name=`resource-get 'ibm_mq_installer' || echo unavailable`
249
+
250
+	# If we don't have a package, report blocked status; we can't proceed.
251
+	if [ "$cfg_mq_pkg_name" = "unavailable" ]; then
252
+		juju-log "IBM MQ: missing required ibm_mq_installer resource"
253
+		status-set blocked "missing required ibm_mq_installer resource"
254
+		return 0
255
+	fi 
256
+	cfg_mq_pkg_name_empty=`file $cfg_mq_pkg_name | { grep -q empty && echo "True"; } || echo "False"`
257
+	if [ "$cfg_mq_pkg_name_empty" = "True" ]; then
258
+		juju-log "IBM MQ : MQ package is corrupt or empty, place the correct archive  to extract & install"
259
+		status-set blocked "Empty IBM MQ resources"
260
+		return 0
261
+	fi 
262
+
263
+	juju-log "IBM MQ: using $cfg_mq_pkg_name as the ibm_mq_installer resource"
264
+	ARCHIVE_DIR=`dirname $cfg_mq_pkg_name`
265
+	# Extract the installer contents
266
+	if [ -f  $cfg_mq_pkg_name ]; then
267
+		juju-log "IBM MQ: extracting the ibm_mq_installer resource"
268
+		status-set maintenance "extracting the ibm_mq_installer resource"
269
+		if [ -f $ARCHIVE_DIR/MQ*.rpm ]; then
270
+			juju-log "IBM MQ: ibm_mq_installer resource already extracted"
271
+		else
272
+			cd $ARCHIVE_DIR
273
+			juju-log " IBM MQ : Extracting MQ package"
274
+			status-set maintenance "Extracting MQ Install package"
275
+			tar -xzvf $cfg_mq_pkg_name
276
+			if [ $? != 0 ]; then
277
+				juju-log "IBM MQ: Unable to extract the MQ package content. Verify whether the package is corrupt."
278
+				# Remove corrupt archive file
279
+				rm -rf ARCHIVE_DIR
280
+				return 0
281
+			else
282
+				juju-log "IBM MQ : MQ packages downloaded and extracted successfully"
283
+			fi
284
+		fi
285
+	fi
286
+	# Do the actual IBM MQ install
287
+	# Check MQ package availability
288
+	if [ -f  $ARCHIVE_DIR/MQServer/MQSeriesServer*rpm ] && [ -f  $ARCHIVE_DIR/MQServer/MQSeriesRuntime*rpm ]; then
289
+		echo "MQ Packages available for installation.";
290
+		$ARCHIVE_DIR/MQServer/mqlicense.sh -accept
291
+		juju-log "Installing available MQ packages."
292
+		rpm $RPM_INSTALL_ARG --prefix $MQ_INSTALL_PATH $ARCHIVE_DIR/MQServer/MQSeries*rpm
293
+		if [ $? == 0 ]; then
294
+			juju-log "IBM MQ : Installation of MQ is successfull"
295
+		else
296
+			juju-log "IBM MQ : Error while installing IBM MQ "
297
+			status-set blocked "installation failed"
298
+			return 1
299
+		fi
300
+		# Configure system values  for MQ
301
+		configure_system
302
+		set_state 'ibm-mq.installed'
303
+		status-set active "IBM MQ is ready"
304
+	else
305
+		status-set blocked "MQ Packages missing. Please check README file Upgrade MQ charm after adding the MQ packages"
306
+	fi
307
+}
308
+
309
+
310
+@when 'ibm-mq.installed'
311
+@when 'messaging.connected'
312
+function export_mq_details(){
313
+	juju-log "on ibm_mq.connected triggered here"
314
+	services=$(relation_call --state=messaging.connected services) || true
315
+	for service in $services; do
316
+		juju-log "$service"
317
+		consumer_hostname=$(relation_call --state=messaging.connected get_consumer_hostname) || true
318
+		create_QM_Queue $service $consumer_hostname
319
+		juju-log "create_QM_Queue values are QM_name=$QM_Name Qname=$Qname hostname=$hostname port=$port"
320
+		if [ ! -z "$port" -a ! -z "$hostname" -a ! -z "$QM_Name" ]; then
321
+			relation_call --state=messaging.connected set_mq_details $service $QM_Name $Qname $hostname $port || true
322
+		fi
323
+	done
324
+}
325
+
326
+@when 'messaging.departed' 'ibm-mq.installed'
327
+function remove_mq_QM_Q() {
328
+	juju-log "in delete_QM_Queue.."
329
+	services=$(relation_call --state=messaging.departed services) || true
330
+	for service in $services; do
331
+		juju-log "$service"
332
+		delete_QM_Queue $service
333
+		juju-log "delete_QM_Queue done."
334
+		juju-log "Calling dismiss for $service"
335
+		relation_call --state=messaging.departed dismiss $service || true
336
+	done
337
+ }
338
+
339
+
340
+reactive_handler_main
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
+1
Back to file index

tests/01-deploy.py

 1
--- 
 2
+++ tests/01-deploy.py
 3
@@ -0,0 +1,49 @@
 4
+#!/usr/bin/env python3
 5
+
 6
+import unittest
 7
+import amulet
 8
+
 9
+
10
+# Lots of prereqs on this charm (eg: java), so give it a large timeout
11
+seconds_to_wait = 1500
12
+
13
+
14
+class TestDeploy(unittest.TestCase):
15
+    """
16
+    Deployment test for the IBM MQ charm.
17
+    """
18
+    def setUp(self):
19
+        self.d = amulet.Deployment(series='xenial')
20
+        self.d.add('ibm-mq', 'cs:~ibmcharmers/ibm-mq')
21
+        self.d.add('ibm-was-base', 'cs:~shilkaul/wasdummy-0')
22
+        self.d.relate('ibm-mq:messaging',
23
+                      'ibm-was-base:wasmessaging')
24
+        self.d.setup(timeout=900)
25
+        self.d.sentry.wait(timeout=1800)
26
+
27
+    def test_deployed(self):
28
+        """ Test to see if the charms are deployed successfully. """
29
+        self.assertTrue(self.d.deployed)
30
+
31
+    def test_running(self):
32
+        """ Test that, if deployed,
33
+            everything is set up and running correctly. """
34
+        ibm_mq_unit = self.d.sentry['ibm-mq'][0]
35
+
36
+        # Verify that the ubuntu user is in the mqm group
37
+        output, code = ibm_mq_unit.run('groups ubuntu')
38
+        print("### Check that mqm user group is created ###")
39
+        print(output)
40
+        assert 'mqm' in output, 'Ubuntu user not in mqm group.'
41
+
42
+        # Running as mqm, root does not work
43
+        # Check the existence of Queue manager.
44
+        cmd = 'su -l mqm -c "/opt/mqm/bin/dspmq -o all"'
45
+        print("####### Display IBM MQ Queue manager #######")
46
+        output, code = ibm_mq_unit.run(cmd)
47
+        print(output)
48
+        assert code == 0, 'Unable to display the MQ queue manager QMA'
49
+
50
+
51
+if __name__ == '__main__':
52
+    unittest.main()
Back to file index

tests/tests.yaml

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