~vtas-hyperscale-ci/hyperscale-1

Owner: vtas-hyperscale-ci
Status: Needs Review
Vote: +0 (+2 needed for approval)

CPP?: No
OIL?: No

This is a deployment charm for Veritas HyperScale Controller services. The charm is non-reactive and requires Veritas HyperScale Packages tar file as a resource. This tar file will only be provided to the licensed users and the charm WILL not function without it.

1) Installs Veritas HyperScale controller packages : vrtsofcore, vrtsofmn, vrtsofui, vrtsspt. Also installs required packages.
2) Updates Nova, cinder and ceilometer configuration files with HyperScale specific changes.
- For nova, enabled_filters is updated.
- For cinder, scheduler filter and block drivers are updated
3) Requires the following relations :
- shared-db:mysql
- db-admin:mysql
- identity-admin:keystone
- amqp:rabbitmq-server
4) HyperScale services are restarted after all the relations are complete.


Tests

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

Add Comment

Login to comment/vote on this review.


Policy Checklist

Description Unreviewed Pass Fail

General

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

Testing and Quality

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

Metadata

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

Security

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

All changes | Changes since last revision

Source Diff

Files changed 77

Inline diff comments 0

No comments yet.

Back to file index

LICENSE

  1
--- 
  2
+++ LICENSE
  3
@@ -0,0 +1,202 @@
  4
+
  5
+                                 Apache License
  6
+                           Version 2.0, January 2004
  7
+                        http://www.apache.org/licenses/
  8
+
  9
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
 10
+
 11
+   1. Definitions.
 12
+
 13
+      "License" shall mean the terms and conditions for use, reproduction,
 14
+      and distribution as defined by Sections 1 through 9 of this document.
 15
+
 16
+      "Licensor" shall mean the copyright owner or entity authorized by
 17
+      the copyright owner that is granting the License.
 18
+
 19
+      "Legal Entity" shall mean the union of the acting entity and all
 20
+      other entities that control, are controlled by, or are under common
 21
+      control with that entity. For the purposes of this definition,
 22
+      "control" means (i) the power, direct or indirect, to cause the
 23
+      direction or management of such entity, whether by contract or
 24
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
 25
+      outstanding shares, or (iii) beneficial ownership of such entity.
 26
+
 27
+      "You" (or "Your") shall mean an individual or Legal Entity
 28
+      exercising permissions granted by this License.
 29
+
 30
+      "Source" form shall mean the preferred form for making modifications,
 31
+      including but not limited to software source code, documentation
 32
+      source, and configuration files.
 33
+
 34
+      "Object" form shall mean any form resulting from mechanical
 35
+      transformation or translation of a Source form, including but
 36
+      not limited to compiled object code, generated documentation,
 37
+      and conversions to other media types.
 38
+
 39
+      "Work" shall mean the work of authorship, whether in Source or
 40
+      Object form, made available under the License, as indicated by a
 41
+      copyright notice that is included in or attached to the work
 42
+      (an example is provided in the Appendix below).
 43
+
 44
+      "Derivative Works" shall mean any work, whether in Source or Object
 45
+      form, that is based on (or derived from) the Work and for which the
 46
+      editorial revisions, annotations, elaborations, or other modifications
 47
+      represent, as a whole, an original work of authorship. For the purposes
 48
+      of this License, Derivative Works shall not include works that remain
 49
+      separable from, or merely link (or bind by name) to the interfaces of,
 50
+      the Work and Derivative Works thereof.
 51
+
 52
+      "Contribution" shall mean any work of authorship, including
 53
+      the original version of the Work and any modifications or additions
 54
+      to that Work or Derivative Works thereof, that is intentionally
 55
+      submitted to Licensor for inclusion in the Work by the copyright owner
 56
+      or by an individual or Legal Entity authorized to submit on behalf of
 57
+      the copyright owner. For the purposes of this definition, "submitted"
 58
+      means any form of electronic, verbal, or written communication sent
 59
+      to the Licensor or its representatives, including but not limited to
 60
+      communication on electronic mailing lists, source code control systems,
 61
+      and issue tracking systems that are managed by, or on behalf of, the
 62
+      Licensor for the purpose of discussing and improving the Work, but
 63
+      excluding communication that is conspicuously marked or otherwise
 64
+      designated in writing by the copyright owner as "Not a Contribution."
 65
+
 66
+      "Contributor" shall mean Licensor and any individual or Legal Entity
 67
+      on behalf of whom a Contribution has been received by Licensor and
 68
+      subsequently incorporated within the Work.
 69
+
 70
+   2. Grant of Copyright License. Subject to the terms and conditions of
 71
+      this License, each Contributor hereby grants to You a perpetual,
 72
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
 73
+      copyright license to reproduce, prepare Derivative Works of,
 74
+      publicly display, publicly perform, sublicense, and distribute the
 75
+      Work and such Derivative Works in Source or Object form.
 76
+
 77
+   3. Grant of Patent License. Subject to the terms and conditions of
 78
+      this License, each Contributor hereby grants to You a perpetual,
 79
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
 80
+      (except as stated in this section) patent license to make, have made,
 81
+      use, offer to sell, sell, import, and otherwise transfer the Work,
 82
+      where such license applies only to those patent claims licensable
 83
+      by such Contributor that are necessarily infringed by their
 84
+      Contribution(s) alone or by combination of their Contribution(s)
 85
+      with the Work to which such Contribution(s) was submitted. If You
 86
+      institute patent litigation against any entity (including a
 87
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
 88
+      or a Contribution incorporated within the Work constitutes direct
 89
+      or contributory patent infringement, then any patent licenses
 90
+      granted to You under this License for that Work shall terminate
 91
+      as of the date such litigation is filed.
 92
+
 93
+   4. Redistribution. You may reproduce and distribute copies of the
 94
+      Work or Derivative Works thereof in any medium, with or without
 95
+      modifications, and in Source or Object form, provided that You
 96
+      meet the following conditions:
 97
+
 98
+      (a) You must give any other recipients of the Work or
 99
+          Derivative Works a copy of this License; and
100
+
101
+      (b) You must cause any modified files to carry prominent notices
102
+          stating that You changed the files; and
103
+
104
+      (c) You must retain, in the Source form of any Derivative Works
105
+          that You distribute, all copyright, patent, trademark, and
106
+          attribution notices from the Source form of the Work,
107
+          excluding those notices that do not pertain to any part of
108
+          the Derivative Works; and
109
+
110
+      (d) If the Work includes a "NOTICE" text file as part of its
111
+          distribution, then any Derivative Works that You distribute must
112
+          include a readable copy of the attribution notices contained
113
+          within such NOTICE file, excluding those notices that do not
114
+          pertain to any part of the Derivative Works, in at least one
115
+          of the following places: within a NOTICE text file distributed
116
+          as part of the Derivative Works; within the Source form or
117
+          documentation, if provided along with the Derivative Works; or,
118
+          within a display generated by the Derivative Works, if and
119
+          wherever such third-party notices normally appear. The contents
120
+          of the NOTICE file are for informational purposes only and
121
+          do not modify the License. You may add Your own attribution
122
+          notices within Derivative Works that You distribute, alongside
123
+          or as an addendum to the NOTICE text from the Work, provided
124
+          that such additional attribution notices cannot be construed
125
+          as modifying the License.
126
+
127
+      You may add Your own copyright statement to Your modifications and
128
+      may provide additional or different license terms and conditions
129
+      for use, reproduction, or distribution of Your modifications, or
130
+      for any such Derivative Works as a whole, provided Your use,
131
+      reproduction, and distribution of the Work otherwise complies with
132
+      the conditions stated in this License.
133
+
134
+   5. Submission of Contributions. Unless You explicitly state otherwise,
135
+      any Contribution intentionally submitted for inclusion in the Work
136
+      by You to the Licensor shall be under the terms and conditions of
137
+      this License, without any additional terms or conditions.
138
+      Notwithstanding the above, nothing herein shall supersede or modify
139
+      the terms of any separate license agreement you may have executed
140
+      with Licensor regarding such Contributions.
141
+
142
+   6. Trademarks. This License does not grant permission to use the trade
143
+      names, trademarks, service marks, or product names of the Licensor,
144
+      except as required for reasonable and customary use in describing the
145
+      origin of the Work and reproducing the content of the NOTICE file.
146
+
147
+   7. Disclaimer of Warranty. Unless required by applicable law or
148
+      agreed to in writing, Licensor provides the Work (and each
149
+      Contributor provides its Contributions) on an "AS IS" BASIS,
150
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
151
+      implied, including, without limitation, any warranties or conditions
152
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
153
+      PARTICULAR PURPOSE. You are solely responsible for determining the
154
+      appropriateness of using or redistributing the Work and assume any
155
+      risks associated with Your exercise of permissions under this License.
156
+
157
+   8. Limitation of Liability. In no event and under no legal theory,
158
+      whether in tort (including negligence), contract, or otherwise,
159
+      unless required by applicable law (such as deliberate and grossly
160
+      negligent acts) or agreed to in writing, shall any Contributor be
161
+      liable to You for damages, including any direct, indirect, special,
162
+      incidental, or consequential damages of any character arising as a
163
+      result of this License or out of the use or inability to use the
164
+      Work (including but not limited to damages for loss of goodwill,
165
+      work stoppage, computer failure or malfunction, or any and all
166
+      other commercial damages or losses), even if such Contributor
167
+      has been advised of the possibility of such damages.
168
+
169
+   9. Accepting Warranty or Additional Liability. While redistributing
170
+      the Work or Derivative Works thereof, You may choose to offer,
171
+      and charge a fee for, acceptance of support, warranty, indemnity,
172
+      or other liability obligations and/or rights consistent with this
173
+      License. However, in accepting such obligations, You may act only
174
+      on Your own behalf and on Your sole responsibility, not on behalf
175
+      of any other Contributor, and only if You agree to indemnify,
176
+      defend, and hold each Contributor harmless for any liability
177
+      incurred by, or claims asserted against, such Contributor by reason
178
+      of your accepting any such warranty or additional liability.
179
+
180
+   END OF TERMS AND CONDITIONS
181
+
182
+   APPENDIX: How to apply the Apache License to your work.
183
+
184
+      To apply the Apache License to your work, attach the following
185
+      boilerplate notice, with the fields enclosed by brackets "[]"
186
+      replaced with your own identifying information. (Don't include
187
+      the brackets!)  The text should be enclosed in the appropriate
188
+      comment syntax for the file format. We also recommend that a
189
+      file or class name and description of purpose be included on the
190
+      same "printed page" as the copyright notice for easier
191
+      identification within third-party archives.
192
+
193
+   Copyright [yyyy] [name of copyright owner]
194
+
195
+   Licensed under the Apache License, Version 2.0 (the "License");
196
+   you may not use this file except in compliance with the License.
197
+   You may obtain a copy of the License at
198
+
199
+       http://www.apache.org/licenses/LICENSE-2.0
200
+
201
+   Unless required by applicable law or agreed to in writing, software
202
+   distributed under the License is distributed on an "AS IS" BASIS,
203
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
204
+   See the License for the specific language governing permissions and
205
+   limitations under the License.
Back to file index

README.md

 1
--- 
 2
+++ README.md
 3
@@ -0,0 +1,72 @@
 4
+Overview
 5
+---------
 6
+This charm includes Veritas™ HyperScale software for Canonical OpenStack deployments.
 7
+Veritas HyperScale is a software-defined storage management solution for OpenStack-based virtualized cloud environments.
 8
+
 9
+This charm is developed to support HyperScale deployment on Ubuntu Xenial and OpenStack Ocata releases. It is designed to be deployed with other OpenStack components, beginning with Ocata release.
10
+
11
+HyperScale charm provides the following services:
12
+    - hyperscale-mq-controller
13
+    - hyperscale-mq-consumer
14
+    - hyperscale-api
15
+    - hyperscale-serengeti
16
+    - hyperscale-zookeeper
17
+
18
+
19
+Usage
20
+-----
21
+This Veritas HyperScale charm requires the following Openstack Services
22
+to be deployed on a single Juju system:
23
+    - cinder
24
+    - nova-cloud-controller
25
+    - openstack-dashboard
26
+    - keystone
27
+    - rabbitmq-server
28
+    - ceilometer
29
+
30
+These services must be deployed using Juju charms.
31
+This is supported only with Juju 2.0 and later versions.
32
+
33
+
34
+Configuration
35
+-------------
36
+The default values for the config options should work for most deployments.
37
+This charm does not support changing default configuration values.
38
+
39
+
40
+Deployment 
41
+----------
42
+1. Download hyperscale_packages.tar from the following link and save it to a temporary location:
43
+<downloadlocationlink>
44
+
45
+2. Run the following command to deploy the HyperScale charm:
46
+# juju deploy hyperscale --series=xenial --resource install="<path to hyperscale_packages.tar file>" --to <machine_ID>
47
+
48
+Here, machine_ID is the Juju system where all other OpenStack components are deployed.
49
+
50
+The following ports are opened as part of this HyperScale charm deployment:
51
+- 8753
52
+- 42181
53
+
54
+
55
+Relations
56
+---------
57
+- This charm requires relation with mysql, rabbimq-server, and keystone.
58
+- Before adding these relations, ensure that you set the Keystone Admin password.
59
+- Run the following commands to add the required relations: 
60
+    # juju add-relation hyperscale  rabbitmq-server:amqp
61
+    # juju add-relation hyperscale  mysql:shared-db
62
+    # juju add-relation hyperscale  mysql:db-admin
63
+    # juju add-relation hyperscale  keystone:identity-admin
64
+
65
+
66
+High Availability / Clustering
67
+------------------------------
68
+This charm does not support HA or clustering in this release.
69
+
70
+
71
+Contact Information
72
+-------------------
73
+Author: Veritas Technologies LLC
74
+Bugs: 
75
+Location: 
Back to file index

charm-helpers.yaml

1
--- 
2
+++ charm-helpers.yaml
3
@@ -0,0 +1,4 @@
4
+destination: lib/charmhelpers
5
+branch: lp:charm-helpers
6
+include:
7
+  - core
Back to file index

config.yaml

 1
--- 
 2
+++ config.yaml
 3
@@ -0,0 +1,44 @@
 4
+options:
 5
+  debug:
 6
+    type: boolean
 7
+    default: False
 8
+    description: Enable verbose logging.
 9
+  verbose:
10
+    type: boolean
11
+    default: False
12
+    description: Enable debug logging.
13
+  use-syslog:
14
+    type: boolean
15
+    default: False
16
+    description: |
17
+      Setting this to True will allow supporting services to log to syslog.
18
+  config-file:
19
+    default: "/etc/hyperscale/hyperscale.conf"
20
+    type: string
21
+    description: "Location of hyperscale configuration file"
22
+  admin-port:
23
+    default: 35357
24
+    type: int
25
+    description: Port the bind the Admin API server to.
26
+  hyperscale_api_listen_port:
27
+    default: 8753
28
+    type: int
29
+    description: Port to bind the hyperscale API
30
+  # Section for API configuration
31
+  api_paste_config:
32
+    default: "/etc/hyperscale/api-paste.ini"
33
+    type: string
34
+    description: Hyperscale configuration file
35
+  # Database settings used to request access via shared-db-relation-* relations
36
+  database:
37
+    default: "HyperScale"
38
+    type: string
39
+    description: Hyperscale database name.
40
+  database-user:
41
+    default: "hyperscale"
42
+    type: string
43
+    description: Username used for connecting to the hyperscale database.
44
+  enable_telemetry: 
45
+    type: boolean
46
+    default: False
47
+    description: Enable telemetry for Hyperscale 
Back to file index

copyright

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

hooks/actions.py

1
--- 
2
+++ hooks/actions.py
3
@@ -0,0 +1,5 @@
4
+from charmhelpers.core import hookenv
5
+
6
+
7
+def log_start(service_name):
8
+    hookenv.log('hyperscale starting')
Back to file index

hooks/amqp-relation-broken

  1
--- 
  2
+++ hooks/amqp-relation-broken
  3
@@ -0,0 +1,398 @@
  4
+#!/usr/bin/python
  5
+# Copyright 2016 Canonical Ltd
  6
+#
  7
+# Licensed under the Apache License, Version 2.0 (the "License");
  8
+# you may not use this file except in compliance with the License.
  9
+# You may obtain a copy of the License at
 10
+#
 11
+#  http://www.apache.org/licenses/LICENSE-2.0
 12
+#
 13
+# Unless required by applicable law or agreed to in writing, software
 14
+# distributed under the License is distributed on an "AS IS" BASIS,
 15
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 16
+# See the License for the specific language governing permissions and
 17
+# limitations under the License.
 18
+
 19
+import sys
 20
+import os
 21
+import json
 22
+import subprocess 
 23
+
 24
+sys.path.append('lib')
 25
+from charmhelpers.core import hookenv
 26
+from charmhelpers.core.hookenv import (
 27
+    config,
 28
+    status_set,
 29
+    is_relation_made,
 30
+    relation_set,
 31
+    relation_get,
 32
+    relation_ids,
 33
+    relation_id,
 34
+    resource_get,
 35
+    unit_get,
 36
+    open_port,
 37
+    Hooks,
 38
+    log,
 39
+    UnregisteredHookError,
 40
+    network_get_primary_address,
 41
+ )
 42
+from hyperscale_utils import (
 43
+    sync_db,
 44
+    set_value,
 45
+    get_value,
 46
+    delete_value,
 47
+    get_openflame_version,
 48
+    update_openflame_nodes,
 49
+    delete_db,
 50
+    run_cmd,
 51
+    controller_save_config,
 52
+    install_zk,
 53
+    controller_ceil_config,
 54
+    controller_copy_files,
 55
+    controller_config_horizon,
 56
+    create_rabbitmq_exchange,
 57
+    delete_rabbitmq_exchange,
 58
+    mysql_controller_config,
 59
+    controller_config_repo,
 60
+    controller_config_identity,
 61
+    priv_grant_hyperscale,
 62
+)
 63
+
 64
+from charmhelpers.core.host import (
 65
+    service_restart,
 66
+    service_running,
 67
+)
 68
+
 69
+
 70
+hooks = Hooks()
 71
+os.putenv('LC_ALL', "C")
 72
+OFDB = "/var/opt/VRTSofcore/ofdb"
 73
+PYTHON2 = "/usr/bin/python2.7"
 74
+AMQP_CONF = '/opt/VRTSofcore/etc/amqp.conf'
 75
+RABBITMQ_PLUGINS = '/usr/sbin/rabbitmq-plugins'
 76
+NETINTFS = '/var/opt/VRTSofcore/.netintfs'
 77
+ZK_PORT="42181"
 78
+HS_API_PORT="8753"
 79
+hs_services =  [ 'hyperscale-api.service',
 80
+    'hyperscale-mq-consumer.service',
 81
+    'hyperscale-mq-controller.service',
 82
+    'hyperscale-serengeti.service',
 83
+    'hyperscale-zookeeper.service',
 84
+    'hyperscale-ceilometer.service',
 85
+]
 86
+
 87
+hs_relations = ['identity-admin', 'shared-db', 'db-admin', 'amqp']
 88
+
 89
+def relationship_status():
 90
+    rel_miss = []
 91
+    for rel in hs_relations:
 92
+        if not is_relation_made(rel):
 93
+            rel_miss.append(rel)
 94
+    return rel_miss
 95
+
 96
+def restart_services():
 97
+    if not relationship_status():
 98
+        for service in hs_services:
 99
+             service_restart(service)
100
+    else:
101
+        hookenv.log('Missing relations. Cannot start HyperScale services')
102
+
103
+@hooks.hook('install.next')
104
+def install():
105
+    hookenv.log('Installing Zookeeper')
106
+    cmd = "touch " + OFDB
107
+    os.system(cmd)
108
+    install_zk()
109
+    controller_config_repo()
110
+    set_value(OFDB, 'CONTROLLER' , 'CONFIG_DONE', "0")
111
+    status_set('maintenance', 'Installation done for HyperScale Packages')
112
+
113
+@hooks.hook('config-changed')
114
+def config_changed():
115
+    hookenv.log('Configuring HyperScale')
116
+
117
+    is_config_done = get_value(OFDB, 'CONTROLLER', 'CONFIG_DONE')
118
+    if is_config_done == '0':
119
+        hostip = unit_get('private-address')
120
+        controller_save_config(hostip)
121
+        cmd = (PYTHON2  + ' -B /opt/VRTSofmn/adm/dna_netinfo.py')
122
+        lst = run_cmd(cmd.split(' '))
123
+        print lst
124
+        hookenv.log(hostip)
125
+        controller_ceil_config()
126
+        controller_copy_files()
127
+        controller_config_horizon(hostip)
128
+        set_value(OFDB, 'CONTROLLER' , 'CONFIG_DONE', "1")
129
+        rel_miss = relationship_status()
130
+        if not rel_miss:
131
+            status_set('maintenance', 'Relations complete. Status will be updated after services restart')
132
+        else:
133
+            status_set('blocked', 'Missing relations : ' + ' '.join(rel_miss))
134
+
135
+    hookenv.log("HyperScale config-changed: Success")
136
+
137
+@hooks.hook('db-admin-relation-joined')
138
+def db_admin_joined():
139
+     host = None
140
+     conf = config()
141
+     hookenv.log('Creating relation db-admin')
142
+     hookenv.log(conf['database-user'])
143
+     try:
144
+        host = network_get_primary_address('shared-db')
145
+     except NotImplementedError:
146
+        host = unit_get('private-address')
147
+
148
+     relation_set(database=conf['database'],
149
+        hostname=host)
150
+     status_set('maintenance', 'Relation observed: db-admin')
151
+     hookenv.log("HyperScale db-admin-relation-joined: Success")
152
+
153
+@hooks.hook('db-admin-relation-changed')
154
+def db_admin_changed():
155
+     conf = config()
156
+     host = None
157
+     passwd = relation_get('password')
158
+     host = relation_get('host')
159
+     user = relation_get('user')
160
+     set_value(OFDB, 'CONTROLLER' , 'DB_ADMIN_USER', user)
161
+     set_value(OFDB, 'CONTROLLER' , 'DB_ADMIN_PASSWD', passwd)
162
+     set_value(OFDB, 'CONTROLLER' , 'DB_HOST', host)
163
+     if is_relation_made('shared-db'):
164
+         ret = priv_grant_hyperscale()
165
+         if ret != 0:
166
+             hookenv.log('Grant access for HyperScale failed. Check logs')
167
+             sys.exit(1)
168
+         restart_services()
169
+         status_set('maintenance', 'Relation changed : db-admin')
170
+     else:
171
+         hookenv.log("DB grant for HyperScale user will be done after shared-db relation completes")
172
+         status_set('blocked','Waiting for shared-db relation to be made')
173
+     hookenv.log("HyperScale db-admin-relation-changed: Success")
174
+
175
+@hooks.hook('db-admin-relation-departed')
176
+def db_admin_departed():
177
+    pass
178
+
179
+@hooks.hook('db-admin-relation-broken')
180
+def db_admin_broken():
181
+    pass
182
+
183
+@hooks.hook('shared-db-relation-joined')
184
+def db_joined():
185
+     host = None
186
+     conf = config()
187
+     hookenv.log('Creating Relation')
188
+     hookenv.log(conf['database-user'])
189
+     try:
190
+        host = network_get_primary_address('shared-db')
191
+     except NotImplementedError:
192
+        host = unit_get('private-address')
193
+
194
+     status_set('maintenance', 'Relation observed: shared-db')
195
+     relation_set(database=conf['database'],
196
+        username=conf['database-user'],
197
+        hostname=host)
198
+     hookenv.log("HyperScale shared-db-relation-joined: Success")
199
+
200
+@hooks.hook('shared-db-relation-changed')
201
+def db_changed():
202
+     if is_relation_made('shared-db'):
203
+        conf = config()
204
+        host = None
205
+        try:
206
+            host = network_get_primary_address('shared-db')
207
+        except NotImplementedError:
208
+            host = unit_get('private-address')
209
+
210
+        status_set('maintenance', 'Relation joined: shared-db')
211
+        passwd = relation_get('password')
212
+        db_host = relation_get('db_host')
213
+        ctlr_ip = unit_get('private-address')
214
+        try:
215
+            sync_db(db_host, passwd)
216
+            IDGEN='/opt/VRTSofcore/adm/idgen.py'
217
+            if os.path.isfile(IDGEN):
218
+                of_version = get_openflame_version()
219
+                ctlid = subprocess.check_output([IDGEN, "--type", "hostid"])
220
+                set_value(OFDB, 'CONTROLLER' , 'CTLR_INSTANCE_HOSTID', ctlid)
221
+                hostname = get_value(OFDB, 'CONTROLLER', 'CONTROLLER_NAME')
222
+                retval = update_openflame_nodes(db_host, passwd, hostname, ctlid,
223
+                                                ctlr_ip, 'N/A',
224
+                                                'controller', 'up', ctlid, of_version)
225
+            mysql_controller_config(db_host,passwd)
226
+            restart_services()
227
+            if is_relation_made('db-admin'): 
228
+            # If db-admin relation happened before shared-db, then grant permissions from here
229
+                ret = priv_grant_hyperscale()
230
+                if ret != 0:
231
+                   hookenv.log('Error granting permission to HyperScale user. Check logs')
232
+                   sys.exit(1)
233
+        except Exception as e:
234
+            errstr = 'Error creating database on controller' + str(e)
235
+            hookenv.log(errstr)
236
+            sys.exit(1)
237
+     else:
238
+        hookenv.log('Relation shared-db not complete. Will retry')
239
+        sys.exit(1)
240
+     hookenv.log("HyperScale shared-db-relation-changed: Success")
241
+
242
+@hooks.hook('shared-db-relation-broken')
243
+def db_broken():
244
+    status_set('maintenance', 'Shared-db: broken')
245
+    return
246
+
247
+@hooks.hook('shared-db-relation-departed')
248
+def db_departed():
249
+    status_set('maintenance', 'Shared-db: departed')
250
+    passwd = relation_get('password')
251
+    db_host = relation_get('db_host')
252
+    delete_db(db_host, passwd)
253
+    return
254
+
255
+@hooks.hook('amqp-relation-joined')
256
+def rabbitmq_relation_joined():
257
+    relation_id = None
258
+    conf = config()
259
+    relation_set(relation_id=relation_id,
260
+                 username='hyperscale', vhost='/' , admin=True)
261
+    cmd = RABBITMQ_PLUGINS + ' enable rabbitmq_management'
262
+    subprocess.call(cmd.split(' '))
263
+    service_restart('rabbitmq-server')
264
+    status_set('maintenance', 'Relation joined: amqp')
265
+    hookenv.log("HyperScale amqp-relation-joined: Success")
266
+    return
267
+
268
+
269
+@hooks.hook('amqp-relation-changed')
270
+def rabbitmq_relation_changed():
271
+    if is_relation_made('amqp'):
272
+        hostname = ''
273
+        private_address =''
274
+        password = ''
275
+        op=relation_get(rid=relation_id())
276
+        rel_data = list(op.keys())
277
+
278
+        if 'password' in rel_data and 'private-address' in rel_data:
279
+            hostname = str(op['hostname']) if 'hostname' in rel_data else ''
280
+            private_address = str(op['private-address'])
281
+            password = str (op['password'])
282
+            create_rabbitmq_exchange('/',private_address=private_address,
283
+                password=password)
284
+            with open(AMQP_CONF,'r') as json_file:
285
+                json_data = json.load(json_file)
286
+                json_file.close()
287
+            json_data['server'] = private_address
288
+            json_data['port'] = 5672
289
+            json_data['user'] = 'hyperscale'
290
+            json_data['password'] = password
291
+            with open(AMQP_CONF ,'w') as json_file:
292
+                json.dump(json_data,json_file)
293
+                json_file.close()
294
+            set_value(OFDB, 'CONTROLLER', 'RABBITMQ_PORT', '5672')
295
+        restart_services()
296
+
297
+        status_set('maintenance', 'Relation changed: amqp')
298
+    else:
299
+        log('HyperScale to rabbitmq connection not made')
300
+        status_set('maintenance', 'Relation incomplete: amqp')
301
+    hookenv.log("HyperScale amqp-relation-changed: Success")
302
+    return
303
+
304
+
305
+@hooks.hook('amqp-relation-departed')
306
+def rabbitmq_relation_departed():
307
+    hostname = ''
308
+    private_address =''
309
+    password = ''
310
+    op=relation_get(rid=relation_id())
311
+    rel_data = list(op.keys())
312
+    if op is not None:
313
+        if 'password' in rel_data and 'private-address' in rel_data:
314
+            hostname = str(op['hostname']) if 'hostname' in rel_data else ''
315
+            private_address = str(op['private-address'])
316
+            password= str (op['password'])
317
+            delete_rabbitmq_exchange('/',private_address=private_address,
318
+                password=password)
319
+    return
320
+
321
+@hooks.hook('identity-admin-relation-changed')
322
+def identity_admin_relation_changed():
323
+  #  if is_relation_made('identity-admin') and is_relation_made('shared-db') \
324
+   #    and is_relation_made('amqp'):
325
+    op=relation_get(rid=relation_id())
326
+    if is_relation_made('identity-admin') and \
327
+       op.get('service_password',None) is not None:
328
+         hostname = ''
329
+         private_address =''
330
+         password = ''
331
+         auth_url = ('http://%s:5000/v3')%op['private-address']
332
+         set_value(OFDB, 'CONTROLLER' , 'AUTH_URL', auth_url)
333
+         ret = controller_config_identity(op)
334
+         if (ret != 0):
335
+                    log('Identity configuration failed for HyperScale. Check /var/opt/VRTSofcore/logs/ofengine.log for failure')
336
+                    assert(ret)
337
+         status_set('maintenance', 'Relation changed : identity-admin')
338
+         restart_services()
339
+
340
+    else:
341
+         log('HyperScale to keystone relation not made')
342
+         status_set('maintenance', 'Relation incomplete: identity-admin')
343
+         sys.exit(1)
344
+    hookenv.log("HyperScale identity-admin-relation-changed: Success")
345
+    return
346
+
347
+@hooks.hook('identity-admin-relation-departed')
348
+def identity_admin_relation_departed():
349
+    hostname = ''
350
+    private_address =''
351
+    password = ''
352
+    op=relation_get(rid=relation_id())
353
+    if op.get('service_password',None) is not None:
354
+        auth_url = ('http://%s:5000/v3')%op['private-address']
355
+	set_value(OFDB, 'CONTROLLER' , 'AUTH_URL', auth_url)
356
+	cmd = ('/opt/VRTSofcore/bin/ofexec --operation controller_unconf_juju '
357
+	'--params controller_ip=%s;openstack_passwd=%s;'
358
+	'region_name=%s --run'
359
+	)%(op['private-address'], op['service_password'],
360
+	op['service_region'])
361
+	lst = run_cmd(cmd.split(' '))
362
+	if (lst['ret'] != 0):
363
+		log('Check /var/opt/VRTSofcore/logs/ofengine.log for failure')
364
+		assert(lst['ret'] == 0)
365
+    else:
366
+        delete_value(OFDB, 'CONTROLLER', 'MGMT_INTF')
367
+
368
+    return
369
+
370
+@hooks.hook('update-status')
371
+def update_status():
372
+    # Check status of services and update status accordingly
373
+    failed_services = []
374
+    rel_miss = relationship_status()
375
+    if not rel_miss:
376
+        for service in hs_services:
377
+            if not service_running(service):
378
+               failed_services.append(service)
379
+        if not failed_services:
380
+            status_set('active', 'HyperScale Unit ready')
381
+        else:
382
+            status_set('maintenance', 'Some Hyperscale services have failed : ' + ' '.join(failed_services))
383
+            sys.exit(1)
384
+    else:
385
+        status_set('blocked', 'Missing relations : ' + ' '.join(rel_miss))
386
+
387
+@hooks.hook('start')
388
+def start():
389
+    open_port(ZK_PORT)
390
+    open_port(HS_API_PORT)
391
+    if not relationship_status():
392
+       status_set('waiting', 'Hyperscale service will start after relations are complete') 
393
+    else:
394
+       restart_services()
395
+
396
+
397
+if __name__ == '__main__':
398
+    try:
399
+        hooks.execute(sys.argv)
400
+    except UnregisteredHookError as e:
401
+        hookenv.log('Unknown hook {} - skipping.'.format(e))
Back to file index

hooks/amqp-relation-changed

  1
--- 
  2
+++ hooks/amqp-relation-changed
  3
@@ -0,0 +1,398 @@
  4
+#!/usr/bin/python
  5
+# Copyright 2016 Canonical Ltd
  6
+#
  7
+# Licensed under the Apache License, Version 2.0 (the "License");
  8
+# you may not use this file except in compliance with the License.
  9
+# You may obtain a copy of the License at
 10
+#
 11
+#  http://www.apache.org/licenses/LICENSE-2.0
 12
+#
 13
+# Unless required by applicable law or agreed to in writing, software
 14
+# distributed under the License is distributed on an "AS IS" BASIS,
 15
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 16
+# See the License for the specific language governing permissions and
 17
+# limitations under the License.
 18
+
 19
+import sys
 20
+import os
 21
+import json
 22
+import subprocess 
 23
+
 24
+sys.path.append('lib')
 25
+from charmhelpers.core import hookenv
 26
+from charmhelpers.core.hookenv import (
 27
+    config,
 28
+    status_set,
 29
+    is_relation_made,
 30
+    relation_set,
 31
+    relation_get,
 32
+    relation_ids,
 33
+    relation_id,
 34
+    resource_get,
 35
+    unit_get,
 36
+    open_port,
 37
+    Hooks,
 38
+    log,
 39
+    UnregisteredHookError,
 40
+    network_get_primary_address,
 41
+ )
 42
+from hyperscale_utils import (
 43
+    sync_db,
 44
+    set_value,
 45
+    get_value,
 46
+    delete_value,
 47
+    get_openflame_version,
 48
+    update_openflame_nodes,
 49
+    delete_db,
 50
+    run_cmd,
 51
+    controller_save_config,
 52
+    install_zk,
 53
+    controller_ceil_config,
 54
+    controller_copy_files,
 55
+    controller_config_horizon,
 56
+    create_rabbitmq_exchange,
 57
+    delete_rabbitmq_exchange,
 58
+    mysql_controller_config,
 59
+    controller_config_repo,
 60
+    controller_config_identity,
 61
+    priv_grant_hyperscale,
 62
+)
 63
+
 64
+from charmhelpers.core.host import (
 65
+    service_restart,
 66
+    service_running,
 67
+)
 68
+
 69
+
 70
+hooks = Hooks()
 71
+os.putenv('LC_ALL', "C")
 72
+OFDB = "/var/opt/VRTSofcore/ofdb"
 73
+PYTHON2 = "/usr/bin/python2.7"
 74
+AMQP_CONF = '/opt/VRTSofcore/etc/amqp.conf'
 75
+RABBITMQ_PLUGINS = '/usr/sbin/rabbitmq-plugins'
 76
+NETINTFS = '/var/opt/VRTSofcore/.netintfs'
 77
+ZK_PORT="42181"
 78
+HS_API_PORT="8753"
 79
+hs_services =  [ 'hyperscale-api.service',
 80
+    'hyperscale-mq-consumer.service',
 81
+    'hyperscale-mq-controller.service',
 82
+    'hyperscale-serengeti.service',
 83
+    'hyperscale-zookeeper.service',
 84
+    'hyperscale-ceilometer.service',
 85
+]
 86
+
 87
+hs_relations = ['identity-admin', 'shared-db', 'db-admin', 'amqp']
 88
+
 89
+def relationship_status():
 90
+    rel_miss = []
 91
+    for rel in hs_relations:
 92
+        if not is_relation_made(rel):
 93
+            rel_miss.append(rel)
 94
+    return rel_miss
 95
+
 96
+def restart_services():
 97
+    if not relationship_status():
 98
+        for service in hs_services:
 99
+             service_restart(service)
100
+    else:
101
+        hookenv.log('Missing relations. Cannot start HyperScale services')
102
+
103
+@hooks.hook('install.next')
104
+def install():
105
+    hookenv.log('Installing Zookeeper')
106
+    cmd = "touch " + OFDB
107
+    os.system(cmd)
108
+    install_zk()
109
+    controller_config_repo()
110
+    set_value(OFDB, 'CONTROLLER' , 'CONFIG_DONE', "0")
111
+    status_set('maintenance', 'Installation done for HyperScale Packages')
112
+
113
+@hooks.hook('config-changed')
114
+def config_changed():
115
+    hookenv.log('Configuring HyperScale')
116
+
117
+    is_config_done = get_value(OFDB, 'CONTROLLER', 'CONFIG_DONE')
118
+    if is_config_done == '0':
119
+        hostip = unit_get('private-address')
120
+        controller_save_config(hostip)
121
+        cmd = (PYTHON2  + ' -B /opt/VRTSofmn/adm/dna_netinfo.py')
122
+        lst = run_cmd(cmd.split(' '))
123
+        print lst
124
+        hookenv.log(hostip)
125
+        controller_ceil_config()
126
+        controller_copy_files()
127
+        controller_config_horizon(hostip)
128
+        set_value(OFDB, 'CONTROLLER' , 'CONFIG_DONE', "1")
129
+        rel_miss = relationship_status()
130
+        if not rel_miss:
131
+            status_set('maintenance', 'Relations complete. Status will be updated after services restart')
132
+        else:
133
+            status_set('blocked', 'Missing relations : ' + ' '.join(rel_miss))
134
+
135
+    hookenv.log("HyperScale config-changed: Success")
136
+
137
+@hooks.hook('db-admin-relation-joined')
138
+def db_admin_joined():
139
+     host = None
140
+     conf = config()
141
+     hookenv.log('Creating relation db-admin')
142
+     hookenv.log(conf['database-user'])
143
+     try:
144
+        host = network_get_primary_address('shared-db')
145
+     except NotImplementedError:
146
+        host = unit_get('private-address')
147
+
148
+     relation_set(database=conf['database'],
149
+        hostname=host)
150
+     status_set('maintenance', 'Relation observed: db-admin')
151
+     hookenv.log("HyperScale db-admin-relation-joined: Success")
152
+
153
+@hooks.hook('db-admin-relation-changed')
154
+def db_admin_changed():
155
+     conf = config()
156
+     host = None
157
+     passwd = relation_get('password')
158
+     host = relation_get('host')
159
+     user = relation_get('user')
160
+     set_value(OFDB, 'CONTROLLER' , 'DB_ADMIN_USER', user)
161
+     set_value(OFDB, 'CONTROLLER' , 'DB_ADMIN_PASSWD', passwd)
162
+     set_value(OFDB, 'CONTROLLER' , 'DB_HOST', host)
163
+     if is_relation_made('shared-db'):
164
+         ret = priv_grant_hyperscale()
165
+         if ret != 0:
166
+             hookenv.log('Grant access for HyperScale failed. Check logs')
167
+             sys.exit(1)
168
+         restart_services()
169
+         status_set('maintenance', 'Relation changed : db-admin')
170
+     else:
171
+         hookenv.log("DB grant for HyperScale user will be done after shared-db relation completes")
172
+         status_set('blocked','Waiting for shared-db relation to be made')
173
+     hookenv.log("HyperScale db-admin-relation-changed: Success")
174
+
175
+@hooks.hook('db-admin-relation-departed')
176
+def db_admin_departed():
177
+    pass
178
+
179
+@hooks.hook('db-admin-relation-broken')
180
+def db_admin_broken():
181
+    pass
182
+
183
+@hooks.hook('shared-db-relation-joined')
184
+def db_joined():
185
+     host = None
186
+     conf = config()
187
+     hookenv.log('Creating Relation')
188
+     hookenv.log(conf['database-user'])
189
+     try:
190
+        host = network_get_primary_address('shared-db')
191
+     except NotImplementedError:
192
+        host = unit_get('private-address')
193
+
194
+     status_set('maintenance', 'Relation observed: shared-db')
195
+     relation_set(database=conf['database'],
196
+        username=conf['database-user'],
197
+        hostname=host)
198
+     hookenv.log("HyperScale shared-db-relation-joined: Success")
199
+
200
+@hooks.hook('shared-db-relation-changed')
201
+def db_changed():
202
+     if is_relation_made('shared-db'):
203
+        conf = config()
204
+        host = None
205
+        try:
206
+            host = network_get_primary_address('shared-db')
207
+        except NotImplementedError:
208
+            host = unit_get('private-address')
209
+
210
+        status_set('maintenance', 'Relation joined: shared-db')
211
+        passwd = relation_get('password')
212
+        db_host = relation_get('db_host')
213
+        ctlr_ip = unit_get('private-address')
214
+        try:
215
+            sync_db(db_host, passwd)
216
+            IDGEN='/opt/VRTSofcore/adm/idgen.py'
217
+            if os.path.isfile(IDGEN):
218
+                of_version = get_openflame_version()
219
+                ctlid = subprocess.check_output([IDGEN, "--type", "hostid"])
220
+                set_value(OFDB, 'CONTROLLER' , 'CTLR_INSTANCE_HOSTID', ctlid)
221
+                hostname = get_value(OFDB, 'CONTROLLER', 'CONTROLLER_NAME')
222
+                retval = update_openflame_nodes(db_host, passwd, hostname, ctlid,
223
+                                                ctlr_ip, 'N/A',
224
+                                                'controller', 'up', ctlid, of_version)
225
+            mysql_controller_config(db_host,passwd)
226
+            restart_services()
227
+            if is_relation_made('db-admin'): 
228
+            # If db-admin relation happened before shared-db, then grant permissions from here
229
+                ret = priv_grant_hyperscale()
230
+                if ret != 0:
231
+                   hookenv.log('Error granting permission to HyperScale user. Check logs')
232
+                   sys.exit(1)
233
+        except Exception as e:
234
+            errstr = 'Error creating database on controller' + str(e)
235
+            hookenv.log(errstr)
236
+            sys.exit(1)
237
+     else:
238
+        hookenv.log('Relation shared-db not complete. Will retry')
239
+        sys.exit(1)
240
+     hookenv.log("HyperScale shared-db-relation-changed: Success")
241
+
242
+@hooks.hook('shared-db-relation-broken')
243
+def db_broken():
244
+    status_set('maintenance', 'Shared-db: broken')
245
+    return
246
+
247
+@hooks.hook('shared-db-relation-departed')
248
+def db_departed():
249
+    status_set('maintenance', 'Shared-db: departed')
250
+    passwd = relation_get('password')
251
+    db_host = relation_get('db_host')
252
+    delete_db(db_host, passwd)
253
+    return
254
+
255
+@hooks.hook('amqp-relation-joined')
256
+def rabbitmq_relation_joined():
257
+    relation_id = None
258
+    conf = config()
259
+    relation_set(relation_id=relation_id,
260
+                 username='hyperscale', vhost='/' , admin=True)
261
+    cmd = RABBITMQ_PLUGINS + ' enable rabbitmq_management'
262
+    subprocess.call(cmd.split(' '))
263
+    service_restart('rabbitmq-server')
264
+    status_set('maintenance', 'Relation joined: amqp')
265
+    hookenv.log("HyperScale amqp-relation-joined: Success")
266
+    return
267
+
268
+
269
+@hooks.hook('amqp-relation-changed')
270
+def rabbitmq_relation_changed():
271
+    if is_relation_made('amqp'):
272
+        hostname = ''
273
+        private_address =''
274
+        password = ''
275
+        op=relation_get(rid=relation_id())
276
+        rel_data = list(op.keys())
277
+
278
+        if 'password' in rel_data and 'private-address' in rel_data:
279
+            hostname = str(op['hostname']) if 'hostname' in rel_data else ''
280
+            private_address = str(op['private-address'])
281
+            password = str (op['password'])
282
+            create_rabbitmq_exchange('/',private_address=private_address,
283
+                password=password)
284
+            with open(AMQP_CONF,'r') as json_file:
285
+                json_data = json.load(json_file)
286
+                json_file.close()
287
+            json_data['server'] = private_address
288
+            json_data['port'] = 5672
289
+            json_data['user'] = 'hyperscale'
290
+            json_data['password'] = password
291
+            with open(AMQP_CONF ,'w') as json_file:
292
+                json.dump(json_data,json_file)
293
+                json_file.close()
294
+            set_value(OFDB, 'CONTROLLER', 'RABBITMQ_PORT', '5672')
295
+        restart_services()
296
+
297
+        status_set('maintenance', 'Relation changed: amqp')
298
+    else:
299
+        log('HyperScale to rabbitmq connection not made')
300
+        status_set('maintenance', 'Relation incomplete: amqp')
301
+    hookenv.log("HyperScale amqp-relation-changed: Success")
302
+    return
303
+
304
+
305
+@hooks.hook('amqp-relation-departed')
306
+def rabbitmq_relation_departed():
307
+    hostname = ''
308
+    private_address =''
309
+    password = ''
310
+    op=relation_get(rid=relation_id())
311
+    rel_data = list(op.keys())
312
+    if op is not None:
313
+        if 'password' in rel_data and 'private-address' in rel_data:
314
+            hostname = str(op['hostname']) if 'hostname' in rel_data else ''
315
+            private_address = str(op['private-address'])
316
+            password= str (op['password'])
317
+            delete_rabbitmq_exchange('/',private_address=private_address,
318
+                password=password)
319
+    return
320
+
321
+@hooks.hook('identity-admin-relation-changed')
322
+def identity_admin_relation_changed():
323
+  #  if is_relation_made('identity-admin') and is_relation_made('shared-db') \
324
+   #    and is_relation_made('amqp'):
325
+    op=relation_get(rid=relation_id())
326
+    if is_relation_made('identity-admin') and \
327
+       op.get('service_password',None) is not None:
328
+         hostname = ''
329
+         private_address =''
330
+         password = ''
331
+         auth_url = ('http://%s:5000/v3')%op['private-address']
332
+         set_value(OFDB, 'CONTROLLER' , 'AUTH_URL', auth_url)
333
+         ret = controller_config_identity(op)
334
+         if (ret != 0):
335
+                    log('Identity configuration failed for HyperScale. Check /var/opt/VRTSofcore/logs/ofengine.log for failure')
336
+                    assert(ret)
337
+         status_set('maintenance', 'Relation changed : identity-admin')
338
+         restart_services()
339
+
340
+    else:
341
+         log('HyperScale to keystone relation not made')
342
+         status_set('maintenance', 'Relation incomplete: identity-admin')
343
+         sys.exit(1)
344
+    hookenv.log("HyperScale identity-admin-relation-changed: Success")
345
+    return
346
+
347
+@hooks.hook('identity-admin-relation-departed')
348
+def identity_admin_relation_departed():
349
+    hostname = ''
350
+    private_address =''
351
+    password = ''
352
+    op=relation_get(rid=relation_id())
353
+    if op.get('service_password',None) is not None:
354
+        auth_url = ('http://%s:5000/v3')%op['private-address']
355
+	set_value(OFDB, 'CONTROLLER' , 'AUTH_URL', auth_url)
356
+	cmd = ('/opt/VRTSofcore/bin/ofexec --operation controller_unconf_juju '
357
+	'--params controller_ip=%s;openstack_passwd=%s;'
358
+	'region_name=%s --run'
359
+	)%(op['private-address'], op['service_password'],
360
+	op['service_region'])
361
+	lst = run_cmd(cmd.split(' '))
362
+	if (lst['ret'] != 0):
363
+		log('Check /var/opt/VRTSofcore/logs/ofengine.log for failure')
364
+		assert(lst['ret'] == 0)
365
+    else:
366
+        delete_value(OFDB, 'CONTROLLER', 'MGMT_INTF')
367
+
368
+    return
369
+
370
+@hooks.hook('update-status')
371
+def update_status():
372
+    # Check status of services and update status accordingly
373
+    failed_services = []
374
+    rel_miss = relationship_status()
375
+    if not rel_miss:
376
+        for service in hs_services:
377
+            if not service_running(service):
378
+               failed_services.append(service)
379
+        if not failed_services:
380
+            status_set('active', 'HyperScale Unit ready')
381
+        else:
382
+            status_set('maintenance', 'Some Hyperscale services have failed : ' + ' '.join(failed_services))
383
+            sys.exit(1)
384
+    else:
385
+        status_set('blocked', 'Missing relations : ' + ' '.join(rel_miss))
386
+
387
+@hooks.hook('start')
388
+def start():
389
+    open_port(ZK_PORT)
390
+    open_port(HS_API_PORT)
391
+    if not relationship_status():
392
+       status_set('waiting', 'Hyperscale service will start after relations are complete') 
393
+    else:
394
+       restart_services()
395
+
396
+
397
+if __name__ == '__main__':
398
+    try:
399
+        hooks.execute(sys.argv)
400
+    except UnregisteredHookError as e:
401
+        hookenv.log('Unknown hook {} - skipping.'.format(e))
Back to file index

hooks/amqp-relation-departed

  1
--- 
  2
+++ hooks/amqp-relation-departed
  3
@@ -0,0 +1,398 @@
  4
+#!/usr/bin/python
  5
+# Copyright 2016 Canonical Ltd
  6
+#
  7
+# Licensed under the Apache License, Version 2.0 (the "License");
  8
+# you may not use this file except in compliance with the License.
  9
+# You may obtain a copy of the License at
 10
+#
 11
+#  http://www.apache.org/licenses/LICENSE-2.0
 12
+#
 13
+# Unless required by applicable law or agreed to in writing, software
 14
+# distributed under the License is distributed on an "AS IS" BASIS,
 15
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 16
+# See the License for the specific language governing permissions and
 17
+# limitations under the License.
 18
+
 19
+import sys
 20
+import os
 21
+import json
 22
+import subprocess 
 23
+
 24
+sys.path.append('lib')
 25
+from charmhelpers.core import hookenv
 26
+from charmhelpers.core.hookenv import (
 27
+    config,
 28
+    status_set,
 29
+    is_relation_made,
 30
+    relation_set,
 31
+    relation_get,
 32
+    relation_ids,
 33
+    relation_id,
 34
+    resource_get,
 35
+    unit_get,
 36
+    open_port,
 37
+    Hooks,
 38
+    log,
 39
+    UnregisteredHookError,
 40
+    network_get_primary_address,
 41
+ )
 42
+from hyperscale_utils import (
 43
+    sync_db,
 44
+    set_value,
 45
+    get_value,
 46
+    delete_value,
 47
+    get_openflame_version,
 48
+    update_openflame_nodes,
 49
+    delete_db,
 50
+    run_cmd,
 51
+    controller_save_config,
 52
+    install_zk,
 53
+    controller_ceil_config,
 54
+    controller_copy_files,
 55
+    controller_config_horizon,
 56
+    create_rabbitmq_exchange,
 57
+    delete_rabbitmq_exchange,
 58
+    mysql_controller_config,
 59
+    controller_config_repo,
 60
+    controller_config_identity,
 61
+    priv_grant_hyperscale,
 62
+)
 63
+
 64
+from charmhelpers.core.host import (
 65
+    service_restart,
 66
+    service_running,
 67
+)
 68
+
 69
+
 70
+hooks = Hooks()
 71
+os.putenv('LC_ALL', "C")
 72
+OFDB = "/var/opt/VRTSofcore/ofdb"
 73
+PYTHON2 = "/usr/bin/python2.7"
 74
+AMQP_CONF = '/opt/VRTSofcore/etc/amqp.conf'
 75
+RABBITMQ_PLUGINS = '/usr/sbin/rabbitmq-plugins'
 76
+NETINTFS = '/var/opt/VRTSofcore/.netintfs'
 77
+ZK_PORT="42181"
 78
+HS_API_PORT="8753"
 79
+hs_services =  [ 'hyperscale-api.service',
 80
+    'hyperscale-mq-consumer.service',
 81
+    'hyperscale-mq-controller.service',
 82
+    'hyperscale-serengeti.service',
 83
+    'hyperscale-zookeeper.service',
 84
+    'hyperscale-ceilometer.service',
 85
+]
 86
+
 87
+hs_relations = ['identity-admin', 'shared-db', 'db-admin', 'amqp']
 88
+
 89
+def relationship_status():
 90
+    rel_miss = []
 91
+    for rel in hs_relations:
 92
+        if not is_relation_made(rel):
 93
+            rel_miss.append(rel)
 94
+    return rel_miss
 95
+
 96
+def restart_services():
 97
+    if not relationship_status():
 98
+        for service in hs_services:
 99
+             service_restart(service)
100
+    else:
101
+        hookenv.log('Missing relations. Cannot start HyperScale services')
102
+
103
+@hooks.hook('install.next')
104
+def install():
105
+    hookenv.log('Installing Zookeeper')
106
+    cmd = "touch " + OFDB
107
+    os.system(cmd)
108
+    install_zk()
109
+    controller_config_repo()
110
+    set_value(OFDB, 'CONTROLLER' , 'CONFIG_DONE', "0")
111
+    status_set('maintenance', 'Installation done for HyperScale Packages')
112
+
113
+@hooks.hook('config-changed')
114
+def config_changed():
115
+    hookenv.log('Configuring HyperScale')
116
+
117
+    is_config_done = get_value(OFDB, 'CONTROLLER', 'CONFIG_DONE')
118
+    if is_config_done == '0':
119
+        hostip = unit_get('private-address')
120
+        controller_save_config(hostip)
121
+        cmd = (PYTHON2  + ' -B /opt/VRTSofmn/adm/dna_netinfo.py')
122
+        lst = run_cmd(cmd.split(' '))
123
+        print lst
124
+        hookenv.log(hostip)
125
+        controller_ceil_config()
126
+        controller_copy_files()
127
+        controller_config_horizon(hostip)
128
+        set_value(OFDB, 'CONTROLLER' , 'CONFIG_DONE', "1")
129
+        rel_miss = relationship_status()
130
+        if not rel_miss:
131
+            status_set('maintenance', 'Relations complete. Status will be updated after services restart')
132
+        else:
133
+            status_set('blocked', 'Missing relations : ' + ' '.join(rel_miss))
134
+
135
+    hookenv.log("HyperScale config-changed: Success")
136
+
137
+@hooks.hook('db-admin-relation-joined')
138
+def db_admin_joined():
139
+     host = None
140
+     conf = config()
141
+     hookenv.log('Creating relation db-admin')
142
+     hookenv.log(conf['database-user'])
143
+     try:
144
+        host = network_get_primary_address('shared-db')
145
+     except NotImplementedError:
146
+        host = unit_get('private-address')
147
+
148
+     relation_set(database=conf['database'],
149
+        hostname=host)
150
+     status_set('maintenance', 'Relation observed: db-admin')
151
+     hookenv.log("HyperScale db-admin-relation-joined: Success")
152
+
153
+@hooks.hook('db-admin-relation-changed')
154
+def db_admin_changed():
155
+     conf = config()
156
+     host = None
157
+     passwd = relation_get('password')
158
+     host = relation_get('host')
159
+     user = relation_get('user')
160
+     set_value(OFDB, 'CONTROLLER' , 'DB_ADMIN_USER', user)
161
+     set_value(OFDB, 'CONTROLLER' , 'DB_ADMIN_PASSWD', passwd)
162
+     set_value(OFDB, 'CONTROLLER' , 'DB_HOST', host)
163
+     if is_relation_made('shared-db'):
164
+         ret = priv_grant_hyperscale()
165
+         if ret != 0:
166
+             hookenv.log('Grant access for HyperScale failed. Check logs')
167
+             sys.exit(1)
168
+         restart_services()
169
+         status_set('maintenance', 'Relation changed : db-admin')
170
+     else:
171
+         hookenv.log("DB grant for HyperScale user will be done after shared-db relation completes")
172
+         status_set('blocked','Waiting for shared-db relation to be made')
173
+     hookenv.log("HyperScale db-admin-relation-changed: Success")
174
+
175
+@hooks.hook('db-admin-relation-departed')
176
+def db_admin_departed():
177
+    pass
178
+
179
+@hooks.hook('db-admin-relation-broken')
180
+def db_admin_broken():
181
+    pass
182
+
183
+@hooks.hook('shared-db-relation-joined')
184
+def db_joined():
185
+     host = None
186
+     conf = config()
187
+     hookenv.log('Creating Relation')
188
+     hookenv.log(conf['database-user'])
189
+     try:
190
+        host = network_get_primary_address('shared-db')
191
+     except NotImplementedError:
192
+        host = unit_get('private-address')
193
+
194
+     status_set('maintenance', 'Relation observed: shared-db')
195
+     relation_set(database=conf['database'],
196
+        username=conf['database-user'],
197
+        hostname=host)
198
+     hookenv.log("HyperScale shared-db-relation-joined: Success")
199
+
200
+@hooks.hook('shared-db-relation-changed')
201
+def db_changed():
202
+     if is_relation_made('shared-db'):
203
+        conf = config()
204
+        host = None
205
+        try:
206
+            host = network_get_primary_address('shared-db')
207
+        except NotImplementedError:
208
+            host = unit_get('private-address')
209
+
210
+        status_set('maintenance', 'Relation joined: shared-db')
211
+        passwd = relation_get('password')
212
+        db_host = relation_get('db_host')
213
+        ctlr_ip = unit_get('private-address')
214
+        try:
215
+            sync_db(db_host, passwd)
216
+            IDGEN='/opt/VRTSofcore/adm/idgen.py'
217
+            if os.path.isfile(IDGEN):
218
+                of_version = get_openflame_version()
219
+                ctlid = subprocess.check_output([IDGEN, "--type", "hostid"])
220
+                set_value(OFDB, 'CONTROLLER' , 'CTLR_INSTANCE_HOSTID', ctlid)
221
+                hostname = get_value(OFDB, 'CONTROLLER', 'CONTROLLER_NAME')
222
+                retval = update_openflame_nodes(db_host, passwd, hostname, ctlid,
223
+                                                ctlr_ip, 'N/A',
224
+                                                'controller', 'up', ctlid, of_version)
225
+            mysql_controller_config(db_host,passwd)
226
+            restart_services()
227
+            if is_relation_made('db-admin'): 
228
+            # If db-admin relation happened before shared-db, then grant permissions from here
229
+                ret = priv_grant_hyperscale()
230
+                if ret != 0:
231
+                   hookenv.log('Error granting permission to HyperScale user. Check logs')
232
+                   sys.exit(1)
233
+        except Exception as e:
234
+            errstr = 'Error creating database on controller' + str(e)
235
+            hookenv.log(errstr)
236
+            sys.exit(1)
237
+     else:
238
+        hookenv.log('Relation shared-db not complete. Will retry')
239
+        sys.exit(1)
240
+     hookenv.log("HyperScale shared-db-relation-changed: Success")
241
+
242
+@hooks.hook('shared-db-relation-broken')
243
+def db_broken():
244
+    status_set('maintenance', 'Shared-db: broken')
245
+    return
246
+
247
+@hooks.hook('shared-db-relation-departed')
248
+def db_departed():
249
+    status_set('maintenance', 'Shared-db: departed')
250
+    passwd = relation_get('password')
251
+    db_host = relation_get('db_host')
252
+    delete_db(db_host, passwd)
253
+    return
254
+
255
+@hooks.hook('amqp-relation-joined')
256
+def rabbitmq_relation_joined():
257
+    relation_id = None
258
+    conf = config()
259
+    relation_set(relation_id=relation_id,
260
+                 username='hyperscale', vhost='/' , admin=True)
261
+    cmd = RABBITMQ_PLUGINS + ' enable rabbitmq_management'
262
+    subprocess.call(cmd.split(' '))
263
+    service_restart('rabbitmq-server')
264
+    status_set('maintenance', 'Relation joined: amqp')
265
+    hookenv.log("HyperScale amqp-relation-joined: Success")
266
+    return
267
+
268
+
269
+@hooks.hook('amqp-relation-changed')
270
+def rabbitmq_relation_changed():
271
+    if is_relation_made('amqp'):
272
+        hostname = ''
273
+        private_address =''
274
+        password = ''
275
+        op=relation_get(rid=relation_id())
276
+        rel_data = list(op.keys())
277
+
278
+        if 'password' in rel_data and 'private-address' in rel_data:
279
+            hostname = str(op['hostname']) if 'hostname' in rel_data else ''
280
+            private_address = str(op['private-address'])
281
+            password = str (op['password'])
282
+            create_rabbitmq_exchange('/',private_address=private_address,
283
+                password=password)
284
+            with open(AMQP_CONF,'r') as json_file:
285
+                json_data = json.load(json_file)
286
+                json_file.close()
287
+            json_data['server'] = private_address
288
+            json_data['port'] = 5672
289
+            json_data['user'] = 'hyperscale'
290
+            json_data['password'] = password
291
+            with open(AMQP_CONF ,'w') as json_file:
292
+                json.dump(json_data,json_file)
293
+                json_file.close()
294
+            set_value(OFDB, 'CONTROLLER', 'RABBITMQ_PORT', '5672')
295
+        restart_services()
296
+
297
+        status_set('maintenance', 'Relation changed: amqp')
298
+    else:
299
+        log('HyperScale to rabbitmq connection not made')
300
+        status_set('maintenance', 'Relation incomplete: amqp')
301
+    hookenv.log("HyperScale amqp-relation-changed: Success")
302
+    return
303
+
304
+
305
+@hooks.hook('amqp-relation-departed')
306
+def rabbitmq_relation_departed():
307
+    hostname = ''
308
+    private_address =''
309
+    password = ''
310
+    op=relation_get(rid=relation_id())
311
+    rel_data = list(op.keys())
312
+    if op is not None:
313
+        if 'password' in rel_data and 'private-address' in rel_data:
314
+            hostname = str(op['hostname']) if 'hostname' in rel_data else ''
315
+            private_address = str(op['private-address'])
316
+            password= str (op['password'])
317
+            delete_rabbitmq_exchange('/',private_address=private_address,
318
+                password=password)
319
+    return
320
+
321
+@hooks.hook('identity-admin-relation-changed')
322
+def identity_admin_relation_changed():
323
+  #  if is_relation_made('identity-admin') and is_relation_made('shared-db') \
324
+   #    and is_relation_made('amqp'):
325
+    op=relation_get(rid=relation_id())
326
+    if is_relation_made('identity-admin') and \
327
+       op.get('service_password',None) is not None:
328
+         hostname = ''
329
+         private_address =''
330
+         password = ''
331
+         auth_url = ('http://%s:5000/v3')%op['private-address']
332
+         set_value(OFDB, 'CONTROLLER' , 'AUTH_URL', auth_url)
333
+         ret = controller_config_identity(op)
334
+         if (ret != 0):
335
+                    log('Identity configuration failed for HyperScale. Check /var/opt/VRTSofcore/logs/ofengine.log for failure')
336
+                    assert(ret)
337
+         status_set('maintenance', 'Relation changed : identity-admin')
338
+         restart_services()
339
+
340
+    else:
341
+         log('HyperScale to keystone relation not made')
342
+         status_set('maintenance', 'Relation incomplete: identity-admin')
343
+         sys.exit(1)
344
+    hookenv.log("HyperScale identity-admin-relation-changed: Success")
345
+    return
346
+
347
+@hooks.hook('identity-admin-relation-departed')
348
+def identity_admin_relation_departed():
349
+    hostname = ''
350
+    private_address =''
351
+    password = ''
352
+    op=relation_get(rid=relation_id())
353
+    if op.get('service_password',None) is not None:
354
+        auth_url = ('http://%s:5000/v3')%op['private-address']
355
+	set_value(OFDB, 'CONTROLLER' , 'AUTH_URL', auth_url)
356
+	cmd = ('/opt/VRTSofcore/bin/ofexec --operation controller_unconf_juju '
357
+	'--params controller_ip=%s;openstack_passwd=%s;'
358
+	'region_name=%s --run'
359
+	)%(op['private-address'], op['service_password'],
360
+	op['service_region'])
361
+	lst = run_cmd(cmd.split(' '))
362
+	if (lst['ret'] != 0):
363
+		log('Check /var/opt/VRTSofcore/logs/ofengine.log for failure')
364
+		assert(lst['ret'] == 0)
365
+    else:
366
+        delete_value(OFDB, 'CONTROLLER', 'MGMT_INTF')
367
+
368
+    return
369
+
370
+@hooks.hook('update-status')
371
+def update_status():
372
+    # Check status of services and update status accordingly
373
+    failed_services = []
374
+    rel_miss = relationship_status()
375
+    if not rel_miss:
376
+        for service in hs_services:
377
+            if not service_running(service):
378
+               failed_services.append(service)
379
+        if not failed_services:
380
+            status_set('active', 'HyperScale Unit ready')
381
+        else:
382
+            status_set('maintenance', 'Some Hyperscale services have failed : ' + ' '.join(failed_services))
383
+            sys.exit(1)
384
+    else:
385
+        status_set('blocked', 'Missing relations : ' + ' '.join(rel_miss))
386
+
387
+@hooks.hook('start')
388
+def start():
389
+    open_port(ZK_PORT)
390
+    open_port(HS_API_PORT)
391
+    if not relationship_status():
392
+       status_set('waiting', 'Hyperscale service will start after relations are complete') 
393
+    else:
394
+       restart_services()
395
+
396
+
397
+if __name__ == '__main__':
398
+    try:
399
+        hooks.execute(sys.argv)
400
+    except UnregisteredHookError as e:
401
+        hookenv.log('Unknown hook {} - skipping.'.format(e))
Back to file index

hooks/amqp-relation-joined

  1
--- 
  2
+++ hooks/amqp-relation-joined
  3
@@ -0,0 +1,398 @@
  4
+#!/usr/bin/python
  5
+# Copyright 2016 Canonical Ltd
  6
+#
  7
+# Licensed under the Apache License, Version 2.0 (the "License");
  8
+# you may not use this file except in compliance with the License.
  9
+# You may obtain a copy of the License at
 10
+#
 11
+#  http://www.apache.org/licenses/LICENSE-2.0
 12
+#
 13
+# Unless required by applicable law or agreed to in writing, software
 14
+# distributed under the License is distributed on an "AS IS" BASIS,
 15
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 16
+# See the License for the specific language governing permissions and
 17
+# limitations under the License.
 18
+
 19
+import sys
 20
+import os
 21
+import json
 22
+import subprocess 
 23
+
 24
+sys.path.append('lib')
 25
+from charmhelpers.core import hookenv
 26
+from charmhelpers.core.hookenv import (
 27
+    config,
 28
+    status_set,
 29
+    is_relation_made,
 30
+    relation_set,
 31
+    relation_get,
 32
+    relation_ids,
 33
+    relation_id,
 34
+    resource_get,
 35
+    unit_get,
 36
+    open_port,
 37
+    Hooks,
 38
+    log,
 39
+    UnregisteredHookError,
 40
+    network_get_primary_address,
 41
+ )
 42
+from hyperscale_utils import (
 43
+    sync_db,
 44
+    set_value,
 45
+    get_value,
 46
+    delete_value,
 47
+    get_openflame_version,
 48
+    update_openflame_nodes,
 49
+    delete_db,
 50
+    run_cmd,
 51
+    controller_save_config,
 52
+    install_zk,
 53
+    controller_ceil_config,
 54
+    controller_copy_files,
 55
+    controller_config_horizon,
 56
+    create_rabbitmq_exchange,
 57
+    delete_rabbitmq_exchange,
 58
+    mysql_controller_config,
 59
+    controller_config_repo,
 60
+    controller_config_identity,
 61
+    priv_grant_hyperscale,
 62
+)
 63
+
 64
+from charmhelpers.core.host import (
 65
+    service_restart,
 66
+    service_running,
 67
+)
 68
+
 69
+
 70
+hooks = Hooks()
 71
+os.putenv('LC_ALL', "C")
 72
+OFDB = "/var/opt/VRTSofcore/ofdb"
 73
+PYTHON2 = "/usr/bin/python2.7"
 74
+AMQP_CONF = '/opt/VRTSofcore/etc/amqp.conf'
 75
+RABBITMQ_PLUGINS = '/usr/sbin/rabbitmq-plugins'
 76
+NETINTFS = '/var/opt/VRTSofcore/.netintfs'
 77
+ZK_PORT="42181"
 78
+HS_API_PORT="8753"
 79
+hs_services =  [ 'hyperscale-api.service',
 80
+    'hyperscale-mq-consumer.service',
 81
+    'hyperscale-mq-controller.service',
 82
+    'hyperscale-serengeti.service',
 83
+    'hyperscale-zookeeper.service',
 84
+    'hyperscale-ceilometer.service',
 85
+]
 86
+
 87
+hs_relations = ['identity-admin', 'shared-db', 'db-admin', 'amqp']
 88
+
 89
+def relationship_status():
 90
+    rel_miss = []
 91
+    for rel in hs_relations:
 92
+        if not is_relation_made(rel):
 93
+            rel_miss.append(rel)
 94
+    return rel_miss
 95
+
 96
+def restart_services():
 97
+    if not relationship_status():
 98
+        for service in hs_services:
 99
+             service_restart(service)
100
+    else:
101
+        hookenv.log('Missing relations. Cannot start HyperScale services')
102
+
103
+@hooks.hook('install.next')
104
+def install():
105
+    hookenv.log('Installing Zookeeper')
106
+    cmd = "touch " + OFDB
107
+    os.system(cmd)
108
+    install_zk()
109
+    controller_config_repo()
110
+    set_value(OFDB, 'CONTROLLER' , 'CONFIG_DONE', "0")
111
+    status_set('maintenance', 'Installation done for HyperScale Packages')
112
+
113
+@hooks.hook('config-changed')
114
+def config_changed():
115
+    hookenv.log('Configuring HyperScale')
116
+
117
+    is_config_done = get_value(OFDB, 'CONTROLLER', 'CONFIG_DONE')
118
+    if is_config_done == '0':
119
+        hostip = unit_get('private-address')
120
+        controller_save_config(hostip)
121
+        cmd = (PYTHON2  + ' -B /opt/VRTSofmn/adm/dna_netinfo.py')
122
+        lst = run_cmd(cmd.split(' '))
123
+        print lst
124
+        hookenv.log(hostip)
125
+        controller_ceil_config()
126
+        controller_copy_files()
127
+        controller_config_horizon(hostip)
128
+        set_value(OFDB, 'CONTROLLER' , 'CONFIG_DONE', "1")
129
+        rel_miss = relationship_status()
130
+        if not rel_miss:
131
+            status_set('maintenance', 'Relations complete. Status will be updated after services restart')
132
+        else:
133
+            status_set('blocked', 'Missing relations : ' + ' '.join(rel_miss))
134
+
135
+    hookenv.log("HyperScale config-changed: Success")
136
+
137
+@hooks.hook('db-admin-relation-joined')
138
+def db_admin_joined():
139
+     host = None
140
+     conf = config()
141
+     hookenv.log('Creating relation db-admin')
142
+     hookenv.log(conf['database-user'])
143
+     try:
144
+        host = network_get_primary_address('shared-db')
145
+     except NotImplementedError:
146
+        host = unit_get('private-address')
147
+
148
+     relation_set(database=conf['database'],
149
+        hostname=host)
150
+     status_set('maintenance', 'Relation observed: db-admin')
151
+     hookenv.log("HyperScale db-admin-relation-joined: Success")
152
+
153
+@hooks.hook('db-admin-relation-changed')
154
+def db_admin_changed():
155
+     conf = config()
156
+     host = None
157
+     passwd = relation_get('password')
158
+     host = relation_get('host')
159
+     user = relation_get('user')
160
+     set_value(OFDB, 'CONTROLLER' , 'DB_ADMIN_USER', user)
161
+     set_value(OFDB, 'CONTROLLER' , 'DB_ADMIN_PASSWD', passwd)
162
+     set_value(OFDB, 'CONTROLLER' , 'DB_HOST', host)
163
+     if is_relation_made('shared-db'):
164
+         ret = priv_grant_hyperscale()
165
+         if ret != 0:
166
+             hookenv.log('Grant access for HyperScale failed. Check logs')
167
+             sys.exit(1)
168
+         restart_services()
169
+         status_set('maintenance', 'Relation changed : db-admin')
170
+     else:
171
+         hookenv.log("DB grant for HyperScale user will be done after shared-db relation completes")
172
+         status_set('blocked','Waiting for shared-db relation to be made')
173
+     hookenv.log("HyperScale db-admin-relation-changed: Success")
174
+
175
+@hooks.hook('db-admin-relation-departed')
176
+def db_admin_departed():
177
+    pass
178
+
179
+@hooks.hook('db-admin-relation-broken')
180
+def db_admin_broken():
181
+    pass
182
+
183
+@hooks.hook('shared-db-relation-joined')
184
+def db_joined():
185
+     host = None
186
+     conf = config()
187
+     hookenv.log('Creating Relation')
188
+     hookenv.log(conf['database-user'])
189
+     try:
190
+        host = network_get_primary_address('shared-db')
191
+     except NotImplementedError:
192
+        host = unit_get('private-address')
193
+
194
+     status_set('maintenance', 'Relation observed: shared-db')
195
+     relation_set(database=conf['database'],
196
+        username=conf['database-user'],
197
+        hostname=host)
198
+     hookenv.log("HyperScale shared-db-relation-joined: Success")
199
+
200
+@hooks.hook('shared-db-relation-changed')
201
+def db_changed():
202
+     if is_relation_made('shared-db'):
203
+        conf = config()
204
+        host = None
205
+        try:
206
+            host = network_get_primary_address('shared-db')
207
+        except NotImplementedError:
208
+            host = unit_get('private-address')
209
+
210
+        status_set('maintenance', 'Relation joined: shared-db')
211
+        passwd = relation_get('password')
212
+        db_host = relation_get('db_host')
213
+        ctlr_ip = unit_get('private-address')
214
+        try:
215
+            sync_db(db_host, passwd)
216
+            IDGEN='/opt/VRTSofcore/adm/idgen.py'
217
+            if os.path.isfile(IDGEN):
218
+                of_version = get_openflame_version()
219
+                ctlid = subprocess.check_output([IDGEN, "--type", "hostid"])
220
+                set_value(OFDB, 'CONTROLLER' , 'CTLR_INSTANCE_HOSTID', ctlid)
221
+                hostname = get_value(OFDB, 'CONTROLLER', 'CONTROLLER_NAME')
222
+                retval = update_openflame_nodes(db_host, passwd, hostname, ctlid,
223
+                                                ctlr_ip, 'N/A',
224
+                                                'controller', 'up', ctlid, of_version)
225
+            mysql_controller_config(db_host,passwd)
226
+            restart_services()
227
+            if is_relation_made('db-admin'): 
228
+            # If db-admin relation happened before shared-db, then grant permissions from here
229
+                ret = priv_grant_hyperscale()
230
+                if ret != 0:
231
+                   hookenv.log('Error granting permission to HyperScale user. Check logs')
232
+                   sys.exit(1)
233
+        except Exception as e:
234
+            errstr = 'Error creating database on controller' + str(e)
235
+            hookenv.log(errstr)
236
+            sys.exit(1)
237
+     else:
238
+        hookenv.log('Relation shared-db not complete. Will retry')
239
+        sys.exit(1)
240
+     hookenv.log("HyperScale shared-db-relation-changed: Success")
241
+
242
+@hooks.hook('shared-db-relation-broken')
243
+def db_broken():
244
+    status_set('maintenance', 'Shared-db: broken')
245
+    return
246
+
247
+@hooks.hook('shared-db-relation-departed')
248
+def db_departed():
249
+    status_set('maintenance', 'Shared-db: departed')
250
+    passwd = relation_get('password')
251
+    db_host = relation_get('db_host')
252
+    delete_db(db_host, passwd)
253
+    return
254
+
255
+@hooks.hook('amqp-relation-joined')
256
+def rabbitmq_relation_joined():
257
+    relation_id = None
258
+    conf = config()
259
+    relation_set(relation_id=relation_id,
260
+                 username='hyperscale', vhost='/' , admin=True)
261
+    cmd = RABBITMQ_PLUGINS + ' enable rabbitmq_management'
262
+    subprocess.call(cmd.split(' '))
263
+    service_restart('rabbitmq-server')
264
+    status_set('maintenance', 'Relation joined: amqp')
265
+    hookenv.log("HyperScale amqp-relation-joined: Success")
266
+    return
267
+
268
+
269
+@hooks.hook('amqp-relation-changed')
270
+def rabbitmq_relation_changed():
271
+    if is_relation_made('amqp'):
272
+        hostname = ''
273
+        private_address =''
274
+        password = ''
275
+        op=relation_get(rid=relation_id())
276
+        rel_data = list(op.keys())
277
+
278
+        if 'password' in rel_data and 'private-address' in rel_data:
279
+            hostname = str(op['hostname']) if 'hostname' in rel_data else ''
280
+            private_address = str(op['private-address'])
281
+            password = str (op['password'])
282
+            create_rabbitmq_exchange('/',private_address=private_address,
283
+                password=password)
284
+            with open(AMQP_CONF,'r') as json_file:
285
+                json_data = json.load(json_file)
286
+                json_file.close()
287
+            json_data['server'] = private_address
288
+            json_data['port'] = 5672
289
+            json_data['user'] = 'hyperscale'
290
+            json_data['password'] = password
291
+            with open(AMQP_CONF ,'w') as json_file:
292
+                json.dump(json_data,json_file)
293
+                json_file.close()
294
+            set_value(OFDB, 'CONTROLLER', 'RABBITMQ_PORT', '5672')
295
+        restart_services()
296
+
297
+        status_set('maintenance', 'Relation changed: amqp')
298
+    else:
299
+        log('HyperScale to rabbitmq connection not made')
300
+        status_set('maintenance', 'Relation incomplete: amqp')
301
+    hookenv.log("HyperScale amqp-relation-changed: Success")
302
+    return
303
+
304
+
305
+@hooks.hook('amqp-relation-departed')
306
+def rabbitmq_relation_departed():
307
+    hostname = ''
308
+    private_address =''
309
+    password = ''
310
+    op=relation_get(rid=relation_id())
311
+    rel_data = list(op.keys())
312
+    if op is not None:
313
+        if 'password' in rel_data and 'private-address' in rel_data:
314
+            hostname = str(op['hostname']) if 'hostname' in rel_data else ''
315
+            private_address = str(op['private-address'])
316
+            password= str (op['password'])
317
+            delete_rabbitmq_exchange('/',private_address=private_address,
318
+                password=password)
319
+    return
320
+
321
+@hooks.hook('identity-admin-relation-changed')
322
+def identity_admin_relation_changed():
323
+  #  if is_relation_made('identity-admin') and is_relation_made('shared-db') \
324
+   #    and is_relation_made('amqp'):
325
+    op=relation_get(rid=relation_id())
326
+    if is_relation_made('identity-admin') and \
327
+       op.get('service_password',None) is not None:
328
+         hostname = ''
329
+         private_address =''
330
+         password = ''
331
+         auth_url = ('http://%s:5000/v3')%op['private-address']
332
+         set_value(OFDB, 'CONTROLLER' , 'AUTH_URL', auth_url)
333
+         ret = controller_config_identity(op)
334
+         if (ret != 0):
335
+                    log('Identity configuration failed for HyperScale. Check /var/opt/VRTSofcore/logs/ofengine.log for failure')
336
+                    assert(ret)
337
+         status_set('maintenance', 'Relation changed : identity-admin')
338
+         restart_services()
339
+
340
+    else:
341
+         log('HyperScale to keystone relation not made')
342
+         status_set('maintenance', 'Relation incomplete: identity-admin')
343
+         sys.exit(1)
344
+    hookenv.log("HyperScale identity-admin-relation-changed: Success")
345
+    return
346
+
347
+@hooks.hook('identity-admin-relation-departed')
348
+def identity_admin_relation_departed():
349
+    hostname = ''
350
+    private_address =''
351
+    password = ''
352
+    op=relation_get(rid=relation_id())
353
+    if op.get('service_password',None) is not None:
354
+        auth_url = ('http://%s:5000/v3')%op['private-address']
355
+	set_value(OFDB, 'CONTROLLER' , 'AUTH_URL', auth_url)
356
+	cmd = ('/opt/VRTSofcore/bin/ofexec --operation controller_unconf_juju '
357
+	'--params controller_ip=%s;openstack_passwd=%s;'
358
+	'region_name=%s --run'
359
+	)%(op['private-address'], op['service_password'],
360
+	op['service_region'])
361
+	lst = run_cmd(cmd.split(' '))
362
+	if (lst['ret'] != 0):
363
+		log('Check /var/opt/VRTSofcore/logs/ofengine.log for failure')
364
+		assert(lst['ret'] == 0)
365
+    else:
366
+        delete_value(OFDB, 'CONTROLLER', 'MGMT_INTF')
367
+
368
+    return
369
+
370
+@hooks.hook('update-status')
371
+def update_status():
372
+    # Check status of services and update status accordingly
373
+    failed_services = []
374
+    rel_miss = relationship_status()
375
+    if not rel_miss:
376
+        for service in hs_services:
377
+            if not service_running(service):
378
+               failed_services.append(service)
379
+        if not failed_services:
380
+            status_set('active', 'HyperScale Unit ready')
381
+        else:
382
+            status_set('maintenance', 'Some Hyperscale services have failed : ' + ' '.join(failed_services))
383
+            sys.exit(1)
384
+    else:
385
+        status_set('blocked', 'Missing relations : ' + ' '.join(rel_miss))
386
+
387
+@hooks.hook('start')
388
+def start():
389
+    open_port(ZK_PORT)
390
+    open_port(HS_API_PORT)
391
+    if not relationship_status():
392
+       status_set('waiting', 'Hyperscale service will start after relations are complete') 
393
+    else:
394
+       restart_services()
395
+
396
+
397
+if __name__ == '__main__':
398
+    try:
399
+        hooks.execute(sys.argv)
400
+    except UnregisteredHookError as e:
401
+        hookenv.log('Unknown hook {} - skipping.'.format(e))
Back to file index

hooks/config-changed

  1
--- 
  2
+++ hooks/config-changed
  3
@@ -0,0 +1,398 @@
  4
+#!/usr/bin/python
  5
+# Copyright 2016 Canonical Ltd
  6
+#
  7
+# Licensed under the Apache License, Version 2.0 (the "License");
  8
+# you may not use this file except in compliance with the License.
  9
+# You may obtain a copy of the License at
 10
+#
 11
+#  http://www.apache.org/licenses/LICENSE-2.0
 12
+#
 13
+# Unless required by applicable law or agreed to in writing, software
 14
+# distributed under the License is distributed on an "AS IS" BASIS,
 15
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 16
+# See the License for the specific language governing permissions and
 17
+# limitations under the License.
 18
+
 19
+import sys
 20
+import os
 21
+import json
 22
+import subprocess 
 23
+
 24
+sys.path.append('lib')
 25
+from charmhelpers.core import hookenv
 26
+from charmhelpers.core.hookenv import (
 27
+    config,
 28
+    status_set,
 29
+    is_relation_made,
 30
+    relation_set,
 31
+    relation_get,
 32
+    relation_ids,
 33
+    relation_id,
 34
+    resource_get,
 35
+    unit_get,
 36
+    open_port,
 37
+    Hooks,
 38
+    log,
 39
+    UnregisteredHookError,
 40
+    network_get_primary_address,
 41
+ )
 42
+from hyperscale_utils import (
 43
+    sync_db,
 44
+    set_value,
 45
+    get_value,
 46
+    delete_value,
 47
+    get_openflame_version,
 48
+    update_openflame_nodes,
 49
+    delete_db,
 50
+    run_cmd,
 51
+    controller_save_config,
 52
+    install_zk,
 53
+    controller_ceil_config,
 54
+    controller_copy_files,
 55
+    controller_config_horizon,
 56
+    create_rabbitmq_exchange,
 57
+    delete_rabbitmq_exchange,
 58
+    mysql_controller_config,
 59
+    controller_config_repo,
 60
+    controller_config_identity,
 61
+    priv_grant_hyperscale,
 62
+)
 63
+
 64
+from charmhelpers.core.host import (
 65
+    service_restart,
 66
+    service_running,
 67
+)
 68
+
 69
+
 70
+hooks = Hooks()
 71
+os.putenv('LC_ALL', "C")
 72
+OFDB = "/var/opt/VRTSofcore/ofdb"
 73
+PYTHON2 = "/usr/bin/python2.7"
 74
+AMQP_CONF = '/opt/VRTSofcore/etc/amqp.conf'
 75
+RABBITMQ_PLUGINS = '/usr/sbin/rabbitmq-plugins'
 76
+NETINTFS = '/var/opt/VRTSofcore/.netintfs'
 77
+ZK_PORT="42181"
 78
+HS_API_PORT="8753"
 79
+hs_services =  [ 'hyperscale-api.service',
 80
+    'hyperscale-mq-consumer.service',
 81
+    'hyperscale-mq-controller.service',
 82
+    'hyperscale-serengeti.service',
 83
+    'hyperscale-zookeeper.service',
 84
+    'hyperscale-ceilometer.service',
 85
+]
 86
+
 87
+hs_relations = ['identity-admin', 'shared-db', 'db-admin', 'amqp']
 88
+
 89
+def relationship_status():
 90
+    rel_miss = []
 91
+    for rel in hs_relations:
 92
+        if not is_relation_made(rel):
 93
+            rel_miss.append(rel)
 94
+    return rel_miss
 95
+
 96
+def restart_services():
 97
+    if not relationship_status():
 98
+        for service in hs_services:
 99
+             service_restart(service)
100
+    else:
101
+        hookenv.log('Missing relations. Cannot start HyperScale services')
102
+
103
+@hooks.hook('install.next')
104
+def install():
105
+    hookenv.log('Installing Zookeeper')
106
+    cmd = "touch " + OFDB
107
+    os.system(cmd)
108
+    install_zk()
109
+    controller_config_repo()
110
+    set_value(OFDB, 'CONTROLLER' , 'CONFIG_DONE', "0")
111
+    status_set('maintenance', 'Installation done for HyperScale Packages')
112
+
113
+@hooks.hook('config-changed')
114
+def config_changed():
115
+    hookenv.log('Configuring HyperScale')
116
+
117
+    is_config_done = get_value(OFDB, 'CONTROLLER', 'CONFIG_DONE')
118
+    if is_config_done == '0':
119
+        hostip = unit_get('private-address')
120
+        controller_save_config(hostip)
121
+        cmd = (PYTHON2  + ' -B /opt/VRTSofmn/adm/dna_netinfo.py')
122
+        lst = run_cmd(cmd.split(' '))
123
+        print lst
124
+        hookenv.log(hostip)
125
+        controller_ceil_config()
126
+        controller_copy_files()
127
+        controller_config_horizon(hostip)
128
+        set_value(OFDB, 'CONTROLLER' , 'CONFIG_DONE', "1")
129
+        rel_miss = relationship_status()
130
+        if not rel_miss:
131
+            status_set('maintenance', 'Relations complete. Status will be updated after services restart')
132
+        else:
133
+            status_set('blocked', 'Missing relations : ' + ' '.join(rel_miss))
134
+
135
+    hookenv.log("HyperScale config-changed: Success")
136
+
137
+@hooks.hook('db-admin-relation-joined')
138
+def db_admin_joined():
139
+     host = None
140
+     conf = config()
141
+     hookenv.log('Creating relation db-admin')
142
+     hookenv.log(conf['database-user'])
143
+     try:
144
+        host = network_get_primary_address('shared-db')
145
+     except NotImplementedError:
146
+        host = unit_get('private-address')
147
+
148
+     relation_set(database=conf['database'],
149
+        hostname=host)
150
+     status_set('maintenance', 'Relation observed: db-admin')
151
+     hookenv.log("HyperScale db-admin-relation-joined: Success")
152
+
153
+@hooks.hook('db-admin-relation-changed')
154
+def db_admin_changed():
155
+     conf = config()
156
+     host = None
157
+     passwd = relation_get('password')
158
+     host = relation_get('host')
159
+     user = relation_get('user')
160
+     set_value(OFDB, 'CONTROLLER' , 'DB_ADMIN_USER', user)
161
+     set_value(OFDB, 'CONTROLLER' , 'DB_ADMIN_PASSWD', passwd)
162
+     set_value(OFDB, 'CONTROLLER' , 'DB_HOST', host)
163
+     if is_relation_made('shared-db'):
164
+         ret = priv_grant_hyperscale()
165
+         if ret != 0:
166
+             hookenv.log('Grant access for HyperScale failed. Check logs')
167
+             sys.exit(1)
168
+         restart_services()
169
+         status_set('maintenance', 'Relation changed : db-admin')
170
+     else:
171
+         hookenv.log("DB grant for HyperScale user will be done after shared-db relation completes")
172
+         status_set('blocked','Waiting for shared-db relation to be made')
173
+     hookenv.log("HyperScale db-admin-relation-changed: Success")
174
+
175
+@hooks.hook('db-admin-relation-departed')
176
+def db_admin_departed():
177
+    pass
178
+
179
+@hooks.hook('db-admin-relation-broken')
180
+def db_admin_broken():
181
+    pass
182
+
183
+@hooks.hook('shared-db-relation-joined')
184
+def db_joined():
185
+     host = None
186
+     conf = config()
187
+     hookenv.log('Creating Relation')
188
+     hookenv.log(conf['database-user'])
189
+     try:
190
+        host = network_get_primary_address('shared-db')
191
+     except NotImplementedError:
192
+        host = unit_get('private-address')
193
+
194
+     status_set('maintenance', 'Relation observed: shared-db')
195
+     relation_set(database=conf['database'],
196
+        username=conf['database-user'],
197
+        hostname=host)
198
+     hookenv.log("HyperScale shared-db-relation-joined: Success")
199
+
200
+@hooks.hook('shared-db-relation-changed')
201
+def db_changed():
202
+     if is_relation_made('shared-db'):
203
+        conf = config()
204
+        host = None
205
+        try:
206
+            host = network_get_primary_address('shared-db')
207
+        except NotImplementedError:
208
+            host = unit_get('private-address')
209
+
210
+        status_set('maintenance', 'Relation joined: shared-db')
211
+        passwd = relation_get('password')
212
+        db_host = relation_get('db_host')
213
+        ctlr_ip = unit_get('private-address')
214
+        try:
215
+            sync_db(db_host, passwd)
216
+            IDGEN='/opt/VRTSofcore/adm/idgen.py'
217
+            if os.path.isfile(IDGEN):
218
+                of_version = get_openflame_version()
219
+                ctlid = subprocess.check_output([IDGEN, "--type", "hostid"])
220
+                set_value(OFDB, 'CONTROLLER' , 'CTLR_INSTANCE_HOSTID', ctlid)
221
+                hostname = get_value(OFDB, 'CONTROLLER', 'CONTROLLER_NAME')
222
+                retval = update_openflame_nodes(db_host, passwd, hostname, ctlid,
223
+                                                ctlr_ip, 'N/A',
224
+                                                'controller', 'up', ctlid, of_version)
225
+            mysql_controller_config(db_host,passwd)
226
+            restart_services()
227
+            if is_relation_made('db-admin'): 
228
+            # If db-admin relation happened before shared-db, then grant permissions from here
229
+                ret = priv_grant_hyperscale()
230
+                if ret != 0:
231
+                   hookenv.log('Error granting permission to HyperScale user. Check logs')
232
+                   sys.exit(1)
233
+        except Exception as e:
234
+            errstr = 'Error creating database on controller' + str(e)
235
+            hookenv.log(errstr)
236
+            sys.exit(1)
237
+     else:
238
+        hookenv.log('Relation shared-db not complete. Will retry')
239
+        sys.exit(1)
240
+     hookenv.log("HyperScale shared-db-relation-changed: Success")
241
+
242
+@hooks.hook('shared-db-relation-broken')
243
+def db_broken():
244
+    status_set('maintenance', 'Shared-db: broken')
245
+    return
246
+
247
+@hooks.hook('shared-db-relation-departed')
248
+def db_departed():
249
+    status_set('maintenance', 'Shared-db: departed')
250
+    passwd = relation_get('password')
251
+    db_host = relation_get('db_host')
252
+    delete_db(db_host, passwd)
253
+    return
254
+
255
+@hooks.hook('amqp-relation-joined')
256
+def rabbitmq_relation_joined():
257
+    relation_id = None
258
+    conf = config()
259
+    relation_set(relation_id=relation_id,
260
+                 username='hyperscale', vhost='/' , admin=True)
261
+    cmd = RABBITMQ_PLUGINS + ' enable rabbitmq_management'
262
+    subprocess.call(cmd.split(' '))
263
+    service_restart('rabbitmq-server')
264
+    status_set('maintenance', 'Relation joined: amqp')
265
+    hookenv.log("HyperScale amqp-relation-joined: Success")
266
+    return
267
+
268
+
269
+@hooks.hook('amqp-relation-changed')
270
+def rabbitmq_relation_changed():
271
+    if is_relation_made('amqp'):
272
+        hostname = ''
273
+        private_address =''
274
+        password = ''
275
+        op=relation_get(rid=relation_id())
276
+        rel_data = list(op.keys())
277
+
278
+        if 'password' in rel_data and 'private-address' in rel_data:
279
+            hostname = str(op['hostname']) if 'hostname' in rel_data else ''
280
+            private_address = str(op['private-address'])
281
+            password = str (op['password'])
282
+            create_rabbitmq_exchange('/',private_address=private_address,
283
+                password=password)
284
+            with open(AMQP_CONF,'r') as json_file:
285
+                json_data = json.load(json_file)
286
+                json_file.close()
287
+            json_data['server'] = private_address
288
+            json_data['port'] = 5672
289
+            json_data['user'] = 'hyperscale'
290
+            json_data['password'] = password
291
+            with open(AMQP_CONF ,'w') as json_file:
292
+                json.dump(json_data,json_file)
293
+                json_file.close()
294
+            set_value(OFDB, 'CONTROLLER', 'RABBITMQ_PORT', '5672')
295
+        restart_services()
296
+
297
+        status_set('maintenance', 'Relation changed: amqp')
298
+    else:
299
+        log('HyperScale to rabbitmq connection not made')
300
+        status_set('maintenance', 'Relation incomplete: amqp')
301
+    hookenv.log("HyperScale amqp-relation-changed: Success")
302
+    return
303
+
304
+
305
+@hooks.hook('amqp-relation-departed')
306
+def rabbitmq_relation_departed():
307
+    hostname = ''
308
+    private_address =''
309
+    password = ''
310
+    op=relation_get(rid=relation_id())
311
+    rel_data = list(op.keys())
312
+    if op is not None:
313
+        if 'password' in rel_data and 'private-address' in rel_data:
314
+            hostname = str(op['hostname']) if 'hostname' in rel_data else ''
315
+            private_address = str(op['private-address'])
316
+            password= str (op['password'])
317
+            delete_rabbitmq_exchange('/',private_address=private_address,
318
+                password=password)
319
+    return
320
+
321
+@hooks.hook('identity-admin-relation-changed')
322
+def identity_admin_relation_changed():
323
+  #  if is_relation_made('identity-admin') and is_relation_made('shared-db') \
324
+   #    and is_relation_made('amqp'):
325
+    op=relation_get(rid=relation_id())
326
+    if is_relation_made('identity-admin') and \
327
+       op.get('service_password',None) is not None:
328
+         hostname = ''
329
+         private_address =''
330
+         password = ''
331
+         auth_url = ('http://%s:5000/v3')%op['private-address']
332
+         set_value(OFDB, 'CONTROLLER' , 'AUTH_URL', auth_url)
333
+         ret = controller_config_identity(op)
334
+         if (ret != 0):
335
+                    log('Identity configuration failed for HyperScale. Check /var/opt/VRTSofcore/logs/ofengine.log for failure')
336
+                    assert(ret)
337
+         status_set('maintenance', 'Relation changed : identity-admin')
338
+         restart_services()
339
+
340
+    else:
341
+         log('HyperScale to keystone relation not made')
342
+         status_set('maintenance', 'Relation incomplete: identity-admin')
343
+         sys.exit(1)
344
+    hookenv.log("HyperScale identity-admin-relation-changed: Success")
345
+    return
346
+
347
+@hooks.hook('identity-admin-relation-departed')
348
+def identity_admin_relation_departed():
349
+    hostname = ''
350
+    private_address =''
351
+    password = ''
352
+    op=relation_get(rid=relation_id())
353
+    if op.get('service_password',None) is not None:
354
+        auth_url = ('http://%s:5000/v3')%op['private-address']
355
+	set_value(OFDB, 'CONTROLLER' , 'AUTH_URL', auth_url)
356
+	cmd = ('/opt/VRTSofcore/bin/ofexec --operation controller_unconf_juju '
357
+	'--params controller_ip=%s;openstack_passwd=%s;'
358
+	'region_name=%s --run'
359
+	)%(op['private-address'], op['service_password'],
360
+	op['service_region'])
361
+	lst = run_cmd(cmd.split(' '))
362
+	if (lst['ret'] != 0):
363
+		log('Check /var/opt/VRTSofcore/logs/ofengine.log for failure')
364
+		assert(lst['ret'] == 0)
365
+    else:
366
+        delete_value(OFDB, 'CONTROLLER', 'MGMT_INTF')
367
+
368
+    return
369
+
370
+@hooks.hook('update-status')
371
+def update_status():
372
+    # Check status of services and update status accordingly
373
+    failed_services = []
374
+    rel_miss = relationship_status()
375
+    if not rel_miss:
376
+        for service in hs_services:
377
+            if not service_running(service):
378
+               failed_services.append(service)
379
+        if not failed_services:
380
+            status_set('active', 'HyperScale Unit ready')
381
+        else:
382
+            status_set('maintenance', 'Some Hyperscale services have failed : ' + ' '.join(failed_services))
383
+            sys.exit(1)
384
+    else:
385
+        status_set('blocked', 'Missing relations : ' + ' '.join(rel_miss))
386
+
387
+@hooks.hook('start')
388
+def start():
389
+    open_port(ZK_PORT)
390
+    open_port(HS_API_PORT)
391
+    if not relationship_status():
392
+       status_set('waiting', 'Hyperscale service will start after relations are complete') 
393
+    else:
394
+       restart_services()
395
+
396
+
397
+if __name__ == '__main__':
398
+    try:
399
+        hooks.execute(sys.argv)
400
+    except UnregisteredHookError as e:
401
+        hookenv.log('Unknown hook {} - skipping.'.format(e))
Back to file index

hooks/db-admin-relation-broken

  1
--- 
  2
+++ hooks/db-admin-relation-broken
  3
@@ -0,0 +1,398 @@
  4
+#!/usr/bin/python
  5
+# Copyright 2016 Canonical Ltd
  6
+#
  7
+# Licensed under the Apache License, Version 2.0 (the "License");
  8
+# you may not use this file except in compliance with the License.
  9
+# You may obtain a copy of the License at
 10
+#
 11
+#  http://www.apache.org/licenses/LICENSE-2.0
 12
+#
 13
+# Unless required by applicable law or agreed to in writing, software
 14
+# distributed under the License is distributed on an "AS IS" BASIS,
 15
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 16
+# See the License for the specific language governing permissions and
 17
+# limitations under the License.
 18
+
 19
+import sys
 20
+import os
 21
+import json
 22
+import subprocess 
 23
+
 24
+sys.path.append('lib')
 25
+from charmhelpers.core import hookenv
 26
+from charmhelpers.core.hookenv import (
 27
+    config,
 28
+    status_set,
 29
+    is_relation_made,
 30
+    relation_set,
 31
+    relation_get,
 32
+    relation_ids,
 33
+    relation_id,
 34
+    resource_get,
 35
+    unit_get,
 36
+    open_port,
 37
+    Hooks,
 38
+    log,
 39
+    UnregisteredHookError,
 40
+    network_get_primary_address,
 41
+ )
 42
+from hyperscale_utils import (
 43
+    sync_db,
 44
+    set_value,
 45
+    get_value,
 46
+    delete_value,
 47
+    get_openflame_version,
 48
+    update_openflame_nodes,
 49
+    delete_db,
 50
+    run_cmd,
 51
+    controller_save_config,
 52
+    install_zk,
 53
+    controller_ceil_config,
 54
+    controller_copy_files,
 55
+    controller_config_horizon,
 56
+    create_rabbitmq_exchange,
 57
+    delete_rabbitmq_exchange,
 58
+    mysql_controller_config,
 59
+    controller_config_repo,
 60
+    controller_config_identity,
 61
+    priv_grant_hyperscale,
 62
+)
 63
+
 64
+from charmhelpers.core.host import (
 65
+    service_restart,
 66
+    service_running,
 67
+)
 68
+
 69
+
 70
+hooks = Hooks()
 71
+os.putenv('LC_ALL', "C")
 72
+OFDB = "/var/opt/VRTSofcore/ofdb"
 73
+PYTHON2 = "/usr/bin/python2.7"
 74
+AMQP_CONF = '/opt/VRTSofcore/etc/amqp.conf'
 75
+RABBITMQ_PLUGINS = '/usr/sbin/rabbitmq-plugins'
 76
+NETINTFS = '/var/opt/VRTSofcore/.netintfs'
 77
+ZK_PORT="42181"
 78
+HS_API_PORT="8753"
 79
+hs_services =  [ 'hyperscale-api.service',
 80
+    'hyperscale-mq-consumer.service',
 81
+    'hyperscale-mq-controller.service',
 82
+    'hyperscale-serengeti.service',
 83
+    'hyperscale-zookeeper.service',
 84
+    'hyperscale-ceilometer.service',
 85
+]
 86
+
 87
+hs_relations = ['identity-admin', 'shared-db', 'db-admin', 'amqp']
 88
+
 89
+def relationship_status():
 90
+    rel_miss = []
 91
+    for rel in hs_relations:
 92
+        if not is_relation_made(rel):
 93
+            rel_miss.append(rel)
 94
+    return rel_miss
 95
+
 96
+def restart_services():
 97
+    if not relationship_status():
 98
+        for service in hs_services:
 99
+             service_restart(service)
100
+    else:
101
+        hookenv.log('Missing relations. Cannot start HyperScale services')
102
+
103
+@hooks.hook('install.next')
104
+def install():
105
+    hookenv.log('Installing Zookeeper')
106
+    cmd = "touch " + OFDB
107
+    os.system(cmd)
108
+    install_zk()
109
+    controller_config_repo()
110
+    set_value(OFDB, 'CONTROLLER' , 'CONFIG_DONE', "0")
111
+    status_set('maintenance', 'Installation done for HyperScale Packages')
112
+
113
+@hooks.hook('config-changed')
114
+def config_changed():
115
+    hookenv.log('Configuring HyperScale')
116
+
117
+    is_config_done = get_value(OFDB, 'CONTROLLER', 'CONFIG_DONE')
118
+    if is_config_done == '0':
119
+        hostip = unit_get('private-address')
120
+        controller_save_config(hostip)
121
+        cmd = (PYTHON2  + ' -B /opt/VRTSofmn/adm/dna_netinfo.py')
122
+        lst = run_cmd(cmd.split(' '))
123
+        print lst
124
+        hookenv.log(hostip)
125
+        controller_ceil_config()
126
+        controller_copy_files()
127
+        controller_config_horizon(hostip)
128
+        set_value(OFDB, 'CONTROLLER' , 'CONFIG_DONE', "1")
129
+        rel_miss = relationship_status()
130
+        if not rel_miss:
131
+            status_set('maintenance', 'Relations complete. Status will be updated after services restart')
132
+        else:
133
+            status_set('blocked', 'Missing relations : ' + ' '.join(rel_miss))
134
+
135
+    hookenv.log("HyperScale config-changed: Success")
136
+
137
+@hooks.hook('db-admin-relation-joined')
138
+def db_admin_joined():
139
+     host = None
140
+     conf = config()
141
+     hookenv.log('Creating relation db-admin')
142
+     hookenv.log(conf['database-user'])
143
+     try:
144
+        host = network_get_primary_address('shared-db')
145
+     except NotImplementedError:
146
+        host = unit_get('private-address')
147
+
148
+     relation_set(database=conf['database'],
149
+        hostname=host)
150
+     status_set('maintenance', 'Relation observed: db-admin')
151
+     hookenv.log("HyperScale db-admin-relation-joined: Success")
152
+
153
+@hooks.hook('db-admin-relation-changed')
154
+def db_admin_changed():
155
+     conf = config()
156
+     host = None
157
+     passwd = relation_get('password')
158
+     host = relation_get('host')
159
+     user = relation_get('user')
160
+     set_value(OFDB, 'CONTROLLER' , 'DB_ADMIN_USER', user)
161
+     set_value(OFDB, 'CONTROLLER' , 'DB_ADMIN_PASSWD', passwd)
162
+     set_value(OFDB, 'CONTROLLER' , 'DB_HOST', host)
163
+     if is_relation_made('shared-db'):
164
+         ret = priv_grant_hyperscale()
165
+         if ret != 0:
166
+             hookenv.log('Grant access for HyperScale failed. Check logs')
167
+             sys.exit(1)
168
+         restart_services()
169
+         status_set('maintenance', 'Relation changed : db-admin')
170
+     else:
171
+         hookenv.log("DB grant for HyperScale user will be done after shared-db relation completes")
172
+         status_set('blocked','Waiting for shared-db relation to be made')
173
+     hookenv.log("HyperScale db-admin-relation-changed: Success")
174
+
175
+@hooks.hook('db-admin-relation-departed')
176
+def db_admin_departed():
177
+    pass
178
+
179
+@hooks.hook('db-admin-relation-broken')
180
+def db_admin_broken():
181
+    pass
182
+
183
+@hooks.hook('shared-db-relation-joined')
184
+def db_joined():
185
+     host = None
186
+     conf = config()
187
+     hookenv.log('Creating Relation')
188
+     hookenv.log(conf['database-user'])
189
+     try:
190
+        host = network_get_primary_address('shared-db')
191
+     except NotImplementedError:
192
+        host = unit_get('private-address')
193
+
194
+     status_set('maintenance', 'Relation observed: shared-db')
195
+     relation_set(database=conf['database'],
196
+        username=conf['database-user'],
197
+        hostname=host)
198
+     hookenv.log("HyperScale shared-db-relation-joined: Success")
199
+
200
+@hooks.hook('shared-db-relation-changed')
201
+def db_changed():
202
+     if is_relation_made('shared-db'):
203
+        conf = config()
204
+        host = None
205
+        try:
206
+            host = network_get_primary_address('shared-db')
207
+        except NotImplementedError:
208
+            host = unit_get('private-address')
209
+
210
+        status_set('maintenance', 'Relation joined: shared-db')
211
+        passwd = relation_get('password')
212
+        db_host = relation_get('db_host')
213
+        ctlr_ip = unit_get('private-address')
214
+        try:
215
+            sync_db(db_host, passwd)
216
+            IDGEN='/opt/VRTSofcore/adm/idgen.py'
217
+            if os.path.isfile(IDGEN):
218
+                of_version = get_openflame_version()
219
+                ctlid = subprocess.check_output([IDGEN, "--type", "hostid"])
220
+                set_value(OFDB, 'CONTROLLER' , 'CTLR_INSTANCE_HOSTID', ctlid)
221
+                hostname = get_value(OFDB, 'CONTROLLER', 'CONTROLLER_NAME')
222
+                retval = update_openflame_nodes(db_host, passwd, hostname, ctlid,
223
+                                                ctlr_ip, 'N/A',
224
+                                                'controller', 'up', ctlid, of_version)
225
+            mysql_controller_config(db_host,passwd)
226
+            restart_services()
227
+            if is_relation_made('db-admin'): 
228
+            # If db-admin relation happened before shared-db, then grant permissions from here
229
+                ret = priv_grant_hyperscale()
230
+                if ret != 0:
231
+                   hookenv.log('Error granting permission to HyperScale user. Check logs')
232
+                   sys.exit(1)
233
+        except Exception as e:
234
+            errstr = 'Error creating database on controller' + str(e)
235
+            hookenv.log(errstr)
236
+            sys.exit(1)
237
+     else:
238
+        hookenv.log('Relation shared-db not complete. Will retry')
239
+        sys.exit(1)
240
+     hookenv.log("HyperScale shared-db-relation-changed: Success")
241
+
242
+@hooks.hook('shared-db-relation-broken')
243
+def db_broken():
244
+    status_set('maintenance', 'Shared-db: broken')
245
+    return
246
+
247
+@hooks.hook('shared-db-relation-departed')
248
+def db_departed():
249
+    status_set('maintenance', 'Shared-db: departed')
250
+    passwd = relation_get('password')
251
+    db_host = relation_get('db_host')
252
+    delete_db(db_host, passwd)
253
+    return
254
+
255
+@hooks.hook('amqp-relation-joined')
256
+def rabbitmq_relation_joined():
257
+    relation_id = None
258
+    conf = config()
259
+    relation_set(relation_id=relation_id,
260
+                 username='hyperscale', vhost='/' , admin=True)
261
+    cmd = RABBITMQ_PLUGINS + ' enable rabbitmq_management'
262
+    subprocess.call(cmd.split(' '))
263
+    service_restart('rabbitmq-server')
264
+    status_set('maintenance', 'Relation joined: amqp')
265
+    hookenv.log("HyperScale amqp-relation-joined: Success")
266
+    return
267
+
268
+
269
+@hooks.hook('amqp-relation-changed')
270
+def rabbitmq_relation_changed():
271
+    if is_relation_made('amqp'):
272
+        hostname = ''
273
+        private_address =''
274
+        password = ''
275
+        op=relation_get(rid=relation_id())
276
+        rel_data = list(op.keys())
277
+
278
+        if 'password' in rel_data and 'private-address' in rel_data:
279
+            hostname = str(op['hostname']) if 'hostname' in rel_data else ''
280
+            private_address = str(op['private-address'])
281
+            password = str (op['password'])
282
+            create_rabbitmq_exchange('/',private_address=private_address,
283
+                password=password)
284
+            with open(AMQP_CONF,'r') as json_file:
285
+                json_data = json.load(json_file)
286
+                json_file.close()
287
+            json_data['server'] = private_address
288
+            json_data['port'] = 5672
289
+            json_data['user'] = 'hyperscale'
290
+            json_data['password'] = password
291
+            with open(AMQP_CONF ,'w') as json_file:
292
+                json.dump(json_data,json_file)
293
+                json_file.close()
294
+            set_value(OFDB, 'CONTROLLER', 'RABBITMQ_PORT', '5672')
295
+        restart_services()
296
+
297
+        status_set('maintenance', 'Relation changed: amqp')
298
+    else:
299
+        log('HyperScale to rabbitmq connection not made')
300
+        status_set('maintenance', 'Relation incomplete: amqp')
301
+    hookenv.log("HyperScale amqp-relation-changed: Success")
302
+    return
303
+
304
+
305
+@hooks.hook('amqp-relation-departed')
306
+def rabbitmq_relation_departed():
307
+    hostname = ''
308
+    private_address =''
309
+    password = ''
310
+    op=relation_get(rid=relation_id())
311
+    rel_data = list(op.keys())
312
+    if op is not None:
313
+        if 'password' in rel_data and 'private-address' in rel_data:
314
+            hostname = str(op['hostname']) if 'hostname' in rel_data else ''
315
+            private_address = str(op['private-address'])
316
+            password= str (op['password'])
317
+            delete_rabbitmq_exchange('/',private_address=private_address,
318
+                password=password)
319
+    return
320
+
321
+@hooks.hook('identity-admin-relation-changed')
322
+def identity_admin_relation_changed():
323
+  #  if is_relation_made('identity-admin') and is_relation_made('shared-db') \
324
+   #    and is_relation_made('amqp'):
325
+    op=relation_get(rid=relation_id())
326
+    if is_relation_made('identity-admin') and \
327
+       op.get('service_password',None) is not None:
328
+         hostname = ''
329
+         private_address =''
330
+         password = ''
331
+         auth_url = ('http://%s:5000/v3')%op['private-address']
332
+         set_value(OFDB, 'CONTROLLER' , 'AUTH_URL', auth_url)
333
+         ret = controller_config_identity(op)
334
+         if (ret != 0):
335
+                    log('Identity configuration failed for HyperScale. Check /var/opt/VRTSofcore/logs/ofengine.log for failure')
336
+                    assert(ret)
337
+         status_set('maintenance', 'Relation changed : identity-admin')
338
+         restart_services()
339
+
340
+    else:
341
+         log('HyperScale to keystone relation not made')
342
+         status_set('maintenance', 'Relation incomplete: identity-admin')
343
+         sys.exit(1)
344
+    hookenv.log("HyperScale identity-admin-relation-changed: Success")
345
+    return
346
+
347
+@hooks.hook('identity-admin-relation-departed')
348
+def identity_admin_relation_departed():
349
+    hostname = ''
350
+    private_address =''
351
+    password = ''
352
+    op=relation_get(rid=relation_id())
353
+    if op.get('service_password',None) is not None:
354
+        auth_url = ('http://%s:5000/v3')%op['private-address']
355
+	set_value(OFDB, 'CONTROLLER' , 'AUTH_URL', auth_url)
356
+	cmd = ('/opt/VRTSofcore/bin/ofexec --operation controller_unconf_juju '
357
+	'--params controller_ip=%s;openstack_passwd=%s;'
358
+	'region_name=%s --run'
359
+	)%(op['private-address'], op['service_password'],
360
+	op['service_region'])
361
+	lst = run_cmd(cmd.split(' '))
362
+	if (lst['ret'] != 0):
363
+		log('Check /var/opt/VRTSofcore/logs/ofengine.log for failure')
364
+		assert(lst['ret'] == 0)
365
+    else:
366
+        delete_value(OFDB, 'CONTROLLER', 'MGMT_INTF')
367
+
368
+    return
369
+
370
+@hooks.hook('update-status')
371
+def update_status():
372
+    # Check status of services and update status accordingly
373
+    failed_services = []
374
+    rel_miss = relationship_status()
375
+    if not rel_miss:
376
+        for service in hs_services:
377
+            if not service_running(service):
378
+               failed_services.append(service)
379
+        if not failed_services:
380
+            status_set('active', 'HyperScale Unit ready')
381
+        else:
382
+            status_set('maintenance', 'Some Hyperscale services have failed : ' + ' '.join(failed_services))
383
+            sys.exit(1)
384
+    else:
385
+        status_set('blocked', 'Missing relations : ' + ' '.join(rel_miss))
386
+
387
+@hooks.hook('start')
388
+def start():
389
+    open_port(ZK_PORT)
390
+    open_port(HS_API_PORT)
391
+    if not relationship_status():
392
+       status_set('waiting', 'Hyperscale service will start after relations are complete') 
393
+    else:
394
+       restart_services()
395
+
396
+
397
+if __name__ == '__main__':
398
+    try:
399
+        hooks.execute(sys.argv)
400
+    except UnregisteredHookError as e:
401
+        hookenv.log('Unknown hook {} - skipping.'.format(e))
Back to file index

hooks/db-admin-relation-changed

  1
--- 
  2
+++ hooks/db-admin-relation-changed
  3
@@ -0,0 +1,398 @@
  4
+#!/usr/bin/python
  5
+# Copyright 2016 Canonical Ltd
  6
+#
  7
+# Licensed under the Apache License, Version 2.0 (the "License");
  8
+# you may not use this file except in compliance with the License.
  9
+# You may obtain a copy of the License at
 10
+#
 11
+#  http://www.apache.org/licenses/LICENSE-2.0
 12
+#
 13
+# Unless required by applicable law or agreed to in writing, software
 14
+# distributed under the License is distributed on an "AS IS" BASIS,
 15
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 16
+# See the License for the specific language governing permissions and
 17
+# limitations under the License.
 18
+
 19
+import sys
 20
+import os
 21
+import json
 22
+import subprocess 
 23
+
 24
+sys.path.append('lib')
 25
+from charmhelpers.core import hookenv
 26
+from charmhelpers.core.hookenv import (
 27
+    config,
 28
+    status_set,
 29
+    is_relation_made,
 30
+    relation_set,
 31
+    relation_get,
 32
+    relation_ids,
 33
+    relation_id,
 34
+    resource_get,
 35
+    unit_get,
 36
+    open_port,
 37
+    Hooks,
 38
+    log,
 39
+    UnregisteredHookError,
 40
+    network_get_primary_address,
 41
+ )
 42
+from hyperscale_utils import (
 43
+    sync_db,
 44
+    set_value,
 45
+    get_value,
 46
+    delete_value,
 47
+    get_openflame_version,
 48
+    update_openflame_nodes,
 49
+    delete_db,
 50
+    run_cmd,
 51
+    controller_save_config,
 52
+    install_zk,
 53
+    controller_ceil_config,
 54
+    controller_copy_files,
 55
+    controller_config_horizon,
 56
+    create_rabbitmq_exchange,
 57
+    delete_rabbitmq_exchange,
 58
+    mysql_controller_config,
 59
+    controller_config_repo,
 60
+    controller_config_identity,
 61
+    priv_grant_hyperscale,
 62
+)
 63
+
 64
+from charmhelpers.core.host import (
 65
+    service_restart,
 66
+    service_running,
 67
+)
 68
+
 69
+
 70
+hooks = Hooks()
 71
+os.putenv('LC_ALL', "C")
 72
+OFDB = "/var/opt/VRTSofcore/ofdb"
 73
+PYTHON2 = "/usr/bin/python2.7"
 74
+AMQP_CONF = '/opt/VRTSofcore/etc/amqp.conf'
 75
+RABBITMQ_PLUGINS = '/usr/sbin/rabbitmq-plugins'
 76
+NETINTFS = '/var/opt/VRTSofcore/.netintfs'
 77
+ZK_PORT="42181"
 78
+HS_API_PORT="8753"
 79
+hs_services =  [ 'hyperscale-api.service',
 80
+    'hyperscale-mq-consumer.service',
 81
+    'hyperscale-mq-controller.service',
 82
+    'hyperscale-serengeti.service',
 83
+    'hyperscale-zookeeper.service',
 84
+    'hyperscale-ceilometer.service',
 85
+]
 86
+
 87
+hs_relations = ['identity-admin', 'shared-db', 'db-admin', 'amqp']
 88
+
 89
+def relationship_status():
 90
+    rel_miss = []
 91
+    for rel in hs_relations:
 92
+        if not is_relation_made(rel):
 93
+            rel_miss.append(rel)
 94
+    return rel_miss
 95
+
 96
+def restart_services():
 97
+    if not relationship_status():
 98
+        for service in hs_services:
 99
+             service_restart(service)
100
+    else:
101
+        hookenv.log('Missing relations. Cannot start HyperScale services')
102
+
103
+@hooks.hook('install.next')
104
+def install():
105
+    hookenv.log('Installing Zookeeper')
106
+    cmd = "touch " + OFDB
107
+    os.system(cmd)
108
+    install_zk()
109
+    controller_config_repo()
110
+    set_value(OFDB, 'CONTROLLER' , 'CONFIG_DONE', "0")
111
+    status_set('maintenance', 'Installation done for HyperScale Packages')
112
+
113
+@hooks.hook('config-changed')
114
+def config_changed():
115
+    hookenv.log('Configuring HyperScale')
116
+
117
+    is_config_done = get_value(OFDB, 'CONTROLLER', 'CONFIG_DONE')
118
+    if is_config_done == '0':
119
+        hostip = unit_get('private-address')
120
+        controller_save_config(hostip)
121
+        cmd = (PYTHON2  + ' -B /opt/VRTSofmn/adm/dna_netinfo.py')
122
+        lst = run_cmd(cmd.split(' '))
123
+        print lst
124
+        hookenv.log(hostip)
125
+        controller_ceil_config()
126
+        controller_copy_files()
127
+        controller_config_horizon(hostip)
128
+        set_value(OFDB, 'CONTROLLER' , 'CONFIG_DONE', "1")
129
+        rel_miss = relationship_status()
130
+        if not rel_miss:
131
+            status_set('maintenance', 'Relations complete. Status will be updated after services restart')
132
+        else:
133
+            status_set('blocked', 'Missing relations : ' + ' '.join(rel_miss))
134
+
135
+    hookenv.log("HyperScale config-changed: Success")
136
+
137
+@hooks.hook('db-admin-relation-joined')
138
+def db_admin_joined():
139
+     host = None
140
+     conf = config()
141
+     hookenv.log('Creating relation db-admin')
142
+     hookenv.log(conf['database-user'])
143
+     try:
144
+        host = network_get_primary_address('shared-db')
145
+     except NotImplementedError:
146
+        host = unit_get('private-address')
147
+
148
+     relation_set(database=conf['database'],
149
+        hostname=host)
150
+     status_set('maintenance', 'Relation observed: db-admin')
151
+     hookenv.log("HyperScale db-admin-relation-joined: Success")
152
+
153
+@hooks.hook('db-admin-relation-changed')
154
+def db_admin_changed():
155
+     conf = config()
156
+     host = None
157
+     passwd = relation_get('password')
158
+     host = relation_get('host')
159
+     user = relation_get('user')
160
+     set_value(OFDB, 'CONTROLLER' , 'DB_ADMIN_USER', user)
161
+     set_value(OFDB, 'CONTROLLER' , 'DB_ADMIN_PASSWD', passwd)
162
+     set_value(OFDB, 'CONTROLLER' , 'DB_HOST', host)
163
+     if is_relation_made('shared-db'):
164
+         ret = priv_grant_hyperscale()
165
+         if ret != 0:
166
+             hookenv.log('Grant access for HyperScale failed. Check logs')
167
+             sys.exit(1)
168
+         restart_services()
169
+         status_set('maintenance', 'Relation changed : db-admin')
170
+     else:
171
+         hookenv.log("DB grant for HyperScale user will be done after shared-db relation completes")
172
+         status_set('blocked','Waiting for shared-db relation to be made')
173
+     hookenv.log("HyperScale db-admin-relation-changed: Success")
174
+
175
+@hooks.hook('db-admin-relation-departed')
176
+def db_admin_departed():
177
+    pass
178
+
179
+@hooks.hook('db-admin-relation-broken')
180
+def db_admin_broken():
181
+    pass
182
+
183
+@hooks.hook('shared-db-relation-joined')
184
+def db_joined():
185
+     host = None
186
+     conf = config()
187
+     hookenv.log('Creating Relation')
188
+     hookenv.log(conf['database-user'])
189
+     try:
190
+        host = network_get_primary_address('shared-db')
191
+     except NotImplementedError:
192
+        host = unit_get('private-address')
193
+
194
+     status_set('maintenance', 'Relation observed: shared-db')
195
+     relation_set(database=conf['database'],
196
+        username=conf['database-user'],
197
+        hostname=host)
198
+     hookenv.log("HyperScale shared-db-relation-joined: Success")
199
+
200
+@hooks.hook('shared-db-relation-changed')
201
+def db_changed():
202
+     if is_relation_made('shared-db'):
203
+        conf = config()
204
+        host = None
205
+        try:
206
+            host = network_get_primary_address('shared-db')
207
+        except NotImplementedError:
208
+            host = unit_get('private-address')
209
+
210
+        status_set('maintenance', 'Relation joined: shared-db')
211
+        passwd = relation_get('password')
212
+        db_host = relation_get('db_host')
213
+        ctlr_ip = unit_get('private-address')
214
+        try:
215
+            sync_db(db_host, passwd)
216
+            IDGEN='/opt/VRTSofcore/adm/idgen.py'
217
+            if os.path.isfile(IDGEN):
218
+                of_version = get_openflame_version()
219
+                ctlid = subprocess.check_output([IDGEN, "--type", "hostid"])
220
+                set_value(OFDB, 'CONTROLLER' , 'CTLR_INSTANCE_HOSTID', ctlid)
221
+                hostname = get_value(OFDB, 'CONTROLLER', 'CONTROLLER_NAME')
222
+                retval = update_openflame_nodes(db_host, passwd, hostname, ctlid,
223
+                                                ctlr_ip, 'N/A',
224
+                                                'controller', 'up', ctlid, of_version)
225
+            mysql_controller_config(db_host,passwd)
226
+            restart_services()
227
+            if is_relation_made('db-admin'): 
228
+            # If db-admin relation happened before shared-db, then grant permissions from here
229
+                ret = priv_grant_hyperscale()
230
+                if ret != 0:
231
+                   hookenv.log('Error granting permission to HyperScale user. Check logs')
232
+                   sys.exit(1)
233
+        except Exception as e:
234
+            errstr = 'Error creating database on controller' + str(e)
235
+            hookenv.log(errstr)
236
+            sys.exit(1)
237
+     else:
238
+        hookenv.log('Relation shared-db not complete. Will retry')
239
+        sys.exit(1)
240
+     hookenv.log("HyperScale shared-db-relation-changed: Success")
241
+
242
+@hooks.hook('shared-db-relation-broken')
243
+def db_broken():
244
+    status_set('maintenance', 'Shared-db: broken')
245
+    return
246
+
247
+@hooks.hook('shared-db-relation-departed')
248
+def db_departed():
249
+    status_set('maintenance', 'Shared-db: departed')
250
+    passwd = relation_get('password')
251
+    db_host = relation_get('db_host')
252
+    delete_db(db_host, passwd)
253
+    return
254
+
255
+@hooks.hook('amqp-relation-joined')
256
+def rabbitmq_relation_joined():
257
+    relation_id = None
258
+    conf = config()
259
+    relation_set(relation_id=relation_id,
260
+                 username='hyperscale', vhost='/' , admin=True)
261
+    cmd = RABBITMQ_PLUGINS + ' enable rabbitmq_management'
262
+    subprocess.call(cmd.split(' '))
263
+    service_restart('rabbitmq-server')
264
+    status_set('maintenance', 'Relation joined: amqp')
265
+    hookenv.log("HyperScale amqp-relation-joined: Success")
266
+    return
267
+
268
+
269
+@hooks.hook('amqp-relation-changed')
270
+def rabbitmq_relation_changed():
271
+    if is_relation_made('amqp'):
272
+        hostname = ''
273
+        private_address =''
274
+        password = ''
275
+        op=relation_get(rid=relation_id())
276
+        rel_data = list(op.keys())
277
+
278
+        if 'password' in rel_data and 'private-address' in rel_data:
279
+            hostname = str(op['hostname']) if 'hostname' in rel_data else ''
280
+            private_address = str(op['private-address'])
281
+            password = str (op['password'])
282
+            create_rabbitmq_exchange('/',private_address=private_address,
283
+                password=password)
284
+            with open(AMQP_CONF,'r') as json_file:
285
+                json_data = json.load(json_file)
286
+                json_file.close()
287
+            json_data['server'] = private_address
288
+            json_data['port'] = 5672
289
+            json_data['user'] = 'hyperscale'
290
+            json_data['password'] = password
291
+            with open(AMQP_CONF ,'w') as json_file:
292
+                json.dump(json_data,json_file)
293
+                json_file.close()
294
+            set_value(OFDB, 'CONTROLLER', 'RABBITMQ_PORT', '5672')
295
+        restart_services()
296
+
297
+        status_set('maintenance', 'Relation changed: amqp')
298
+    else:
299
+        log('HyperScale to rabbitmq connection not made')
300
+        status_set('maintenance', 'Relation incomplete: amqp')
301
+    hookenv.log("HyperScale amqp-relation-changed: Success")
302
+    return
303
+
304
+
305
+@hooks.hook('amqp-relation-departed')
306
+def rabbitmq_relation_departed():
307
+    hostname = ''
308
+    private_address =''
309
+    password = ''
310
+    op=relation_get(rid=relation_id())
311
+    rel_data = list(op.keys())
312
+    if op is not None:
313
+        if 'password' in rel_data and 'private-address' in rel_data:
314
+            hostname = str(op['hostname']) if 'hostname' in rel_data else ''
315
+            private_address = str(op['private-address'])
316
+            password= str (op['password'])
317
+            delete_rabbitmq_exchange('/',private_address=private_address,
318
+                password=password)
319
+    return
320
+
321
+@hooks.hook('identity-admin-relation-changed')
322
+def identity_admin_relation_changed():
323
+  #  if is_relation_made('identity-admin') and is_relation_made('shared-db') \
324
+   #    and is_relation_made('amqp'):
325
+    op=relation_get(rid=relation_id())
326
+    if is_relation_made('identity-admin') and \
327
+       op.get('service_password',None) is not None:
328
+         hostname = ''
329
+         private_address =''
330
+         password = ''
331
+         auth_url = ('http://%s:5000/v3')%op['private-address']
332
+         set_value(OFDB, 'CONTROLLER' , 'AUTH_URL', auth_url)
333
+         ret = controller_config_identity(op)
334
+         if (ret != 0):
335
+                    log('Identity configuration failed for HyperScale. Check /var/opt/VRTSofcore/logs/ofengine.log for failure')
336
+                    assert(ret)
337
+         status_set('maintenance', 'Relation changed : identity-admin')
338
+         restart_services()
339
+
340
+    else:
341
+         log('HyperScale to keystone relation not made')
342
+         status_set('maintenance', 'Relation incomplete: identity-admin')
343
+         sys.exit(1)
344
+    hookenv.log("HyperScale identity-admin-relation-changed: Success")
345
+    return
346
+
347
+@hooks.hook('identity-admin-relation-departed')
348
+def identity_admin_relation_departed():
349
+    hostname = ''
350
+    private_address =''
351
+    password = ''
352
+    op=relation_get(rid=relation_id())
353
+    if op.get('service_password',None) is not None:
354
+        auth_url = ('http://%s:5000/v3')%op['private-address']
355
+	set_value(OFDB, 'CONTROLLER' , 'AUTH_URL', auth_url)
356
+	cmd = ('/opt/VRTSofcore/bin/ofexec --operation controller_unconf_juju '
357
+	'--params controller_ip=%s;openstack_passwd=%s;'
358
+	'region_name=%s --run'
359
+	)%(op['private-address'], op['service_password'],
360
+	op['service_region'])
361
+	lst = run_cmd(cmd.split(' '))
362
+	if (lst['ret'] != 0):
363
+		log('Check /var/opt/VRTSofcore/logs/ofengine.log for failure')
364
+		assert(lst['ret'] == 0)
365
+    else:
366
+        delete_value(OFDB, 'CONTROLLER', 'MGMT_INTF')
367
+
368
+    return
369
+
370
+@hooks.hook('update-status')
371
+def update_status():
372
+    # Check status of services and update status accordingly
373
+    failed_services = []
374
+    rel_miss = relationship_status()
375
+    if not rel_miss:
376
+        for service in hs_services:
377
+            if not service_running(service):
378
+               failed_services.append(service)
379
+        if not failed_services:
380
+            status_set('active', 'HyperScale Unit ready')
381
+        else:
382
+            status_set('maintenance', 'Some Hyperscale services have failed : ' + ' '.join(failed_services))
383
+            sys.exit(1)
384
+    else:
385
+        status_set('blocked', 'Missing relations : ' + ' '.join(rel_miss))
386
+
387
+@hooks.hook('start')
388
+def start():
389
+    open_port(ZK_PORT)
390
+    open_port(HS_API_PORT)
391
+    if not relationship_status():
392
+       status_set('waiting', 'Hyperscale service will start after relations are complete') 
393
+    else:
394
+       restart_services()
395
+
396
+
397
+if __name__ == '__main__':
398
+    try:
399
+        hooks.execute(sys.argv)
400
+    except UnregisteredHookError as e:
401
+        hookenv.log('Unknown hook {} - skipping.'.format(e))
Back to file index

hooks/db-admin-relation-departed

  1
--- 
  2
+++ hooks/db-admin-relation-departed
  3
@@ -0,0 +1,398 @@
  4
+#!/usr/bin/python
  5
+# Copyright 2016 Canonical Ltd
  6
+#
  7
+# Licensed under the Apache License, Version 2.0 (the "License");
  8
+# you may not use this file except in compliance with the License.
  9
+# You may obtain a copy of the License at
 10
+#
 11
+#  http://www.apache.org/licenses/LICENSE-2.0
 12
+#
 13
+# Unless required by applicable law or agreed to in writing, software
 14
+# distributed under the License is distributed on an "AS IS" BASIS,
 15
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 16
+# See the License for the specific language governing permissions and
 17
+# limitations under the License.
 18
+
 19
+import sys
 20
+import os
 21
+import json
 22
+import subprocess 
 23
+
 24
+sys.path.append('lib')
 25
+from charmhelpers.core import hookenv
 26
+from charmhelpers.core.hookenv import (
 27
+    config,
 28
+    status_set,
 29
+    is_relation_made,
 30
+    relation_set,
 31
+    relation_get,
 32
+    relation_ids,
 33
+    relation_id,
 34
+    resource_get,
 35
+    unit_get,
 36
+    open_port,
 37
+    Hooks,
 38
+    log,
 39
+    UnregisteredHookError,
 40
+    network_get_primary_address,
 41
+ )
 42
+from hyperscale_utils import (
 43
+    sync_db,
 44
+    set_value,
 45
+    get_value,
 46
+    delete_value,
 47
+    get_openflame_version,
 48
+    update_openflame_nodes,
 49
+    delete_db,
 50
+    run_cmd,
 51
+    controller_save_config,
 52
+    install_zk,
 53
+    controller_ceil_config,
 54
+    controller_copy_files,
 55
+    controller_config_horizon,
 56
+    create_rabbitmq_exchange,
 57
+    delete_rabbitmq_exchange,
 58
+    mysql_controller_config,
 59
+    controller_config_repo,
 60
+    controller_config_identity,
 61
+    priv_grant_hyperscale,
 62
+)
 63
+
 64
+from charmhelpers.core.host import (
 65
+    service_restart,
 66
+    service_running,
 67
+)
 68
+
 69
+
 70
+hooks = Hooks()
 71
+os.putenv('LC_ALL', "C")
 72
+OFDB = "/var/opt/VRTSofcore/ofdb"
 73
+PYTHON2 = "/usr/bin/python2.7"
 74
+AMQP_CONF = '/opt/VRTSofcore/etc/amqp.conf'
 75
+RABBITMQ_PLUGINS = '/usr/sbin/rabbitmq-plugins'
 76
+NETINTFS = '/var/opt/VRTSofcore/.netintfs'
 77
+ZK_PORT="42181"
 78
+HS_API_PORT="8753"
 79
+hs_services =  [ 'hyperscale-api.service',
 80
+    'hyperscale-mq-consumer.service',
 81
+    'hyperscale-mq-controller.service',
 82
+    'hyperscale-serengeti.service',
 83
+    'hyperscale-zookeeper.service',
 84
+    'hyperscale-ceilometer.service',
 85
+]
 86
+
 87
+hs_relations = ['identity-admin', 'shared-db', 'db-admin', 'amqp']
 88
+
 89
+def relationship_status():
 90
+    rel_miss = []
 91
+    for rel in hs_relations:
 92
+        if not is_relation_made(rel):
 93
+            rel_miss.append(rel)
 94
+    return rel_miss
 95
+
 96
+def restart_services():
 97
+    if not relationship_status():
 98
+        for service in hs_services:
 99
+             service_restart(service)
100
+    else:
101
+        hookenv.log('Missing relations. Cannot start HyperScale services')
102
+
103
+@hooks.hook('install.next')
104
+def install():
105
+    hookenv.log('Installing Zookeeper')
106
+    cmd = "touch " + OFDB
107
+    os.system(cmd)
108
+    install_zk()
109
+    controller_config_repo()
110
+    set_value(OFDB, 'CONTROLLER' , 'CONFIG_DONE', "0")
111
+    status_set('maintenance', 'Installation done for HyperScale Packages')
112
+
113
+@hooks.hook('config-changed')
114
+def config_changed():
115
+    hookenv.log('Configuring HyperScale')
116
+
117
+    is_config_done = get_value(OFDB, 'CONTROLLER', 'CONFIG_DONE')
118
+    if is_config_done == '0':
119
+        hostip = unit_get('private-address')
120
+        controller_save_config(hostip)
121
+        cmd = (PYTHON2  + ' -B /opt/VRTSofmn/adm/dna_netinfo.py')
122
+        lst = run_cmd(cmd.split(' '))
123
+        print lst
124
+        hookenv.log(hostip)
125
+        controller_ceil_config()
126
+        controller_copy_files()
127
+        controller_config_horizon(hostip)
128
+        set_value(OFDB, 'CONTROLLER' , 'CONFIG_DONE', "1")
129
+        rel_miss = relationship_status()
130
+        if not rel_miss:
131
+            status_set('maintenance', 'Relations complete. Status will be updated after services restart')
132
+        else:
133
+            status_set('blocked', 'Missing relations : ' + ' '.join(rel_miss))
134
+
135
+    hookenv.log("HyperScale config-changed: Success")
136
+
137
+@hooks.hook('db-admin-relation-joined')
138
+def db_admin_joined():
139
+     host = None
140
+     conf = config()
141
+     hookenv.log('Creating relation db-admin')
142
+     hookenv.log(conf['database-user'])
143
+     try:
144
+        host = network_get_primary_address('shared-db')
145
+     except NotImplementedError:
146
+        host = unit_get('private-address')
147
+
148
+     relation_set(database=conf['database'],
149
+        hostname=host)
150
+     status_set('maintenance', 'Relation observed: db-admin')
151
+     hookenv.log("HyperScale db-admin-relation-joined: Success")
152
+
153
+@hooks.hook('db-admin-relation-changed')
154
+def db_admin_changed():
155
+     conf = config()
156
+     host = None
157
+     passwd = relation_get('password')
158
+     host = relation_get('host')
159
+     user = relation_get('user')
160
+     set_value(OFDB, 'CONTROLLER' , 'DB_ADMIN_USER', user)
161
+     set_value(OFDB, 'CONTROLLER' , 'DB_ADMIN_PASSWD', passwd)
162
+     set_value(OFDB, 'CONTROLLER' , 'DB_HOST', host)
163
+     if is_relation_made('shared-db'):
164
+         ret = priv_grant_hyperscale()
165
+         if ret != 0:
166
+             hookenv.log('Grant access for HyperScale failed. Check logs')
167
+             sys.exit(1)
168
+         restart_services()
169
+         status_set('maintenance', 'Relation changed : db-admin')
170
+     else:
171
+         hookenv.log("DB grant for HyperScale user will be done after shared-db relation completes")
172
+         status_set('blocked','Waiting for shared-db relation to be made')
173
+     hookenv.log("HyperScale db-admin-relation-changed: Success")
174
+
175
+@hooks.hook('db-admin-relation-departed')
176
+def db_admin_departed():
177
+    pass
178
+
179
+@hooks.hook('db-admin-relation-broken')
180
+def db_admin_broken():
181
+    pass
182
+
183
+@hooks.hook('shared-db-relation-joined')
184
+def db_joined():
185
+     host = None
186
+     conf = config()
187
+     hookenv.log('Creating Relation')
188
+     hookenv.log(conf['database-user'])
189
+     try:
190
+        host = network_get_primary_address('shared-db')
191
+     except NotImplementedError:
192
+        host = unit_get('private-address')
193
+
194
+     status_set('maintenance', 'Relation observed: shared-db')
195
+     relation_set(database=conf['database'],
196
+        username=conf['database-user'],
197
+        hostname=host)
198
+     hookenv.log("HyperScale shared-db-relation-joined: Success")
199
+
200
+@hooks.hook('shared-db-relation-changed')
201
+def db_changed():
202
+     if is_relation_made('shared-db'):
203
+        conf = config()
204
+        host = None
205
+        try:
206
+            host = network_get_primary_address('shared-db')
207
+        except NotImplementedError:
208
+            host = unit_get('private-address')
209
+
210
+        status_set('maintenance', 'Relation joined: shared-db')
211
+        passwd = relation_get('password')
212
+        db_host = relation_get('db_host')
213
+        ctlr_ip = unit_get('private-address')
214
+        try:
215
+            sync_db(db_host, passwd)
216
+            IDGEN='/opt/VRTSofcore/adm/idgen.py'
217
+            if os.path.isfile(IDGEN):
218
+                of_version = get_openflame_version()
219
+                ctlid = subprocess.check_output([IDGEN, "--type", "hostid"])
220
+                set_value(OFDB, 'CONTROLLER' , 'CTLR_INSTANCE_HOSTID', ctlid)
221
+                hostname = get_value(OFDB, 'CONTROLLER', 'CONTROLLER_NAME')
222
+                retval = update_openflame_nodes(db_host, passwd, hostname, ctlid,
223
+                                                ctlr_ip, 'N/A',
224
+                                                'controller', 'up', ctlid, of_version)
225
+            mysql_controller_config(db_host,passwd)
226
+            restart_services()
227
+            if is_relation_made('db-admin'): 
228
+            # If db-admin relation happened before shared-db, then grant permissions from here
229
+                ret = priv_grant_hyperscale()
230
+                if ret != 0:
231
+                   hookenv.log('Error granting permission to HyperScale user. Check logs')
232
+                   sys.exit(1)
233
+        except Exception as e:
234
+            errstr = 'Error creating database on controller' + str(e)
235
+            hookenv.log(errstr)
236
+            sys.exit(1)
237
+     else:
238
+        hookenv.log('Relation shared-db not complete. Will retry')
239
+        sys.exit(1)
240
+     hookenv.log("HyperScale shared-db-relation-changed: Success")
241
+
242
+@hooks.hook('shared-db-relation-broken')
243
+def db_broken():
244
+    status_set('maintenance', 'Shared-db: broken')
245
+    return
246
+
247
+@hooks.hook('shared-db-relation-departed')
248
+def db_departed():
249
+    status_set('maintenance', 'Shared-db: departed')
250
+    passwd = relation_get('password')
251
+    db_host = relation_get('db_host')
252
+    delete_db(db_host, passwd)
253
+    return
254
+
255
+@hooks.hook('amqp-relation-joined')
256
+def rabbitmq_relation_joined():
257
+    relation_id = None
258
+    conf = config()
259
+    relation_set(relation_id=relation_id,
260
+                 username='hyperscale', vhost='/' , admin=True)
261
+    cmd = RABBITMQ_PLUGINS + ' enable rabbitmq_management'
262
+    subprocess.call(cmd.split(' '))
263
+    service_restart('rabbitmq-server')
264
+    status_set('maintenance', 'Relation joined: amqp')
265
+    hookenv.log("HyperScale amqp-relation-joined: Success")
266
+    return
267
+
268
+
269
+@hooks.hook('amqp-relation-changed')
270
+def rabbitmq_relation_changed():
271
+    if is_relation_made('amqp'):
272
+        hostname = ''
273
+        private_address =''
274
+        password = ''
275
+        op=relation_get(rid=relation_id())
276
+        rel_data = list(op.keys())
277
+
278
+        if 'password' in rel_data and 'private-address' in rel_data:
279
+            hostname = str(op['hostname']) if 'hostname' in rel_data else ''
280
+            private_address = str(op['private-address'])
281
+            password = str (op['password'])
282
+            create_rabbitmq_exchange('/',private_address=private_address,
283
+                password=password)
284
+            with open(AMQP_CONF,'r') as json_file:
285
+                json_data = json.load(json_file)
286
+                json_file.close()
287
+            json_data['server'] = private_address
288
+            json_data['port'] = 5672
289
+            json_data['user'] = 'hyperscale'
290
+            json_data['password'] = password
291
+            with open(AMQP_CONF ,'w') as json_file:
292
+                json.dump(json_data,json_file)
293
+                json_file.close()
294
+            set_value(OFDB, 'CONTROLLER', 'RABBITMQ_PORT', '5672')
295
+        restart_services()
296
+
297
+        status_set('maintenance', 'Relation changed: amqp')
298
+    else:
299
+        log('HyperScale to rabbitmq connection not made')
300
+        status_set('maintenance', 'Relation incomplete: amqp')
301
+    hookenv.log("HyperScale amqp-relation-changed: Success")
302
+    return
303
+
304
+
305
+@hooks.hook('amqp-relation-departed')
306
+def rabbitmq_relation_departed():
307
+    hostname = ''
308
+    private_address =''
309
+    password = ''
310
+    op=relation_get(rid=relation_id())
311
+    rel_data = list(op.keys())
312
+    if op is not None:
313
+        if 'password' in rel_data and 'private-address' in rel_data:
314
+            hostname = str(op['hostname']) if 'hostname' in rel_data else ''
315
+            private_address = str(op['private-address'])
316
+            password= str (op['password'])
317
+            delete_rabbitmq_exchange('/',private_address=private_address,
318
+                password=password)
319
+    return
320
+
321
+@hooks.hook('identity-admin-relation-changed')
322
+def identity_admin_relation_changed():
323
+  #  if is_relation_made('identity-admin') and is_relation_made('shared-db') \
324
+   #    and is_relation_made('amqp'):
325
+    op=relation_get(rid=relation_id())
326
+    if is_relation_made('identity-admin') and \
327
+       op.get('service_password',None) is not None:
328
+         hostname = ''
329
+         private_address =''
330
+         password = ''
331
+         auth_url = ('http://%s:5000/v3')%op['private-address']
332
+         set_value(OFDB, 'CONTROLLER' , 'AUTH_URL', auth_url)
333
+         ret = controller_config_identity(op)
334
+         if (ret != 0):
335
+                    log('Identity configuration failed for HyperScale. Check /var/opt/VRTSofcore/logs/ofengine.log for failure')
336
+                    assert(ret)
337
+         status_set('maintenance', 'Relation changed : identity-admin')
338
+         restart_services()
339
+
340
+    else:
341
+         log('HyperScale to keystone relation not made')
342
+         status_set('maintenance', 'Relation incomplete: identity-admin')
343
+         sys.exit(1)
344
+    hookenv.log("HyperScale identity-admin-relation-changed: Success")
345
+    return
346
+
347
+@hooks.hook('identity-admin-relation-departed')
348
+def identity_admin_relation_departed():
349
+    hostname = ''
350
+    private_address =''
351
+    password = ''
352
+    op=relation_get(rid=relation_id())
353
+    if op.get('service_password',None) is not None:
354
+        auth_url = ('http://%s:5000/v3')%op['private-address']
355
+	set_value(OFDB, 'CONTROLLER' , 'AUTH_URL', auth_url)
356
+	cmd = ('/opt/VRTSofcore/bin/ofexec --operation controller_unconf_juju '
357
+	'--params controller_ip=%s;openstack_passwd=%s;'
358
+	'region_name=%s --run'
359
+	)%(op['private-address'], op['service_password'],
360
+	op['service_region'])
361
+	lst = run_cmd(cmd.split(' '))
362
+	if (lst['ret'] != 0):
363
+		log('Check /var/opt/VRTSofcore/logs/ofengine.log for failure')
364
+		assert(lst['ret'] == 0)
365
+    else:
366
+        delete_value(OFDB, 'CONTROLLER', 'MGMT_INTF')
367
+
368
+    return
369
+
370
+@hooks.hook('update-status')
371
+def update_status():
372
+    # Check status of services and update status accordingly
373
+    failed_services = []
374
+    rel_miss = relationship_status()
375
+    if not rel_miss:
376
+        for service in hs_services:
377
+            if not service_running(service):
378
+               failed_services.append(service)
379
+        if not failed_services:
380
+            status_set('active', 'HyperScale Unit ready')
381
+        else:
382
+            status_set('maintenance', 'Some Hyperscale services have failed : ' + ' '.join(failed_services))
383
+            sys.exit(1)
384
+    else:
385
+        status_set('blocked', 'Missing relations : ' + ' '.join(rel_miss))
386
+
387
+@hooks.hook('start')
388
+def start():
389
+    open_port(ZK_PORT)
390
+    open_port(HS_API_PORT)
391
+    if not relationship_status():
392
+       status_set('waiting', 'Hyperscale service will start after relations are complete') 
393
+    else:
394
+       restart_services()
395
+
396
+
397
+if __name__ == '__main__':
398
+    try:
399
+        hooks.execute(sys.argv)
400
+    except UnregisteredHookError as e:
401
+        hookenv.log('Unknown hook {} - skipping.'.format(e))
Back to file index

hooks/db-admin-relation-joined

  1
--- 
  2
+++ hooks/db-admin-relation-joined
  3
@@ -0,0 +1,398 @@
  4
+#!/usr/bin/python
  5
+# Copyright 2016 Canonical Ltd
  6
+#
  7
+# Licensed under the Apache License, Version 2.0 (the "License");
  8
+# you may not use this file except in compliance with the License.
  9
+# You may obtain a copy of the License at
 10
+#
 11
+#  http://www.apache.org/licenses/LICENSE-2.0
 12
+#
 13
+# Unless required by applicable law or agreed to in writing, software
 14
+# distributed under the License is distributed on an "AS IS" BASIS,
 15
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 16
+# See the License for the specific language governing permissions and
 17
+# limitations under the License.
 18
+
 19
+import sys
 20
+import os
 21
+import json
 22
+import subprocess 
 23
+
 24
+sys.path.append('lib')
 25
+from charmhelpers.core import hookenv
 26
+from charmhelpers.core.hookenv import (
 27
+    config,
 28
+    status_set,
 29
+    is_relation_made,
 30
+    relation_set,
 31
+    relation_get,
 32
+    relation_ids,
 33
+    relation_id,
 34
+    resource_get,
 35
+    unit_get,
 36
+    open_port,
 37
+    Hooks,
 38
+    log,
 39
+    UnregisteredHookError,
 40
+    network_get_primary_address,
 41
+ )
 42
+from hyperscale_utils import (
 43
+    sync_db,
 44
+    set_value,
 45
+    get_value,
 46
+    delete_value,
 47
+    get_openflame_version,
 48
+    update_openflame_nodes,
 49
+    delete_db,
 50
+    run_cmd,
 51
+    controller_save_config,
 52
+    install_zk,
 53
+    controller_ceil_config,
 54
+    controller_copy_files,
 55
+    controller_config_horizon,
 56
+    create_rabbitmq_exchange,
 57
+    delete_rabbitmq_exchange,
 58
+    mysql_controller_config,
 59
+    controller_config_repo,
 60
+    controller_config_identity,
 61
+    priv_grant_hyperscale,
 62
+)
 63
+
 64
+from charmhelpers.core.host import (
 65
+    service_restart,
 66
+    service_running,
 67
+)
 68
+
 69
+
 70
+hooks = Hooks()
 71
+os.putenv('LC_ALL', "C")
 72
+OFDB = "/var/opt/VRTSofcore/ofdb"
 73
+PYTHON2 = "/usr/bin/python2.7"
 74
+AMQP_CONF = '/opt/VRTSofcore/etc/amqp.conf'
 75
+RABBITMQ_PLUGINS = '/usr/sbin/rabbitmq-plugins'
 76
+NETINTFS = '/var/opt/VRTSofcore/.netintfs'
 77
+ZK_PORT="42181"
 78
+HS_API_PORT="8753"
 79
+hs_services =  [ 'hyperscale-api.service',
 80
+    'hyperscale-mq-consumer.service',
 81
+    'hyperscale-mq-controller.service',
 82
+    'hyperscale-serengeti.service',
 83
+    'hyperscale-zookeeper.service',
 84
+    'hyperscale-ceilometer.service',
 85
+]
 86
+
 87
+hs_relations = ['identity-admin', 'shared-db', 'db-admin', 'amqp']
 88
+
 89
+def relationship_status():
 90
+    rel_miss = []
 91
+    for rel in hs_relations:
 92
+        if not is_relation_made(rel):
 93
+            rel_miss.append(rel)
 94
+    return rel_miss
 95
+
 96
+def restart_services():
 97
+    if not relationship_status():
 98
+        for service in hs_services:
 99
+             service_restart(service)
100
+    else:
101
+        hookenv.log('Missing relations. Cannot start HyperScale services')
102
+
103
+@hooks.hook('install.next')
104
+def install():
105
+    hookenv.log('Installing Zookeeper')
106
+    cmd = "touch " + OFDB
107
+    os.system(cmd)
108
+    install_zk()
109
+    controller_config_repo()
110
+    set_value(OFDB, 'CONTROLLER' , 'CONFIG_DONE', "0")
111
+    status_set('maintenance', 'Installation done for HyperScale Packages')
112
+
113
+@hooks.hook('config-changed')
114
+def config_changed():
115
+    hookenv.log('Configuring HyperScale')
116
+
117
+    is_config_done = get_value(OFDB, 'CONTROLLER', 'CONFIG_DONE')
118
+    if is_config_done == '0':
119
+        hostip = unit_get('private-address')
120
+        controller_save_config(hostip)
121
+        cmd = (PYTHON2  + ' -B /opt/VRTSofmn/adm/dna_netinfo.py')
122
+        lst = run_cmd(cmd.split(' '))
123
+        print lst
124
+        hookenv.log(hostip)
125
+        controller_ceil_config()
126
+        controller_copy_files()
127
+        controller_config_horizon(hostip)
128
+        set_value(OFDB, 'CONTROLLER' , 'CONFIG_DONE', "1")
129
+        rel_miss = relationship_status()
130
+        if not rel_miss:
131
+            status_set('maintenance', 'Relations complete. Status will be updated after services restart')
132
+        else:
133
+            status_set('blocked', 'Missing relations : ' + ' '.join(rel_miss))
134
+
135
+    hookenv.log("HyperScale config-changed: Success")
136
+
137
+@hooks.hook('db-admin-relation-joined')
138
+def db_admin_joined():
139
+     host = None
140
+     conf = config()
141
+     hookenv.log('Creating relation db-admin')
142
+     hookenv.log(conf['database-user'])
143
+     try:
144
+        host = network_get_primary_address('shared-db')
145
+     except NotImplementedError:
146
+        host = unit_get('private-address')
147
+
148
+     relation_set(database=conf['database'],
149
+        hostname=host)
150
+     status_set('maintenance', 'Relation observed: db-admin')
151
+     hookenv.log("HyperScale db-admin-relation-joined: Success")
152
+
153
+@hooks.hook('db-admin-relation-changed')
154
+def db_admin_changed():
155
+     conf = config()
156
+     host = None
157
+     passwd = relation_get('password')
158
+     host = relation_get('host')
159
+     user = relation_get('user')
160
+     set_value(OFDB, 'CONTROLLER' , 'DB_ADMIN_USER', user)
161
+     set_value(OFDB, 'CONTROLLER' , 'DB_ADMIN_PASSWD', passwd)
162
+     set_value(OFDB, 'CONTROLLER' , 'DB_HOST', host)
163
+     if is_relation_made('shared-db'):
164
+         ret = priv_grant_hyperscale()
165
+         if ret != 0:
166
+             hookenv.log('Grant access for HyperScale failed. Check logs')
167
+             sys.exit(1)
168
+         restart_services()
169
+         status_set('maintenance', 'Relation changed : db-admin')
170
+     else:
171
+         hookenv.log("DB grant for HyperScale user will be done after shared-db relation completes")
172
+         status_set('blocked','Waiting for shared-db relation to be made')
173
+     hookenv.log("HyperScale db-admin-relation-changed: Success")
174
+
175
+@hooks.hook('db-admin-relation-departed')
176
+def db_admin_departed():
177
+    pass
178
+
179
+@hooks.hook('db-admin-relation-broken')
180
+def db_admin_broken():
181
+    pass
182
+
183
+@hooks.hook('shared-db-relation-joined')
184
+def db_joined():
185
+     host = None
186
+     conf = config()
187
+     hookenv.log('Creating Relation')
188
+     hookenv.log(conf['database-user'])
189
+     try:
190
+        host = network_get_primary_address('shared-db')
191
+     except NotImplementedError:
192
+        host = unit_get('private-address')
193
+
194
+     status_set('maintenance', 'Relation observed: shared-db')
195
+     relation_set(database=conf['database'],
196
+        username=conf['database-user'],
197
+        hostname=host)
198
+     hookenv.log("HyperScale shared-db-relation-joined: Success")
199
+
200
+@hooks.hook('shared-db-relation-changed')
201
+def db_changed():
202
+     if is_relation_made('shared-db'):
203
+        conf = config()
204
+        host = None
205
+        try:
206
+            host = network_get_primary_address('shared-db')
207
+        except NotImplementedError:
208
+            host = unit_get('private-address')
209
+
210
+        status_set('maintenance', 'Relation joined: shared-db')
211
+        passwd = relation_get('password')
212
+        db_host = relation_get('db_host')
213
+        ctlr_ip = unit_get('private-address')
214
+        try:
215
+            sync_db(db_host, passwd)
216
+            IDGEN='/opt/VRTSofcore/adm/idgen.py'
217
+            if os.path.isfile(IDGEN):
218
+                of_version = get_openflame_version()
219
+                ctlid = subprocess.check_output([IDGEN, "--type", "hostid"])
220
+                set_value(OFDB, 'CONTROLLER' , 'CTLR_INSTANCE_HOSTID', ctlid)
221
+                hostname = get_value(OFDB, 'CONTROLLER', 'CONTROLLER_NAME')
222
+                retval = update_openflame_nodes(db_host, passwd, hostname, ctlid,
223
+                                                ctlr_ip, 'N/A',
224
+                                                'controller', 'up', ctlid, of_version)
225
+            mysql_controller_config(db_host,passwd)
226
+            restart_services()
227
+            if is_relation_made('db-admin'): 
228
+            # If db-admin relation happened before shared-db, then grant permissions from here
229
+                ret = priv_grant_hyperscale()
230
+                if ret != 0:
231
+                   hookenv.log('Error granting permission to HyperScale user. Check logs')
232
+                   sys.exit(1)
233
+        except Exception as e:
234
+            errstr = 'Error creating database on controller' + str(e)
235
+            hookenv.log(errstr)
236
+            sys.exit(1)
237
+     else:
238
+        hookenv.log('Relation shared-db not complete. Will retry')
239
+        sys.exit(1)
240
+     hookenv.log("HyperScale shared-db-relation-changed: Success")
241
+
242
+@hooks.hook('shared-db-relation-broken')
243
+def db_broken():
244
+    status_set('maintenance', 'Shared-db: broken')
245
+    return
246
+
247
+@hooks.hook('shared-db-relation-departed')
248
+def db_departed():
249
+    status_set('maintenance', 'Shared-db: departed')
250
+    passwd = relation_get('password')
251
+    db_host = relation_get('db_host')
252
+    delete_db(db_host, passwd)
253
+    return
254
+
255
+@hooks.hook('amqp-relation-joined')
256
+def rabbitmq_relation_joined():
257
+    relation_id = None
258
+    conf = config()
259
+    relation_set(relation_id=relation_id,
260
+                 username='hyperscale', vhost='/' , admin=True)
261
+    cmd = RABBITMQ_PLUGINS + ' enable rabbitmq_management'
262
+    subprocess.call(cmd.split(' '))
263
+    service_restart('rabbitmq-server')
264
+    status_set('maintenance', 'Relation joined: amqp')
265
+    hookenv.log("HyperScale amqp-relation-joined: Success")
266
+    return
267
+
268
+
269
+@hooks.hook('amqp-relation-changed')
270
+def rabbitmq_relation_changed():
271
+    if is_relation_made('amqp'):
272
+        hostname = ''
273
+        private_address =''
274
+        password = ''
275
+        op=relation_get(rid=relation_id())
276
+        rel_data = list(op.keys())
277
+
278
+        if 'password' in rel_data and 'private-address' in rel_data:
279
+            hostname = str(op['hostname']) if 'hostname' in rel_data else ''
280
+            private_address = str(op['private-address'])
281
+            password = str (op['password'])
282
+            create_rabbitmq_exchange('/',private_address=private_address,
283
+                password=password)
284
+            with open(AMQP_CONF,'r') as json_file:
285
+                json_data = json.load(json_file)
286
+                json_file.close()
287
+            json_data['server'] = private_address
288
+            json_data['port'] = 5672
289
+            json_data['user'] = 'hyperscale'
290
+            json_data['password'] = password
291
+            with open(AMQP_CONF ,'w') as json_file:
292
+                json.dump(json_data,json_file)
293
+                json_file.close()
294
+            set_value(OFDB, 'CONTROLLER', 'RABBITMQ_PORT', '5672')
295
+        restart_services()
296
+
297
+        status_set('maintenance', 'Relation changed: amqp')
298
+    else:
299
+        log('HyperScale to rabbitmq connection not made')
300
+        status_set('maintenance', 'Relation incomplete: amqp')
301
+    hookenv.log("HyperScale amqp-relation-changed: Success")
302
+    return
303
+
304
+
305
+@hooks.hook('amqp-relation-departed')
306
+def rabbitmq_relation_departed():
307
+    hostname = ''
308
+    private_address =''
309
+    password = ''
310
+    op=relation_get(rid=relation_id())
311
+    rel_data = list(op.keys())
312
+    if op is not None:
313
+        if 'password' in rel_data and 'private-address' in rel_data:
314
+            hostname = str(op['hostname']) if 'hostname' in rel_data else ''
315
+            private_address = str(op['private-address'])
316
+            password= str (op['password'])
317
+            delete_rabbitmq_exchange('/',private_address=private_address,
318
+                password=password)
319
+    return
320
+
321
+@hooks.hook('identity-admin-relation-changed')
322
+def identity_admin_relation_changed():
323
+  #  if is_relation_made('identity-admin') and is_relation_made('shared-db') \
324
+   #    and is_relation_made('amqp'):
325
+    op=relation_get(rid=relation_id())
326
+    if is_relation_made('identity-admin') and \
327
+       op.get('service_password',None) is not None:
328
+         hostname = ''
329
+         private_address =''
330
+         password = ''
331
+         auth_url = ('http://%s:5000/v3')%op['private-address']
332
+         set_value(OFDB, 'CONTROLLER' , 'AUTH_URL', auth_url)
333
+         ret = controller_config_identity(op)
334
+         if (ret != 0):
335
+                    log('Identity configuration failed for HyperScale. Check /var/opt/VRTSofcore/logs/ofengine.log for failure')
336
+                    assert(ret)
337
+         status_set('maintenance', 'Relation changed : identity-admin')
338
+         restart_services()
339
+
340
+    else:
341
+         log('HyperScale to keystone relation not made')
342
+         status_set('maintenance', 'Relation incomplete: identity-admin')
343
+         sys.exit(1)
344
+    hookenv.log("HyperScale identity-admin-relation-changed: Success")
345
+    return
346
+
347
+@hooks.hook('identity-admin-relation-departed')
348
+def identity_admin_relation_departed():
349
+    hostname = ''
350
+    private_address =''
351
+    password = ''
352
+    op=relation_get(rid=relation_id())
353
+    if op.get('service_password',None) is not None:
354
+        auth_url = ('http://%s:5000/v3')%op['private-address']
355
+	set_value(OFDB, 'CONTROLLER' , 'AUTH_URL', auth_url)
356
+	cmd = ('/opt/VRTSofcore/bin/ofexec --operation controller_unconf_juju '
357
+	'--params controller_ip=%s;openstack_passwd=%s;'
358
+	'region_name=%s --run'
359
+	)%(op['private-address'], op['service_password'],
360
+	op['service_region'])
361
+	lst = run_cmd(cmd.split(' '))
362
+	if (lst['ret'] != 0):
363
+		log('Check /var/opt/VRTSofcore/logs/ofengine.log for failure')
364
+		assert(lst['ret'] == 0)
365
+    else:
366
+        delete_value(OFDB, 'CONTROLLER', 'MGMT_INTF')
367
+
368
+    return
369
+
370
+@hooks.hook('update-status')
371
+def update_status():
372
+    # Check status of services and update status accordingly
373
+    failed_services = []
374
+    rel_miss = relationship_status()
375
+    if not rel_miss:
376
+        for service in hs_services:
377
+            if not service_running(service):
378
+               failed_services.append(service)
379
+        if not failed_services:
380
+            status_set('active', 'HyperScale Unit ready')
381
+        else:
382
+            status_set('maintenance', 'Some Hyperscale services have failed : ' + ' '.join(failed_services))
383
+            sys.exit(1)
384
+    else:
385
+        status_set('blocked', 'Missing relations : ' + ' '.join(rel_miss))
386
+
387
+@hooks.hook('start')
388
+def start():
389
+    open_port(ZK_PORT)
390
+    open_port(HS_API_PORT)
391
+    if not relationship_status():
392
+       status_set('waiting', 'Hyperscale service will start after relations are complete') 
393
+    else:
394
+       restart_services()
395
+
396
+
397
+if __name__ == '__main__':
398
+    try:
399
+        hooks.execute(sys.argv)
400
+    except UnregisteredHookError as e:
401
+        hookenv.log('Unknown hook {} - skipping.'.format(e))
Back to file index

hooks/hyperscale_hooks.py

  1
--- 
  2
+++ hooks/hyperscale_hooks.py
  3
@@ -0,0 +1,398 @@
  4
+#!/usr/bin/python
  5
+# Copyright 2016 Canonical Ltd
  6
+#
  7
+# Licensed under the Apache License, Version 2.0 (the "License");
  8
+# you may not use this file except in compliance with the License.
  9
+# You may obtain a copy of the License at
 10
+#
 11
+#  http://www.apache.org/licenses/LICENSE-2.0
 12
+#
 13
+# Unless required by applicable law or agreed to in writing, software
 14
+# distributed under the License is distributed on an "AS IS" BASIS,
 15
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 16
+# See the License for the specific language governing permissions and
 17
+# limitations under the License.
 18
+
 19
+import sys
 20
+import os
 21
+import json
 22
+import subprocess 
 23
+
 24
+sys.path.append('lib')
 25
+from charmhelpers.core import hookenv
 26
+from charmhelpers.core.hookenv import (
 27
+    config,
 28
+    status_set,
 29
+    is_relation_made,
 30
+    relation_set,
 31
+    relation_get,
 32
+    relation_ids,
 33
+    relation_id,
 34
+    resource_get,
 35
+    unit_get,
 36
+    open_port,
 37
+    Hooks,
 38
+    log,
 39
+    UnregisteredHookError,
 40
+    network_get_primary_address,
 41
+ )
 42
+from hyperscale_utils import (
 43
+    sync_db,
 44
+    set_value,
 45
+    get_value,
 46
+    delete_value,
 47
+    get_openflame_version,
 48
+    update_openflame_nodes,
 49
+    delete_db,
 50
+    run_cmd,
 51
+    controller_save_config,
 52
+    install_zk,
 53
+    controller_ceil_config,
 54
+    controller_copy_files,
 55
+    controller_config_horizon,
 56
+    create_rabbitmq_exchange,
 57
+    delete_rabbitmq_exchange,
 58
+    mysql_controller_config,
 59
+    controller_config_repo,
 60
+    controller_config_identity,
 61
+    priv_grant_hyperscale,
 62
+)
 63
+
 64
+from charmhelpers.core.host import (
 65
+    service_restart,
 66
+    service_running,
 67
+)
 68
+
 69
+
 70
+hooks = Hooks()
 71
+os.putenv('LC_ALL', "C")
 72
+OFDB = "/var/opt/VRTSofcore/ofdb"
 73
+PYTHON2 = "/usr/bin/python2.7"
 74
+AMQP_CONF = '/opt/VRTSofcore/etc/amqp.conf'
 75
+RABBITMQ_PLUGINS = '/usr/sbin/rabbitmq-plugins'
 76
+NETINTFS = '/var/opt/VRTSofcore/.netintfs'
 77
+ZK_PORT="42181"
 78
+HS_API_PORT="8753"
 79
+hs_services =  [ 'hyperscale-api.service',
 80
+    'hyperscale-mq-consumer.service',
 81
+    'hyperscale-mq-controller.service',
 82
+    'hyperscale-serengeti.service',
 83
+    'hyperscale-zookeeper.service',
 84
+    'hyperscale-ceilometer.service',
 85
+]
 86
+
 87
+hs_relations = ['identity-admin', 'shared-db', 'db-admin', 'amqp']
 88
+
 89
+def relationship_status():
 90
+    rel_miss = []
 91
+    for rel in hs_relations:
 92
+        if not is_relation_made(rel):
 93
+            rel_miss.append(rel)
 94
+    return rel_miss
 95
+
 96
+def restart_services():
 97
+    if not relationship_status():
 98
+        for service in hs_services:
 99
+             service_restart(service)
100
+    else:
101
+        hookenv.log('Missing relations. Cannot start HyperScale services')
102
+
103
+@hooks.hook('install.next')
104
+def install():
105
+    hookenv.log('Installing Zookeeper')
106
+    cmd = "touch " + OFDB
107
+    os.system(cmd)
108
+    install_zk()
109
+    controller_config_repo()
110
+    set_value(OFDB, 'CONTROLLER' , 'CONFIG_DONE', "0")
111
+    status_set('maintenance', 'Installation done for HyperScale Packages')
112
+
113
+@hooks.hook('config-changed')
114
+def config_changed():
115
+    hookenv.log('Configuring HyperScale')
116
+
117
+    is_config_done = get_value(OFDB, 'CONTROLLER', 'CONFIG_DONE')
118
+    if is_config_done == '0':
119
+        hostip = unit_get('private-address')
120
+        controller_save_config(hostip)
121
+        cmd = (PYTHON2  + ' -B /opt/VRTSofmn/adm/dna_netinfo.py')
122
+        lst = run_cmd(cmd.split(' '))
123
+        print lst
124
+        hookenv.log(hostip)
125
+        controller_ceil_config()
126
+        controller_copy_files()
127
+        controller_config_horizon(hostip)
128
+        set_value(OFDB, 'CONTROLLER' , 'CONFIG_DONE', "1")
129
+        rel_miss = relationship_status()
130
+        if not rel_miss:
131
+            status_set('maintenance', 'Relations complete. Status will be updated after services restart')
132
+        else:
133
+            status_set('blocked', 'Missing relations : ' + ' '.join(rel_miss))
134
+
135
+    hookenv.log("HyperScale config-changed: Success")
136
+
137
+@hooks.hook('db-admin-relation-joined')
138
+def db_admin_joined():
139
+     host = None
140
+     conf = config()
141
+     hookenv.log('Creating relation db-admin')
142
+     hookenv.log(conf['database-user'])
143
+     try:
144
+        host = network_get_primary_address('shared-db')
145
+     except NotImplementedError:
146
+        host = unit_get('private-address')
147
+
148
+     relation_set(database=conf['database'],
149
+        hostname=host)
150
+     status_set('maintenance', 'Relation observed: db-admin')
151
+     hookenv.log("HyperScale db-admin-relation-joined: Success")
152
+
153
+@hooks.hook('db-admin-relation-changed')
154
+def db_admin_changed():
155
+     conf = config()
156
+     host = None
157
+     passwd = relation_get('password')
158
+     host = relation_get('host')
159
+     user = relation_get('user')
160
+     set_value(OFDB, 'CONTROLLER' , 'DB_ADMIN_USER', user)
161
+     set_value(OFDB, 'CONTROLLER' , 'DB_ADMIN_PASSWD', passwd)
162
+     set_value(OFDB, 'CONTROLLER' , 'DB_HOST', host)
163
+     if is_relation_made('shared-db'):
164
+         ret = priv_grant_hyperscale()
165
+         if ret != 0:
166
+             hookenv.log('Grant access for HyperScale failed. Check logs')
167
+             sys.exit(1)
168
+         restart_services()
169
+         status_set('maintenance', 'Relation changed : db-admin')
170
+     else:
171
+         hookenv.log("DB grant for HyperScale user will be done after shared-db relation completes")
172
+         status_set('blocked','Waiting for shared-db relation to be made')
173
+     hookenv.log("HyperScale db-admin-relation-changed: Success")
174
+
175
+@hooks.hook('db-admin-relation-departed')
176
+def db_admin_departed():
177
+    pass
178
+
179
+@hooks.hook('db-admin-relation-broken')
180
+def db_admin_broken():
181
+    pass
182
+
183
+@hooks.hook('shared-db-relation-joined')
184
+def db_joined():
185
+     host = None
186
+     conf = config()
187
+     hookenv.log('Creating Relation')
188
+     hookenv.log(conf['database-user'])
189
+     try:
190
+        host = network_get_primary_address('shared-db')
191
+     except NotImplementedError:
192
+        host = unit_get('private-address')
193
+
194
+     status_set('maintenance', 'Relation observed: shared-db')
195
+     relation_set(database=conf['database'],
196
+        username=conf['database-user'],
197
+        hostname=host)
198
+     hookenv.log("HyperScale shared-db-relation-joined: Success")
199
+
200
+@hooks.hook('shared-db-relation-changed')
201
+def db_changed():
202
+     if is_relation_made('shared-db'):
203
+        conf = config()
204
+        host = None
205
+        try:
206
+            host = network_get_primary_address('shared-db')
207
+        except NotImplementedError:
208
+            host = unit_get('private-address')
209
+
210
+        status_set('maintenance', 'Relation joined: shared-db')
211
+        passwd = relation_get('password')
212
+        db_host = relation_get('db_host')
213
+        ctlr_ip = unit_get('private-address')
214
+        try:
215
+            sync_db(db_host, passwd)
216
+            IDGEN='/opt/VRTSofcore/adm/idgen.py'
217
+            if os.path.isfile(IDGEN):
218
+                of_version = get_openflame_version()
219
+                ctlid = subprocess.check_output([IDGEN, "--type", "hostid"])
220
+                set_value(OFDB, 'CONTROLLER' , 'CTLR_INSTANCE_HOSTID', ctlid)
221
+                hostname = get_value(OFDB, 'CONTROLLER', 'CONTROLLER_NAME')
222
+                retval = update_openflame_nodes(db_host, passwd, hostname, ctlid,
223
+                                                ctlr_ip, 'N/A',
224
+                                                'controller', 'up', ctlid, of_version)
225
+            mysql_controller_config(db_host,passwd)
226
+            restart_services()
227
+            if is_relation_made('db-admin'): 
228
+            # If db-admin relation happened before shared-db, then grant permissions from here
229
+                ret = priv_grant_hyperscale()
230
+                if ret != 0:
231
+                   hookenv.log('Error granting permission to HyperScale user. Check logs')
232
+                   sys.exit(1)
233
+        except Exception as e:
234
+            errstr = 'Error creating database on controller' + str(e)
235
+            hookenv.log(errstr)
236
+            sys.exit(1)
237
+     else:
238
+        hookenv.log('Relation shared-db not complete. Will retry')
239
+        sys.exit(1)
240
+     hookenv.log("HyperScale shared-db-relation-changed: Success")
241
+
242
+@hooks.hook('shared-db-relation-broken')
243
+def db_broken():
244
+    status_set('maintenance', 'Shared-db: broken')
245
+    return
246
+
247
+@hooks.hook('shared-db-relation-departed')
248
+def db_departed():
249
+    status_set('maintenance', 'Shared-db: departed')
250
+    passwd = relation_get('password')
251
+    db_host = relation_get('db_host')
252
+    delete_db(db_host, passwd)
253
+    return
254
+
255
+@hooks.hook('amqp-relation-joined')
256
+def rabbitmq_relation_joined():
257
+    relation_id = None
258
+    conf = config()
259
+    relation_set(relation_id=relation_id,
260
+                 username='hyperscale', vhost='/' , admin=True)
261
+    cmd = RABBITMQ_PLUGINS + ' enable rabbitmq_management'
262
+    subprocess.call(cmd.split(' '))
263
+    service_restart('rabbitmq-server')
264
+    status_set('maintenance', 'Relation joined: amqp')
265
+    hookenv.log("HyperScale amqp-relation-joined: Success")
266
+    return
267
+
268
+
269
+@hooks.hook('amqp-relation-changed')
270
+def rabbitmq_relation_changed():
271
+    if is_relation_made('amqp'):
272
+        hostname = ''
273
+        private_address =''
274
+        password = ''
275
+        op=relation_get(rid=relation_id())
276
+        rel_data = list(op.keys())
277
+
278
+        if 'password' in rel_data and 'private-address' in rel_data:
279
+            hostname = str(op['hostname']) if 'hostname' in rel_data else ''
280
+            private_address = str(op['private-address'])
281
+            password = str (op['password'])
282
+            create_rabbitmq_exchange('/',private_address=private_address,
283
+                password=password)
284
+            with open(AMQP_CONF,'r') as json_file:
285
+                json_data = json.load(json_file)
286
+                json_file.close()
287
+            json_data['server'] = private_address
288
+            json_data['port'] = 5672
289
+            json_data['user'] = 'hyperscale'
290
+            json_data['password'] = password
291
+            with open(AMQP_CONF ,'w') as json_file:
292
+                json.dump(json_data,json_file)
293
+                json_file.close()
294
+            set_value(OFDB, 'CONTROLLER', 'RABBITMQ_PORT', '5672')
295
+        restart_services()
296
+
297
+        status_set('maintenance', 'Relation changed: amqp')
298
+    else:
299
+        log('HyperScale to rabbitmq connection not made')
300
+        status_set('maintenance', 'Relation incomplete: amqp')
301
+    hookenv.log("HyperScale amqp-relation-changed: Success")
302
+    return
303
+
304
+
305
+@hooks.hook('amqp-relation-departed')
306
+def rabbitmq_relation_departed():
307
+    hostname = ''
308
+    private_address =''
309
+    password = ''
310
+    op=relation_get(rid=relation_id())
311
+    rel_data = list(op.keys())
312
+    if op is not None:
313
+        if 'password' in rel_data and 'private-address' in rel_data:
314
+            hostname = str(op['hostname']) if 'hostname' in rel_data else ''
315
+            private_address = str(op['private-address'])
316
+            password= str (op['password'])
317
+            delete_rabbitmq_exchange('/',private_address=private_address,
318
+                password=password)
319
+    return
320
+
321
+@hooks.hook('identity-admin-relation-changed')
322
+def identity_admin_relation_changed():
323
+  #  if is_relation_made('identity-admin') and is_relation_made('shared-db') \
324
+   #    and is_relation_made('amqp'):
325
+    op=relation_get(rid=relation_id())
326
+    if is_relation_made('identity-admin') and \
327
+       op.get('service_password',None) is not None:
328
+         hostname = ''
329
+         private_address =''
330
+         password = ''
331
+         auth_url = ('http://%s:5000/v3')%op['private-address']
332
+         set_value(OFDB, 'CONTROLLER' , 'AUTH_URL', auth_url)
333
+         ret = controller_config_identity(op)
334
+         if (ret != 0):
335
+                    log('Identity configuration failed for HyperScale. Check /var/opt/VRTSofcore/logs/ofengine.log for failure')
336
+                    assert(ret)
337
+         status_set('maintenance', 'Relation changed : identity-admin')
338
+         restart_services()
339
+
340
+    else:
341
+         log('HyperScale to keystone relation not made')
342
+         status_set('maintenance', 'Relation incomplete: identity-admin')
343
+         sys.exit(1)
344
+    hookenv.log("HyperScale identity-admin-relation-changed: Success")
345
+    return
346
+
347
+@hooks.hook('identity-admin-relation-departed')
348
+def identity_admin_relation_departed():
349
+    hostname = ''
350
+    private_address =''
351
+    password = ''
352
+    op=relation_get(rid=relation_id())
353
+    if op.get('service_password',None) is not None:
354
+        auth_url = ('http://%s:5000/v3')%op['private-address']
355
+	set_value(OFDB, 'CONTROLLER' , 'AUTH_URL', auth_url)
356
+	cmd = ('/opt/VRTSofcore/bin/ofexec --operation controller_unconf_juju '
357
+	'--params controller_ip=%s;openstack_passwd=%s;'
358
+	'region_name=%s --run'
359
+	)%(op['private-address'], op['service_password'],
360
+	op['service_region'])
361
+	lst = run_cmd(cmd.split(' '))
362
+	if (lst['ret'] != 0):
363
+		log('Check /var/opt/VRTSofcore/logs/ofengine.log for failure')
364
+		assert(lst['ret'] == 0)
365
+    else:
366
+        delete_value(OFDB, 'CONTROLLER', 'MGMT_INTF')
367
+
368
+    return
369
+
370
+@hooks.hook('update-status')
371
+def update_status():
372
+    # Check status of services and update status accordingly
373
+    failed_services = []
374
+    rel_miss = relationship_status()
375
+    if not rel_miss:
376
+        for service in hs_services:
377
+            if not service_running(service):
378
+               failed_services.append(service)
379
+        if not failed_services:
380
+            status_set('active', 'HyperScale Unit ready')
381
+        else:
382
+            status_set('maintenance', 'Some Hyperscale services have failed : ' + ' '.join(failed_services))
383
+            sys.exit(1)
384
+    else:
385
+        status_set('blocked', 'Missing relations : ' + ' '.join(rel_miss))
386
+
387
+@hooks.hook('start')
388
+def start():
389
+    open_port(ZK_PORT)
390
+    open_port(HS_API_PORT)
391
+    if not relationship_status():
392
+       status_set('waiting', 'Hyperscale service will start after relations are complete') 
393
+    else:
394
+       restart_services()
395
+
396
+
397
+if __name__ == '__main__':
398
+    try:
399
+        hooks.execute(sys.argv)
400
+    except UnregisteredHookError as e:
401
+        hookenv.log('Unknown hook {} - skipping.'.format(e))
Back to file index

hooks/hyperscale_utils.py

  1
--- 
  2
+++ hooks/hyperscale_utils.py
  3
@@ -0,0 +1,460 @@
  4
+#!/usr/bin/python
  5
+# Copyright 2016 Canonical Ltd
  6
+#
  7
+# Licensed under the Apache License, Version 2.0 (the "License");
  8
+# you may not use this file except in compliance with the License.
  9
+# You may obtain a copy of the License at
 10
+#
 11
+#  http://www.apache.org/licenses/LICENSE-2.0
 12
+#
 13
+# Unless required by applicable law or agreed to in writing, software
 14
+# distributed under the License is distributed on an "AS IS" BASIS,
 15
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 16
+# See the License for the specific language governing permissions and
 17
+# limitations under the License.
 18
+import os
 19
+import sys
 20
+import glob
 21
+import re
 22
+import pymysql as db
 23
+import subprocess
 24
+from subprocess import PIPE
 25
+
 26
+sys.path.append('/opt/VRTSofcore/lib/modules')
 27
+sys.path.insert(0, os.path.join(os.environ['CHARM_DIR'], 'lib'))
 28
+
 29
+import ofutils
 30
+import db_access
 31
+import constants
 32
+import ceilometer_conf
 33
+import ofopenstack
 34
+
 35
+from charmhelpers.core.hookenv import (
 36
+    config,
 37
+    is_relation_made,
 38
+    network_get_primary_address,
 39
+    unit_get,
 40
+    relation_set,
 41
+    relation_ids,
 42
+    relation_get,
 43
+    status_set,
 44
+    log,
 45
+)
 46
+CRUDINI = "/usr/bin/crudini"
 47
+DPKG = "/usr/bin/dpkg"
 48
+OPENSTACK_CMD = '/usr/bin/openstack'
 49
+SERVICE_USER = 'hyperscale'
 50
+EXTRACT_DIR="/var/tmp/vrts_pkgs"
 51
+
 52
+RABBITMQADMIN = '/opt/VRTSofcore/adm/rabbitmqadmin'
 53
+OFEXEC = '/opt/VRTSofcore/bin/ofexec'
 54
+RABBIT_EXCHANGE = [ 'hyperscale-controller', 'hyperscale-recv', 
 55
+                    'hyperscale-datanode', 'hyperscale-datanode-hypervisor',
 56
+                    'hyperscale-compute-hy', 'hyperscale-storage',
 57
+                    'hyperscale-stats' ]
 58
+
 59
+OFMN_PATH="/opt/VRTSofmn"
 60
+
 61
+def sync_db(host, passwd):
 62
+
 63
+    dbname = "HyperScale"
 64
+    conn = db.connect(host, 'hyperscale', passwd, dbname)
 65
+    dbconn =  conn.cursor()
 66
+    query = "SHOW TABLES FROM " + dbname
 67
+    dbconn.execute(query)
 68
+    log(dbconn.fetchone())
 69
+    if dbconn.rowcount == 0:
 70
+        log("Creating Hyperscale database ")
 71
+        #sql_dir = os.environ['CHARM_DIR'] + "/db"
 72
+        sql_dir = OFMN_PATH + "/db"
 73
+        filelist = sorted(glob.glob(sql_dir + "/*.sql"))
 74
+        for filename in filelist:
 75
+            log("Running SQL FILE :" + filename)
 76
+        # Table doesn't exist
 77
+            fd = open(filename, 'r')
 78
+            sqlfile = fd.read()
 79
+            fd.close()
 80
+            sqlfile = os.linesep.join([s for s in sqlfile.splitlines() if s])
 81
+            sqlcmd = sqlfile.split(';')
 82
+            for cmd in sqlcmd:
 83
+                log(cmd)
 84
+                if not cmd or cmd.startswith("-") or cmd.isspace():
 85
+                   log("Ignoring command")
 86
+                else:
 87
+                   log("Executing command")
 88
+                   dbconn.execute(cmd)
 89
+    else:
 90
+        log("Hyperscale database already exists. Doing nothing")
 91
+    if dbconn is not None:
 92
+        dbconn.close()
 93
+    if conn is not None:
 94
+        conn.close()
 95
+
 96
+def priv_grant_hyperscale():
 97
+    retval = 0
 98
+    dbconn = None
 99
+    user = get_value(constants.OPENFLAME_DB, 'CONTROLLER' , 'DB_ADMIN_USER')
100
+    passwd = get_value(constants.OPENFLAME_DB, 'CONTROLLER' , 'DB_ADMIN_PASSWD')
101
+    host = get_value(constants.OPENFLAME_DB, 'CONTROLLER' , 'DB_HOST')
102
+    user_passwd = get_value(constants.OPENFLAME_DB, 'CONTROLLER' , 'MYSQL_HYPERSCALE_PASSWD')
103
+    try:
104
+        conn = db.connect(host,user,passwd)
105
+        dbconn = conn.cursor();
106
+        query = "GRANT ALL ON HyperScale.* TO 'hyperscale'@'%' IDENTIFIED BY '" + user_passwd + "'"
107
+        dbconn.execute(query)
108
+        query = "GRANT ALL ON nova.* TO 'hyperscale'@'%' IDENTIFIED BY '" + user_passwd + "'"
109
+        dbconn.execute(query)
110
+        query = "GRANT ALL ON cinder.* TO 'hyperscale'@'%' IDENTIFIED BY '" + user_passwd + "'"
111
+        dbconn.execute(query)
112
+        query = "FLUSH PRIVILEGES"
113
+        dbconn.execute(query)
114
+    except db.Error as exc:
115
+        log(str(exc))
116
+        retval = 1
117
+    finally:
118
+        if dbconn is not None:
119
+            dbconn.close()
120
+        if conn is not None:
121
+            conn.close()
122
+    return retval
123
+
124
+def controller_config_repo():
125
+    arch_dir = constants.UBUNTU_REPO + '/amd64'
126
+    cmd = constants.MKDIR+ ' -p ' + arch_dir
127
+    ret, lst = ofutils.run(cmd)
128
+    if ret != 0:
129
+        return ret, str(lst)
130
+
131
+    cmd = constants.CP +' '+ EXTRACT_DIR + '/*.deb '+ arch_dir
132
+    ret, lst = ofutils.run(cmd)
133
+    if ret != 0:
134
+        return ret, str(lst)
135
+
136
+    cmd = (constants.TAR + ' -xzf ' + constants.OPENFLAME_CS_REPO_DIR +
137
+           '/computepkgs_deb.tar.gz -C '+arch_dir)
138
+    ret, lst = ofutils.run(cmd)
139
+    if ret != 0:
140
+        return ret, str(lst)
141
+
142
+    cmd = 'cd ' + constants.UBUNTU_REPO + ' && '
143
+    cmd += constants.DPKG_SCANPACKAGES +' amd64 | gzip -9c > '+ arch_dir+'/Packages.gz'
144
+    ret, lst = ofutils.run(cmd)
145
+    if ret != 0:
146
+        return ret, str(lst)
147
+
148
+    cmd = constants.FIND + ' ' + constants.UBUNTU_REPO + '  -exec chmod 0755 {} \;'
149
+    ret, lst = ofutils.run(cmd)
150
+    if ret != 0:
151
+       return ret, str(lst)
152
+
153
+
154
+    src = constants.CONTROLLER_TEMPLATE_DIR + '/' + constants.OF_APACHE2_CONF
155
+    dest = constants.APACHE2_CONFD_AV
156
+    if ofutils.copy(dest, src) != 0:
157
+        return -1, 'Error copying ' + src + ' to ' + dest
158
+
159
+    cmd = constants.LN + ' -sf ' + src + ' '
160
+    cmd += constants.APACHE2_CONFD_EN + '/' + constants.OF_APACHE2_CONF
161
+    ret, lst = ofutils.run(cmd)
162
+    if ret != 0:
163
+       return ret, str(lst)
164
+
165
+    cmd = ofutils.service_restart('apache2')
166
+    ret, lst = ofutils.run(cmd)
167
+    if ret != 0:
168
+       return ret, str(lst)
169
+
170
+def set_value(file, section, key, value):
171
+    if not section or not key or not value: return -1
172
+    cmd = CRUDINI + " --set "
173
+    cmd += file + ' ' + section + ' '
174
+    cmd += key + ' ' + value  + ' 1>/dev/null 2>&1'
175
+
176
+    out = run_cmd(cmd.split(' '))
177
+
178
+    return out['ret']
179
+
180
+def get_value(file, section, key):
181
+    if not file or not section or not key: return -1
182
+    cmd = CRUDINI + " --get "
183
+    cmd += file + ' ' + section + ' '
184
+    cmd += key
185
+
186
+    olist = []
187
+    lst = run_cmd(cmd.split(' '))
188
+    if lst['ret'] != 0: return ''
189
+    return lst['stdout'].strip()
190
+
191
+def delete_value(file, section, key):
192
+    if not file or not section or not key: return -1
193
+    cmd = constants.CRUDINI + " --del "
194
+    cmd += file + ' ' + section + ' ' + key + ' 1>/dev/null 2>&1'
195
+    lst = run_cmd(cmd.split(' '))
196
+
197
+    return lst['ret']
198
+
199
+def _run_cmd(cmd):
200
+    ret = -1
201
+    lst = []
202
+    if not cmd: return -1, lst
203
+
204
+    try:
205
+        p = subprocess.Popen(cmd, stdout=subprocess.PIPE,stderr=subprocess.STDOUT,shell=True)
206
+        out, err = p.communicate()
207
+        ret = p.returncode
208
+    except Exception:
209
+        return ret, lst
210
+
211
+    lst = out.splitlines()
212
+    return ret, lst
213
+
214
+def get_openflame_version():
215
+    ver = ''
216
+    package = 'vrtsofcore' 
217
+    cmd = DPKG + ' -s ' + package + ' | grep Version | awk \'{print $2}\' |awk -F"-" \'{print $1}\''
218
+    ret, lst = ofutils.run(cmd)
219
+    if ret == 0:
220
+       ver = lst
221
+    return ver
222
+
223
+def update_openflame_nodes(host, passwd, hostname, hostid, ip_address, data_ip,
224
+                               personality, status, hypervisor_id, of_version = '0.0.0.0'):
225
+
226
+    retval = 0
227
+    ulist = []
228
+    conn = None
229
+    dbconn = None
230
+    data = (hostname, hostid, ip_address, data_ip, personality, status,
231
+                hypervisor_id, of_version)
232
+
233
+    ulist.append(data)
234
+    query = "INSERT INTO HyperScale.hyperscale_nodes " \
235
+                    "(hostname, hostid, ip_address, data_ip, personality, status, hypervisor_id, of_version) "\
236
+                    "VALUES "\
237
+                    "(%s, %s, %s, %s, %s, %s, %s, %s) "\
238
+                    "ON DUPLICATE KEY UPDATE "\
239
+                    "hostname=VALUES(hostname), hostid=VALUES(hostid), personality=VALUES(personality), "\
240
+                    "status=VALUES(status), ip_address=VALUES(ip_address), "\
241
+                    "data_ip=VALUES(data_ip), hypervisor_id=VALUES(hypervisor_id), of_version=VALUES(of_version)"
242
+
243
+    try:
244
+        dbname = "HyperScale"
245
+        conn = db.connect(host, 'hyperscale', passwd, dbname)
246
+        dbconn = conn.cursor(db.cursors.DictCursor)
247
+        dbconn.executemany(query, ulist)
248
+        conn.commit()
249
+
250
+    except db.Error as exc:
251
+        log(str(exc))
252
+        retval = 1
253
+
254
+    finally:
255
+        if dbconn is not None:
256
+            dbconn.close()
257
+        if conn is not None:
258
+            conn.close()
259
+
260
+    return retval
261
+
262
+def delete_db(host, passwd):
263
+    dbconn = None
264
+    conn = None
265
+    try:
266
+        dbname = "HyperScale"
267
+        conn = db.connect(host, 'hyperscale', passwd, dbname)
268
+        dbconn =  conn.cursor()
269
+        query = "drop database if exists " + dbname
270
+        dbconn.execute(query)
271
+    except db.Error as e:
272
+        log(str(e))
273
+        retval = 0
274
+    finally:
275
+        if dbconn is not None:
276
+            dbconn.close()
277
+        if conn is not None:
278
+            conn.close()
279
+
280
+def install_zk():
281
+    ret = 0
282
+    zk_installed = False
283
+    msg = 'Success'
284
+
285
+    file_count = ofutils.get_file_count(constants.ZK_DIR)
286
+
287
+    if file_count == -1:
288
+        ret = -1
289
+        msg = 'Corrupt or missing directory ' + constants.ZK_DIR
290
+    elif file_count < 10: # Zookeeper not installed
291
+        cmd = (constants.TAR + ' -xzf ' + constants.OPENFLAME_CS_REPO_DIR +
292
+                           '/zookeeper.tar.gz -C /usr/share')
293
+        ret, lst = ofutils.run(cmd)
294
+        if ret != 0:
295
+            msg = 'Error installing zookeeper.tar.gz - ' + str(lst)
296
+        else:
297
+            zk_installed = True
298
+
299
+    db_access.db_set_value('CONTROLLER', 'ZK_INSTALLED',
300
+                           'True' if zk_installed else 'False')
301
+    return ret, msg
302
+
303
+def controller_save_config(controller_ip):
304
+    log('controller_save_config')
305
+    db_access.db_set_value('CONTROLLER', 'HYPERVISOR_IP', controller_ip)
306
+    db_access.db_set_value('CONTROLLER', 'CONTROLLER_IP', controller_ip)
307
+    db_access.db_set_value('CONTROLLER', 'MGMT_IP', controller_ip)
308
+    db_access.db_set_value('CONTROLLER', 'BREX_IP', controller_ip)
309
+    host_name = ofutils.get_hostname()
310
+    db_access.db_set_value('CONTROLLER', 'CONTROLLER_NAME', host_name)
311
+
312
+def mysql_controller_config(db_host, passwd):
313
+    log('mysql_controller_config')
314
+    db_access.db_set_value_secure('CONTROLLER', 'MYSQL_ROOT_PASSWORD', passwd)
315
+    db_access.db_set_value_secure('CONTROLLER', 'MYSQL_HYPERSCALE_PASSWORD', passwd)
316
+    db_access.db_set_value_secure('CONTROLLER', 'MYSQL_HYPERSCALE_USER', 'hyperscale')
317
+    db_access.db_set_value_secure('CONTROLLER', 'MYSQL_HYPERSCALE_DB', 'HyperScale')
318
+    db_access.db_set_value_secure('CONTROLLER', 'MYSQL_HYPERSCALE_HOST', db_host)
319
+    db_access.db_set_value('CONTROLLER', 'MYSQL_HYPERSCALE_USER', 'hyperscale')
320
+    db_access.db_set_value('CONTROLLER', 'MYSQL_HYPERSCALE_PASSWD', passwd)
321
+    db_access.db_set_value('CONTROLLER', 'MYSQL_HYPERSCALE_DB', 'HyperScale')
322
+    db_access.db_set_value('CONTROLLER', 'MYSQL_HOST_IP', db_host)
323
+    db_access.db_set_value('CONTROLLER', 'MYSQL_HYPERSCALE_HOST', db_host)
324
+    connection = "mysql://hyperscale:" + passwd +  "@" + db_host + "/HyperScale"
325
+    db_access.db_set_value('CONTROLLER', 'SQL_CONNECTION', connection)
326
+    # Also create connection string in hyperscale.conf
327
+    filename = "/etc/hyperscale/hyperscale.conf"
328
+#   set_value(filename, "database", "sql_connection", connection)
329
+    set_value(filename, "database", "connection", connection)
330
+
331
+def controller_ceil_config():
332
+    ret, msg = ceilometer_conf.config_ceil_ctlr()
333
+    if ret != 0:
334
+        log('ERROR : config_ceilometer')
335
+
336
+def controller_copy_files():
337
+    ret, msg = ofopenstack.copy_files(True)
338
+
339
+    if ret != 0:
340
+        log('ERROR :copy_files ')
341
+
342
+def controller_config_horizon(controller_ip):
343
+    ret, msg = ofopenstack.config_horizon(controller_ip)
344
+    if ret != 0:
345
+        log('ERROR : config_horizon ')
346
+
347
+def controller_config_identity(op):
348
+    cmd = ('/opt/VRTSofcore/bin/ofexec --operation controller_conf_juju '
349
+             '--params controller_ip=%s;openstack_passwd=%s;'
350
+         'region_name=%s --run'
351
+           )%(op['private-address'], op['service_password'],
352
+             op['service_region'])
353
+    is_config_done = get_value(constants.OPENFLAME_DB, 'CONTROLLER', 'MGMT_INTF')
354
+    if not is_config_done:
355
+        lst = run_cmd(cmd.split(' '))
356
+        return lst['ret']
357
+    else:
358
+        return 0
359
+
360
+def run_cmd(cmd):
361
+    print (' '.join(cmd))
362
+    process = subprocess.Popen(cmd, stdout=PIPE, stderr=PIPE)
363
+    out, err = process.communicate()
364
+    exitcode = process.returncode
365
+    return {'stdout':str(out), 'stderr':str(err),'ret':exitcode}
366
+
367
+def get_rabbitmq_exchanges(vhost, **kwargs):
368
+    cmd = [RABBITMQADMIN]
369
+    cmd += ['-H' , kwargs['private_address'] , '-V', vhost]
370
+    cmd += ['-u', 'hyperscale', '-p' , kwargs['password'],'list', 'exchanges']
371
+
372
+    return run_cmd(cmd)
373
+
374
+def create_rabbitmq_exchange(vhost, **kwargs):
375
+    out = get_rabbitmq_exchanges(vhost, **kwargs)
376
+    if len(out['stdout']) > 0:
377
+        for exchange in RABBIT_EXCHANGE:
378
+            if out['stdout'].find(exchange) < 0:
379
+                cmd = [RABBITMQADMIN]
380
+                cmd += ['-H' , kwargs['private_address'] , '-V', vhost]
381
+                cmd += ['declare', 'exchange', 'name='+exchange, 'type=direct']
382
+                cmd += ['durable=true']
383
+                cmd += ['-u', 'hyperscale', '-p' , kwargs['password']]
384
+                output=run_cmd(cmd)
385
+                if output['ret'] == 0:
386
+                    log(exchange + ' ' + output['stdout'])
387
+                else:
388
+                    log(exchange + ' ' + output['stderr'])
389
+                    return -1
390
+                # Add hyperscale user to openstack vhost as well
391
+                cmd = [RABBITMQADMIN] 
392
+                cmd += ['declare', 'permission', 'vhost=openstack', 'user=hyperscale']
393
+                cmd += [ 'configure=".*"', 'write=".*"', 'read=".*"' ]
394
+                output = run_cmd(cmd)
395
+                if output['ret'] == 0:
396
+                    log(exchange + ' ' + output['stdout'])
397
+                else:
398
+                    log(exchange + ' ' + output['stderr'])
399
+                    return -1
400
+        return 0
401
+    else:
402
+        log('Failed to connect to rabbitmq ' + out['stderr'])
403
+        return -1 
404
+
405
+def delete_rabbitmq_exchange(vhost, **kwargs):
406
+    out = get_rabbitmq_exchanges(vhost, **kwargs)
407
+    if len(out['stdout']) > 0:
408
+        print (out)
409
+        ret = 0
410
+        for exchange in RABBIT_EXCHANGE:
411
+            if out['stdout'].find(exchange) > 0:
412
+                cmd = [RABBITMQADMIN]
413
+                cmd += ['-H' , kwargs['private_address'] , '-V', vhost]
414
+                cmd += ['delete', 'exchange', 'name='+exchange]
415
+                cmd += ['-u', 'hyperscale', '-p' , kwargs['password']]
416
+                output=run_cmd(cmd)
417
+                if output['ret'] == 0:
418
+                    log(exchange + ' ' + output['stdout'])
419
+                else:
420
+                    log(exchange + ' ' + output['stderr'])
421
+                    ret = -1 
422
+        return ret  
423
+    else:
424
+        log('Failed to connect to rabbitmq ' + out['stderr'])
425
+        return -1 
426
+
427
+
428
+#def config_keystone(private-address,service_password,service_port,service_protocol,service_region,service_tenant_name,service_username):
429
+def config_keystone(relation_dict):
430
+    print(relation_dict)
431
+    private_address = relation_dict['private-address']
432
+    service_password = relation_dict['service_password']
433
+    service_port = relation_dict['service_port']
434
+    service_protocol = relation_dict['service_protocol']
435
+    service_region = relation_dict['service_region']
436
+    service_tenant_name = relation_dict['service_tenant_name']
437
+    service_username = relation_dict['service_username']
438
+    
439
+    auth_url  = service_protocol+ '://' + private_address + ':'
440
+    auth_url += service_port + '/v2.0'
441
+    os.environ['OS_USERNAME'] = service_username
442
+    os.environ['OS_PASSWORD'] = service_password
443
+    os.environ['OS_AUTH_URL'] = auth_url
444
+    os.environ['OS_TENANT_NAME'] = service_tenant_name
445
+    os.environ['OS_REGION_NAME'] = service_region
446
+
447
+    cmd = (OPENSTACK_CMD+' user create --password {0} --email {1} {2} '.format(
448
+        service_password, 'hyperscale@localhost', SERVICE_USER)
449
+            + service_password)
450
+    print (cmd)
451
+    output = run_cmd(cmd.split(' '))
452
+    print (output)
453
+    return 0
454
+
455
+def controller_telemetry():
456
+    cmd = ' /opt/VRTSofcore/adm/system_cron.sh'
457
+    ofutils.run(cmd)
458
+
459
+    ret, lst = ofutils.run('/usr/bin/python /usr/bin/hyperscale-telemetry')
460
+
461
+    if ret != 0:
462
+        msg = 'osa_controller_telemetry - Error running telemetry on the controller'
463
+        log(msg)
Back to file index

hooks/identity-admin-relation-changed

  1
--- 
  2
+++ hooks/identity-admin-relation-changed
  3
@@ -0,0 +1,398 @@
  4
+#!/usr/bin/python
  5
+# Copyright 2016 Canonical Ltd
  6
+#
  7
+# Licensed under the Apache License, Version 2.0 (the "License");
  8
+# you may not use this file except in compliance with the License.
  9
+# You may obtain a copy of the License at
 10
+#
 11
+#  http://www.apache.org/licenses/LICENSE-2.0
 12
+#
 13
+# Unless required by applicable law or agreed to in writing, software
 14
+# distributed under the License is distributed on an "AS IS" BASIS,
 15
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 16
+# See the License for the specific language governing permissions and
 17
+# limitations under the License.
 18
+
 19
+import sys
 20
+import os
 21
+import json
 22
+import subprocess 
 23
+
 24
+sys.path.append('lib')
 25
+from charmhelpers.core import hookenv
 26
+from charmhelpers.core.hookenv import (
 27
+    config,
 28
+    status_set,
 29
+    is_relation_made,
 30
+    relation_set,
 31
+    relation_get,
 32
+    relation_ids,
 33
+    relation_id,
 34
+    resource_get,
 35
+    unit_get,
 36
+    open_port,
 37
+    Hooks,
 38
+    log,
 39
+    UnregisteredHookError,
 40
+    network_get_primary_address,
 41
+ )
 42
+from hyperscale_utils import (
 43
+    sync_db,
 44
+    set_value,
 45
+    get_value,
 46
+    delete_value,
 47
+    get_openflame_version,
 48
+    update_openflame_nodes,
 49
+    delete_db,
 50
+    run_cmd,
 51
+    controller_save_config,
 52
+    install_zk,
 53
+    controller_ceil_config,
 54
+    controller_copy_files,
 55
+    controller_config_horizon,
 56
+    create_rabbitmq_exchange,
 57
+    delete_rabbitmq_exchange,
 58
+    mysql_controller_config,
 59
+    controller_config_repo,
 60
+    controller_config_identity,
 61
+    priv_grant_hyperscale,
 62
+)
 63
+
 64
+from charmhelpers.core.host import (
 65
+    service_restart,
 66
+    service_running,
 67
+)
 68
+
 69
+
 70
+hooks = Hooks()
 71
+os.putenv('LC_ALL', "C")
 72
+OFDB = "/var/opt/VRTSofcore/ofdb"
 73
+PYTHON2 = "/usr/bin/python2.7"
 74
+AMQP_CONF = '/opt/VRTSofcore/etc/amqp.conf'
 75
+RABBITMQ_PLUGINS = '/usr/sbin/rabbitmq-plugins'
 76
+NETINTFS = '/var/opt/VRTSofcore/.netintfs'
 77
+ZK_PORT="42181"
 78
+HS_API_PORT="8753"
 79
+hs_services =  [ 'hyperscale-api.service',
 80
+    'hyperscale-mq-consumer.service',
 81
+    'hyperscale-mq-controller.service',
 82
+    'hyperscale-serengeti.service',
 83
+    'hyperscale-zookeeper.service',
 84
+    'hyperscale-ceilometer.service',
 85
+]
 86
+
 87
+hs_relations = ['identity-admin', 'shared-db', 'db-admin', 'amqp']
 88
+
 89
+def relationship_status():
 90
+    rel_miss = []
 91
+    for rel in hs_relations:
 92
+        if not is_relation_made(rel):
 93
+            rel_miss.append(rel)
 94
+    return rel_miss
 95
+
 96
+def restart_services():
 97
+    if not relationship_status():
 98
+        for service in hs_services:
 99
+             service_restart(service)
100
+    else:
101
+        hookenv.log('Missing relations. Cannot start HyperScale services')
102
+
103
+@hooks.hook('install.next')
104
+def install():
105
+    hookenv.log('Installing Zookeeper')
106
+    cmd = "touch " + OFDB
107
+    os.system(cmd)
108
+    install_zk()
109
+    controller_config_repo()
110
+    set_value(OFDB, 'CONTROLLER' , 'CONFIG_DONE', "0")
111
+    status_set('maintenance', 'Installation done for HyperScale Packages')
112
+
113
+@hooks.hook('config-changed')
114
+def config_changed():
115
+    hookenv.log('Configuring HyperScale')
116
+
117
+    is_config_done = get_value(OFDB, 'CONTROLLER', 'CONFIG_DONE')
118
+    if is_config_done == '0':
119
+        hostip = unit_get('private-address')
120
+        controller_save_config(hostip)
121
+        cmd = (PYTHON2  + ' -B /opt/VRTSofmn/adm/dna_netinfo.py')
122
+        lst = run_cmd(cmd.split(' '))
123
+        print lst
124
+        hookenv.log(hostip)
125
+        controller_ceil_config()
126
+        controller_copy_files()
127
+        controller_config_horizon(hostip)
128
+        set_value(OFDB, 'CONTROLLER' , 'CONFIG_DONE', "1")
129
+        rel_miss = relationship_status()
130
+        if not rel_miss:
131
+            status_set('maintenance', 'Relations complete. Status will be updated after services restart')
132
+        else:
133
+            status_set('blocked', 'Missing relations : ' + ' '.join(rel_miss))
134
+
135
+    hookenv.log("HyperScale config-changed: Success")
136
+
137
+@hooks.hook('db-admin-relation-joined')
138
+def db_admin_joined():
139
+     host = None
140
+     conf = config()
141
+     hookenv.log('Creating relation db-admin')
142
+     hookenv.log(conf['database-user'])
143
+     try:
144
+        host = network_get_primary_address('shared-db')
145
+     except NotImplementedError:
146
+        host = unit_get('private-address')
147
+
148
+     relation_set(database=conf['database'],
149
+        hostname=host)
150
+     status_set('maintenance', 'Relation observed: db-admin')
151
+     hookenv.log("HyperScale db-admin-relation-joined: Success")
152
+
153
+@hooks.hook('db-admin-relation-changed')
154
+def db_admin_changed():
155
+     conf = config()
156
+     host = None
157
+     passwd = relation_get('password')
158
+     host = relation_get('host')
159
+     user = relation_get('user')
160
+     set_value(OFDB, 'CONTROLLER' , 'DB_ADMIN_USER', user)
161
+     set_value(OFDB, 'CONTROLLER' , 'DB_ADMIN_PASSWD', passwd)
162
+     set_value(OFDB, 'CONTROLLER' , 'DB_HOST', host)
163
+     if is_relation_made('shared-db'):
164
+         ret = priv_grant_hyperscale()
165
+         if ret != 0:
166
+             hookenv.log('Grant access for HyperScale failed. Check logs')
167
+             sys.exit(1)
168
+         restart_services()
169
+         status_set('maintenance', 'Relation changed : db-admin')
170
+     else:
171
+         hookenv.log("DB grant for HyperScale user will be done after shared-db relation completes")
172
+         status_set('blocked','Waiting for shared-db relation to be made')
173
+     hookenv.log("HyperScale db-admin-relation-changed: Success")
174
+
175
+@hooks.hook('db-admin-relation-departed')
176
+def db_admin_departed():
177
+    pass
178
+
179
+@hooks.hook('db-admin-relation-broken')
180
+def db_admin_broken():
181
+    pass
182
+
183
+@hooks.hook('shared-db-relation-joined')
184
+def db_joined():
185
+     host = None
186
+     conf = config()
187
+     hookenv.log('Creating Relation')
188
+     hookenv.log(conf['database-user'])
189
+     try:
190
+        host = network_get_primary_address('shared-db')
191
+     except NotImplementedError:
192
+        host = unit_get('private-address')
193
+
194
+     status_set('maintenance', 'Relation observed: shared-db')
195
+     relation_set(database=conf['database'],
196
+        username=conf['database-user'],
197
+        hostname=host)
198
+     hookenv.log("HyperScale shared-db-relation-joined: Success")
199
+
200
+@hooks.hook('shared-db-relation-changed')
201
+def db_changed():
202
+     if is_relation_made('shared-db'):
203
+        conf = config()
204
+        host = None
205
+        try:
206
+            host = network_get_primary_address('shared-db')
207
+        except NotImplementedError:
208
+            host = unit_get('private-address')
209
+
210
+        status_set('maintenance', 'Relation joined: shared-db')
211
+        passwd = relation_get('password')
212
+        db_host = relation_get('db_host')
213
+        ctlr_ip = unit_get('private-address')
214
+        try:
215
+            sync_db(db_host, passwd)
216
+            IDGEN='/opt/VRTSofcore/adm/idgen.py'
217
+            if os.path.isfile(IDGEN):
218
+                of_version = get_openflame_version()
219
+                ctlid = subprocess.check_output([IDGEN, "--type", "hostid"])
220
+                set_value(OFDB, 'CONTROLLER' , 'CTLR_INSTANCE_HOSTID', ctlid)
221
+                hostname = get_value(OFDB, 'CONTROLLER', 'CONTROLLER_NAME')
222
+                retval = update_openflame_nodes(db_host, passwd, hostname, ctlid,
223
+                                                ctlr_ip, 'N/A',
224
+                                                'controller', 'up', ctlid, of_version)
225
+            mysql_controller_config(db_host,passwd)
226
+            restart_services()
227
+            if is_relation_made('db-admin'): 
228
+            # If db-admin relation happened before shared-db, then grant permissions from here
229
+                ret = priv_grant_hyperscale()
230
+                if ret != 0:
231
+                   hookenv.log('Error granting permission to HyperScale user. Check logs')
232
+                   sys.exit(1)
233
+        except Exception as e:
234
+            errstr = 'Error creating database on controller' + str(e)
235
+            hookenv.log(errstr)
236
+            sys.exit(1)
237
+     else:
238
+        hookenv.log('Relation shared-db not complete. Will retry')
239
+        sys.exit(1)
240
+     hookenv.log("HyperScale shared-db-relation-changed: Success")
241
+
242
+@hooks.hook('shared-db-relation-broken')
243
+def db_broken():
244
+    status_set('maintenance', 'Shared-db: broken')
245
+    return
246
+
247
+@hooks.hook('shared-db-relation-departed')
248
+def db_departed():
249
+    status_set('maintenance', 'Shared-db: departed')
250
+    passwd = relation_get('password')
251
+    db_host = relation_get('db_host')
252
+    delete_db(db_host, passwd)
253
+    return
254
+
255
+@hooks.hook('amqp-relation-joined')
256
+def rabbitmq_relation_joined():
257
+    relation_id = None
258
+    conf = config()
259
+    relation_set(relation_id=relation_id,
260
+                 username='hyperscale', vhost='/' , admin=True)
261
+    cmd = RABBITMQ_PLUGINS + ' enable rabbitmq_management'
262
+    subprocess.call(cmd.split(' '))
263
+    service_restart('rabbitmq-server')
264
+    status_set('maintenance', 'Relation joined: amqp')
265
+    hookenv.log("HyperScale amqp-relation-joined: Success")
266
+    return
267
+
268
+
269
+@hooks.hook('amqp-relation-changed')
270
+def rabbitmq_relation_changed():
271
+    if is_relation_made('amqp'):
272
+        hostname = ''
273
+        private_address =''
274
+        password = ''
275
+        op=relation_get(rid=relation_id())
276
+        rel_data = list(op.keys())
277
+
278
+        if 'password' in rel_data and 'private-address' in rel_data:
279
+            hostname = str(op['hostname']) if 'hostname' in rel_data else ''
280
+            private_address = str(op['private-address'])
281
+            password = str (op['password'])
282
+            create_rabbitmq_exchange('/',private_address=private_address,
283
+                password=password)
284
+            with open(AMQP_CONF,'r') as json_file:
285
+                json_data = json.load(json_file)
286
+                json_file.close()
287
+            json_data['server'] = private_address
288
+            json_data['port'] = 5672
289
+            json_data['user'] = 'hyperscale'
290
+            json_data['password'] = password
291
+            with open(AMQP_CONF ,'w') as json_file:
292
+                json.dump(json_data,json_file)
293
+                json_file.close()
294
+            set_value(OFDB, 'CONTROLLER', 'RABBITMQ_PORT', '5672')
295
+        restart_services()
296
+
297
+        status_set('maintenance', 'Relation changed: amqp')
298
+    else:
299
+        log('HyperScale to rabbitmq connection not made')
300
+        status_set('maintenance', 'Relation incomplete: amqp')
301
+    hookenv.log("HyperScale amqp-relation-changed: Success")
302
+    return
303
+
304
+
305
+@hooks.hook('amqp-relation-departed')
306
+def rabbitmq_relation_departed():
307
+    hostname = ''
308
+    private_address =''
309
+    password = ''
310
+    op=relation_get(rid=relation_id())
311
+    rel_data = list(op.keys())
312
+    if op is not None:
313
+        if 'password' in rel_data and 'private-address' in rel_data:
314
+            hostname = str(op['hostname']) if 'hostname' in rel_data else ''
315
+            private_address = str(op['private-address'])
316
+            password= str (op['password'])
317
+            delete_rabbitmq_exchange('/',private_address=private_address,
318
+                password=password)
319
+    return
320
+
321
+@hooks.hook('identity-admin-relation-changed')
322
+def identity_admin_relation_changed():
323
+  #  if is_relation_made('identity-admin') and is_relation_made('shared-db') \
324
+   #    and is_relation_made('amqp'):
325
+    op=relation_get(rid=relation_id())
326
+    if is_relation_made('identity-admin') and \
327
+       op.get('service_password',None) is not None:
328
+         hostname = ''
329
+         private_address =''
330
+         password = ''
331
+         auth_url = ('http://%s:5000/v3')%op['private-address']
332
+         set_value(OFDB, 'CONTROLLER' , 'AUTH_URL', auth_url)
333
+         ret = controller_config_identity(op)
334
+         if (ret != 0):
335
+                    log('Identity configuration failed for HyperScale. Check /var/opt/VRTSofcore/logs/ofengine.log for failure')
336
+                    assert(ret)
337
+         status_set('maintenance', 'Relation changed : identity-admin')
338
+         restart_services()
339
+
340
+    else:
341
+         log('HyperScale to keystone relation not made')
342
+         status_set('maintenance', 'Relation incomplete: identity-admin')
343
+         sys.exit(1)
344
+    hookenv.log("HyperScale identity-admin-relation-changed: Success")
345
+    return
346
+
347
+@hooks.hook('identity-admin-relation-departed')
348
+def identity_admin_relation_departed():
349
+    hostname = ''
350
+    private_address =''
351
+    password = ''
352
+    op=relation_get(rid=relation_id())
353
+    if op.get('service_password',None) is not None:
354
+        auth_url = ('http://%s:5000/v3')%op['private-address']
355
+	set_value(OFDB, 'CONTROLLER' , 'AUTH_URL', auth_url)
356
+	cmd = ('/opt/VRTSofcore/bin/ofexec --operation controller_unconf_juju '
357
+	'--params controller_ip=%s;openstack_passwd=%s;'
358
+	'region_name=%s --run'
359
+	)%(op['private-address'], op['service_password'],
360
+	op['service_region'])
361
+	lst = run_cmd(cmd.split(' '))
362
+	if (lst['ret'] != 0):
363
+		log('Check /var/opt/VRTSofcore/logs/ofengine.log for failure')
364
+		assert(lst['ret'] == 0)
365
+    else:
366
+        delete_value(OFDB, 'CONTROLLER', 'MGMT_INTF')
367
+
368
+    return
369
+
370
+@hooks.hook('update-status')
371
+def update_status():
372
+    # Check status of services and update status accordingly
373
+    failed_services = []
374
+    rel_miss = relationship_status()
375
+    if not rel_miss:
376
+        for service in hs_services:
377
+            if not service_running(service):
378
+               failed_services.append(service)
379
+        if not failed_services:
380
+            status_set('active', 'HyperScale Unit ready')
381
+        else:
382
+            status_set('maintenance', 'Some Hyperscale services have failed : ' + ' '.join(failed_services))
383
+            sys.exit(1)
384
+    else:
385
+        status_set('blocked', 'Missing relations : ' + ' '.join(rel_miss))
386
+
387
+@hooks.hook('start')
388
+def start():
389
+    open_port(ZK_PORT)
390
+    open_port(HS_API_PORT)
391
+    if not relationship_status():
392
+       status_set('waiting', 'Hyperscale service will start after relations are complete') 
393
+    else:
394
+       restart_services()
395
+
396
+
397
+if __name__ == '__main__':
398
+    try:
399
+        hooks.execute(sys.argv)
400
+    except UnregisteredHookError as e:
401
+        hookenv.log('Unknown hook {} - skipping.'.format(e))
Back to file index

hooks/identity-admin-relation-departed

  1
--- 
  2
+++ hooks/identity-admin-relation-departed
  3
@@ -0,0 +1,398 @@
  4
+#!/usr/bin/python
  5
+# Copyright 2016 Canonical Ltd
  6
+#
  7
+# Licensed under the Apache License, Version 2.0 (the "License");
  8
+# you may not use this file except in compliance with the License.
  9
+# You may obtain a copy of the License at
 10
+#
 11
+#  http://www.apache.org/licenses/LICENSE-2.0
 12
+#
 13
+# Unless required by applicable law or agreed to in writing, software
 14
+# distributed under the License is distributed on an "AS IS" BASIS,
 15
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 16
+# See the License for the specific language governing permissions and
 17
+# limitations under the License.
 18
+
 19
+import sys
 20
+import os
 21
+import json
 22
+import subprocess 
 23
+
 24
+sys.path.append('lib')
 25
+from charmhelpers.core import hookenv
 26
+from charmhelpers.core.hookenv import (
 27
+    config,
 28
+    status_set,
 29
+    is_relation_made,
 30
+    relation_set,
 31
+    relation_get,
 32
+    relation_ids,
 33
+    relation_id,
 34
+    resource_get,
 35
+    unit_get,
 36
+    open_port,
 37
+    Hooks,
 38
+    log,
 39
+    UnregisteredHookError,
 40
+    network_get_primary_address,
 41
+ )
 42
+from hyperscale_utils import (
 43
+    sync_db,
 44
+    set_value,
 45
+    get_value,
 46
+    delete_value,
 47
+    get_openflame_version,
 48
+    update_openflame_nodes,
 49
+    delete_db,
 50
+    run_cmd,
 51
+    controller_save_config,
 52
+    install_zk,
 53
+    controller_ceil_config,
 54
+    controller_copy_files,
 55
+    controller_config_horizon,
 56
+    create_rabbitmq_exchange,
 57
+    delete_rabbitmq_exchange,
 58
+    mysql_controller_config,
 59
+    controller_config_repo,
 60
+    controller_config_identity,
 61
+    priv_grant_hyperscale,
 62
+)
 63
+
 64
+from charmhelpers.core.host import (
 65
+    service_restart,
 66
+    service_running,
 67
+)
 68
+
 69
+
 70
+hooks = Hooks()
 71
+os.putenv('LC_ALL', "C")
 72
+OFDB = "/var/opt/VRTSofcore/ofdb"
 73
+PYTHON2 = "/usr/bin/python2.7"
 74
+AMQP_CONF = '/opt/VRTSofcore/etc/amqp.conf'
 75
+RABBITMQ_PLUGINS = '/usr/sbin/rabbitmq-plugins'
 76
+NETINTFS = '/var/opt/VRTSofcore/.netintfs'
 77
+ZK_PORT="42181"
 78
+HS_API_PORT="8753"
 79
+hs_services =  [ 'hyperscale-api.service',
 80
+    'hyperscale-mq-consumer.service',
 81
+    'hyperscale-mq-controller.service',
 82
+    'hyperscale-serengeti.service',
 83
+    'hyperscale-zookeeper.service',
 84
+    'hyperscale-ceilometer.service',
 85
+]
 86
+
 87
+hs_relations = ['identity-admin', 'shared-db', 'db-admin', 'amqp']
 88
+
 89
+def relationship_status():
 90
+    rel_miss = []
 91
+    for rel in hs_relations:
 92
+        if not is_relation_made(rel):
 93
+            rel_miss.append(rel)
 94
+    return rel_miss
 95
+
 96
+def restart_services():
 97
+    if not relationship_status():
 98
+        for service in hs_services:
 99
+             service_restart(service)
100
+    else:
101
+        hookenv.log('Missing relations. Cannot start HyperScale services')
102
+
103
+@hooks.hook('install.next')
104
+def install():
105
+    hookenv.log('Installing Zookeeper')
106
+    cmd = "touch " + OFDB
107
+    os.system(cmd)
108
+    install_zk()
109
+    controller_config_repo()
110
+    set_value(OFDB, 'CONTROLLER' , 'CONFIG_DONE', "0")
111
+    status_set('maintenance', 'Installation done for HyperScale Packages')
112
+
113
+@hooks.hook('config-changed')
114
+def config_changed():
115
+    hookenv.log('Configuring HyperScale')
116
+
117
+    is_config_done = get_value(OFDB, 'CONTROLLER', 'CONFIG_DONE')
118
+    if is_config_done == '0':
119
+        hostip = unit_get('private-address')
120
+        controller_save_config(hostip)
121
+        cmd = (PYTHON2  + ' -B /opt/VRTSofmn/adm/dna_netinfo.py')
122
+        lst = run_cmd(cmd.split(' '))
123
+        print lst
124
+        hookenv.log(hostip)
125
+        controller_ceil_config()
126
+        controller_copy_files()
127
+        controller_config_horizon(hostip)
128
+        set_value(OFDB, 'CONTROLLER' , 'CONFIG_DONE', "1")
129
+        rel_miss = relationship_status()
130
+        if not rel_miss:
131
+            status_set('maintenance', 'Relations complete. Status will be updated after services restart')
132
+        else:
133
+            status_set('blocked', 'Missing relations : ' + ' '.join(rel_miss))
134
+
135
+    hookenv.log("HyperScale config-changed: Success")
136
+
137
+@hooks.hook('db-admin-relation-joined')
138
+def db_admin_joined():
139
+     host = None
140
+     conf = config()
141
+     hookenv.log('Creating relation db-admin')
142
+     hookenv.log(conf['database-user'])
143
+     try:
144
+        host = network_get_primary_address('shared-db')
145
+     except NotImplementedError:
146
+        host = unit_get('private-address')
147
+
148
+     relation_set(database=conf['database'],
149
+        hostname=host)
150
+     status_set('maintenance', 'Relation observed: db-admin')
151
+     hookenv.log("HyperScale db-admin-relation-joined: Success")
152
+
153
+@hooks.hook('db-admin-relation-changed')
154
+def db_admin_changed():
155
+     conf = config()
156
+     host = None
157
+     passwd = relation_get('password')
158
+     host = relation_get('host')
159
+     user = relation_get('user')
160
+     set_value(OFDB, 'CONTROLLER' , 'DB_ADMIN_USER', user)
161
+     set_value(OFDB, 'CONTROLLER' , 'DB_ADMIN_PASSWD', passwd)
162
+     set_value(OFDB, 'CONTROLLER' , 'DB_HOST', host)
163
+     if is_relation_made('shared-db'):
164
+         ret = priv_grant_hyperscale()
165
+         if ret != 0:
166
+             hookenv.log('Grant access for HyperScale failed. Check logs')
167
+             sys.exit(1)
168
+         restart_services()
169
+         status_set('maintenance', 'Relation changed : db-admin')
170
+     else:
171
+         hookenv.log("DB grant for HyperScale user will be done after shared-db relation completes")
172
+         status_set('blocked','Waiting for shared-db relation to be made')
173
+     hookenv.log("HyperScale db-admin-relation-changed: Success")
174
+
175
+@hooks.hook('db-admin-relation-departed')
176
+def db_admin_departed():
177
+    pass
178
+
179
+@hooks.hook('db-admin-relation-broken')
180
+def db_admin_broken():
181
+    pass
182
+
183
+@hooks.hook('shared-db-relation-joined')
184
+def db_joined():
185
+     host = None
186
+     conf = config()
187
+     hookenv.log('Creating Relation')
188
+     hookenv.log(conf['database-user'])
189
+     try:
190
+        host = network_get_primary_address('shared-db')
191
+     except NotImplementedError:
192
+        host = unit_get('private-address')
193
+
194
+     status_set('maintenance', 'Relation observed: shared-db')
195
+     relation_set(database=conf['database'],
196
+        username=conf['database-user'],
197
+        hostname=host)
198
+     hookenv.log("HyperScale shared-db-relation-joined: Success")
199
+
200
+@hooks.hook('shared-db-relation-changed')
201
+def db_changed():
202
+     if is_relation_made('shared-db'):
203
+        conf = config()
204
+        host = None
205
+        try:
206
+            host = network_get_primary_address('shared-db')
207
+        except NotImplementedError:
208
+            host = unit_get('private-address')
209
+
210
+        status_set('maintenance', 'Relation joined: shared-db')
211
+        passwd = relation_get('password')
212
+        db_host = relation_get('db_host')
213
+        ctlr_ip = unit_get('private-address')
214
+        try:
215
+            sync_db(db_host, passwd)
216
+            IDGEN='/opt/VRTSofcore/adm/idgen.py'
217
+            if os.path.isfile(IDGEN):
218
+                of_version = get_openflame_version()
219
+                ctlid = subprocess.check_output([IDGEN, "--type", "hostid"])
220
+                set_value(OFDB, 'CONTROLLER' , 'CTLR_INSTANCE_HOSTID', ctlid)
221
+                hostname = get_value(OFDB, 'CONTROLLER', 'CONTROLLER_NAME')
222
+                retval = update_openflame_nodes(db_host, passwd, hostname, ctlid,
223
+                                                ctlr_ip, 'N/A',
224
+                                                'controller', 'up', ctlid, of_version)
225
+            mysql_controller_config(db_host,passwd)
226
+            restart_services()
227
+            if is_relation_made('db-admin'): 
228
+            # If db-admin relation happened before shared-db, then grant permissions from here
229
+                ret = priv_grant_hyperscale()
230
+                if ret != 0:
231
+                   hookenv.log('Error granting permission to HyperScale user. Check logs')
232
+                   sys.exit(1)
233
+        except Exception as e:
234
+            errstr = 'Error creating database on controller' + str(e)
235
+            hookenv.log(errstr)
236
+            sys.exit(1)
237
+     else:
238
+        hookenv.log('Relation shared-db not complete. Will retry')
239
+        sys.exit(1)
240
+     hookenv.log("HyperScale shared-db-relation-changed: Success")
241
+
242
+@hooks.hook('shared-db-relation-broken')
243
+def db_broken():
244
+    status_set('maintenance', 'Shared-db: broken')
245
+    return
246
+
247
+@hooks.hook('shared-db-relation-departed')
248
+def db_departed():
249
+    status_set('maintenance', 'Shared-db: departed')
250
+    passwd = relation_get('password')
251
+    db_host = relation_get('db_host')
252
+    delete_db(db_host, passwd)
253
+    return
254
+
255
+@hooks.hook('amqp-relation-joined')
256
+def rabbitmq_relation_joined():
257
+    relation_id = None
258
+    conf = config()
259
+    relation_set(relation_id=relation_id,
260
+                 username='hyperscale', vhost='/' , admin=True)
261
+    cmd = RABBITMQ_PLUGINS + ' enable rabbitmq_management'
262
+    subprocess.call(cmd.split(' '))
263
+    service_restart('rabbitmq-server')
264
+    status_set('maintenance', 'Relation joined: amqp')
265
+    hookenv.log("HyperScale amqp-relation-joined: Success")
266
+    return
267
+
268
+
269
+@hooks.hook('amqp-relation-changed')
270
+def rabbitmq_relation_changed():
271
+    if is_relation_made('amqp'):
272
+        hostname = ''
273
+        private_address =''
274
+        password = ''
275
+        op=relation_get(rid=relation_id())
276
+        rel_data = list(op.keys())
277
+
278
+        if 'password' in rel_data and 'private-address' in rel_data:
279
+            hostname = str(op['hostname']) if 'hostname' in rel_data else ''
280
+            private_address = str(op['private-address'])
281
+            password = str (op['password'])
282
+            create_rabbitmq_exchange('/',private_address=private_address,
283
+                password=password)
284
+            with open(AMQP_CONF,'r') as json_file:
285
+                json_data = json.load(json_file)
286
+                json_file.close()
287
+            json_data['server'] = private_address
288
+            json_data['port'] = 5672
289
+            json_data['user'] = 'hyperscale'
290
+            json_data['password'] = password
291
+            with open(AMQP_CONF ,'w') as json_file:
292
+                json.dump(json_data,json_file)
293
+                json_file.close()
294
+            set_value(OFDB, 'CONTROLLER', 'RABBITMQ_PORT', '5672')
295
+        restart_services()
296
+
297
+        status_set('maintenance', 'Relation changed: amqp')
298
+    else:
299
+        log('HyperScale to rabbitmq connection not made')
300
+        status_set('maintenance', 'Relation incomplete: amqp')
301
+    hookenv.log("HyperScale amqp-relation-changed: Success")
302
+    return
303
+
304
+
305
+@hooks.hook('amqp-relation-departed')
306
+def rabbitmq_relation_departed():
307
+    hostname = ''
308
+    private_address =''
309
+    password = ''
310
+    op=relation_get(rid=relation_id())
311
+    rel_data = list(op.keys())
312
+    if op is not None:
313
+        if 'password' in rel_data and 'private-address' in rel_data:
314
+            hostname = str(op['hostname']) if 'hostname' in rel_data else ''
315
+            private_address = str(op['private-address'])
316
+            password= str (op['password'])
317
+            delete_rabbitmq_exchange('/',private_address=private_address,
318
+                password=password)
319
+    return
320
+
321
+@hooks.hook('identity-admin-relation-changed')
322
+def identity_admin_relation_changed():
323
+  #  if is_relation_made('identity-admin') and is_relation_made('shared-db') \
324
+   #    and is_relation_made('amqp'):
325
+    op=relation_get(rid=relation_id())
326
+    if is_relation_made('identity-admin') and \
327
+       op.get('service_password',None) is not None:
328
+         hostname = ''
329
+         private_address =''
330
+         password = ''
331
+         auth_url = ('http://%s:5000/v3')%op['private-address']
332
+         set_value(OFDB, 'CONTROLLER' , 'AUTH_URL', auth_url)
333
+         ret = controller_config_identity(op)
334
+         if (ret != 0):
335
+                    log('Identity configuration failed for HyperScale. Check /var/opt/VRTSofcore/logs/ofengine.log for failure')
336
+                    assert(ret)
337
+         status_set('maintenance', 'Relation changed : identity-admin')
338
+         restart_services()
339
+
340
+    else:
341
+         log('HyperScale to keystone relation not made')
342
+         status_set('maintenance', 'Relation incomplete: identity-admin')
343
+         sys.exit(1)
344
+    hookenv.log("HyperScale identity-admin-relation-changed: Success")
345
+    return
346
+
347
+@hooks.hook('identity-admin-relation-departed')
348
+def identity_admin_relation_departed():
349
+    hostname = ''
350
+    private_address =''
351
+    password = ''
352
+    op=relation_get(rid=relation_id())
353
+    if op.get('service_password',None) is not None:
354
+        auth_url = ('http://%s:5000/v3')%op['private-address']
355
+	set_value(OFDB, 'CONTROLLER' , 'AUTH_URL', auth_url)
356
+	cmd = ('/opt/VRTSofcore/bin/ofexec --operation controller_unconf_juju '
357
+	'--params controller_ip=%s;openstack_passwd=%s;'
358
+	'region_name=%s --run'
359
+	)%(op['private-address'], op['service_password'],
360
+	op['service_region'])
361
+	lst = run_cmd(cmd.split(' '))
362
+	if (lst['ret'] != 0):
363
+		log('Check /var/opt/VRTSofcore/logs/ofengine.log for failure')
364
+		assert(lst['ret'] == 0)
365
+    else:
366
+        delete_value(OFDB, 'CONTROLLER', 'MGMT_INTF')
367
+
368
+    return
369
+
370
+@hooks.hook('update-status')
371
+def update_status():
372
+    # Check status of services and update status accordingly
373
+    failed_services = []
374
+    rel_miss = relationship_status()
375
+    if not rel_miss:
376
+        for service in hs_services:
377
+            if not service_running(service):
378
+               failed_services.append(service)
379
+        if not failed_services:
380
+            status_set('active', 'HyperScale Unit ready')
381
+        else:
382
+            status_set('maintenance', 'Some Hyperscale services have failed : ' + ' '.join(failed_services))
383
+            sys.exit(1)
384
+    else:
385
+        status_set('blocked', 'Missing relations : ' + ' '.join(rel_miss))
386
+
387
+@hooks.hook('start')
388
+def start():
389
+    open_port(ZK_PORT)
390
+    open_port(HS_API_PORT)
391
+    if not relationship_status():
392
+       status_set('waiting', 'Hyperscale service will start after relations are complete') 
393
+    else:
394
+       restart_services()
395
+
396
+
397
+if __name__ == '__main__':
398
+    try:
399
+        hooks.execute(sys.argv)
400
+    except UnregisteredHookError as e:
401
+        hookenv.log('Unknown hook {} - skipping.'.format(e))
Back to file index

hooks/install

 1
--- 
 2
+++ hooks/install
 3
@@ -0,0 +1,69 @@
 4
+#!/bin/bash
 5
+set -xe
 6
+export LC_ALL="C"
 7
+# By default unit does not have python2. So install before invoking python based hooks.
 8
+declare -a DEPS=('apt' 'netaddr' 'netifaces' 'pip' 'yaml' 'dnspython' 'amqp' 'kombu' 'kazoo' 'anyjson' 'sqlalchemy' 'openstackclient' 'pycurl')
 9
+
10
+check_and_install() {
11
+    pkg="${1}-${2}"
12
+    if ! dpkg -s ${pkg} 2>&1 > /dev/null; then
13
+        apt-get -y install ${pkg}
14
+    fi
15
+}
16
+
17
+PYTHON="python"
18
+
19
+for dep in ${DEPS[@]}; do
20
+    check_and_install ${PYTHON} ${dep}
21
+done
22
+
23
+APT_PKGS=('python3-pip' 'dpkg-dev' 'ipcalc' 'crudini' 'openjdk-8-jre-headless' 'mysql-client')
24
+for pkg in ${APT_PKGS[@]}; do
25
+    if ! dpkg -s ${pkg} 2>&1 > /dev/null; then
26
+	apt-get -y install ${pkg}
27
+    fi
28
+done
29
+
30
+PIP_PKGS=('charmhelpers' 'pymysql' 'pycrypto' 'eventlet')
31
+for pkg in ${PIP_PKGS[@]}; do
32
+	pip install ${pkg}
33
+done
34
+
35
+python - << EOF
36
+import sys
37
+import os
38
+sys.path.append('lib')
39
+from charmhelpers.core.hookenv import (
40
+   log,
41
+   config,
42
+   resource_get
43
+)
44
+PKG_DIR = "/var/tmp/vrts_pkgs"
45
+log('Installing Veritas HyperScale')
46
+config = config()
47
+install_file = resource_get("install")
48
+if not os.path.exists(PKG_DIR):
49
+    os.makedirs(PKG_DIR)
50
+cmd = 'tar -zxf ' + install_file + ' -C ' + PKG_DIR
51
+os.system(cmd)
52
+# TODO: Add VRTSexplorer
53
+pkglist = ['vrtsofcore', 'vrtsofmn', 'vrtsofui', 'vrtsofspt']
54
+for pkgname in pkglist:
55
+    pkgname = PKG_DIR + "/" + pkgname + "*.deb"
56
+    cmd = "dpkg -i --force-overwrite " + pkgname
57
+    ret = os.system(cmd)
58
+    if ret != 0:
59
+       log("Package installation failed.")
60
+       sys.exit(1)
61
+
62
+EOF
63
+VRTS_REPO="ppa:vtas-hyperscale-ci/hyperscale-ppa"
64
+add-apt-repository -y ${VRTS_REPO}
65
+apt-get -y update
66
+DPKG_OPT="--force-overwrite"
67
+# Install vrts ceilometer package
68
+VRTS_PKG=('vrts-hyperscale-ceilometer')
69
+for pkg in ${VRTS_PKG[@]}; do
70
+	apt-get -y -o Dpkg::Options::="${DPKG_OPT}" install ${pkg}
71
+done
72
+exec ./hooks/install.next
Back to file index

hooks/install.next

  1
--- 
  2
+++ hooks/install.next
  3
@@ -0,0 +1,398 @@
  4
+#!/usr/bin/python
  5
+# Copyright 2016 Canonical Ltd
  6
+#
  7
+# Licensed under the Apache License, Version 2.0 (the "License");
  8
+# you may not use this file except in compliance with the License.
  9
+# You may obtain a copy of the License at
 10
+#
 11
+#  http://www.apache.org/licenses/LICENSE-2.0
 12
+#
 13
+# Unless required by applicable law or agreed to in writing, software
 14
+# distributed under the License is distributed on an "AS IS" BASIS,
 15
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 16
+# See the License for the specific language governing permissions and
 17
+# limitations under the License.
 18
+
 19
+import sys
 20
+import os
 21
+import json
 22
+import subprocess 
 23
+
 24
+sys.path.append('lib')
 25
+from charmhelpers.core import hookenv
 26
+from charmhelpers.core.hookenv import (
 27
+    config,
 28
+    status_set,
 29
+    is_relation_made,
 30
+    relation_set,
 31
+    relation_get,
 32
+    relation_ids,
 33
+    relation_id,
 34
+    resource_get,
 35
+    unit_get,
 36
+    open_port,
 37
+    Hooks,
 38
+    log,
 39
+    UnregisteredHookError,
 40
+    network_get_primary_address,
 41
+ )
 42
+from hyperscale_utils import (
 43
+    sync_db,
 44
+    set_value,
 45
+    get_value,
 46
+    delete_value,
 47
+    get_openflame_version,
 48
+    update_openflame_nodes,
 49
+    delete_db,
 50
+    run_cmd,
 51
+    controller_save_config,
 52
+    install_zk,
 53
+    controller_ceil_config,
 54
+    controller_copy_files,
 55
+    controller_config_horizon,
 56
+    create_rabbitmq_exchange,
 57
+    delete_rabbitmq_exchange,
 58
+    mysql_controller_config,
 59
+    controller_config_repo,
 60
+    controller_config_identity,
 61
+    priv_grant_hyperscale,
 62
+)
 63
+
 64
+from charmhelpers.core.host import (
 65
+    service_restart,
 66
+    service_running,
 67
+)
 68
+
 69
+
 70
+hooks = Hooks()
 71
+os.putenv('LC_ALL', "C")
 72
+OFDB = "/var/opt/VRTSofcore/ofdb"
 73
+PYTHON2 = "/usr/bin/python2.7"
 74
+AMQP_CONF = '/opt/VRTSofcore/etc/amqp.conf'
 75
+RABBITMQ_PLUGINS = '/usr/sbin/rabbitmq-plugins'
 76
+NETINTFS = '/var/opt/VRTSofcore/.netintfs'
 77
+ZK_PORT="42181"
 78
+HS_API_PORT="8753"
 79
+hs_services =  [ 'hyperscale-api.service',
 80
+    'hyperscale-mq-consumer.service',
 81
+    'hyperscale-mq-controller.service',
 82
+    'hyperscale-serengeti.service',
 83
+    'hyperscale-zookeeper.service',
 84
+    'hyperscale-ceilometer.service',
 85
+]
 86
+
 87
+hs_relations = ['identity-admin', 'shared-db', 'db-admin', 'amqp']
 88
+
 89
+def relationship_status():
 90
+    rel_miss = []
 91
+    for rel in hs_relations:
 92
+        if not is_relation_made(rel):
 93
+            rel_miss.append(rel)
 94
+    return rel_miss
 95
+
 96
+def restart_services():
 97
+    if not relationship_status():
 98
+        for service in hs_services:
 99
+             service_restart(service)
100
+    else:
101
+        hookenv.log('Missing relations. Cannot start HyperScale services')
102
+
103
+@hooks.hook('install.next')
104
+def install():
105
+    hookenv.log('Installing Zookeeper')
106
+    cmd = "touch " + OFDB
107
+    os.system(cmd)
108
+    install_zk()
109
+    controller_config_repo()
110
+    set_value(OFDB, 'CONTROLLER' , 'CONFIG_DONE', "0")
111
+    status_set('maintenance', 'Installation done for HyperScale Packages')
112
+
113
+@hooks.hook('config-changed')
114
+def config_changed():
115
+    hookenv.log('Configuring HyperScale')
116
+
117
+    is_config_done = get_value(OFDB, 'CONTROLLER', 'CONFIG_DONE')
118
+    if is_config_done == '0':
119
+        hostip = unit_get('private-address')
120
+        controller_save_config(hostip)
121
+        cmd = (PYTHON2  + ' -B /opt/VRTSofmn/adm/dna_netinfo.py')
122
+        lst = run_cmd(cmd.split(' '))
123
+        print lst
124
+        hookenv.log(hostip)
125
+        controller_ceil_config()
126
+        controller_copy_files()
127
+        controller_config_horizon(hostip)
128
+        set_value(OFDB, 'CONTROLLER' , 'CONFIG_DONE', "1")
129
+        rel_miss = relationship_status()
130
+        if not rel_miss:
131
+            status_set('maintenance', 'Relations complete. Status will be updated after services restart')
132
+        else:
133
+            status_set('blocked', 'Missing relations : ' + ' '.join(rel_miss))
134
+
135
+    hookenv.log("HyperScale config-changed: Success")
136
+
137
+@hooks.hook('db-admin-relation-joined')
138
+def db_admin_joined():
139
+     host = None
140
+     conf = config()
141
+     hookenv.log('Creating relation db-admin')
142
+     hookenv.log(conf['database-user'])
143
+     try:
144
+        host = network_get_primary_address('shared-db')
145
+     except NotImplementedError:
146
+        host = unit_get('private-address')
147
+
148
+     relation_set(database=conf['database'],
149
+        hostname=host)
150
+     status_set('maintenance', 'Relation observed: db-admin')
151
+     hookenv.log("HyperScale db-admin-relation-joined: Success")
152
+
153
+@hooks.hook('db-admin-relation-changed')
154
+def db_admin_changed():
155
+     conf = config()
156
+     host = None
157
+     passwd = relation_get('password')
158
+     host = relation_get('host')
159
+     user = relation_get('user')
160
+     set_value(OFDB, 'CONTROLLER' , 'DB_ADMIN_USER', user)
161
+     set_value(OFDB, 'CONTROLLER' , 'DB_ADMIN_PASSWD', passwd)
162
+     set_value(OFDB, 'CONTROLLER' , 'DB_HOST', host)
163
+     if is_relation_made('shared-db'):
164
+         ret = priv_grant_hyperscale()
165
+         if ret != 0:
166
+             hookenv.log('Grant access for HyperScale failed. Check logs')
167
+             sys.exit(1)
168
+         restart_services()
169
+         status_set('maintenance', 'Relation changed : db-admin')
170
+     else:
171
+         hookenv.log("DB grant for HyperScale user will be done after shared-db relation completes")
172
+         status_set('blocked','Waiting for shared-db relation to be made')
173
+     hookenv.log("HyperScale db-admin-relation-changed: Success")
174
+
175
+@hooks.hook('db-admin-relation-departed')
176
+def db_admin_departed():
177
+    pass
178
+
179
+@hooks.hook('db-admin-relation-broken')
180
+def db_admin_broken():
181
+    pass
182
+
183
+@hooks.hook('shared-db-relation-joined')
184
+def db_joined():
185
+     host = None
186
+     conf = config()
187
+     hookenv.log('Creating Relation')
188
+     hookenv.log(conf['database-user'])
189
+     try:
190
+        host = network_get_primary_address('shared-db')
191
+     except NotImplementedError:
192
+        host = unit_get('private-address')
193
+
194
+     status_set('maintenance', 'Relation observed: shared-db')
195
+     relation_set(database=conf['database'],
196
+        username=conf['database-user'],
197
+        hostname=host)
198
+     hookenv.log("HyperScale shared-db-relation-joined: Success")
199
+
200
+@hooks.hook('shared-db-relation-changed')
201
+def db_changed():
202
+     if is_relation_made('shared-db'):
203
+        conf = config()
204
+        host = None
205
+        try:
206
+            host = network_get_primary_address('shared-db')
207
+        except NotImplementedError:
208
+            host = unit_get('private-address')
209
+
210
+        status_set('maintenance', 'Relation joined: shared-db')
211
+        passwd = relation_get('password')
212
+        db_host = relation_get('db_host')
213
+        ctlr_ip = unit_get('private-address')
214
+        try:
215
+            sync_db(db_host, passwd)
216
+            IDGEN='/opt/VRTSofcore/adm/idgen.py'
217
+            if os.path.isfile(IDGEN):
218
+                of_version = get_openflame_version()
219
+                ctlid = subprocess.check_output([IDGEN, "--type", "hostid"])
220
+                set_value(OFDB, 'CONTROLLER' , 'CTLR_INSTANCE_HOSTID', ctlid)
221
+                hostname = get_value(OFDB, 'CONTROLLER', 'CONTROLLER_NAME')
222
+                retval = update_openflame_nodes(db_host, passwd, hostname, ctlid,
223
+                                                ctlr_ip, 'N/A',
224
+                                                'controller', 'up', ctlid, of_version)
225
+            mysql_controller_config(db_host,passwd)
226
+            restart_services()
227
+            if is_relation_made('db-admin'): 
228
+            # If db-admin relation happened before shared-db, then grant permissions from here
229
+                ret = priv_grant_hyperscale()
230
+                if ret != 0:
231
+                   hookenv.log('Error granting permission to HyperScale user. Check logs')
232
+                   sys.exit(1)
233
+        except Exception as e:
234
+            errstr = 'Error creating database on controller' + str(e)
235
+            hookenv.log(errstr)
236
+            sys.exit(1)
237
+     else:
238
+        hookenv.log('Relation shared-db not complete. Will retry')
239
+        sys.exit(1)
240
+     hookenv.log("HyperScale shared-db-relation-changed: Success")
241
+
242
+@hooks.hook('shared-db-relation-broken')
243
+def db_broken():
244
+    status_set('maintenance', 'Shared-db: broken')
245
+    return
246
+
247
+@hooks.hook('shared-db-relation-departed')
248
+def db_departed():
249
+    status_set('maintenance', 'Shared-db: departed')
250
+    passwd = relation_get('password')
251
+    db_host = relation_get('db_host')
252
+    delete_db(db_host, passwd)
253
+    return
254
+
255
+@hooks.hook('amqp-relation-joined')
256
+def rabbitmq_relation_joined():
257
+    relation_id = None
258
+    conf = config()
259
+    relation_set(relation_id=relation_id,
260
+                 username='hyperscale', vhost='/' , admin=True)
261
+    cmd = RABBITMQ_PLUGINS + ' enable rabbitmq_management'
262
+    subprocess.call(cmd.split(' '))
263
+    service_restart('rabbitmq-server')
264
+    status_set('maintenance', 'Relation joined: amqp')
265
+    hookenv.log("HyperScale amqp-relation-joined: Success")
266
+    return
267
+
268
+
269
+@hooks.hook('amqp-relation-changed')
270
+def rabbitmq_relation_changed():
271
+    if is_relation_made('amqp'):
272
+        hostname = ''
273
+        private_address =''
274
+        password = ''
275
+        op=relation_get(rid=relation_id())
276
+        rel_data = list(op.keys())
277
+
278
+        if 'password' in rel_data and 'private-address' in rel_data:
279
+            hostname = str(op['hostname']) if 'hostname' in rel_data else ''
280
+            private_address = str(op['private-address'])
281
+            password = str (op['password'])
282
+            create_rabbitmq_exchange('/',private_address=private_address,
283
+                password=password)
284
+            with open(AMQP_CONF,'r') as json_file:
285
+                json_data = json.load(json_file)
286
+                json_file.close()
287
+            json_data['server'] = private_address
288
+            json_data['port'] = 5672
289
+            json_data['user'] = 'hyperscale'
290
+            json_data['password'] = password
291
+            with open(AMQP_CONF ,'w') as json_file:
292
+                json.dump(json_data,json_file)
293
+                json_file.close()
294
+            set_value(OFDB, 'CONTROLLER', 'RABBITMQ_PORT', '5672')
295
+        restart_services()
296
+
297
+        status_set('maintenance', 'Relation changed: amqp')
298
+    else:
299
+        log('HyperScale to rabbitmq connection not made')
300
+        status_set('maintenance', 'Relation incomplete: amqp')
301
+    hookenv.log("HyperScale amqp-relation-changed: Success")
302
+    return
303
+
304
+
305
+@hooks.hook('amqp-relation-departed')
306
+def rabbitmq_relation_departed():
307
+    hostname = ''
308
+    private_address =''
309
+    password = ''
310
+    op=relation_get(rid=relation_id())
311
+    rel_data = list(op.keys())
312
+    if op is not None:
313
+        if 'password' in rel_data and 'private-address' in rel_data:
314
+            hostname = str(op['hostname']) if 'hostname' in rel_data else ''
315
+            private_address = str(op['private-address'])
316
+            password= str (op['password'])
317
+            delete_rabbitmq_exchange('/',private_address=private_address,
318
+                password=password)
319
+    return
320
+
321
+@hooks.hook('identity-admin-relation-changed')
322
+def identity_admin_relation_changed():
323
+  #  if is_relation_made('identity-admin') and is_relation_made('shared-db') \
324
+   #    and is_relation_made('amqp'):
325
+    op=relation_get(rid=relation_id())
326
+    if is_relation_made('identity-admin') and \
327
+       op.get('service_password',None) is not None:
328
+         hostname = ''
329
+         private_address =''
330
+         password = ''
331
+         auth_url = ('http://%s:5000/v3')%op['private-address']
332
+         set_value(OFDB, 'CONTROLLER' , 'AUTH_URL', auth_url)
333
+         ret = controller_config_identity(op)
334
+         if (ret != 0):
335
+                    log('Identity configuration failed for HyperScale. Check /var/opt/VRTSofcore/logs/ofengine.log for failure')
336
+                    assert(ret)
337
+         status_set('maintenance', 'Relation changed : identity-admin')
338
+         restart_services()
339
+
340
+    else:
341
+         log('HyperScale to keystone relation not made')
342
+         status_set('maintenance', 'Relation incomplete: identity-admin')
343
+         sys.exit(1)
344
+    hookenv.log("HyperScale identity-admin-relation-changed: Success")
345
+    return
346
+
347
+@hooks.hook('identity-admin-relation-departed')
348
+def identity_admin_relation_departed():
349
+    hostname = ''
350
+    private_address =''
351
+    password = ''
352
+    op=relation_get(rid=relation_id())
353
+    if op.get('service_password',None) is not None:
354
+        auth_url = ('http://%s:5000/v3')%op['private-address']
355
+	set_value(OFDB, 'CONTROLLER' , 'AUTH_URL', auth_url)
356
+	cmd = ('/opt/VRTSofcore/bin/ofexec --operation controller_unconf_juju '
357
+	'--params controller_ip=%s;openstack_passwd=%s;'
358
+	'region_name=%s --run'
359
+	)%(op['private-address'], op['service_password'],
360
+	op['service_region'])
361
+	lst = run_cmd(cmd.split(' '))
362
+	if (lst['ret'] != 0):
363
+		log('Check /var/opt/VRTSofcore/logs/ofengine.log for failure')
364
+		assert(lst['ret'] == 0)
365
+    else:
366
+        delete_value(OFDB, 'CONTROLLER', 'MGMT_INTF')
367
+
368
+    return
369
+
370
+@hooks.hook('update-status')
371
+def update_status():
372
+    # Check status of services and update status accordingly
373
+    failed_services = []
374
+    rel_miss = relationship_status()
375
+    if not rel_miss:
376
+        for service in hs_services:
377
+            if not service_running(service):
378
+               failed_services.append(service)
379
+        if not failed_services:
380
+            status_set('active', 'HyperScale Unit ready')
381
+        else:
382
+            status_set('maintenance', 'Some Hyperscale services have failed : ' + ' '.join(failed_services))
383
+            sys.exit(1)
384
+    else:
385
+        status_set('blocked', 'Missing relations : ' + ' '.join(rel_miss))
386
+
387
+@hooks.hook('start')
388
+def start():
389
+    open_port(ZK_PORT)
390
+    open_port(HS_API_PORT)
391
+    if not relationship_status():
392
+       status_set('waiting', 'Hyperscale service will start after relations are complete') 
393
+    else:
394
+       restart_services()
395
+
396
+
397
+if __name__ == '__main__':
398
+    try:
399
+        hooks.execute(sys.argv)
400
+    except UnregisteredHookError as e:
401
+        hookenv.log('Unknown hook {} - skipping.'.format(e))
Back to file index

hooks/services.py

 1
--- 
 2
+++ hooks/services.py
 3
@@ -0,0 +1,31 @@
 4
+#!/usr/bin/python
 5
+
 6
+from charmhelpers.core.services.base import ServiceManager
 7
+from charmhelpers.core.services import helpers
 8
+
 9
+import actions
10
+
11
+
12
+def manage():
13
+    manager = ServiceManager([
14
+        {
15
+            'service': 'hyperscale',
16
+            'ports': [],  # ports to after start
17
+            'provided_data': [
18
+                # context managers for provided relations
19
+                # e.g.: helpers.HttpRelation()
20
+            ],
21
+            'required_data': [
22
+                # data (contexts) required to start the service
23
+                # e.g.: helpers.RequiredConfig('domain', 'auth_key'),
24
+                #       helpers.MysqlRelation(),
25
+            ],
26
+            'data_ready': [
27
+                helpers.render_template(
28
+                    source='upstart.conf',
29
+                    target='/etc/init/hyperscale'),
30
+                actions.log_start,
31
+            ],
32
+        },
33
+    ])
34
+    manager.manage()
Back to file index

hooks/setup.py

 1
--- 
 2
+++ hooks/setup.py
 3
@@ -0,0 +1,20 @@
 4
+def pre_install():
 5
+    """
 6
+    Do any setup required before the install hook.
 7
+    """
 8
+    install_charmhelpers()
 9
+
10
+
11
+def install_charmhelpers():
12
+    """
13
+    Install the charmhelpers library, if not present.
14
+    """
15
+    try:
16
+        import charmhelpers  # noqa
17
+    except ImportError:
18
+        import subprocess
19
+        subprocess.check_call(['apt-get', 'install', '-y', 'python-pip', 'python3-pip', 'dpkg-dev', 'ipcalc'])
20
+        subprocess.check_call(['apt-get', 'install', '-y', 'python-amqp', 'python-kombu','python-kazoo','python-anyjson','python-sqlalchemy'])
21
+        subprocess.check_call(['apt-get', 'install', '-y', 'crudini'])
22
+        subprocess.check_call(['pip', 'install', 'charmhelpers', 'pymysql', 'pycrypto', 'eventlet'])
23
+        subprocess.check_call(['pip3', 'install', 'charmhelpers', 'pymysql'])
Back to file index

hooks/shared-db-relation-broken

  1
--- 
  2
+++ hooks/shared-db-relation-broken
  3
@@ -0,0 +1,398 @@
  4
+#!/usr/bin/python
  5
+# Copyright 2016 Canonical Ltd
  6
+#
  7
+# Licensed under the Apache License, Version 2.0 (the "License");
  8
+# you may not use this file except in compliance with the License.
  9
+# You may obtain a copy of the License at
 10
+#
 11
+#  http://www.apache.org/licenses/LICENSE-2.0
 12
+#
 13
+# Unless required by applicable law or agreed to in writing, software
 14
+# distributed under the License is distributed on an "AS IS" BASIS,
 15
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 16
+# See the License for the specific language governing permissions and
 17
+# limitations under the License.
 18
+
 19
+import sys
 20
+import os
 21
+import json
 22
+import subprocess 
 23
+
 24
+sys.path.append('lib')
 25
+from charmhelpers.core import hookenv
 26
+from charmhelpers.core.hookenv import (
 27
+    config,
 28
+    status_set,
 29
+    is_relation_made,
 30
+    relation_set,
 31
+    relation_get,
 32
+    relation_ids,
 33
+    relation_id,
 34
+    resource_get,
 35
+    unit_get,
 36
+    open_port,
 37
+    Hooks,
 38
+    log,
 39
+    UnregisteredHookError,
 40
+    network_get_primary_address,
 41
+ )
 42
+from hyperscale_utils import (
 43
+    sync_db,
 44
+    set_value,
 45
+    get_value,
 46
+    delete_value,
 47
+    get_openflame_version,
 48
+    update_openflame_nodes,
 49
+    delete_db,
 50
+    run_cmd,
 51
+    controller_save_config,
 52
+    install_zk,
 53
+    controller_ceil_config,
 54
+    controller_copy_files,
 55
+    controller_config_horizon,
 56
+    create_rabbitmq_exchange,
 57
+    delete_rabbitmq_exchange,
 58
+    mysql_controller_config,
 59
+    controller_config_repo,
 60
+    controller_config_identity,
 61
+    priv_grant_hyperscale,
 62
+)
 63
+
 64
+from charmhelpers.core.host import (
 65
+    service_restart,
 66
+    service_running,
 67
+)
 68
+
 69
+
 70
+hooks = Hooks()
 71
+os.putenv('LC_ALL', "C")
 72
+OFDB = "/var/opt/VRTSofcore/ofdb"
 73
+PYTHON2 = "/usr/bin/python2.7"
 74
+AMQP_CONF = '/opt/VRTSofcore/etc/amqp.conf'
 75
+RABBITMQ_PLUGINS = '/usr/sbin/rabbitmq-plugins'
 76
+NETINTFS = '/var/opt/VRTSofcore/.netintfs'
 77
+ZK_PORT="42181"
 78
+HS_API_PORT="8753"
 79
+hs_services =  [ 'hyperscale-api.service',
 80
+    'hyperscale-mq-consumer.service',
 81
+    'hyperscale-mq-controller.service',
 82
+    'hyperscale-serengeti.service',
 83
+    'hyperscale-zookeeper.service',
 84
+    'hyperscale-ceilometer.service',
 85
+]
 86
+
 87
+hs_relations = ['identity-admin', 'shared-db', 'db-admin', 'amqp']
 88
+
 89
+def relationship_status():
 90
+    rel_miss = []
 91
+    for rel in hs_relations:
 92
+        if not is_relation_made(rel):
 93
+            rel_miss.append(rel)
 94
+    return rel_miss
 95
+
 96
+def restart_services():
 97
+    if not relationship_status():
 98
+        for service in hs_services:
 99
+             service_restart(service)
100
+    else:
101
+        hookenv.log('Missing relations. Cannot start HyperScale services')
102
+
103
+@hooks.hook('install.next')
104
+def install():
105
+    hookenv.log('Installing Zookeeper')
106
+    cmd = "touch " + OFDB
107
+    os.system(cmd)
108
+    install_zk()
109
+    controller_config_repo()
110
+    set_value(OFDB, 'CONTROLLER' , 'CONFIG_DONE', "0")
111
+    status_set('maintenance', 'Installation done for HyperScale Packages')
112
+
113
+@hooks.hook('config-changed')
114
+def config_changed():
115
+    hookenv.log('Configuring HyperScale')
116
+
117
+    is_config_done = get_value(OFDB, 'CONTROLLER', 'CONFIG_DONE')
118
+    if is_config_done == '0':
119
+        hostip = unit_get('private-address')
120
+        controller_save_config(hostip)
121
+        cmd = (PYTHON2  + ' -B /opt/VRTSofmn/adm/dna_netinfo.py')
122
+        lst = run_cmd(cmd.split(' '))
123
+        print lst
124
+        hookenv.log(hostip)
125
+        controller_ceil_config()
126
+        controller_copy_files()
127
+        controller_config_horizon(hostip)
128
+        set_value(OFDB, 'CONTROLLER' , 'CONFIG_DONE', "1")
129
+        rel_miss = relationship_status()
130
+        if not rel_miss:
131
+            status_set('maintenance', 'Relations complete. Status will be updated after services restart')
132
+        else:
133
+            status_set('blocked', 'Missing relations : ' + ' '.join(rel_miss))
134
+
135
+    hookenv.log("HyperScale config-changed: Success")
136
+
137
+@hooks.hook('db-admin-relation-joined')
138
+def db_admin_joined():
139
+     host = None
140
+     conf = config()
141
+     hookenv.log('Creating relation db-admin')
142
+     hookenv.log(conf['database-user'])
143
+     try:
144
+        host = network_get_primary_address('shared-db')
145
+     except NotImplementedError:
146
+        host = unit_get('private-address')
147
+
148
+     relation_set(database=conf['database'],
149
+        hostname=host)
150
+     status_set('maintenance', 'Relation observed: db-admin')
151
+     hookenv.log("HyperScale db-admin-relation-joined: Success")
152
+
153
+@hooks.hook('db-admin-relation-changed')
154
+def db_admin_changed():
155
+     conf = config()
156
+     host = None
157
+     passwd = relation_get('password')
158
+     host = relation_get('host')
159
+     user = relation_get('user')
160
+     set_value(OFDB, 'CONTROLLER' , 'DB_ADMIN_USER', user)
161
+     set_value(OFDB, 'CONTROLLER' , 'DB_ADMIN_PASSWD', passwd)
162
+     set_value(OFDB, 'CONTROLLER' , 'DB_HOST', host)
163
+     if is_relation_made('shared-db'):
164
+         ret = priv_grant_hyperscale()
165
+         if ret != 0:
166
+             hookenv.log('Grant access for HyperScale failed. Check logs')
167
+             sys.exit(1)
168
+         restart_services()
169
+         status_set('maintenance', 'Relation changed : db-admin')
170
+     else:
171
+         hookenv.log("DB grant for HyperScale user will be done after shared-db relation completes")
172
+         status_set('blocked','Waiting for shared-db relation to be made')
173
+     hookenv.log("HyperScale db-admin-relation-changed: Success")
174
+
175
+@hooks.hook('db-admin-relation-departed')
176
+def db_admin_departed():
177
+    pass
178
+
179
+@hooks.hook('db-admin-relation-broken')
180
+def db_admin_broken():
181
+    pass
182
+
183
+@hooks.hook('shared-db-relation-joined')
184
+def db_joined():
185
+     host = None
186
+     conf = config()
187
+     hookenv.log('Creating Relation')
188
+     hookenv.log(conf['database-user'])
189
+     try:
190
+        host = network_get_primary_address('shared-db')
191
+     except NotImplementedError:
192
+        host = unit_get('private-address')
193