~ibmcharmers/ibm-http

Owner: kwmonroe
Status: Needs Fixing
Vote: -1 (+2 needed for approval)

CPP?: No
OIL?: No

Migrating from the old queue:

https://bugs.launchpad.net/charms/+bug/1612535


Tests

Substrate Status Results Last Updated
lxc FAIL Test Results 7 months ago
gce FAIL http://juju-ci.vapour.ws/job/charm-bundle-test-gce/177/console 7 months ago
aws FAIL Test Results 7 months ago

Voted: -1
mbruzek wrote 5 months ago
The charm still requires the "lorem-ipsum" term to deploy. The lorem-ipsum was to test the Juju terms feature. This is not a valid term for the IBM http charm, so "lorem-ipsum/1" needs to be removed from the charm and a new version of the built charm should be pushed to remove that requirement.

Voted: -2
lazypower wrote 5 months ago
Greetings, I was able to give this charm some additional review time today on top of what mbruzek has already filed. First and foremost, thank you for your submission and patience during the review process.

As Matt indicated, the lorem-ipsum terms are a blocking issue, they are not intended to be the final term associated with the charm coming from the store, and only intended to be used for testing. This will need to be updated.

I also see in the README several HTML entity issues that will cause display artifacting when listed in the charm store. I would highly recommend you adopt either code fencing for these particluar excerpts, or use the proper HTML entities to ensure a consistent display between markdown view, and rendered HTML view.

Additionally, I also see that you've declared in the README that there is a minimum juju version. With the release of juju 2.0 there was a new key intoroduced into metadata.yaml where you can explicitly call out the minimum required version of juju in order to deploy the charm. I've included an except from the metadata.yaml docs inline


min-juju-version Charms can declare the minimum Juju version the code is compatible with. This is useful when the code uses features introduced in a specific version of Juju. When supplied this value is the lowest version of Juju controller that will run the charm.

https://jujucharms.com/docs/stable/authors-charm-metadata

I'd also like to see an effort placed in using resources for the delivery of the 10 listed resources on the charm. Simply publishing zero byte resources in the store will cause the user to have a "broken" installation by default that does nothing useful without those resources. I'm unaware of any prohibitive factors here, as the downloads are freely available on the IBM software site.

I was unable to complete additional review at this time due to time constraints, but with some additional effort I'm confident we can bring this -1 to a +1 in short order. Thank you again for your submission, and I look forward to giving this charm another review in the coming days.
Voted: +0
petevg wrote 3 months ago
I checked up on this charm today, but it appears that the code has not been updated, and the previous comments still apply.

Thank you again for you previous work on the charm; we look forward to reviewing the updated code when it lands.

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. johnsca
  • 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. johnsca
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. johnsca
Should be built using charm layers. johnsca
Should use Juju Resources to deliver required payloads. johnsca

Testing and Quality

charm proof must pass without errors or warnings. johnsca
Must include passing unit, functional, or integration tests.
Tests must exercise all relations. johnsca
Tests must exercise config. johnsca
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). johnsca
Must be self contained unless the charm is a proxy for an existing cloud service, e.g. ec2-elb charm.
Must not use symlinks. johnsca
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. johnsca
Should include a tests.yaml for all integration tests. johnsca

Metadata

Must include a full description of what the software does. johnsca
Must include a maintainer email address for a team or individual who will be responsive to contact. johnsca
Must include a license. Call the file 'copyright' and make sure all files' licenses are specified clearly. johnsca
Must be under a Free license. johnsca
Must have a well documented and valid README.md. johnsca
Must describe the service. johnsca
Must describe how it interacts with other services, if applicable. johnsca
Must document the interfaces. johnsca
Must show how to deploy the charm. johnsca
Must define external dependencies, if applicable. johnsca
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. johnsca

Security

Must not run any network services using default passwords.
Must verify and validate any external payload johnsca
  • 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.

All changes | Changes since last revision

Source Diff

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,92 @@
 4
+### Readme
 5
+
 6
+## IBM HTTP-SERVER 8.5
 7
+
 8
+IBM Http Server is a full-featured web server that is included with other products such as IBM WebSphere Application Server at no charge. You can use this web server for projects that do not warrant the expense of a priced and supported http server. The IBM Http Server is based on the Apache Http Server and provides a rich set of Apache features in addition to IBM enhancements.
 9
+
10
+User guides and security guides to support this release are available for
11
+online viewing [User Guide](http://www.ibm.com/support/knowledgecenter/SSEQTJ/welcome)
12
+
13
+
14
+### Prerequisites 
15
+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) required by this charm. Download your licensed IBM Http-Server packages from the 
16
+[Product Page](http://www-01.ibm.com/support/docview.wss?uid=swg27036410).
17
+
18
+### Package for Ubuntu on AMD64 (x86_64):
19
+IBM Installation Manager 1.8.3 (agent.installer.linux.gtk.x86_64_1.8.3000.20150606_0047.zip)
20
+
21
+IBM Http-Server 8.5   
22
+(WAS_V8.5.5_SUPPL_1_OF_3.zip , 
23
+WAS_V8.5.5_SUPPL_2_OF_3.zip , WAS_V8.5.5_SUPPL_3_OF_3.zip)
24
+
25
+### Package for Ubuntu on Power (ppc64le):
26
+IBM Installation Manager 1.8.3 (agent.installer.linux.gtk.ppc64le_1.8.3000.20150606_0047.zip)
27
+
28
+IBM Http-Server 8.5   
29
+(WAS_V8.5.5_SUPL_1_4_FOR_POWERLEML.zip)
30
+
31
+### Usage
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-HTTP-SERVER` by visiting the [im-license-info](http://www-03.ibm.com/software/sla/sladb.nsf/displaylis/39AFC1C1D485C4E085257E7300548B05?OpenDocument) and [http-license-info](http://www-03.ibm.com/software/sla/sladb.nsf/displaylis/96C9C4A5DE44145A85257D8F0078CAF7?OpenDocument) page.  
33
+Search for "IBM-Http-Server" and choose the license that applies to the version you are using.
34
+
35
+IBM-Http-Server is built on top of the ibm-im layer [More Info](https://jujucharms.com/u/ibmcharmers/ibm-im/trusty). So user has to provide the IBM-IM resource when deploying the ibm-http-server.
36
+
37
+As IBM-Http charm is a subordinate charm, any principle charm  ([ibm-was-base](https://jujucharms.com/u/ibmcharmers/ibm-was-base/trusty)/[ibm-was-nd](https://jujucharms.com/u/ibmcharmers/ibm-was-nd/trusty)) should exist on a container before deploying http-server. 
38
+
39
+### Deploy
40
+
41
+Run the following commands to deploy this charm:
42
+
43
+    juju deploy ibm-http --resource ibm_im_installer=</path/to/installer.zip> --resource ibm_http_installer1=</path/to/installer1.zip> --resource ibm_http_installer2=</path/to/installer2.zip> --resource ibm_http_installer3=</path/to/installer3.zip>
lazypower commented 5 months ago
This should really not be using angle brackets to denote paths, as this will be output into an HTML page, and those segments will be missing. If you desire to use angle brackets to denote paths, you should use HTML encoded entities, such as < and >
lazypower commented 5 months ago
In addendum, which my html encoded entites in the previous comment, it is (without the space between the ampersand) & lt; & gt; for < and &rt; respectively
44
+
45
+IBM-Http charm has three components IHS,PLG,WCT. This charm requires acceptance of Terms of Use. When deploying from the Charm Store, these terms will be presented to you for your consideration. To accept the terms:
46
+
47
+    juju agree ibm-im/1 ibm-http-server/2 ibm-http-plg/1 ibm-http-wct/1
48
+
49
+Add a relation between ibm-http and any principle charm(ibm-was-base/ibm-was-nd):
50
+    
51
+    juju add-relation ibm-http <principle charm>
lazypower commented 5 months ago
same comment here regarding angle brackets and HTML entities.
52
+
53
+    
54
+### Upgrade
55
+Once deployed, users can install fixpacks by upgrading the charm:
56
+
57
+    juju attach ibm-http ibm_http_server_fixpack1=</path/to/fixpack.zip>
58
+    juju attach ibm-http ibm_http_server_fixpack2=</path/to/fixpack.zip>
59
+    juju attach ibm-http ibm_http_server_WCT_fixpack1=</path/to/fixpack.zip>
60
+    juju attach ibm-http ibm_http_server_WCT_fixpack2=</path/to/fixpack.zip>
61
+
62
+**Note**: 
63
+IBM-Http-Server has multiple fixpack packages. WCT component of ibm-http charm has a different package. User must make sure to provide all the packages required.
64
+    
65
+If user wants to upgrade the layer charm IBM-IM, provide the IM fixpack.
66
+
67
+    juju attach ibm-http ibm_im_fixpack=</path/to/fixpack.zip>
68
+
69
+
70
+### Installation Verification
71
+  
72
+Once deployed, you can use IBM Http-Server. To verify Http-Server is installed, list the contents of the installation directory:
73
+
74
+    juju run --application ibm-http 'ls /opt/IBM/HTTPServer'
lazypower commented 5 months ago
suggest: Include successful output of this command, delineated as output, so the user has a baseline idea of what to expect from the command.
75
+
76
+## Additional Information
77
+### General
78
+
79
+Details about IBM Http-Server available [here](http://www.ibm.com/support/knowledgecenter/SSEQTJ).
80
+
81
+### Download
82
+
83
+Information on procuring IBM Http-Server product is available at the [Product Page](http://www-01.ibm.com/support/docview.wss?uid=swg27036410).
84
+
85
+### License
86
+
87
+License information for IBM Http-Server can be viewed [Here](http://www-03.ibm.com/software/sla/sladb.nsf/displaylis/96C9C4A5DE44145A85257D8F0078CAF7?OpenDocument).
88
+
89
+### Known Limitations
90
+
91
+This charm makes use of Juju features that are only available in version 2.0 or greater.
92
+
93
+### Contact Information
94
+
95
+For issues with this charm, please contact [IBM Juju Support Team](mailto:jujusupp@us.ibm.com).
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
+  "curl_url":
 6
+    "type": "string"
 7
+    "default": ""
 8
+    "description": |
 9
+      Location of the IBM product installation file(s). This should be a URL
10
+      that curl can use to download files. Multiple URLs should be separated
11
+      by a space. NOTE: cryptographic verification is required and must be
12
+      specified as part of the URL query string with the key a valid hash
13
+      algorithms md5, sha256, or sha512, and the the checksum value itself
14
+      (http://<url>?[md5|sha256|sha512]=<checksum>).
15
+      For example:
16
+        'http://example.com/file.tgz?sha256=<sum>'
17
+        'sftp://example.com/file1.tgz?md5=<sum> ftp://example.com/file2.tgz?md5=<sum>'
18
+  "curl_opts":
19
+    "type": "string"
20
+    "default": ""
21
+    "description": |
22
+      The options passed to the 'curl' command when fetching files from
23
+      curl_url. For example:
24
+        '-u <user:password>'
25
+  "license_accepted":
26
+    "type": "boolean"
27
+    "default": !!bool "false"
28
+    "description": |
29
+      Some IBM charms require acceptance of a license before installation
30
+      can proceed. If required, setting this option to True indicates that you
31
+      have read and accepted the IBM terms and conditions found in the license
32
+      file referenced by the charm.
33
+  "extra_packages":
34
+    "description": "Space separated list of extra deb packages to install.\n"
35
+    "type": "string"
36
+    "default": ""
37
+  "package_status":
38
+    "default": "install"
39
+    "type": "string"
40
+    "description": "The status of service-affecting packages will be set to this value\
41
+      \ in the dpkg database. Valid values are \"install\" and \"hold\".\n"
42
+  "install_sources":
43
+    "description": "List of extra apt sources, per charm-helpers standard format (a\
44
+      \ yaml list of strings encoded as a string). Each source may be either a line\
45
+      \ that can be added directly to sources.list(5), or in the form ppa:<user>/<ppa-name>\
46
+      \ for adding Personal Package Archives, or a distribution component to enable.\n"
47
+    "type": "string"
48
+    "default": ""
49
+  "install_keys":
50
+    "description": "List of signing keys for install_sources package sources, per\
51
+      \ charmhelpers standard format (a yaml list of strings encoded as a string).\
52
+      \ The keys should be the full ASCII armoured GPG public keys. While GPG key\
53
+      \ ids are also supported and looked up on a keyserver, operators should be aware\
54
+      \ that this mechanism is insecure. null can be used if a standard package signing\
55
+      \ key is used that will already be installed on the machine, and for PPA sources\
56
+      \ where the package signing key is securely retrieved from Launchpad.\n"
57
+    "type": "string"
58
+    "default": ""
Back to file index

copyright

 1
--- 
 2
+++ copyright
 3
@@ -0,0 +1,9 @@
 4
+Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0
 5
+
 6
+Files: *
 7
+Copyright: 2015, Canonical Ltd.
 8
+License: GPL-3
 9
+
10
+License: GPL-3
11
+ On Debian GNU/Linux system you can find the complete text of the
12
+ GPL-3 license in '/usr/share/common-licenses/GPL-3'
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/ihs-relation-broken

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

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

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

 1
--- 
 2
+++ hooks/ihs-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/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/was-ihs/@

 1
--- 
 2
+++ hooks/relations/was-ihs/@
 3
@@ -0,0 +1,75 @@
 4
+# Licensed under the Apache License, Version 5.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
+
16
+from charms.reactive import hook
17
+from charms.reactive import RelationBase
18
+from charms.reactive import scopes
19
+
20
+
21
+class db2Requires(RelationBase):
22
+    scope = scopes.GLOBAL
23
+    
24
+    auto_accessors = ['ssh_key1', 'ssh_key2' , 'ssh_key32']
25
+ 
26
+    @hook('{requires:db2}-relation-joined')
27
+    def joined(self):
28
+        self.set_state('{relation_name}.connected')
29
+
30
+    @hook('{requires:db2}-relation-changed')
31
+    def changed(self):
32
+        self.set_state('{relation_name}.available')
33
+
34
+    @hook('{requires:db2}-relation-departed')
35
+    def departed(self):
36
+        self.remove_state('{relation_name}.connected')
37
+        self.remove_state('{relation_name}.available')
38
+
39
+
40
+    # For minor upgrades, provide a way to set java-version independently
41
+    def set_port(self, db2_port):
42
+        self.set_remote('db2_port', db2_port)
43
+
44
+    def unset_ready(self):
45
+        self.set_remote('db2_ready', False)
46
+    
47
+    def get_db_values(self):
48
+        """
49
+        Get the connection string, if available, or None.
50
+        """
51
+        data = {
52
+            'host': self.host(),
53
+            'port': db2-port,
54
+            'path': db2-path,
55
+        }
56
+        if all(data.values()):
57
+            return str.format(
58
+                'host={host} port={port} =path{path}',
59
+                **data)
60
+        return None 
61
+
62
+    def get_port(self):
63
+        #print("In get_port function ",db2_port)
64
+        return self.get_remote('db2_port')
65
+    
66
+#to pass the ssh keys
67
+    def set_ssh_keys(self,ssh_key1,ssh_key2,ssh_key3,dbnames):
68
+        self.set_remote(data={
69
+            'ssh_key1': ssh_key1,
70
+            'ssh_key2': ssh_key2,
71
+            'ssh_key3': ssh_key3,	
72
+            'dbnames': dbnames,
73
+        })
74
+        print("In set_ssh_keys",ssh_key1,ssh_key2,ssh_key3,dbnames)
75
+
76
+
77
+
78
+ 
Back to file index

hooks/relations/was-ihs/README.md

 1
--- 
 2
+++ hooks/relations/was-ihs/README.md
 3
@@ -0,0 +1,39 @@
 4
+
 5
+Overview
 6
+-----------
 7
+
 8
+This interface layer handles the communication between a `IBM WAS Base` or `IBM WAS ND` and `IBM Http Server` charms.
 9
+The provider end of this interface provides the WAS Base or WAS ND service. The consumer/Requires part will be the IBM Http Server which wants the WAS Base/ND installation path, profile name and other information to configure the IBM HTTP Server and WebSphere Plugin for WebSphere Application Server.
10
+
11
+
12
+Usage
13
+------
14
+
15
+#### Provides
16
+IBM WebSphere Application Server product will provide this interface. This interface layer will set the following states, as appropriate:
17
+
18
+ - `{relation_name}.available`: The relation is established, WAS Base/WAS ND service is ready to send it's information.
19
+
20
+ - `{relation_name}.departed` : The relation has been removed. Any cleanup related to the consumer charm(IBM HTTP Server) should happen now on the IBM WAS Base/WAS ND charm since the consumer is going away.
21
+
22
+
23
+#### Requires
24
+
25
+Consumer charm `IBM HTTP Server` will require this interface to connect to WAS Base or WAS ND so that they can share information to configure WebSphere plug-in and to create web server definition. This interface layer will set the following states, as appropriate:
26
+
27
+- `{relation_name}.available` : The consumer charm has been related to a WAS Base/WAS ND provider charm. At this point, the charm waits for Provider charm to send configuration details like installation path, profile name, admin userid, admin password, admin group, host name, port and IP address.
28
+
29
+- `{relation_name}.ready` : IBM Http Server is now ready to access the configuration details provided by WAS Base/WAS ND charm(s). The Http Server charm can access the configuration details using the below methods:
30
+
31
+    - `get_was_path()` - returns the Installation path of WAS.
32
+    - `get_was_port()` - returns running port of WAS.
33
+    - `get_was_hostname()` - returns host name of WAS.
34
+    - `get_ihsadminusr()` - returns IHS admin username to be created.
35
+    - `get_ihsadmingrp()` - returns IHS admin group to be created.
36
+    - `get_ihsadminpw()` - returns IHS admin password to be created.
37
+    - `get_was_profile_name()` - returns the WAS profile name.
38
+    -  `set_isihsstarted()` - This function is called by IBM Htp Server charm to send message to the WAS Base/WAS ND charm.
39
+
40
+Once the Http Server started, send the message `started` to the WAS to restart the application server. 
41
+
42
+- `{relation_name}.departed` : The relation has been removed. Any cleanup related to the provider charm(IBM WAS Base/WAS ND) should happen now on the IBM Http Server charm since the relation is broken.
Back to file index

hooks/relations/was-ihs/interface.yaml

1
--- 
2
+++ hooks/relations/was-ihs/interface.yaml
3
@@ -0,0 +1,5 @@
4
+name: was-ihs
5
+summary: Interface to connect IBM WAS Base/IBM WAS ND and IBM Http Server charms
6
+maintainer: IBM Juju Support Team <jujusupp@us.ibm.com>
7
+version: 1
8
+#repo: ""
Back to file index

hooks/relations/was-ihs/provides.py

 1
--- 
 2
+++ hooks/relations/was-ihs/provides.py
 3
@@ -0,0 +1,55 @@
 4
+from charms.reactive import hook
 5
+from charms.reactive import RelationBase
 6
+from charms.reactive import scopes
 7
+
 8
+
 9
+class wasProvides(RelationBase):
10
+    # Every unit connecting will get the same information
11
+    scope = scopes.GLOBAL
12
+
13
+    @hook('{provides:was-ihs}-relation-{joined,changed}')
14
+    def changed(self):
15
+        conversation = self.conversation()
16
+        conversation.set_state('{relation_name}.available')
17
+        conversation.remove_state('{relation_name}.departed')
18
+
19
+    @hook('{provides:was-ihs}-relation-{broken,departed}')
20
+    def broken(self):
21
+        conversation = self.conversation()
22
+        conversation.remove_state('{relation_name}.available')
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}.available')
32
+        conversation.remove_state('{relation_name}.departed')
33
+
34
+    def set_was_details(self, service, was_path, was_port, hostname,
35
+                        ihsadminusr, ihsadmingrp, ihsadminpw, profilename):
36
+        conversation = self.conversation(service)
37
+        conversation.set_remote(data={
38
+            'was_path': was_path,
39
+            'was_port': was_port,
40
+            'hostname': hostname,
41
+            'ihsadminusr': ihsadminusr,
42
+            'ihsadmingrp': ihsadmingrp,
43
+            'ihsadminpw': ihsadminpw,
44
+            'profilename': profilename
45
+        })
46
+
47
+    def get_isihsstarted(self, service):
48
+        conversation = self.conversation(service)
49
+        return conversation.get_remote('isihsstarted')
50
+
51
+    def services(self):
52
+        """
53
+        Return a list of services connecting to WAS.
54
+        """
55
+        service = []
56
+        for conversation in self.conversations():
57
+            service.append(conversation.scope)
58
+        return service
Back to file index

hooks/relations/was-ihs/requires.py

 1
--- 
 2
+++ hooks/relations/was-ihs/requires.py
 3
@@ -0,0 +1,52 @@
 4
+from charms.reactive import hook
 5
+from charms.reactive import RelationBase
 6
+from charms.reactive import scopes
 7
+
 8
+
 9
+class ihsRequires(RelationBase):
10
+    scope = scopes.GLOBAL
11
+
12
+    auto_accessors = ['was_path', 'was_port', 'hostname', 'ihsadminusr',
13
+                      'ihsadmingrp', 'ihsadminpw', 'profilename',
14
+                      'isihsadminstarted']
15
+
16
+    @hook('{requires:was-ihs}-relation-joined')
17
+    def joined(self):
18
+        self.remove_state('{relation_name}.departed')
19
+        self.set_state('{relation_name}.available')
20
+
21
+    @hook('{requires:was-ihs}-relation-changed')
22
+    def changed(self):
23
+        self.remove_state('{relation_name}.departed')
24
+        if str(self.get_remote('was_port')) != "None":
25
+            self.set_state('{relation_name}.ready')
26
+
27
+    @hook('{requires:was-ihs}-relation-departed')
28
+    def departed(self):
29
+        self.remove_state('{relation_name}.available')
30
+        self.remove_state('{relation_name}.ready')
31
+        self.set_state('{relation_name}.departed')
32
+
33
+    def get_was_path(self):
34
+        return self.get_remote('was_path')
35
+
36
+    def get_was_port(self):
37
+        return self.get_remote('was_port')
38
+
39
+    def get_was_hostname(self):
40
+        return self.get_remote('hostname')
41
+
42
+    def get_ihsadminusr(self):
43
+        return self.get_remote('ihsadminusr')
44
+
45
+    def get_ihsadmingrp(self):
46
+        return self.get_remote('ihsadmingrp')
47
+
48
+    def get_ihsadminpw(self):
49
+        return self.get_remote('ihsadminpw')
50
+
51
+    def get_was_profile_name(self):
52
+        return self.get_remote('profilename')
53
+
54
+    def set_isihsstarted(self, isihsstarted):
55
+        self.set_remote('isihsstarted', isihsstarted)
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,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="#3D0056"/>
13
+     <stop offset="1" stop-color="#EE3D96"/>
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="_1038849216">
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" fill-rule="nonzero" d="M137 680l34 0 0 -360 -34 0 0 360zm109 0l34 0 0 -174 214 0 0 174 34 0 0 -360 -34 0 0 156 -214 0 0 -156 -34 0 0 360zm336 -119c-4,88 59,126 144,126 127,0 137,-78 137,-102 0,-59 -42,-81 -93,-95l-88 -22c-29,-6 -54,-21 -54,-55 0,-53 43,-71 90,-71 52,0 96,28 98,82l35 0c0,-73 -62,-111 -133,-111 -101,0 -124,66 -124,101 0,56 39,76 81,87l80 19c34,8 74,24 74,65 0,52 -57,73 -95,73 -66,0 -119,-23 -117,-97l-35 0z"/>
30
+  </g>
31
+ </g>
32
+</svg>
Back to file index

layer.yaml

 1
--- 
 2
+++ layer.yaml
 3
@@ -0,0 +1,23 @@
 4
+"repo": "bzr+ssh://bazaar.launchpad.net/~ibmcharmers/charms/trusty/layer-ibm-http/trunk/"
 5
+"includes":
 6
+- "layer:ibm-base"
 7
+- "layer:apt"
 8
+- "layer:leadership"
 9
+- "layer:basic"
10
+- "layer:ibm-im"
11
+- "interface:was-ihs"
12
+"options":
13
+  "basic":
14
+    "packages":
15
+    - "unzip"
16
+    - "curl"
17
+    - "unzip"
18
+    "use_venv": !!bool "false"
19
+    "include_system_packages": !!bool "false"
20
+  "ibm-http": {}
21
+  "ibm-im": {}
22
+  "apt":
23
+    "packages": []
24
+  "leadership": {}
25
+  "ibm-base": {}
26
+"is": "ibm-http"
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,182 @@
  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 subprocess
 29
+
 30
+from charmhelpers import fetch
 31
+from charmhelpers.core import hookenv, unitdata
 32
+from charms import reactive
 33
+
 34
+
 35
+__all__ = ['add_source', 'update', 'queue_install', 'install_queued',
 36
+           'installed', 'purge', 'ensure_package_status']
 37
+
 38
+
 39
+def add_source(source, key=None):
 40
+    '''Add an apt source.
 41
+
 42
+    Sets the apt.needs_update state.
 43
+
 44
+    A source may be either a line that can be added directly to
 45
+    sources.list(5), or in the form ppa:<user>/<ppa-name> for adding
 46
+    Personal Package Archives, or a distribution component to enable.
 47
+
 48
+    The package signing key should be an ASCII armoured GPG key. While
 49
+    GPG key ids are also supported, the retrieval mechanism is insecure.
 50
+    There is no need to specify the package signing key for PPAs or for
 51
+    the main Ubuntu archives.
 52
+    '''
 53
+    # Maybe we should remember which sources have been added already
 54
+    # so we don't waste time re-adding them. Is this time significant?
 55
+    fetch.add_source(source, key)
 56
+    reactive.set_state('apt.needs_update')
 57
+
 58
+
 59
+def queue_install(packages, options=None):
 60
+    """Queue one or more deb packages for install.
 61
+
 62
+    The `apt.installed.{name}` state is set once the package is installed.
 63
+
 64
+    If a package has already been installed it will not be reinstalled.
 65
+
 66
+    If a package has already been queued it will not be requeued, and
 67
+    the install options will not be changed.
 68
+
 69
+    Sets the apt.queued_installs state.
 70
+    """
 71
+    if isinstance(packages, str):
 72
+        packages = [packages]
 73
+    # Filter installed packages.
 74
+    store = unitdata.kv()
 75
+    queued_packages = store.getrange('apt.install_queue.', strip=True)
 76
+    packages = {package: options for package in packages
 77
+                if not (package in queued_packages or
 78
+                        reactive.helpers.is_state('apt.installed.' + package))}
 79
+    if packages:
 80
+        unitdata.kv().update(packages, prefix='apt.install_queue.')
 81
+        reactive.set_state('apt.queued_installs')
 82
+
 83
+
 84
+def installed():
 85
+    '''Return the set of deb packages completed install'''
 86
+    return set(state.split('.', 2)[2] for state in reactive.bus.get_states()
 87
+               if state.startswith('apt.installed.'))
 88
+
 89
+
 90
+def purge(packages):
 91
+    """Purge one or more deb packages from the system"""
 92
+    fetch.apt_purge(packages, fatal=True)
 93
+    store = unitdata.kv()
 94
+    store.unsetrange(packages, prefix='apt.install_queue.')
 95
+    for package in packages:
 96
+        reactive.remove_state('apt.installed.{}'.format(package))
 97
+
 98
+
 99
+def update():
100
+    """Update the apt cache.
101
+
102
+    Removes the apt.needs_update state.
103
+    """
104
+    status_set(None, 'Updating apt cache')
105
+    fetch.apt_update(fatal=True)  # Friends don't let friends set fatal=False
106
+    reactive.remove_state('apt.needs_update')
107
+
108
+
109
+def install_queued():
110
+    '''Installs queued deb packages.
111
+
112
+    Removes the apt.queued_installs state and sets the apt.installed state.
113
+
114
+    On failure, sets the unit's workload state to 'blocked' and returns
115
+    False. Package installs remain queued.
116
+
117
+    On success, sets the apt.installed.{packagename} state for each
118
+    installed package and returns True.
119
+    '''
120
+    store = unitdata.kv()
121
+    queue = sorted((options, package)
122
+                   for package, options in store.getrange('apt.install_queue.',
123
+                                                          strip=True).items())
124
+
125
+    installed = set()
126
+    for options, batch in itertools.groupby(queue, lambda x: x[0]):
127
+        packages = [b[1] for b in batch]
128
+        try:
129
+            status_set(None, 'Installing {}'.format(','.join(packages)))
130
+            fetch.apt_install(packages, options, fatal=True)
131
+            store.unsetrange(packages, prefix='apt.install_queue.')
132
+            installed.update(packages)
133
+        except subprocess.CalledProcessError:
134
+            status_set('blocked',
135
+                       'Unable to install packages {}'
136
+                       .format(','.join(packages)))
137
+            return False  # Without setting reactive state.
138
+
139
+    for package in installed:
140
+        reactive.set_state('apt.installed.{}'.format(package))
141
+
142
+    reactive.remove_state('apt.queued_installs')
143
+    return True
144
+
145
+
146
+def ensure_package_status():
147
+    '''Hold or unhold packages per the package_status configuration option.
148
+
149
+    All packages installed using this module and handlers are affected.
150
+
151
+    An mechanism may be added in the future to override this for a
152
+    subset of installed packages.
153
+    '''
154
+    packages = installed()
155
+    if not packages:
156
+        return
157
+    config = hookenv.config()
158
+    package_status = config['package_status']
159
+    changed = reactive.helpers.data_changed('apt.package_status',
160
+                                            (package_status, sorted(packages)))
161
+    if changed:
162
+        if package_status == 'hold':
163
+            hookenv.log('Holding packages {}'.format(','.join(packages)))
164
+            fetch.apt_hold(packages)
165
+        else:
166
+            hookenv.log('Unholding packages {}'.format(','.join(packages)))
167
+            fetch.apt_unhold(packages)
168
+    reactive.remove_state('apt.needs_hold')
169
+
170
+
171
+def status_set(state, message):
172
+    """Set the unit's workload status.
173
+
174
+    Set state == None to keep the same state and just change the message.
175
+    """
176
+    if state is None:
177
+        state = hookenv.status_get()[0]
178
+        if state == 'unknown':
179
+            state = 'maintenance'  # Guess
180
+    if state in ('error', 'blocked'):
181
+        lvl = hookenv.WARNING
182
+    else:
183
+        lvl = hookenv.INFO
184
+    hookenv.status_set(state, message)
185
+    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,159 @@
  4
+import os
  5
+import sys
  6
+import shutil
  7
+import platform
  8
+from glob import glob
  9
+from subprocess import check_call
 10
+
 11
+from charms.layer.execd import execd_preinstall
 12
+
 13
+
 14
+def bootstrap_charm_deps():
 15
+    """
 16
+    Set up the base charm dependencies so that the reactive system can run.
 17
+    """
 18
+    # execd must happen first, before any attempt to install packages or
 19
+    # access the network, because sites use this hook to do bespoke
 20
+    # configuration and install secrets so the rest of this bootstrap
 21
+    # and the charm itself can actually succeed. This call does nothing
 22
+    # unless the operator has created and populated $CHARM_DIR/exec.d.
 23
+    execd_preinstall()
 24
+    # ensure that $CHARM_DIR/bin is on the path, for helper scripts
 25
+    os.environ['PATH'] += ':%s' % os.path.join(os.environ['CHARM_DIR'], 'bin')
 26
+    venv = os.path.abspath('../.venv')
 27
+    vbin = os.path.join(venv, 'bin')
 28
+    vpip = os.path.join(vbin, 'pip')
 29
+    vpy = os.path.join(vbin, 'python')
 30
+    if os.path.exists('wheelhouse/.bootstrapped'):
 31
+        from charms import layer
 32
+        cfg = layer.options('basic')
 33
+        if cfg.get('use_venv') and '.venv' not in sys.executable:
 34
+            # activate the venv
 35
+            os.environ['PATH'] = ':'.join([vbin, os.environ['PATH']])
 36
+            reload_interpreter(vpy)
 37
+        return
 38
+    # bootstrap wheelhouse
 39
+    if os.path.exists('wheelhouse'):
 40
+        with open('/root/.pydistutils.cfg', 'w') as fp:
 41
+            # make sure that easy_install also only uses the wheelhouse
 42
+            # (see https://github.com/pypa/pip/issues/410)
 43
+            charm_dir = os.environ['CHARM_DIR']
 44
+            fp.writelines([
 45
+                "[easy_install]\n",
 46
+                "allow_hosts = ''\n",
 47
+                "find_links = file://{}/wheelhouse/\n".format(charm_dir),
 48
+            ])
 49
+        apt_install(['python3-pip', 'python3-setuptools', 'python3-yaml'])
 50
+        from charms import layer
 51
+        cfg = layer.options('basic')
 52
+        # include packages defined in layer.yaml
 53
+        apt_install(cfg.get('packages', []))
 54
+        # if we're using a venv, set it up
 55
+        if cfg.get('use_venv'):
 56
+            if not os.path.exists(venv):
 57
+                distname, version, series = platform.linux_distribution()
 58
+                if series in ('precise', 'trusty'):
 59
+                    apt_install(['python-virtualenv'])
 60
+                else:
 61
+                    apt_install(['virtualenv'])
 62
+                cmd = ['virtualenv', '-ppython3', '--never-download', venv]
 63
+                if cfg.get('include_system_packages'):
 64
+                    cmd.append('--system-site-packages')
 65
+                check_call(cmd)
 66
+            os.environ['PATH'] = ':'.join([vbin, os.environ['PATH']])
 67
+            pip = vpip
 68
+        else:
 69
+            pip = 'pip3'
 70
+            # save a copy of system pip to prevent `pip3 install -U pip`
 71
+            # from changing it
 72
+            if os.path.exists('/usr/bin/pip'):
 73
+                shutil.copy2('/usr/bin/pip', '/usr/bin/pip.save')
 74
+        # need newer pip, to fix spurious Double Requirement error:
 75
+        # https://github.com/pypa/pip/issues/56
 76
+        check_call([pip, 'install', '-U', '--no-index', '-f', 'wheelhouse',
 77
+                    'pip'])
 78
+        # install the rest of the wheelhouse deps
 79
+        check_call([pip, 'install', '-U', '--no-index', '-f', 'wheelhouse'] +
 80
+                   glob('wheelhouse/*'))
 81
+        if not cfg.get('use_venv'):
 82
+            # restore system pip to prevent `pip3 install -U pip`
 83
+            # from changing it
 84
+            if os.path.exists('/usr/bin/pip.save'):
 85
+                shutil.copy2('/usr/bin/pip.save', '/usr/bin/pip')
 86
+                os.remove('/usr/bin/pip.save')
 87
+        os.remove('/root/.pydistutils.cfg')
 88
+        # flag us as having already bootstrapped so we don't do it again
 89
+        open('wheelhouse/.bootstrapped', 'w').close()
 90
+        # Ensure that the newly bootstrapped libs are available.
 91
+        # Note: this only seems to be an issue with namespace packages.
 92
+        # Non-namespace-package libs (e.g., charmhelpers) are available
 93
+        # without having to reload the interpreter. :/
 94
+        reload_interpreter(vpy if cfg.get('use_venv') else sys.argv[0])
 95
+
 96
+
 97
+def reload_interpreter(python):
 98
+    """
 99
+    Reload the python interpreter to ensure that all deps are available.
100
+
101
+    Newly installed modules in namespace packages sometimes seemt to
102
+    not be picked up by Python 3.
103
+    """
104
+    os.execle(python, python, sys.argv[0], os.environ)
105
+
106
+
107
+def apt_install(packages):
108
+    """
109
+    Install apt packages.
110
+
111
+    This ensures a consistent set of options that are often missed but
112
+    should really be set.
113
+    """
114
+    if isinstance(packages, (str, bytes)):
115
+        packages = [packages]
116
+
117
+    env = os.environ.copy()
118
+
119
+    if 'DEBIAN_FRONTEND' not in env:
120
+        env['DEBIAN_FRONTEND'] = 'noninteractive'
121
+
122
+    cmd = ['apt-get',
123
+           '--option=Dpkg::Options::=--force-confold',
124
+           '--assume-yes',
125
+           'install']
126
+    check_call(cmd + packages, env=env)
127
+
128
+
129
+def init_config_states():
130
+    import yaml
131
+    from charmhelpers.core import hookenv
132
+    from charms.reactive import set_state
133
+    from charms.reactive import toggle_state
134
+    config = hookenv.config()
135
+    config_defaults = {}
136
+    config_defs = {}
137
+    config_yaml = os.path.join(hookenv.charm_dir(), 'config.yaml')
138
+    if os.path.exists(config_yaml):
139
+        with open(config_yaml) as fp:
140
+            config_defs = yaml.safe_load(fp).get('options', {})
141
+            config_defaults = {key: value.get('default')
142
+                               for key, value in config_defs.items()}
143
+    for opt in config_defs.keys():
144
+        if config.changed(opt):
145
+            set_state('config.changed')
146
+            set_state('config.changed.{}'.format(opt))
147
+        toggle_state('config.set.{}'.format(opt), config.get(opt))
148
+        toggle_state('config.default.{}'.format(opt),
149
+                     config.get(opt) == config_defaults[opt])
150
+    hookenv.atexit(clear_config_states)
151
+
152
+
153
+def clear_config_states():
154
+    from charmhelpers.core import hookenv, unitdata
155
+    from charms.reactive import remove_state
156
+    config = hookenv.config()
157
+    remove_state('config.changed')
158
+    for opt in config.keys():
159
+        remove_state('config.changed.{}'.format(opt))
160
+        remove_state('config.set.{}'.format(opt))
161
+        remove_state('config.default.{}'.format(opt))
162
+    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,68 @@
 4
+"name": "ibm-http"
 5
+"summary": "IBM HTTP-SERVER Product"
 6
+"maintainer": "IBM Juju Support Team <jujusupp@us.ibm.com>"
 7
+"description": |
 8
+  IBM HTTP Server is a full-featured web server that is included with other products such as IBM WebSphere Application Server at no charge.
 9
+"tags":
10
+- "ibm"
11
+- "im"
12
+- "ibm"
lazypower commented 5 months ago
This appears to be a duplicate tag. (non blocking comment)
13
+- "apt"
14
+- "leadership"
15
+- "ibm"
16
+- "was-ihs"
17
+"requires":
18
+  "ihs":
19
+    "interface": "was-ihs"
20
+    "scope": "container"
21
+"resources":
22
+  "ibm_im_installer":
23
+    "type": "file"
24
+    "filename": "ibm_im_installer.zip"
25
+    "description": "Installation Manager installer archive"
26
+  "ibm_im_fixpack":
27
+    "type": "file"
28
+    "filename": "ibm_im_fixpack.zip"
29
+    "description": "Installation Manager fix pack archive"
30
+  "ibm_http_installer1":
31
+    "type": "file"
32
+    "filename": "ibm_http.installer1.zip"
33
+    "description": "Http Server installer part1 archive."
34
+  "ibm_http_installer2":
35
+    "type": "file"
36
+    "filename": "ibm_http.installer2.zip"
37
+    "description": "Http Server installer part2 archive."
38
+  "ibm_http_installer3":
39
+    "type": "file"
40
+    "filename": "ibm_http.installer3.zip"
41
+    "description": "Http Server installer part3 archive.."
42
+  "ibm_http_power_installer":
43
+    "type": "file"
44
+    "filename": "ibm_http_power_installer.zip"
45
+    "description": "Http Server power installer archive."
46
+  "ibm_http_server_fixpack1":
47
+    "type": "file"
48
+    "filename": "ibm_http_server_fixpack1.zip"
49
+    "description": "Http Server fix pack part1 archive."
50
+  "ibm_http_server_fixpack2":
51
+    "type": "file"
52
+    "filename": "ibm_http_server_fixpack2.zip"
53
+    "description": "Http Server fix pack part2 archive."
54
+  "ibm_http_server_WCT_fixpack1":
55
+    "type": "file"
56
+    "filename": "ibm_http_server_WCT_fixpack1.zip"
57
+    "description": "Http Server fix pack WCT part1 archive."
58
+  "ibm_http_server_WCT_fixpack2":
59
+    "type": "file"
60
+    "filename": "ibm_http_server_WCT_fixpack2.zip"
61
+    "description": "Http Server fix pack WCT part2 archive."
62
+"series":
63
+- "trusty"
64
+- "xenial"
65
+"subordinate": !!bool "true"
66
+"terms":
67
+- "ibm-im/1"
68
+- "lorem-ipsum/1"
69
+- "ibm-http-server/2"
70
+- "ibm-http-plg/1"
71
+- "ibm-http-wct/1"
Back to file index

reactive/apt.py

  1
--- 
  2
+++ reactive/apt.py
  3
@@ -0,0 +1,131 @@
  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
+    # TODO: Move this to charm-helpers.fetch
 59
+    cmd = ['dpkg-query', '--show', r'--showformat=${Package}\n']
 60
+    installed = set(subprocess.check_output(cmd,
 61
+                                            universal_newlines=True).split())
 62
+    return set(packages) - installed
 63
+
 64
+
 65
+def clear_removed_package_states():
 66
+    """On hook startup, clear install states for removed packages."""
 67
+    removed = filter_installed_packages(charms.apt.installed())
 68
+    if removed:
 69
+        hookenv.log('{} missing packages ({})'.format(len(removed),
 70
+                                                      ','.join(removed)),
 71
+                    WARNING)
 72
+        for package in removed:
 73
+            reactive.remove_state('apt.installed.{}'.format(package))
 74
+
 75
+
 76
+def configure_sources():
 77
+    """Add user specified package sources from the service configuration.
 78
+
 79
+    See charmhelpers.fetch.configure_sources for details.
 80
+    """
 81
+    config = hookenv.config()
 82
+
 83
+    # We don't have enums, so we need to validate this ourselves.
 84
+    package_status = config.get('package_status')
 85
+    if package_status not in ('hold', 'install'):
 86
+        charms.apt.status_set('blocked',
 87
+                              'Unknown package_status {}'
 88
+                              ''.format(package_status))
 89
+        # Die before further hooks are run. This isn't very nice, but
 90
+        # there is no other way to inform the operator that they have
 91
+        # invalid configuration.
 92
+        raise SystemExit(0)
 93
+
 94
+    sources = config.get('install_sources')
 95
+    keys = config.get('install_keys')
 96
+    if reactive.helpers.data_changed('apt.configure_sources', (sources, keys)):
 97
+        fetch.configure_sources(update=False,
 98
+                                sources_var='install_sources',
 99
+                                keys_var='install_keys')
100
+        reactive.set_state('apt.needs_update')
101
+
102
+    extra_packages = sorted(config.get('extra_packages', '').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
+    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" ]; 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_http.py

  1
--- 
  2
+++ reactive/ibm_http.py
  3
@@ -0,0 +1,653 @@
  4
+# !/usr/bin/env python
  5
+import os
  6
+import subprocess
  7
+import os.path
  8
+import zipfile
  9
+import shutil
 10
+
 11
+from charms.reactive import hook
 12
+from charms.reactive import is_state
 13
+from charmhelpers.core import hookenv
 14
+from charms.reactive import when, when_not, set_state, remove_state
 15
+from subprocess import STDOUT
 16
+
 17
+ARCHITECTURE = os.uname()
 18
+IM_INSTALL_PATH = '/opt/IBM/InstallationManager'
 19
+IHS_install_path = "/opt/IBM/HTTPServer"
 20
+PLG_install_path = "/opt/IBM/WebSphere/Plugins"
 21
+WCT_install_path = "/opt/IBM/WebSphere/Toolbox"
 22
+config = hookenv.config()
 23
+CHARM_DIR = os.getcwd()
 24
+
 25
+
 26
+@when('ibm-im.installed')
 27
+@when_not('ibm-http-server.installed')
 28
+def install_ibm_http():
 29
+    if not (("ppc64le" in ARCHITECTURE) or ("x86_64" in ARCHITECTURE)):
 30
+        hookenv.log("IBM HTTP: only supported on x86_64 or ppc64le")
 31
+        hookenv.status_set('blocked', 'IBM HTTP: unsupported architecture')
 32
+        return 1
 33
+
 34
+    # Fail fast if we're on an unsupported arch
 35
+    if "x86_64" in ARCHITECTURE:
 36
+        print("architecture is x86_64")
 37
+        subprocess.check_call(['apt-get', 'install', '-y', 'libc6-i386'],
 38
+                              stdout=open(os.devnull, 'wb'), stderr=STDOUT)
 39
+        subprocess.check_call(['apt-get', 'install', '-y', 'gcc-multilib'],
 40
+                              stdout=open(os.devnull, 'wb'), stderr=STDOUT)
 41
+        # Get the installable resource
 42
+        hookenv.log("IBM HTTP: fetching the ibm_http_installer1 resource")
 43
+        hookenv.status_set('active', 'fetching ibm_http_installer1 resource')
 44
+        http_installer1 = hookenv.resource_get('ibm_http_installer1')
 45
+
 46
+        hookenv.log("IBM HTTP: fetching the ibm_http_installer2 resource")
 47
+        hookenv.status_set('active', 'fetching ibm_http_installer2 resource')
 48
+        http_installer2 = hookenv.resource_get('ibm_http_installer2')
 49
+
 50
+        hookenv.log("IBM HTTP: fetching the ibm_http_installer3 resource")
 51
+        hookenv.status_set('active', 'fetching ibm_http_installer3 resource')
 52
+        http_installer3 = hookenv.resource_get('ibm_http_installer3')
 53
+
 54
+        # If we don't have a package,report blocked status;we can't proceed.
 55
+        if ((http_installer1 is False or http_installer2 is False or
 56
+             http_installer3 is False)):
 57
+            hookenv.log("IBM HTTP: missing required ibm_http resources")
 58
+            hookenv.status_set("blocked", "Required packages are missing")
 59
+            return 0
 60
+
 61
+        command1 = ["file", http_installer1]
 62
+        p1 = subprocess.Popen(command1, stdout=subprocess.PIPE,
 63
+                              stderr=subprocess.PIPE, shell=False)
 64
+        output1, err = p1.communicate()
 65
+        http_installer1_msg = str(output1)
 66
+
 67
+        command2 = ["file", http_installer2]
 68
+        p2 = subprocess.Popen(command2, stdout=subprocess.PIPE,
 69
+                              stderr=subprocess.PIPE, shell=False)
 70
+        output2, err = p2.communicate()
 71
+        http_installer2_msg = str(output2)
 72
+
 73
+        command3 = ["file", http_installer3]
 74
+        p3 = subprocess.Popen(command3, stdout=subprocess.PIPE,
 75
+                              stderr=subprocess.PIPE, shell=False)
 76
+        output3, err = p3.communicate()
 77
+        http_installer3_msg = str(output3)
 78
+
 79
+        if ((("empty" in http_installer1_msg) or
 80
+             ("empty" in http_installer2_msg) or
 81
+             ("empty" in http_installer3_msg))):
 82
+            hookenv.log("IBM HTTP: missing required ibm_http"
 83
+                        "resources,empty packages are found")
 84
+            hookenv.status_set("blocked", "Required packages are empty")
 85
+            return 0
 86
+        else:
 87
+            http_server_installers = (http_installer1, http_installer2,
 88
+                                      http_installer3)
 89
+            print(http_server_installers)
 90
+            CHARM_DIR = os.getcwd()
 91
+            charmpath = CHARM_DIR+"/../resources"
 92
+            if os.path.exists(CHARM_DIR+"/../resources/HTTP"):
 93
+                hookenv.log("IBM HTTP: dir exist already.")
 94
+            else:
 95
+                os.makedirs(CHARM_DIR+"/../resources/HTTP")
 96
+            if ((os.path.exists(charmpath+"/HTTP/disk1") and
 97
+                 os.path.exists(charmpath+"/HTTP/disk2") and
 98
+                 os.path.exists(charmpath+"/HTTP//disk3"))):
 99
+                hookenv.log("IBM HTTP: Packages extracted already.")
100
+            else:
101
+                hookenv.log("IBM HTTP: Extracting package contents.")
102
+                # checking whether zip file extracted properly
103
+                try:
104
+                    for i in http_server_installers:
105
+                        filename = i
106
+                        with zipfile.ZipFile(filename) as z:
107
+                            z.extractall(charmpath+"/HTTP")
108
+                            hookenv.log("IBM HTTP: Extracted")
109
+                except subprocess.CalledProcessError as e:
110
+                    print(e.output)
111
+                    hookenv.log("IBM HTTP: Unable to extract packages")
112
+                    hookenv.status_set("blocked", "Package is corrupt")
113
+                    shutil.rmtree(charmpath+"/HTTP")
114
+                    return 0
115
+            # Installtion
116
+            http_repo = str(CHARM_DIR)+"/../resources/HTTP"
117
+            hookenv.status_set('active', "IBM HTTP: Installing")
118
+            try:
119
+                subprocess.check_call([IM_INSTALL_PATH +
120
+                                       '/eclipse/tools/imcl', 'install',
121
+                                       'com.ibm.websphere.IHS.v85',
122
+                                       '-installationDirectory',
123
+                                       IHS_install_path, '-repositories',
124
+                                       http_repo, '-acceptLicense',
125
+                                       '-properties', 'user.ihs.httpPort=80'])
126
+                subprocess.check_call([IM_INSTALL_PATH + '/eclipse/tools/imcl',
127
+                                       'install', 'com.ibm.websphere.PLG.v85',
128
+                                       '-installationDirectory',
129
+                                       PLG_install_path, '-repositories',
130
+                                       http_repo, '-acceptLicense'])
131
+                subprocess.check_call([IM_INSTALL_PATH +
132
+                                       '/eclipse/tools/imcl', 'install',
133
+                                       'com.ibm.websphere.WCT.v85',
134
+                                       '-installationDirectory',
135
+                                       WCT_install_path, '-repositories',
136
+                                       http_repo, '-acceptLicense'])
137
+                hookenv.status_set("active", "IBM HTTP: HTTP Server"
138
+                                   "Installed successfully")
139
+                set_state('ibm-http-server.installed')
140
+            except subprocess.CalledProcessError as e:
141
+                print(e.output)
142
+                hookenv.status_set("maintenance", "IBM HTTP:"
143
+                                   "Error installing HTTP")
144
+                return 1
145
+
146
+    elif "ppc64le" in ARCHITECTURE:
147
+        print("architecture is ppc64le")
148
+        # Get the installable resource
149
+        hookenv.log("IBM HTTP: fetching ibm__http_power_installer")
150
+        hookenv.status_set('active', 'fetching http_power_installer')
151
+        http_power_installer = hookenv.resource_get('ibm_http_power_installer')
152
+
153
+        # If we don't have a package, report status; we can't proceed.
154
+        if (http_power_installer is False):
155
+            hookenv.log("IBM HTTP: missing ibm_http resources")
156
+            hookenv.status_set('blocked', 'Packages missing')
157
+            return 0
158
+
159
+        command = ["file", http_power_installer]
160
+        p1 = subprocess.Popen(command, stdout=subprocess.PIPE,
161
+                              stderr=subprocess.PIPE, shell=False)
162
+        output, err = p1.communicate()
163
+        http_power_installer_msg = str(output)
164
+
165
+        if "empty" in http_power_installer_msg:
166
+            hookenv.log("IBM HTTP: empty packages are found")
167
+            hookenv.status_set("blocked", "Packages are empty."
168
+                               "Please provide actual packages")
169
+            return 0
170
+        else:
171
+            CHARM_DIR = os.getcwd()
172
+            charmpath = CHARM_DIR+"/../resources"
173
+            if os.path.exists(CHARM_DIR+"/../resources/HTTP"):
174
+                hookenv.log("IBM HTTP: dir exist already.")
175
+            else:
176
+                os.makedirs(CHARM_DIR+"/../resources/HTTP")
177
+            if os.path.exists(charmpath+"/HTTP/disk1"):
178
+                hookenv.log("IBM HTTP: Extracted already")
179
+            else:
180
+                hookenv.log("IBM HTTP: Extracting packages.")
181
+                # checking whether zip files extracted properly
182
+                try:
183
+                    zip_ref = zipfile.ZipFile(http_power_installer, 'r')
184
+                    zip_ref.extractall(charmpath+"/HTTP")
185
+                    zip_ref.close()
186
+                    hookenv.log("IBM HTTP: Packages extracted"
187
+                                "available for installation")
188
+                except subprocess.CalledProcessError as e:
189
+                    print(e.output)
190
+                    hookenv.log("IBM HTTP: Unable to extract."
191
+                                "package is corrupt")
192
+                    hookenv.status_set("blocked", "package is corrupt")
193
+                    shutil.rmtree(charmpath+"/HTTP")
194
+                    return 0
195
+            # Installtion
196
+            http_repo = str(CHARM_DIR)+"/../resources/HTTP"
197
+            hookenv.status_set('active', "IBM HTTP: Installing HTTP")
198
+            try:
199
+                subprocess.check_call([IM_INSTALL_PATH +
200
+                                       '/eclipse/tools/imcl', 'install',
201
+                                       'com.ibm.websphere.IHS.le.v85',
202
+                                       '-installationDirectory',
203
+                                       IHS_install_path, '-repositories',
204
+                                       http_repo, '-acceptLicense',
205
+                                       '-properties',
206
+                                       'user.ihs.httpPort=80'])
207
+                subprocess.check_call([IM_INSTALL_PATH +
208
+                                       '/eclipse/tools/imcl', 'install',
209
+                                       'com.ibm.websphere.PLG.le.v85',
210
+                                       '-installationDirectory',
211
+                                       PLG_install_path, '-repositories',
212
+                                       http_repo, '-acceptLicense'])
213
+                subprocess.check_call([IM_INSTALL_PATH +
214
+                                       '/eclipse/tools/imcl', 'install',
215
+                                       'com.ibm.websphere.WCT.le.v85',
216
+                                       '-installationDirectory',
217
+                                       WCT_install_path, '-repositories',
218
+                                       http_repo, '-acceptLicense'])
219
+                hookenv.status_set('active', "IBM HTTP: Installed")
220
+                set_state('ibm-http-server.installed')
221
+            except subprocess.CalledProcessError as e:
222
+                print(e.output)
223
+                hookenv.status_set("maintenance", "IBM HTTP:"
224
+                                   " Error while installing HTTP")
225
+                return 1
226
+
227
+
228
+@when('ibm-http-server.installed')
229
+@when_not('ibm-http-server.updated')
230
+def install_http_server_fixpack():
231
+        # Get the fixpack resource
232
+        CHARM_DIR = os.getcwd()
233
+        hookenv.log("IBM HTTP: fetching ibm_http_server_fixpack1 resource")
234
+        hookenv.status_set('active', 'fetching ibm_http_server_fixpack1')
235
+        http_fixpack1 = hookenv.resource_get('ibm_http_server_fixpack1')
236
+        hookenv.status_set('active', 'fetched ibm_http_server_fixpack1')
237
+
238
+        hookenv.log("IBM HTTP: fetching ibm_http_server_fixpack2 resource")
239
+        hookenv.status_set('active', 'fetching ibm_http_server_fixpack2')
240
+        http_fixpack2 = hookenv.resource_get('ibm_http_server_fixpack2')
241
+        hookenv.status_set('active', 'fetched ibm_http_server_fixpack2')
242
+
243
+        hookenv.log("IBM HTTP: fetching ibm_http_server_WCT_fixpack1 resource")
244
+        hookenv.status_set('active', 'fetching ibm_http_server_WCT_fixpack1')
245
+        http_WCT_fix1 = hookenv.resource_get('ibm_http_server_WCT_fixpack1')
246
+        hookenv.status_set('active', 'fetched ibm_http_server_WCT_fixpack1')
247
+
248
+        hookenv.log("IBM HTTP: fetching ibm_http_server_WCT_fixpack2 resource")
249
+        hookenv.status_set('active', 'fetching ibm_http_server_WCT_fixpack2')
250
+        http_WCT_fix2 = hookenv.resource_get('ibm_http_server_WCT_fixpack2')
251
+        hookenv.status_set('active', 'fetched ibm_http_server_WCT_fixpack2')
252
+
253
+        # If we don't have a fixpack, just exit successfully.
254
+        if ((http_fixpack1 is False or http_fixpack2 is False or
255
+             http_WCT_fix1 is False or http_WCT_fix2 is False)):
256
+            hookenv.log("IBM HTTP: no ibm_http_server_fixpack to install")
257
+            hookenv.status_set('active', 'IBM HTTP is ready')
258
+            return 0
259
+        else:
260
+            command1 = ["file", http_fixpack1]
261
+            p1 = subprocess.Popen(command1, stdout=subprocess.PIPE,
262
+                                  stderr=subprocess.PIPE, shell=False)
263
+            output1, err = p1.communicate()
264
+            http_fixpack_msg1 = str(output1)
265
+
266
+            command2 = ["file", http_fixpack2]
267
+            p2 = subprocess.Popen(command2, stdout=subprocess.PIPE,
268
+                                  stderr=subprocess.PIPE, shell=False)
269
+            output2, err = p2.communicate()
270
+            http_fixpack_msg2 = str(output2)
271
+
272
+            command3 = ["file", http_WCT_fix1]
273
+            p3 = subprocess.Popen(command3, stdout=subprocess.PIPE,
274
+                                  stderr=subprocess.PIPE, shell=False)
275
+            output3, err = p3.communicate()
276
+            http_fixpack_msg3 = str(output3)
277
+
278
+            command4 = ["file", http_WCT_fix2]
279
+            p4 = subprocess.Popen(command4, stdout=subprocess.PIPE,
280
+                                  stderr=subprocess.PIPE, shell=False)
281
+            output4, err = p4.communicate()
282
+            http_fixpack_msg4 = str(output4)
283
+
284
+            if ((("empty" in http_fixpack_msg1) or
285
+                 ("empty" in http_fixpack_msg2) or
286
+                 ("empty" in http_fixpack_msg3) or
287
+                 ("empty" in http_fixpack_msg4))):
288
+                hookenv.log("IBM HTTP: empty packages found")
289
+                hookenv.status_set('active', 'HTTP is ready')
290
+                return 0
291
+            else:
292
+                http_fix_installers = (http_fixpack1, http_fixpack2)
293
+                http_WCT_fixinstallers = (http_WCT_fix1, http_WCT_fix2)
294
+                CHARM_DIR = os.getcwd()
295
+                if os.path.exists(CHARM_DIR+"/../resources/HTTP_FP"):
296
+                    hookenv.log("HTTP_FP dir exist already.")
297
+                else:
298
+                    os.makedirs(CHARM_DIR+"/../resources/HTTP_FP")
299
+                    if os.path.exists(CHARM_DIR+"/../resources/HTTP_WCT_FP"):
300
+                        hookenv.log("HTTP_WCT_FP dir exist already.")
301
+                    else:
302
+                        os.makedirs(CHARM_DIR+"/../resources/HTTP_WCT_FP")
303
+                    hookenv.log("Extracting HTTP fixpack package contents.")
304
+                    # checking whether zip files extracted properly
305
+                    try:
306
+                        for i in http_fix_installers:
307
+                            filename = i
308
+                            hookenv.log("IBM HTTP: Extracting fixpacks.")
309
+                            with zipfile.ZipFile(filename) as z:
310
+                                z.extractall(CHARM_DIR+"/../resources/HTTP_FP")
311
+                                hookenv.log("IBM HTTP: packages extracted")
312
+                    except subprocess.CalledProcessError as e:
313
+                        print(e.output)
314
+                        hookenv.log("IBM HTTP: Unable to extract HTTP_FP")
315
+                        hookenv.status_set('blocked', 'HTTP_FP is corrupt')
316
+                        shutil.rmtree(CHARM_DIR+"/../resources/HTTP_FP")
317
+                        return 0
318
+                    hookenv.log("IBM HTTP: Extracting WCT fixpacks.")
319
+                    try:
320
+                        for i in http_WCT_fixinstallers:
321
+                            filename = i
322
+                            hookenv.log("IBM HTTP: Extracting WCT fixes.")
323
+                            with zipfile.ZipFile(filename) as z:
324
+                                path = CHARM_DIR+"/../resources"
325
+                                z.extractall(path+"/HTTP_WCT_FP")
326
+                                hookenv.log("IBM HTTP: HTTP_WCT_FP extracted")
327
+                    except subprocess.CalledProcessError as e:
328
+                        print(e.output)
329
+                        hookenv.log("IBM HTTP: Unable to extract"
330
+                                    "HTTP_WCT_FPpackage is corrupt")
331
+                        hookenv.status_set("blocked",
332
+                                           "HTTP_WCT_FP is corrupt")
333
+                        shutil.rmtree(CHARM_DIR+"/../resources/HTTP_WCT_FP")
334
+                        return 0
335
+                    # Updation
336
+                    path = str(CHARM_DIR)+"/../resources"
337
+                    http_FP_repo = path+"/HTTP_FP"
338
+                    http_WCT_FP_repo = path+"/HTTP_WCT_FP"
339
+                    hookenv.status_set('active', "IBM HTTP: Updating HTTP")
340
+                    if "x86_64" in ARCHITECTURE:
341
+                        try:
342
+                            subprocess.check_call([IM_INSTALL_PATH +
343
+                                                   '/eclipse/tools/imcl',
344
+                                                   'install',
345
+                                                   'com.ibm.websphere.IHS.v85',
346
+                                                   '-installationDirectory',
347
+                                                   IHS_install_path,
348
+                                                   '-repositories',
349
+                                                   http_FP_repo,
350
+                                                   '-acceptLicense',
351
+                                                   '-properties',
352
+                                                   'user.ihs.httpPort=80'])
353
+                            subprocess.check_call([IM_INSTALL_PATH +
354
+                                                   '/eclipse/tools/imcl',
355
+                                                   'install',
356
+                                                   'com.ibm.websphere.PLG.v85',
357
+                                                   '-installationDirectory',
358
+                                                   PLG_install_path,
359
+                                                   '-repositories',
360
+                                                   http_FP_repo,
361
+                                                   '-acceptLicense'])
362
+                            subprocess.check_call([IM_INSTALL_PATH +
363
+                                                   '/eclipse/tools/imcl',
364
+                                                   'install',
365
+                                                   'com.ibm.websphere.WCT.v85',
366
+                                                   '-installationDirectory',
367
+                                                   WCT_install_path,
368
+                                                   '-repositories',
369
+                                                   http_WCT_FP_repo,
370
+                                                   '-acceptLicense'])
371
+                            hookenv.status_set('active', "IBM HTTP:"
372
+                                               "Updated successfully")
373
+                            set_state('ibm-http-server.updated')
374
+                        except subprocess.CalledProcessError as e:
375
+                            print(e.output)
376
+                            hookenv.status_set('maintenance', "IBM HTTP:"
377
+                                               " Error while updating HTTP")
378
+                            return 1
379
+                    elif "ppc64le" in ARCHITECTURE:
380
+                        try:
381
+                            subprocess.check_call([IM_INSTALL_PATH +
382
+                                                   '/eclipse/tools/imcl',
383
+                                                   'install',
384
+                                                   'com.ibm.websphere.'
385
+                                                   'IHS.le.v85',
386
+                                                   '-installationDirectory',
387
+                                                   IHS_install_path,
388
+                                                   '-repositories',
389
+                                                   http_FP_repo,
390
+                                                   '-acceptLicense',
391
+                                                   '-properties',
392
+                                                   'user.ihs.httpPort=80'])
393
+                            subprocess.check_call([IM_INSTALL_PATH +
394
+                                                   '/eclipse/tools/imcl',
395
+                                                   'install',
396
+                                                   'com.ibm.websphere.'
397
+                                                   'PLG.le.v85',
398
+                                                   '-installationDirectory',
399
+                                                   PLG_install_path,
400
+                                                   '-repositories',
401
+                                                   http_FP_repo,
402
+                                                   '-acceptLicense'])
403
+                            subprocess.check_call([IM_INSTALL_PATH +
404
+                                                   '/eclipse/tools/imcl',
405
+                                                   'install',
406
+                                                   'com.ibm.websphere.'
407
+                                                   'WCT.le.v85',
408
+                                                   '-installationDirectory',
409
+                                                   WCT_install_path,
410
+                                                   '-repositories',
411
+                                                   http_WCT_FP_repo,
412
+                                                   '-acceptLicense'])
413
+                            hookenv.status_set('active', "IBM HTTP:"
414
+                                               "Updated successfully")
415
+                            set_state('ibm-http-server.updated')
416
+                        except subprocess.CalledProcessError as e:
417
+                            print(e.output)
418
+                            hookenv.status_set('maintenance', "IBM HTTP:"
419
+                                               "Error while updating HTTP")
420
+                            return 1
421
+
422
+
423
+@hook('upgrade-charm')
424
+def check_fixpack():
425
+    # fixpack_state = is_state('ibm-http-server.updated')
426
+    if not is_state('ibm-http-server.updated'):
427
+        hookenv.log("IBM HTTP: no fixpack has been installed;"
428
+                    "nothing to upgrade.")
429
+        return 0
430
+    else:
431
+        hookenv.log("IBM HTTP: scanning for new fixpacks to install")
432
+        CHARM_DIR = os.getcwd()
433
+        path = str(CHARM_DIR)+"/../resources"
434
+        DIR1 = path+"/ibm_http_server_fixpack1"
435
+        DIR2 = path+"/ibm_http_server_fixpack2"
436
+        DIR3 = path+"/ibm_http_server_WCT_fixpack1"
437
+        DIR4 = path+"/ibm_http_server_WCT_fixpack2"
438
+        CUR_FIXPACK1 = str(DIR1)+"/ibm_http_server_fixpack1.zip"
439
+        CUR_FIXPACK2 = str(DIR2)+"/ibm_http_server_fixpack2.zip"
440
+        CUR_FIXPACK3 = str(DIR3)+"/ibm_http_server_WCT_fixpack1.zip"
441
+        CUR_FIXPACK4 = str(DIR4)+"/ibm_http_server_WCT_fixpack2.zip"
442
+
443
+        # Sum any existing fixpack to determine if we have a new one
444
+        if ((os.path.exists(DIR1+"/ibm_http_server_fixpack1.zip") and
445
+             os.path.exists(DIR2+"/ibm_http_server_fixpack2.zip") and
446
+             os.path.exists(DIR3+"/ibm_http_server_WCT_fixpack1.zip") and
447
+             os.path.exists(DIR4+"/ibm_http_server_WCT_fixpack2.zip"))):
448
+            hookenv.log("IBM HTTP: Checking checksum values of CUR_Fixpacks")
449
+            command1 = ["md5sum", CUR_FIXPACK1]
450
+            p1 = subprocess.Popen(command1, stdout=subprocess.PIPE,
451
+                                  stderr=subprocess.PIPE, shell=False)
452
+            output1, err = p1.communicate()
453
+            value1 = output1.split()
454
+            CUR_FP1_MD5 = str(value1[0])
455
+
456
+            command2 = ["md5sum", CUR_FIXPACK2]
457
+            p2 = subprocess.Popen(command2, stdout=subprocess.PIPE,
458
+                                  stderr=subprocess.PIPE, shell=False)
459
+            output2, err = p2.communicate()
460
+            value2 = output2.split()
461
+            CUR_FP2_MD5 = str(value2[0])
462
+
463
+            command3 = ["md5sum", CUR_FIXPACK3]
464
+            p3 = subprocess.Popen(command3, stdout=subprocess.PIPE,
465
+                                  stderr=subprocess.PIPE, shell=False)
466
+            output3, err = p3.communicate()
467
+            value3 = output3.split()
468
+            CUR_FP3_MD5 = str(value3[0])
469
+
470
+            command4 = ["md5sum", CUR_FIXPACK4]
471
+            p4 = subprocess.Popen(command4, stdout=subprocess.PIPE,
472
+                                  stderr=subprocess.PIPE, shell=False)
473
+            output4, err = p4.communicate()
474
+            value4 = output4.split()
475
+            CUR_FP4_MD5 = str(value4[0])
476
+
477
+            # Calling resource-get here will fetch the fixpack resource.
478
+            NEW_FIXPACK1 = hookenv.resource_get('ibm_http_server_fixpack1')
479
+            NEW_FIXPACK2 = hookenv.resource_get('ibm_http_server_fixpack2')
480
+            NEW_FIXPACK3 = hookenv.resource_get('ibm_http_server_WCT_fixpack1')
481
+            NEW_FIXPACK4 = hookenv.resource_get('ibm_http_server_WCT_fixpack2')
482
+            if ((NEW_FIXPACK1 is False or NEW_FIXPACK2 is False or
483
+                 NEW_FIXPACK3 is False or NEW_FIXPACK4 is False)):
484
+                hookenv.log("IBM HTTP: no fixpack to install")
485
+            else:
486
+                hookenv.log("IBM HTTP: Checking checksum of NEW_FIXPACKS")
487
+                command5 = ["md5sum", NEW_FIXPACK1]
488
+                p5 = subprocess.Popen(command5, stdout=subprocess.PIPE,
489
+                                      stderr=subprocess.PIPE, shell=False)
490
+                output5, err = p5.communicate()
491
+                value5 = output5.split()
492
+                NEW_FP1_MD5 = str(value5[0])
493
+
494
+                command6 = ["md5sum", NEW_FIXPACK2]
495
+                p6 = subprocess.Popen(command6, stdout=subprocess.PIPE,
496
+                                      stderr=subprocess.PIPE, shell=False)
497
+                output6, err = p6.communicate()
498
+                value6 = output6.split()
499
+                NEW_FP2_MD5 = str(value6[0])
500
+
501
+                command7 = ["md5sum", NEW_FIXPACK3]
502
+                p7 = subprocess.Popen(command7, stdout=subprocess.PIPE,
503
+                                      stderr=subprocess.PIPE, shell=False)
504
+                output7, err = p7.communicate()
505
+                value7 = output7.split()
506
+                NEW_FP3_MD5 = str(value7[0])
507
+
508
+                command8 = ["md5sum", NEW_FIXPACK4]
509
+                p8 = subprocess.Popen(command8, stdout=subprocess.PIPE,
510
+                                      stderr=subprocess.PIPE, shell=False)
511
+                output8, err = p8.communicate()
512
+                value8 = output8.split()
513
+                NEW_FP4_MD5 = str(value8[0])
514
+
515
+                # If sums don't match, we have a new fp. Configure states so
516
+                # we re-run install-ibm-http-server-fixpack().
517
+                if ((CUR_FP1_MD5 != NEW_FP1_MD5 or
518
+                     CUR_FP2_MD5 != NEW_FP2_MD5 or
519
+                     CUR_FP3_MD5 != NEW_FP3_MD5 or
520
+                     CUR_FP4_MD5 != NEW_FP4_MD5)):
521
+                    hookenv.log("IBM HTTP: new fixpack detected " +
522
+                                CUR_FP1_MD5+"versus"+NEW_FP1_MD5+"" +
523
+                                CUR_FP2_MD5+"versus"+NEW_FP2_MD5+"" +
524
+                                CUR_FP3_MD5+"versus"+NEW_FP3_MD5+"" +
525
+                                CUR_FP4_MD5+"versus"+NEW_FP4_MD5)
526
+                    remove_state('ibm-http-server.updated')
527
+                    shutil.rmtree(CHARM_DIR+"/../resources/HTTP_FP")
528
+                    shutil.rmtree(CHARM_DIR+"/../resources/HTTP_WCT_FP")
529
+                else:
530
+                    hookenv.log("IBM HTTP: no new fixpacks to install")
531
+        else:
532
+            hookenv.log("IBM HTTP: no new fixpack to install")
533
+
534
+
535
+@when('ibm-http-server.installed')
536
+@when('ihs.ready')
537
+@when_not('test.configured')
538
+def configure_ihs(ihs):
539
+    hookenv.log("**In configure_ihs reactive function of http charm**")
540
+    was_install_path = str(ihs.get_was_path())
541
+    hostname = str(ihs.get_was_hostname())
542
+    ihsadminusr = str(ihs.get_ihsadminusr())
543
+    ihsadminpw = str(ihs.get_ihsadminpw())
544
+    ihsadmingrp = str(ihs.get_ihsadmingrp())
545
+    profilename = str(ihs.get_was_profile_name())
546
+    hookenv.log("Copied WAS values"+was_install_path+""+hostname+"" +
547
+                ihsadminusr+""+ihsadminpw+""+ihsadmingrp+""+profilename)
548
+    hookenv.status_set("maintenance", "WAS values copied from remote WAS mc")
549
+    set_state('test.configured')
550
+    plugin_path = '/opt/IBM/WebSphere/Toolbox/WCT'
551
+    os.chdir(plugin_path)
552
+    text_file = open("res.txt", "w")
553
+    lines = ["configType=local_standalone\n",
554
+             "enableAdminServerSupport=true\n"
555
+             "enableUserAndPass=true\n"
556
+             "enableWinService=false\n"
557
+             "ihsAdminCreateUserAndGroup=true\n"
558
+             "ihsAdminPassword="+ihsadminpw+"\n"
559
+             "ihsAdminPort=81\n"
560
+             "ihsAdminUnixUserGroup="+ihsadmingrp+"\n"
561
+             "ihsAdminUnixUserID="+ihsadminusr+"\n"
562
+             "mapWebServerToApplications=true\n"
563
+             "profileName="+profilename+"\n"
564
+             "wasExistingLocation="+was_install_path+"\n"
565
+             "webServerConfigFile1=/opt/IBM/HTTPServer/conf/httpd.conf\n"
566
+             "webServerDefinition=webserver1\n"
567
+             "webServerHostName="+hostname+"\n"
568
+             "webServerOS=Linux\n"
569
+             "webServerPortNumber=80\n"
570
+             "webServerSelected=ihs\n"]
571
+    text_file.writelines(lines)
572
+    text_file.close()
573
+    try:
574
+        subprocess.check_call(['/opt/IBM/WebSphere/Toolbox/WCT/wctcmd.sh',
575
+                               '-tool', 'pct', '-defLocPathname',
576
+                               '/opt/IBM/WebSphere/Plugins', '-defLocName',
577
+                               'wasplg', '-createDefinition', '-response',
578
+                               '/opt/IBM/WebSphere/Toolbox/WCT/res.txt'])
579
+        http_path = '/opt/IBM/HTTPServer/bin'
580
+        subprocess.check_call([http_path + '/apachectl', 'start'])
581
+        subprocess.check_call([http_path + '/adminctl', 'start'])
582
+        subprocess.call(['chmod', '-R', '755', '/opt/IBM/HTTPServer/'])
583
+        hookenv.status_set('active', "IBM HTTP: HTTP started successfully")
584
+        ihs.set_isihsstarted('started')
585
+    except subprocess.CalledProcessError as e:
586
+        print(e.output)
587
+        hookenv.status_set('maintenance', "IBM HTTP: Error while starting")
588
+
589
+
590
+@when('test.configured')
591
+@when_not('ihs.ready')
592
+def reset_all_states():
593
+    hookenv.log("Resetting all states for test charm")
594
+    remove_state('test.configured')
595
+
596
+
597
+@when('ihs.departed')
598
+def departed_from_was(self):
599
+    hookenv.status_set("maintenance", "Relation broken from WAS Base")
600
+    http_path = '/opt/IBM/HTTPServer/bin'
601
+    if os.path.exists(http_path):
602
+        subprocess.check_call([http_path + '/apachectl', 'stop'])
603
+        subprocess.check_call([http_path + '/adminctl', 'stop'])
604
+        hookenv.log("Stopped adminctl and apachectl server")
605
+    else:
606
+        hookenv.log("Stopped adminctl and apachectl server")
607
+    if os.path.exists(WCT_install_path):
608
+        subprocess.check_call(['/opt/IBM/WebSphere/Toolbox/WCT/wctcmd.sh',
609
+                               '-tool', 'pct', ' -removeDefinitionLocation',
610
+                               'wasplg', '-defLocPathname',
611
+                               '/opt/IBM/WebSphere/Plugins'])
612
+        hookenv.log("Removed webserver definition")
613
+    else:
614
+        hookenv.log("Removed webserver definition")
615
+    hookenv.log("Test charm and WAS Base departed")
616
+    hookenv.log("IBM HTTP: Removing HTTP-Server")
617
+    if "x86_64" in ARCHITECTURE:
618
+        try:
619
+            subprocess.check_call([IM_INSTALL_PATH + '/eclipse/tools/imcl',
620
+                                   'uninstall', 'com.ibm.websphere.IHS.v85',
621
+                                   '-installationDirectory', IHS_install_path])
622
+            subprocess.check_call([IM_INSTALL_PATH + '/eclipse/tools/imcl',
623
+                                   'uninstall', 'com.ibm.websphere.PLG.v85',
624
+                                   '-installationDirectory', PLG_install_path])
625
+            subprocess.check_call([IM_INSTALL_PATH + '/eclipse/tools/imcl',
626
+                                   'uninstall', 'com.ibm.websphere.WCT.v85',
627
+                                   '-installationDirectory', WCT_install_path])
628
+            hookenv.status_set('active', "IBM HTTP: Uninstalled successfully")
629
+            shutil.rmtree('/opt/IBM/HTTPServer')
630
+            shutil.rmtree('/opt/IBM/WebSphere/Plugins')
631
+            shutil.rmtree('/opt/IBM/WebSphere/Toolbox')
632
+            remove_state('test.configured')
633
+        except subprocess.CalledProcessError as e:
634
+            print(e.output)
635
+            hookenv.status_set('maintenance', "IBM HTTP: Error"
636
+                               "while uninstalling HTTP")
637
+    elif "ppc64le" in ARCHITECTURE:
638
+        try:
639
+            subprocess.check_call([IM_INSTALL_PATH + '/eclipse/tools/imcl',
640
+                                   'uninstall', 'com.ibm.websphere.IHS.le.v85',
641
+                                   '-installationDirectory', IHS_install_path])
642
+            subprocess.check_call([IM_INSTALL_PATH + '/eclipse/tools/imcl',
643
+                                   'uninstall', 'com.ibm.websphere.PLG.le.v85',
644
+                                   '-installationDirectory', PLG_install_path])
645
+            subprocess.check_call([IM_INSTALL_PATH + '/eclipse/tools/imcl',
646
+                                   'uninstall', 'com.ibm.websphere.WCT.le.v85',
647
+                                   '-installationDirectory', WCT_install_path])
648
+            hookenv.status_set('active', "IBM HTTP: Uninstalled successfully")
649
+            shutil.rmtree('/opt/IBM/HTTPServer')
650
+            shutil.rmtree('/opt/IBM/WebSphere/Plugins')
651
+            shutil.rmtree('/opt/IBM/WebSphere/Toolbox')
652
+            remove_state('test.configured')
653
+        except subprocess.CalledProcessError as e:
654
+            print(e.output)
655
+            hookenv.status_set('maintenance', "IBM HTTP: Error"
656
+                               "while uninstalling HTTP")
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,56 @@
 4
+#!/usr/bin/env python3
 5
+
 6
+import amulet
 7
+import re
 8
+import requests
 9
+import unittest
10
+
11
+seconds_to_wait = 20000
12
+
13
+
14
+class TestDeploy(unittest.TestCase):
15
+    """
16
+    Deployment test for the IBM HTTP charm.
17
+
18
+    This charm doesn't do much by itself, so we expect functional
19
+    tests to happen in the charms that use this layer (for example, websphere).
20
+    """
21
+    def setUp(self):
22
+        self.d = amulet.Deployment(series='trusty')
23
+        self.d.add('ibm-was-base', 'cs:~ibmcharmers/trusty/ibm-was-base')
24
+        self.d.add('ibm-http', 'cs:~ibmcharmers/trusty/ibm-http')
25
+        self.d.relate('ibm-was-base:was-ihs', 'ibm-http:ihs')
26
+        self.d.setup(seconds_to_wait)
27
+        self.d.sentry.wait(seconds_to_wait)
28
+
29
+    def test_deploy_with_placeholder_resource(self):
30
+        # The status message when using placeholder resources will include the
31
+        # string "ibm_http_installer resource". If we see that, the test is
32
+        # successful.
33
+        sentry_re = re.compile('ibm_http_installer resource')
34
+        self.d.sentry.wait_for_messages({"ibm-http": sentry_re})
35
+
36
+    def test_was_base_deployed(self):
37
+        self.assertTrue(self.d.deployed)
38
+        unit = self.d.sentry['ibm-was-base'][0]
39
+        state_was_base = unit.info['agent-state']
40
+        print('WAS Base Server is %s' % state_was_base)
41
+        url = 'http://%s:9060/ibm/console' % unit.info['public-address']
42
+        https_url = 'https://%s:9043/ibm/console' % unit.info['public-address']
43
+        response = requests.get(url, verify=False)
44
+        response = requests.get(https_url, verify=False)
45
+        # Raise an exception if the url was not a valid web page.
46
+        response.raise_for_status()
47
+
48
+    def test_was_ihs(self):
49
+        http_unit = self.d.sentry['ibm-http'][0]
50
+        state_http = http_unit.info['agent-state']
51
+        print('Http Server is %s' % state_http)
52
+        url = 'http://%s:80' % http_unit.info['public-address']
53
+        snoop_url = 'http://%s:80/snoop' % http_unit.info['public-address']
54
+        response = requests.get(url, verify=False)
55
+        response = requests.get(snoop_url, verify=False)
56
+        response.raise_for_status()
57
+
58
+if __name__ == '__main__':
59
+    unittest.main()
Back to file index

tests/tests.yaml

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

tox.ini

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