Implements: hedvig fuel cinder plugin
Change-Id: I294de1df8df88ef57a42d5712f6e825f1e991e6d
This commit is contained in:
parent
1eabe89f91
commit
d1829eaa79
|
@ -0,0 +1,3 @@
|
||||||
|
.tox
|
||||||
|
.build
|
||||||
|
*.pyc
|
|
@ -0,0 +1,202 @@
|
||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright {yyyy} {name of copyright owner}
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
fuel-plugin-hedvig-cinder
|
||||||
|
============
|
||||||
|
|
||||||
|
Plugin description
|
|
@ -0,0 +1,4 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# It's a script which deploys your plugin
|
||||||
|
echo fuel-plugin-hedvig-cinder > /tmp/fuel-plugin-hedvig-cinder
|
|
@ -0,0 +1,2 @@
|
||||||
|
$plugin_settings = hiera('fuel-plugin-hedvig-cinder')
|
||||||
|
class {'plugin_hedvig_cinder': }
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,133 @@
|
||||||
|
from eventlet.green import threading
|
||||||
|
import socket
|
||||||
|
import os
|
||||||
|
import hedvigpyc as hc
|
||||||
|
|
||||||
|
from oslo_log import log as logging
|
||||||
|
|
||||||
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
TO_MEGABYTES = 1024 * 1024
|
||||||
|
TO_GIGABYTES = TO_MEGABYTES * 1024
|
||||||
|
|
||||||
|
class ReplicationPolicy:
|
||||||
|
Agnostic = 0
|
||||||
|
RackAware = 1
|
||||||
|
DataCenterAware = 2
|
||||||
|
|
||||||
|
_VALUES_TO_NAMES = {
|
||||||
|
0: "Agnostic",
|
||||||
|
1: "RackAware",
|
||||||
|
2: "DataCenterAware",
|
||||||
|
}
|
||||||
|
|
||||||
|
_NAMES_TO_VALUES = {
|
||||||
|
"Agnostic": 0,
|
||||||
|
"RackAware": 1,
|
||||||
|
"DataCenterAware": 2,
|
||||||
|
}
|
||||||
|
|
||||||
|
class DiskResidence:
|
||||||
|
Flash = 0
|
||||||
|
HDD = 1
|
||||||
|
|
||||||
|
_VALUES_TO_NAMES = {
|
||||||
|
0: "Flash",
|
||||||
|
1: "HDD",
|
||||||
|
}
|
||||||
|
|
||||||
|
_NAMES_TO_VALUES = {
|
||||||
|
"Flash": 0,
|
||||||
|
"HDD": 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
class HedvigConfig():
|
||||||
|
lock_ = threading.RLock()
|
||||||
|
instance_ = None
|
||||||
|
|
||||||
|
# Default Port Configuration
|
||||||
|
defaultHControllerPort_ = 50000
|
||||||
|
|
||||||
|
# Default Cinder Configuration
|
||||||
|
defaultCinderReplicationFactor_ = 3
|
||||||
|
defaultCinderDedupEnable_ = False
|
||||||
|
defaultCinderCompressEnable_ = False
|
||||||
|
defaultCinderCacheEnable_ = False
|
||||||
|
defaultCinderDiskResidence_ = DiskResidence.HDD
|
||||||
|
defaultCinderReplicationPolicy_ = ReplicationPolicy.Agnostic
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.hcontrollerPort_ = HedvigConfig.defaultHControllerPort_
|
||||||
|
|
||||||
|
self.cinderReplicationFactor_ = HedvigConfig.defaultCinderReplicationFactor_
|
||||||
|
self.cinderReplicationPolicy_ = HedvigConfig.defaultCinderReplicationPolicy_
|
||||||
|
self.cinderDedupEnable_ = HedvigConfig.defaultCinderDedupEnable_
|
||||||
|
self.cinderCompressEnable_ = HedvigConfig.defaultCinderCompressEnable_
|
||||||
|
self.cinderCacheEnable_ = HedvigConfig.defaultCinderCacheEnable_
|
||||||
|
self.cinderDiskResidence_ = HedvigConfig.defaultCinderDiskResidence_
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def parseAndGetBooleanEntry(cls, entry):
|
||||||
|
entry = entry.strip(" \t\n").lower()
|
||||||
|
if entry == "true":
|
||||||
|
return True
|
||||||
|
elif entry == "false":
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def parseAndGetReplicationPolicy(cls, strReplicationPolicy):
|
||||||
|
strReplicationPolicy = strReplicationPolicy.strip(" \n\t").lower()
|
||||||
|
if strReplicationPolicy == ReplicationPolicy._VALUES_TO_NAMES[ReplicationPolicy.Agnostic].lower():
|
||||||
|
return ReplicationPolicy.Agnostic
|
||||||
|
elif strReplicationPolicy == ReplicationPolicy._VALUES_TO_NAMES[ReplicationPolicy.RackAware].lower():
|
||||||
|
return ReplicationPolicy.RackAware
|
||||||
|
elif strReplicationPolicy == ReplicationPolicy._VALUES_TO_NAMES[ReplicationPolicy.DataCenterAware].lower():
|
||||||
|
return ReplicationPolicy.DataCenterAware
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def parseAndGetDiskResidence(cls, strDiskResidence):
|
||||||
|
strDiskResidence = strDiskResidence.strip(" \n\t").lower()
|
||||||
|
if strDiskResidence == DiskResidence._VALUES_TO_NAMES[DiskResidence.HDD].lower():
|
||||||
|
return DiskResidence.HDD
|
||||||
|
elif strDiskResidence == DiskResidence._VALUES_TO_NAMES[DiskResidence.Flash].lower():
|
||||||
|
return DiskResidence.Flash
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def getInstance():
|
||||||
|
if not HedvigConfig.instance_:
|
||||||
|
with HedvigConfig.lock_:
|
||||||
|
if not HedvigConfig.instance_:
|
||||||
|
try:
|
||||||
|
HedvigConfig.instance_ = HedvigConfig()
|
||||||
|
LOG.info(_LI('HedvigConfig initialized'))
|
||||||
|
except Exception:
|
||||||
|
LOG.error(_LE('Failed to initialize HedvigConfig'))
|
||||||
|
raise
|
||||||
|
return HedvigConfig.instance_
|
||||||
|
|
||||||
|
def getHedvigControllerPort(self):
|
||||||
|
return self.hcontrollerPort_;
|
||||||
|
|
||||||
|
def getCinderReplicationFactor(self):
|
||||||
|
return self.cinderReplicationFactor_
|
||||||
|
|
||||||
|
def getCinderReplicationPolicy(self):
|
||||||
|
return self.cinderReplicationPolicy_
|
||||||
|
|
||||||
|
def isCinderDedupEnabled(self):
|
||||||
|
return self.cinderDedupEnable_
|
||||||
|
|
||||||
|
def isCinderCacheEnabled(self):
|
||||||
|
return self.cinderCacheEnable_
|
||||||
|
|
||||||
|
def isCinderCompressEnabled(self):
|
||||||
|
return self.cinderCompressEnable_
|
||||||
|
|
||||||
|
def getCinderDiskResidence(self):
|
||||||
|
return self.cinderDiskResidence_
|
|
@ -0,0 +1,383 @@
|
||||||
|
from eventlet.green import os
|
||||||
|
import eventlet
|
||||||
|
import eventlet.queue
|
||||||
|
import os, fcntl
|
||||||
|
import hedvigpyc as hc
|
||||||
|
import time
|
||||||
|
|
||||||
|
from oslo_log import log as logging
|
||||||
|
|
||||||
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
class HedvigPipe():
|
||||||
|
|
||||||
|
pipeQ_ = eventlet.queue.Queue()
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
rfd, wfd = os.pipe()
|
||||||
|
self.rfd_ = rfd
|
||||||
|
self.wfd_ = wfd
|
||||||
|
|
||||||
|
def __del__(self):
|
||||||
|
fds = [self.wfd_, self.rfd_]
|
||||||
|
for fd in fds:
|
||||||
|
try:
|
||||||
|
os.close(fd)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get(cls):
|
||||||
|
try:
|
||||||
|
entry = HedvigPipe.pipeQ_.get(False)
|
||||||
|
HedvigPipe.pipeQ_.task_done()
|
||||||
|
except:
|
||||||
|
entry = HedvigPipe()
|
||||||
|
return entry
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def put(cls, hedvigPipe):
|
||||||
|
HedvigPipe.pipeQ_.put(hedvigPipe)
|
||||||
|
|
||||||
|
class HedvigOpCb():
|
||||||
|
def __init__(self):
|
||||||
|
self.startTime_ = time.time()
|
||||||
|
self.hedvigPipe_ = HedvigPipe.get()
|
||||||
|
self.rfd_ = self.hedvigPipe_.rfd_
|
||||||
|
self.wfd_ = self.hedvigPipe_.wfd_
|
||||||
|
fcntl.fcntl(self.rfd_, fcntl.F_SETFL, os.O_NONBLOCK)
|
||||||
|
self.id_ = Helper.getId()
|
||||||
|
self.pyCallback_ = hc.ObjWithPyCallback()
|
||||||
|
self.pyCallback_.setCallback(self)
|
||||||
|
self.pyCallback_.wfd_ = self.wfd_
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return (("HedvigBaseCb:id:%s:rfd:%s:wfd:%s") %(self.id_, self.rfd_, self.wfd_))
|
||||||
|
|
||||||
|
def __call__(self, x):
|
||||||
|
LOG.debug("Callback received: %s", self)
|
||||||
|
|
||||||
|
def closeFds(self):
|
||||||
|
if not (self.wfd_ or self.rfd_):
|
||||||
|
return
|
||||||
|
fds = [self.wfd_, self.rfd_]
|
||||||
|
self.wfd_ = None
|
||||||
|
self.rfd_ = None
|
||||||
|
for fd in fds:
|
||||||
|
if fd:
|
||||||
|
try:
|
||||||
|
os.close(fd)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
LOG.debug("Closed Fds: %s", self)
|
||||||
|
|
||||||
|
def waitForResult(self, instance):
|
||||||
|
LOG.debug("Waiting for result: %s", self)
|
||||||
|
eventlet.hubs.trampoline(self.rfd_, read= True)
|
||||||
|
LOG.debug("Received notification for result: %s", self)
|
||||||
|
os.read(self.rfd_, 1024)
|
||||||
|
HedvigPipe.pipeQ_.put(self.hedvigPipe_)
|
||||||
|
self.endTime_ = time.time()
|
||||||
|
|
||||||
|
def __del__(self, instance):
|
||||||
|
LOG.debug("Deleting object: %s", self)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def hedvigpycInit(cls, pagesSeedMap, workerThreadCount):
|
||||||
|
hc.hedvigpycInit(pagesSeedMap, workerThreadCount)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def hedvigpycShutdown(cls):
|
||||||
|
hc.hedvigpycShutdown()
|
||||||
|
|
||||||
|
class HGetTgtInstanceOpCb(HedvigOpCb):
|
||||||
|
|
||||||
|
def __init__(self,host):
|
||||||
|
HedvigOpCb.__init__(self)
|
||||||
|
self.op_ = hc.HGetTgtInstanceOp()
|
||||||
|
self.op_.host_ = str(host)
|
||||||
|
|
||||||
|
def getTgtInstance(self):
|
||||||
|
self.pyCallback_.getTgtInstance(self.op_)
|
||||||
|
self.waitForResult(self.__class__.__name__)
|
||||||
|
return self.op_.tgtMap_
|
||||||
|
|
||||||
|
def __del__(self):
|
||||||
|
HedvigOpCb.__del__(self)
|
||||||
|
|
||||||
|
class HDescribeVirtualDiskOpCb(HedvigOpCb):
|
||||||
|
|
||||||
|
def __init__(self,vDiskName):
|
||||||
|
HedvigOpCb.__init__(self)
|
||||||
|
self.op_ = hc.HDescribeVirtualDiskOp()
|
||||||
|
self.op_.vDiskName_ = str(vDiskName)
|
||||||
|
|
||||||
|
def describeVirtualDisk(self):
|
||||||
|
self.pyCallback_.describeVirtualDisk(self.op_)
|
||||||
|
self.waitForResult(self.__class__.__name__)
|
||||||
|
return self.op_.vDiskInfo_
|
||||||
|
|
||||||
|
def __del__(self):
|
||||||
|
HedvigOpCb.__del__(self)
|
||||||
|
|
||||||
|
class HGetLunCinderOpCb(HedvigOpCb):
|
||||||
|
|
||||||
|
def __init__(self,tgtHost,tgtPort,vDiskName):
|
||||||
|
HedvigOpCb.__init__(self)
|
||||||
|
self.op_ = hc.HGetLunCinderOp()
|
||||||
|
self.op_.tgtHost_ = str(tgtHost)
|
||||||
|
self.op_.tgtPort_ = tgtPort
|
||||||
|
self.op_.vDiskName_ = str(vDiskName)
|
||||||
|
|
||||||
|
def getLunCinder(self):
|
||||||
|
self.pyCallback_.getLunCinder(self.op_)
|
||||||
|
self.waitForResult(self.__class__.__name__)
|
||||||
|
return self.op_.lunNumber_
|
||||||
|
|
||||||
|
def __del__(self):
|
||||||
|
HedvigOpCb.__del__(self)
|
||||||
|
|
||||||
|
class HAddLunOpCb(HedvigOpCb):
|
||||||
|
|
||||||
|
def __init__(self,tgtHost,tgtPort,vDiskInfo):
|
||||||
|
HedvigOpCb.__init__(self)
|
||||||
|
LOG.debug("Addlun for virtual disk: %s", vDiskInfo.vDiskName)
|
||||||
|
self.op_ = hc.HAddLunOp()
|
||||||
|
self.op_.tgtHost_ = str(tgtHost)
|
||||||
|
self.op_.tgtPort_ = tgtPort
|
||||||
|
self.op_.vDiskInfo_ = hc.VDiskInfo()
|
||||||
|
self.op_.vDiskInfo_.dedup = vDiskInfo.dedup
|
||||||
|
self.op_.vDiskInfo_.vDiskName = str(vDiskInfo.vDiskName)
|
||||||
|
self.op_.vDiskInfo_.createdBy = str(vDiskInfo.createdBy)
|
||||||
|
self.op_.vDiskInfo_.size = vDiskInfo.size
|
||||||
|
self.op_.vDiskInfo_.replicationFactor = vDiskInfo.replicationFactor
|
||||||
|
self.op_.vDiskInfo_.blockSize = vDiskInfo.blockSize
|
||||||
|
self.op_.vDiskInfo_.exportedBlockSize = vDiskInfo.exportedBlockSize
|
||||||
|
self.op_.vDiskInfo_.isClone = vDiskInfo.isClone
|
||||||
|
#self.op_.vDiskInfo_.generationNbr = vDiskInfo.generationNbr
|
||||||
|
self.op_.vDiskInfo_.cloudEnabled = vDiskInfo.cloudEnabled
|
||||||
|
self.op_.vDiskInfo_.dedupBuckets = str(vDiskInfo.dedupBuckets)
|
||||||
|
self.op_.vDiskInfo_.masterVDiskName = str(vDiskInfo.masterVDiskName)
|
||||||
|
self.op_.vDiskInfo_.dedup = vDiskInfo.dedup
|
||||||
|
self.op_.vDiskInfo_.compressed = vDiskInfo.compressed
|
||||||
|
self.op_.vDiskInfo_.immutable = vDiskInfo.immutable
|
||||||
|
self.op_.vDiskInfo_.cacheEnable = vDiskInfo.cacheEnable
|
||||||
|
self.op_.vDiskInfo_.scsisn = vDiskInfo.scsisn
|
||||||
|
self.op_.vDiskInfo_.vTreeBuffer = str(vDiskInfo.vTreeBuffer)
|
||||||
|
#self.op_.vDiskInfo_.versionCounter = vDiskInfo.versionCounter
|
||||||
|
self.op_.vDiskInfo_.clusteredfilesystem = vDiskInfo.clusteredfilesystem
|
||||||
|
self.op_.vDiskInfo_.description = str(vDiskInfo.description)
|
||||||
|
self.op_.vDiskInfo_.mntLocation = str(vDiskInfo.mntLocation)
|
||||||
|
self.op_.vDiskInfo_.residence = vDiskInfo.residence
|
||||||
|
self.op_.vDiskInfo_.diskType = vDiskInfo.diskType
|
||||||
|
self.op_.vDiskInfo_.cloudProvider = vDiskInfo.cloudProvider
|
||||||
|
self.op_.vDiskInfo_.replicationPolicy = vDiskInfo.replicationPolicy
|
||||||
|
#self.op_.vDiskInfo_.targetLocations = hc.set_string()
|
||||||
|
#for location in vDiskInfo.targetLocations:
|
||||||
|
# self.op_.vDiskInfo_.targetLocations.append(location)
|
||||||
|
#self.op_.vDiskInfo_.cloneInfo = hc.CloneInfo()
|
||||||
|
#self.op_.vDiskInfo_.cloneInfo.baseDisk = str(vDiskInfo.cloneInfo.baseDisk)
|
||||||
|
#self.op_.vDiskInfo_.cloneInfo.snapshot = str(vDiskInfo.cloneInfo.snapshot)
|
||||||
|
#self.op_.vDiskInfo_.cloneInfo.baseVersion = vDiskInfo.cloneInfo.baseVersion
|
||||||
|
#self.op_.vDiskInfo_.cloneInfo.typeOfClone = vDiskInfo.cloneInfo.typeOfClone
|
||||||
|
#self.op_.vDiskInfo_.replicationPolicyInfo = hc.ReplicationPolicyInfo()
|
||||||
|
#self.op_.vDiskInfo_.replicationPolicyInfo.dataCenterNames = hc.buffer_vector()
|
||||||
|
#for dataCenterName in vDiskInfo.replicationPolicyInfo.dataCenterNames:
|
||||||
|
# self.op_.vDiskInfo_.replicationPolicyInfo.dataCenterNames.append(dataCenterName)
|
||||||
|
|
||||||
|
def addLun(self):
|
||||||
|
self.pyCallback_.addLun(self.op_)
|
||||||
|
self.waitForResult(self.__class__.__name__)
|
||||||
|
return self.op_.lunNumber_
|
||||||
|
|
||||||
|
def __del__(self):
|
||||||
|
HedvigOpCb.__del__(self)
|
||||||
|
|
||||||
|
class HDeleteLunOpCb(HedvigOpCb):
|
||||||
|
|
||||||
|
def __init__(self,tgtHost,tgtPort,vDiskName,lun):
|
||||||
|
HedvigOpCb.__init__(self)
|
||||||
|
self.op_ = hc.HDeleteLunOp()
|
||||||
|
self.op_.tgtHost_ = str(tgtHost)
|
||||||
|
self.op_.tgtPort_ = tgtPort
|
||||||
|
self.op_.vDiskName_ = str(vDiskName)
|
||||||
|
self.op_.lunNumber_ = lun
|
||||||
|
|
||||||
|
def deleteLun(self):
|
||||||
|
self.pyCallback_.deleteLun(self.op_)
|
||||||
|
self.waitForResult(self.__class__.__name__)
|
||||||
|
return self.op_.result_
|
||||||
|
|
||||||
|
def __del__(self):
|
||||||
|
HedvigOpCb.__del__(self)
|
||||||
|
|
||||||
|
class HAddAccessOpCb(HedvigOpCb):
|
||||||
|
|
||||||
|
def __init__(self,tgtHost,tgtPort,lun,ip):
|
||||||
|
HedvigOpCb.__init__(self)
|
||||||
|
self.op_ = hc.HAddAccessOp()
|
||||||
|
self.op_.tgtHost_ = str(tgtHost)
|
||||||
|
self.op_.tgtPort_ = tgtPort
|
||||||
|
self.op_.lunNumber_ = lun
|
||||||
|
self.op_.Ip_ = ip
|
||||||
|
|
||||||
|
def addAccess(self):
|
||||||
|
self.pyCallback_.addAccess(self.op_)
|
||||||
|
self.waitForResult(self.__class__.__name__)
|
||||||
|
return self.op_.result_
|
||||||
|
|
||||||
|
def __del__(self):
|
||||||
|
HedvigOpCb.__del__(self)
|
||||||
|
|
||||||
|
class HSnapshotFromTgtOpCb(HedvigOpCb):
|
||||||
|
|
||||||
|
def __init__(self,tgtHost,tgtPort,vDiskName):
|
||||||
|
HedvigOpCb.__init__(self)
|
||||||
|
self.op_ = hc.HSnapshotFromTgtOp()
|
||||||
|
self.op_.tgtHost_ = str(tgtHost)
|
||||||
|
self.op_.tgtPort_ = tgtPort
|
||||||
|
self.op_.vDiskName_ = vDiskName
|
||||||
|
|
||||||
|
def snapshotFromTgt(self):
|
||||||
|
self.pyCallback_.snapshotFromTgt(self.op_)
|
||||||
|
self.waitForResult(self.__class__.__name__)
|
||||||
|
return self.op_.snapshot_
|
||||||
|
|
||||||
|
def __del__(self):
|
||||||
|
HedvigOpCb.__del__(self)
|
||||||
|
|
||||||
|
class HSnapshotOpCb(HedvigOpCb):
|
||||||
|
|
||||||
|
def __init__(self,vDiskName):
|
||||||
|
HedvigOpCb.__init__(self)
|
||||||
|
self.op_ = hc.HSnapshotOp()
|
||||||
|
self.op_.vDiskName_ = str(vDiskName)
|
||||||
|
|
||||||
|
def snapshot(self):
|
||||||
|
self.pyCallback_.snapshot(self.op_)
|
||||||
|
self.waitForResult(self.__class__.__name__)
|
||||||
|
return self.op_.snapshotInfo_
|
||||||
|
|
||||||
|
def __del__(self):
|
||||||
|
HedvigOpCb.__del__(self)
|
||||||
|
|
||||||
|
class HDeleteSnapshotOpCb(HedvigOpCb):
|
||||||
|
|
||||||
|
def __init__(self,snapshotName):
|
||||||
|
HedvigOpCb.__init__(self)
|
||||||
|
self.op_ = hc.HDeleteSnapshotOp()
|
||||||
|
self.op_.snapshotName_ = str(snapshotName)
|
||||||
|
|
||||||
|
def deleteSnapshot(self):
|
||||||
|
self.pyCallback_.deleteSnapshot(self.op_)
|
||||||
|
self.waitForResult(self.__class__.__name__)
|
||||||
|
|
||||||
|
def __del__(self):
|
||||||
|
HedvigOpCb.__del__(self)
|
||||||
|
|
||||||
|
class HCreateVirtualDiskOpCb(HedvigOpCb):
|
||||||
|
|
||||||
|
def __init__(self, vDiskInfo):
|
||||||
|
HedvigOpCb.__init__(self)
|
||||||
|
LOG.debug("Creating virtual disk: %s", vDiskInfo.vDiskName)
|
||||||
|
self.op_ = hc.HCreateVirtualDiskOp()
|
||||||
|
self.op_.vDiskInfo_ = hc.VDiskInfo()
|
||||||
|
self.op_.vDiskInfo_.dedup = vDiskInfo.dedup
|
||||||
|
self.op_.vDiskInfo_.vDiskName = str(vDiskInfo.vDiskName)
|
||||||
|
self.op_.vDiskInfo_.createdBy = vDiskInfo.createdBy
|
||||||
|
self.op_.vDiskInfo_.size = vDiskInfo.size
|
||||||
|
self.op_.vDiskInfo_.replicationFactor = vDiskInfo.replicationFactor
|
||||||
|
self.op_.vDiskInfo_.blockSize = vDiskInfo.blockSize
|
||||||
|
self.op_.vDiskInfo_.exportedBlockSize = vDiskInfo.exportedBlockSize
|
||||||
|
self.op_.vDiskInfo_.isClone = vDiskInfo.isClone
|
||||||
|
self.op_.vDiskInfo_.cloudEnabled = vDiskInfo.cloudEnabled
|
||||||
|
self.op_.vDiskInfo_.dedupBuckets = str(vDiskInfo.dedupBuckets)
|
||||||
|
self.op_.vDiskInfo_.masterVDiskName = str(vDiskInfo.masterVDiskName)
|
||||||
|
self.op_.vDiskInfo_.dedup = vDiskInfo.dedup
|
||||||
|
self.op_.vDiskInfo_.compressed = vDiskInfo.compressed
|
||||||
|
self.op_.vDiskInfo_.immutable = vDiskInfo.immutable
|
||||||
|
self.op_.vDiskInfo_.cacheEnable = vDiskInfo.cacheEnable
|
||||||
|
self.op_.vDiskInfo_.vTreeBuffer = str(vDiskInfo.vTreeBuffer)
|
||||||
|
self.op_.vDiskInfo_.clusteredfilesystem = vDiskInfo.clusteredfilesystem
|
||||||
|
self.op_.vDiskInfo_.description = str(vDiskInfo.description)
|
||||||
|
self.op_.vDiskInfo_.mntLocation = str(vDiskInfo.mntLocation)
|
||||||
|
self.op_.vDiskInfo_.residence = vDiskInfo.residence
|
||||||
|
self.op_.vDiskInfo_.diskType = vDiskInfo.diskType
|
||||||
|
self.op_.vDiskInfo_.cloudProvider = vDiskInfo.cloudProvider
|
||||||
|
self.op_.vDiskInfo_.replicationPolicy = vDiskInfo.replicationPolicy
|
||||||
|
|
||||||
|
def createVirtualDisk(self):
|
||||||
|
self.pyCallback_.createVirtualDisk(self.op_)
|
||||||
|
self.waitForResult(self.__class__.__name__)
|
||||||
|
|
||||||
|
def __del__(self):
|
||||||
|
HedvigOpCb.__del__(self)
|
||||||
|
|
||||||
|
class HResizeVirtualDiskOpCb(HedvigOpCb):
|
||||||
|
|
||||||
|
def __init__(self, vDiskInfo):
|
||||||
|
HedvigOpCb.__init__(self)
|
||||||
|
LOG.debug("Resizing virtual disk: %s", vDiskInfo.vDiskName)
|
||||||
|
self.op_ = hc.HResizeVirtualDiskOp()
|
||||||
|
self.op_.vDiskInfo_ = hc.VDiskInfo()
|
||||||
|
self.op_.vDiskInfo_.dedup = vDiskInfo.dedup
|
||||||
|
self.op_.vDiskInfo_.vDiskName = str(vDiskInfo.vDiskName)
|
||||||
|
self.op_.vDiskInfo_.createdBy = vDiskInfo.createdBy
|
||||||
|
self.op_.vDiskInfo_.size = vDiskInfo.size
|
||||||
|
self.op_.vDiskInfo_.replicationFactor = vDiskInfo.replicationFactor
|
||||||
|
self.op_.vDiskInfo_.blockSize = vDiskInfo.blockSize
|
||||||
|
self.op_.vDiskInfo_.exportedBlockSize = vDiskInfo.exportedBlockSize
|
||||||
|
self.op_.vDiskInfo_.isClone = vDiskInfo.isClone
|
||||||
|
self.op_.vDiskInfo_.cloudEnabled = vDiskInfo.cloudEnabled
|
||||||
|
self.op_.vDiskInfo_.dedupBuckets = str(vDiskInfo.dedupBuckets)
|
||||||
|
self.op_.vDiskInfo_.masterVDiskName = str(vDiskInfo.masterVDiskName)
|
||||||
|
self.op_.vDiskInfo_.dedup = vDiskInfo.dedup
|
||||||
|
self.op_.vDiskInfo_.compressed = vDiskInfo.compressed
|
||||||
|
self.op_.vDiskInfo_.immutable = vDiskInfo.immutable
|
||||||
|
self.op_.vDiskInfo_.cacheEnable = vDiskInfo.cacheEnable
|
||||||
|
self.op_.vDiskInfo_.vTreeBuffer = str(vDiskInfo.vTreeBuffer)
|
||||||
|
self.op_.vDiskInfo_.clusteredfilesystem = vDiskInfo.clusteredfilesystem
|
||||||
|
self.op_.vDiskInfo_.description = str(vDiskInfo.description)
|
||||||
|
self.op_.vDiskInfo_.mntLocation = str(vDiskInfo.mntLocation)
|
||||||
|
self.op_.vDiskInfo_.residence = vDiskInfo.residence
|
||||||
|
self.op_.vDiskInfo_.diskType = vDiskInfo.diskType
|
||||||
|
self.op_.vDiskInfo_.cloudProvider = vDiskInfo.cloudProvider
|
||||||
|
self.op_.vDiskInfo_.replicationPolicy = vDiskInfo.replicationPolicy
|
||||||
|
|
||||||
|
def resizeVirtualDisk(self):
|
||||||
|
self.pyCallback_.resizeVirtualDisk(self.op_)
|
||||||
|
self.waitForResult(self.__class__.__name__)
|
||||||
|
|
||||||
|
def __del__(self):
|
||||||
|
HedvigOpCb.__del__(self)
|
||||||
|
|
||||||
|
class HDeleteVirtualDiskOpCb(HedvigOpCb):
|
||||||
|
|
||||||
|
def __init__(self, vDiskName):
|
||||||
|
HedvigOpCb.__init__(self)
|
||||||
|
self.op_ = hc.HDeleteVirtualDiskOp()
|
||||||
|
self.op_.vDiskName_ = str(vDiskName)
|
||||||
|
|
||||||
|
def deleteVirtualDisk(self):
|
||||||
|
self.pyCallback_.deleteVirtualDisk(self.op_)
|
||||||
|
self.waitForResult(self.__class__.__name__)
|
||||||
|
|
||||||
|
def __del__(self):
|
||||||
|
HedvigOpCb.__del__(self)
|
||||||
|
|
||||||
|
class HGetIqnOpCb(HedvigOpCb):
|
||||||
|
|
||||||
|
def __init__(self, hostname):
|
||||||
|
HedvigOpCb.__init__(self)
|
||||||
|
self.op_ = hc.HGetIqnOp()
|
||||||
|
self.op_.hostname_ = str(hostname)
|
||||||
|
|
||||||
|
def getIqn(self):
|
||||||
|
self.pyCallback_.getIqn(self.op_)
|
||||||
|
self.waitForResult(self.__class__.__name__)
|
||||||
|
return self.op_.iqn_
|
||||||
|
|
||||||
|
def __del__(self):
|
||||||
|
HedvigOpCb.__del__(self)
|
||||||
|
|
||||||
|
from Helper import Helper
|
|
@ -0,0 +1,19 @@
|
||||||
|
from email.Utils import formatdate
|
||||||
|
import xml.etree.ElementTree as ET
|
||||||
|
from datetime import datetime
|
||||||
|
import rfc822
|
||||||
|
from dateutil import parser
|
||||||
|
from dateutil import tz
|
||||||
|
import time
|
||||||
|
import datetime
|
||||||
|
from eventlet import getcurrent
|
||||||
|
|
||||||
|
class Helper(object):
|
||||||
|
def __init__(self, params):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def getId():
|
||||||
|
return id(getcurrent())
|
||||||
|
|
||||||
|
from HedvigOpCb import *
|
|
@ -0,0 +1,584 @@
|
||||||
|
#!/usr/bin/python
|
||||||
|
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||||
|
# Copyright (c) 2012 Hedvig, Inc.
|
||||||
|
# Copyright (c) 2012 OpenStack LLC.
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
"""
|
||||||
|
Volume driver for Hedvig Block Storage.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import netifaces
|
||||||
|
import os
|
||||||
|
import socket
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
|
||||||
|
from cinder import exception
|
||||||
|
from cinder import context
|
||||||
|
from cinder import utils
|
||||||
|
from cinder.db.sqlalchemy import api
|
||||||
|
from cinder.i18n import _, _LE, _LI, _LW
|
||||||
|
from cinder.volume import driver
|
||||||
|
from cinder.volume import volume_types
|
||||||
|
|
||||||
|
from oslo.config import cfg
|
||||||
|
from oslo_concurrency import processutils
|
||||||
|
from oslo_log import log as logging
|
||||||
|
|
||||||
|
from urlparse import urlparse
|
||||||
|
from cinder.volume.drivers.hedvig.HedvigConfig import HedvigConfig
|
||||||
|
from cinder.volume.drivers.hedvig.HedvigOpCb import *
|
||||||
|
import hedvigpyc as hc
|
||||||
|
|
||||||
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
hedvig_opts = [
|
||||||
|
cfg.StrOpt('hedvig_metadata_server',
|
||||||
|
help='The hostname (or IP address) of a hedvig metadata node in the cluster'),
|
||||||
|
]
|
||||||
|
|
||||||
|
CONF = cfg.CONF
|
||||||
|
CONF.register_opts(hedvig_opts)
|
||||||
|
|
||||||
|
class HedvigISCSIDriver(driver.ISCSIDriver):
|
||||||
|
"""Hedvig iSCSI volume driver."""
|
||||||
|
defaultVolumeSizeInGB_ = 1
|
||||||
|
defaultVolumeBlkSize_ = 4096
|
||||||
|
toGB_ = 1024 * 1024 * 1024
|
||||||
|
defaultCreatedBy_ = "OpenStack Cinder"
|
||||||
|
defaultExportedBlkSize_ = 512
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super(HedvigISCSIDriver, self).__init__(*args, **kwargs)
|
||||||
|
self.group_stats = {}
|
||||||
|
self.configuration.append_config_values(hedvig_opts)
|
||||||
|
|
||||||
|
def check_for_setup_error(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def do_setup(self, context):
|
||||||
|
self.context_ = context
|
||||||
|
LOG.debug('Context: %s', context)
|
||||||
|
self.hedvig_metadata_server = getattr(self.configuration, 'hedvig_metadata_server')
|
||||||
|
LOG.info(_LI('Initializing hedvig cinder driver with server - %s'), self.hedvig_metadata_server)
|
||||||
|
HedvigOpCb.hedvigpycInit(self.hedvig_metadata_server, 8)
|
||||||
|
|
||||||
|
def get_volume_stats(self, refresh=False):
|
||||||
|
# we need to get get stats for server.
|
||||||
|
total_capacity = float(1024)
|
||||||
|
used_capacity = float(0)
|
||||||
|
free_capacity = total_capacity - used_capacity
|
||||||
|
self.group_stats = {"volume_backend_name": "hedvig",
|
||||||
|
"vendor_name" : "Hedvig Inc",
|
||||||
|
"driver_version" : "0.99",
|
||||||
|
"storage_protocol" : "ISCSI",
|
||||||
|
"total_capacity_gb": total_capacity,
|
||||||
|
"free_capacity_gb": free_capacity,
|
||||||
|
"reserverd_percentage": 0,
|
||||||
|
"QoS_support": False}
|
||||||
|
return self.group_stats
|
||||||
|
|
||||||
|
def hedvigGetVolumeDetails(self, volume):
|
||||||
|
volName = volume['name']
|
||||||
|
project = volume['project_id']
|
||||||
|
displayName = volume['display_name']
|
||||||
|
displayDescription = volume['display_description']
|
||||||
|
if project == None:
|
||||||
|
project = ""
|
||||||
|
if displayName == None:
|
||||||
|
displayName = ""
|
||||||
|
if displayDescription == None:
|
||||||
|
displayDescription = ""
|
||||||
|
description = project + "\n" + displayName + "\n" + displayDescription
|
||||||
|
size = long(volume['size'])
|
||||||
|
if size == 0:
|
||||||
|
size = HedvigISCSIDriver.defaultVolumeSizeInGB_
|
||||||
|
size = size * HedvigISCSIDriver.toGB_
|
||||||
|
return volName, description, size
|
||||||
|
|
||||||
|
def create_volume(self, volume):
|
||||||
|
"""
|
||||||
|
Driver entry point for creating a new volume.
|
||||||
|
"""
|
||||||
|
LOG.debug("Creating new volume: %s", volume)
|
||||||
|
name, description, size = self.hedvigGetVolumeDetails(volume)
|
||||||
|
volumeTypeId = volume["volume_type_id"]
|
||||||
|
volumeType = None
|
||||||
|
try:
|
||||||
|
LOG.debug("Retrieving volume type details for id: %s", volumeTypeId)
|
||||||
|
volumeType = api.volume_type_get(self.context_, volumeTypeId)
|
||||||
|
LOG.debug("Volume type is: %s", volumeType)
|
||||||
|
except Exception as e:
|
||||||
|
LOG.error(_LE('Failed to retrieve volume type details for id: %s'), volumeTypeId)
|
||||||
|
raise exception.HedvigDriverException()
|
||||||
|
try:
|
||||||
|
LOG.debug("Volume name: %s, description: %s, size: %s", name, description, size)
|
||||||
|
self.hedvigCreateVirtualDisk(name, description, size, volumeType)
|
||||||
|
except Exception as e:
|
||||||
|
LOG.error(_LE('Failed to create volume. name: %s, description: %s, size: %s'), name, description, size)
|
||||||
|
raise exception.HedvigDriverException()
|
||||||
|
|
||||||
|
def delete_volume(self, volume):
|
||||||
|
"""
|
||||||
|
Driver entry point for deleting volume.
|
||||||
|
"""
|
||||||
|
LOG.debug("Deleting volume: %s", volume)
|
||||||
|
name = volume['name']
|
||||||
|
try:
|
||||||
|
self.hedvigDeleteVirtualDisk(name)
|
||||||
|
except Exception as e:
|
||||||
|
LOG.error(_LE('Failed to delete volume. volume: %s'), volume)
|
||||||
|
raise exception.HedvigDriverException()
|
||||||
|
|
||||||
|
def get_export(self, volume):
|
||||||
|
"""
|
||||||
|
Get the iSCSI export details for a volume.
|
||||||
|
"""
|
||||||
|
LOG.debug("volume: %s", volume)
|
||||||
|
pass
|
||||||
|
|
||||||
|
def ensure_export(self, context, volume):
|
||||||
|
"""
|
||||||
|
Driver entry point to get the export info for an existing volume.
|
||||||
|
Irrelevant for Hedvig. Export is created during attachment to instance.
|
||||||
|
"""
|
||||||
|
LOG.debug("context: %s, volume: %s", context, volume)
|
||||||
|
pass
|
||||||
|
|
||||||
|
def create_export(self, context, volume):
|
||||||
|
"""
|
||||||
|
Driver entry point to get the export info for a new volume.
|
||||||
|
Irrelevant for Hedvig. Export is created during attachment to instance.
|
||||||
|
"""
|
||||||
|
LOG.debug("context: %s, volume: %s", context, volume)
|
||||||
|
pass
|
||||||
|
|
||||||
|
def remove_export(self, context, volume):
|
||||||
|
"""
|
||||||
|
Driver entry point to remove an export for a volume.
|
||||||
|
Irrelevant for Hedvig. Export should be deleted on detachment.
|
||||||
|
"""
|
||||||
|
LOG.debug("context: %s, volume: %s", context, volume)
|
||||||
|
pass
|
||||||
|
|
||||||
|
def initialize_connection(self, volume, connector):
|
||||||
|
"""
|
||||||
|
Driver entry point to attach a volume to an instance.
|
||||||
|
|
||||||
|
Assign any created volume to a compute node/controllerVM so that it can be
|
||||||
|
attached to a instance.
|
||||||
|
This driver returns a driver_volume_type of 'iscsi'.
|
||||||
|
The format of the driver data is defined as follows -- similar to _get_iscsi_properties.
|
||||||
|
Example return value:
|
||||||
|
|
||||||
|
{
|
||||||
|
'driver_volume_type': 'iscsi'
|
||||||
|
'data': {
|
||||||
|
'target_discovered': True,
|
||||||
|
'target_iqn': 'iqn.2010-10.com.hedvig:target',
|
||||||
|
'target_portal': '192.168.108.143:3260',
|
||||||
|
'target_lun': '1',
|
||||||
|
'volume_id': 2,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
"""
|
||||||
|
LOG.info(_LI('Initializing connection. volume: %(volume)s, connector: %(connector)s'), {'volume': volume, 'connector': connector})
|
||||||
|
try:
|
||||||
|
computeHost = socket.getfqdn(connector['host'])
|
||||||
|
volName = volume['name']
|
||||||
|
tgtHost = self.hedvigLookupTgt(computeHost)
|
||||||
|
lunnum = self.hedvigGetLun(tgtHost, volName)
|
||||||
|
if lunnum == -1:
|
||||||
|
LOG.error(_LE('Failed to get lun for volume: %(volume)s, hedvig controller: %(tgtHost)s'), {'volume': volume, 'tgtHost': tgtHost})
|
||||||
|
raise Exception("Failed to add lun")
|
||||||
|
|
||||||
|
# Addaccess to the mgmt interface addr and iqn of the compute host
|
||||||
|
compute_host_iqn = self.hedvigGetIqn(computeHost)
|
||||||
|
self.hedvigAddAccess(tgtHost, lunnum, compute_host_iqn)
|
||||||
|
compute_mgmt_addr = socket.gethostbyname(socket.getfqdn(computeHost))
|
||||||
|
self.hedvigAddAccess(tgtHost, lunnum, socket.gethostbyname(socket.getfqdn(computeHost)))
|
||||||
|
|
||||||
|
# Addaccess to both storage and mgmt interface addrs for
|
||||||
|
# iscsi discovery to succeed
|
||||||
|
interfaces = netifaces.interfaces()
|
||||||
|
storage_addr = None
|
||||||
|
mgmt_addr = None
|
||||||
|
if 'br-storage' in interfaces and netifaces.AF_INET in netifaces.ifaddresses('br-storage'):
|
||||||
|
storage_interface = netifaces.ifaddresses('br-storage')[netifaces.AF_INET]
|
||||||
|
if storage_interface and 'addr' in storage_interface[0]:
|
||||||
|
storage_addr = storage_interface[0]['addr']
|
||||||
|
if 'br-mgmt' in interfaces and netifaces.AF_INET in netifaces.ifaddresses('br-mgmt'):
|
||||||
|
mgmt_interface = netifaces.ifaddresses('br-mgmt')[netifaces.AF_INET]
|
||||||
|
if mgmt_interface and 'addr' in mgmt_interface[0]:
|
||||||
|
mgmt_addr = mgmt_interface[0]['addr']
|
||||||
|
if mgmt_addr and (compute_mgmt_addr != mgmt_addr):
|
||||||
|
self.hedvigAddAccess(tgtHost, lunnum, mgmt_addr)
|
||||||
|
if storage_addr and mgmt_addr and (storage_addr != mgmt_addr):
|
||||||
|
self.hedvigAddAccess(tgtHost, lunnum, storage_addr)
|
||||||
|
|
||||||
|
targetName, portal = self.hedvigDoIscsiDiscovery(tgtHost, lunnum)
|
||||||
|
iscsi_properties = ({'target_discovered': True,
|
||||||
|
'target_iqn': targetName,
|
||||||
|
'target_portal': portal,
|
||||||
|
'target_lun': lunnum })
|
||||||
|
LOG.debug("volName: %s, connector: %s, iscsi_properties: %s", volName, connector, iscsi_properties)
|
||||||
|
return {'driver_volume_type': 'iscsi', 'data': iscsi_properties}
|
||||||
|
except Exception as e:
|
||||||
|
LOG.error(_LE('Volume assignment to connect failed. volume: %(volume)s, connector: %(connector)s'), {'volume': volume, 'connector': connector})
|
||||||
|
raise exception.HedvigDriverException()
|
||||||
|
|
||||||
|
def terminate_connection(self, volume, connector, **kwargs):
|
||||||
|
"""
|
||||||
|
Driver entry point to detach volume from instance.
|
||||||
|
"""
|
||||||
|
LOG.debug("Terminating connection. volume: %s, connector: %s", volume, connector)
|
||||||
|
try:
|
||||||
|
computeHost = socket.getfqdn(connector['host']) #connector['host']
|
||||||
|
volName = volume['name']
|
||||||
|
tgtHost = self.hedvigLookupTgt(computeHost)
|
||||||
|
if tgtHost == '':
|
||||||
|
LOG.error(_LE('Failed to get hedvig controller for compute host: %s'), computeHost)
|
||||||
|
raise Exception("Failed to get hedvig controller for compute host: %s" % (computeHost))
|
||||||
|
lunnum = self.hedvigGetLun(tgtHost, volName)
|
||||||
|
if lunnum == -1:
|
||||||
|
LOG.error(_LE('Failed to get lun for volume: %s'), volume)
|
||||||
|
raise Exception("Failed to get lun for volume: %s" % (volume))
|
||||||
|
self.hedvigDeleteLun(tgtHost, volName, lunnum)
|
||||||
|
except Exception as e:
|
||||||
|
LOG.error(_LE('Failed to terminate connection. volume: %(volume)s, connector: %(connector)s'), {'volume': volume, 'connector': connector})
|
||||||
|
raise exception.HedvigDriverException()
|
||||||
|
|
||||||
|
def hedvigLookupTgt(self, host):
|
||||||
|
"""
|
||||||
|
Get the tgt instance associated with the compute host.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
LOG.debug("Looking up hedvig controller for compute host: %s", host)
|
||||||
|
hedvigGetTgtInstanceOp = HGetTgtInstanceOpCb(host)
|
||||||
|
tgtMap = hedvigGetTgtInstanceOp.getTgtInstance()
|
||||||
|
tgt = None
|
||||||
|
if "block" in tgtMap:
|
||||||
|
tgtList = tgtMap["block"]
|
||||||
|
if len(tgtList) > 0:
|
||||||
|
tgt = tgtList[0]
|
||||||
|
if not tgt:
|
||||||
|
raise exception.NotFound(name=host)
|
||||||
|
LOG.debug("Found hedvig controller: %s, for host: %s", tgt, host)
|
||||||
|
return tgt
|
||||||
|
except Exception as e:
|
||||||
|
LOG.error(_LE('Failed to get hedvig controller for compute host: %s'), host)
|
||||||
|
raise e
|
||||||
|
|
||||||
|
def hedvigDoIscsiLogout(self, targetName, portal, toThrow=False):
|
||||||
|
try:
|
||||||
|
(retOut, retErr) = utils.execute("iscsiadm", "--mode", "node", "--targetname", targetName, "--portal", portal, "--logout", run_as_root=True)
|
||||||
|
if retErr != None and len(retErr) > 0:
|
||||||
|
LOG.error(_LE('Failed iscsi logout. targetName: %(targetName)s, portal: %(portal)s'), {'targetName': targetName, 'portal': portal})
|
||||||
|
except processutils.ProcessExecutionError as e:
|
||||||
|
LOG.error(_LE('Error occurred during iscsi logout. targetName: %(targetName)s, portal: %(portal)s, stdout: %(stdout)s, stderr: %(stderr)s, exit_code: %(exit_code)s'), {'targetName': targetName, 'portal': portal, 'stdout': e.stdout, 'stderr': e.stderr, 'exit_code': e.exit_code})
|
||||||
|
if toThrow:
|
||||||
|
raise e
|
||||||
|
|
||||||
|
def hedvigDoIscsiDiscovery(self, tgtHost, lunNum):
|
||||||
|
LOG.debug("Do iscsi discovery, hedvig controller: %s, lun: %s", tgtHost, lunNum)
|
||||||
|
try:
|
||||||
|
(retOut , retErr) = utils.execute("iscsiadm", "-m" , "discovery", "-t", "sendtargets", "-p", tgtHost, run_as_root=True)
|
||||||
|
LOG.debug("Done iscsi discovery, hedvig controller: %s, lun: %s, output: %s, error: %s", tgtHost, lunNum, retOut, retErr)
|
||||||
|
if retErr != None and len(retErr) > 0:
|
||||||
|
# logout not in use targets
|
||||||
|
for line in retErr.rstrip(" ").split("\n"):
|
||||||
|
if "target:" not in line:
|
||||||
|
continue
|
||||||
|
line = line[line.find("target:") + len("target:") :]
|
||||||
|
line = line[:line.find("],")]
|
||||||
|
targetName, portal = line.split("portal:")
|
||||||
|
targetName = targetName.strip(" ").strip(",")
|
||||||
|
portal = portal.strip(" ").strip(",")
|
||||||
|
self.hedvigDoIscsiLogout(targetName, portal)
|
||||||
|
targetName = None
|
||||||
|
portal = None
|
||||||
|
if retOut != None and len(retOut) > 0:
|
||||||
|
expectedTarget = tgtHost + "-" + str(lunNum)
|
||||||
|
for line in retOut.strip(" ").split("\n"):
|
||||||
|
if expectedTarget in line:
|
||||||
|
portal, targetName = line.strip(" ").split(" ")
|
||||||
|
portal = portal.strip(" ").split(",")[0]
|
||||||
|
targetName = targetName.strip(" ")
|
||||||
|
break
|
||||||
|
except processutils.ProcessExecutionError as e:
|
||||||
|
LOG.error(_LE('Error occurred during iscsi discovery. stdout: %(stdout)s, stderr: %(stderr)s, exit_code: %(exit_code)s'), {'stdout': e.stdout, 'stderr': e.stderr, 'exit_code': e.exit_code})
|
||||||
|
raise e
|
||||||
|
if targetName == None or portal == None:
|
||||||
|
raise Exception("Failed iscsi discovery. hedvig controller: %s, lun: %s" % (tgtHost, lunNum))
|
||||||
|
return targetName, portal
|
||||||
|
|
||||||
|
def hedvigDeleteLun(self, tgtHost, vDiskName, lunnum):
|
||||||
|
LOG.debug("Deleting lun. hedvig controller: %s, vDiskName: %s, lun: %s", tgtHost, vDiskName, lunnum)
|
||||||
|
tgtPort = HedvigConfig.getInstance().getHedvigControllerPort()
|
||||||
|
hedvigDeleteLunOp = HDeleteLunOpCb(tgtHost, tgtPort, vDiskName, lunnum)
|
||||||
|
result = hedvigDeleteLunOp.deleteLun()
|
||||||
|
return result
|
||||||
|
|
||||||
|
def hedvigGetLun(self, tgtHost, vDiskName):
|
||||||
|
"""
|
||||||
|
Looks up lun based on tgthost and vDiskName.
|
||||||
|
If lun does not exist then call addLun and return the lun number.
|
||||||
|
If lun exists, just return the lun number.
|
||||||
|
"""
|
||||||
|
LOG.debug("Getting lun. hedvig controller: %s, vDiskName: %s", tgtHost, vDiskName)
|
||||||
|
tgtPort = HedvigConfig.getInstance().getHedvigControllerPort()
|
||||||
|
hedvigGetLunOp = HGetLunCinderOpCb(tgtHost, tgtPort, vDiskName)
|
||||||
|
lunNo = hedvigGetLunOp.getLunCinder()
|
||||||
|
if lunNo > -1:
|
||||||
|
LOG.debug("Found lun: %s", str(lunNo))
|
||||||
|
return lunNo
|
||||||
|
|
||||||
|
# If the lun is not found, add lun for the vdisk
|
||||||
|
hedvigDescribeVirtualDiskOp = HDescribeVirtualDiskOpCb(vDiskName)
|
||||||
|
vDiskInfo = hedvigDescribeVirtualDiskOp.describeVirtualDisk()
|
||||||
|
tgtPort = HedvigConfig.getInstance().getHedvigControllerPort()
|
||||||
|
hedvigAddLunOp = HAddLunOpCb(tgtHost, tgtPort, vDiskInfo)
|
||||||
|
lunNo = hedvigAddLunOp.addLun()
|
||||||
|
LOG.debug("Found lun: %s", str(lunNo))
|
||||||
|
return lunNo
|
||||||
|
|
||||||
|
def hedvigGetIqn(self, hostname):
|
||||||
|
"""
|
||||||
|
Looks up the iqn for the given host.
|
||||||
|
"""
|
||||||
|
LOG.debug("Getting IQN for hostname: %s", hostname)
|
||||||
|
hedvigGetIqnOp = HGetIqnOpCb(hostname)
|
||||||
|
iqn = hedvigGetIqnOp.getIqn()
|
||||||
|
LOG.debug("Got IQN: %s, for hostname: %s", iqn, hostname)
|
||||||
|
return iqn
|
||||||
|
|
||||||
|
def hedvigAddAccess(self, tgtHost, lun, initiator):
|
||||||
|
"""
|
||||||
|
Adds access to LUN for initiator's ip/iqn
|
||||||
|
"""
|
||||||
|
LOG.debug("Adding access. hedvig controller: %s, lun: %s, initiator: %s", tgtHost, lun, initiator)
|
||||||
|
try:
|
||||||
|
tgtPort = HedvigConfig.getInstance().getHedvigControllerPort()
|
||||||
|
hedvigAddAccessOp = HAddAccessOpCb(tgtHost, tgtPort, lun, initiator)
|
||||||
|
result = hedvigAddAccessOp.addAccess()
|
||||||
|
return result
|
||||||
|
except Exception as e:
|
||||||
|
LOG.error(_LE('Failed to add access. hedvig controller: %(controller)s, lun: %(lun)s, initiator: %(initiator)s'), {'controller': tgtHost, 'lun': lun, 'initiator': initiator})
|
||||||
|
raise e
|
||||||
|
|
||||||
|
def create_snapshot(self, snapshot):
|
||||||
|
"""
|
||||||
|
Driver entry point for creating a snapshot.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
ctxt = context.get_admin_context()
|
||||||
|
volName = snapshot['volume_name']
|
||||||
|
snapshotName = snapshot['name']
|
||||||
|
project = snapshot['project_id']
|
||||||
|
snapshotId = snapshot['id']
|
||||||
|
LOG.debug("Creating snapshot. volName: %s, snapshotName: %s, project: %s, snapshotId: %s", volName, snapshotName, project, snapshotId)
|
||||||
|
hedvigSnapshotName = self.hedvigCreateSnapshot(volName)
|
||||||
|
# Set the snapshot name to ret value.
|
||||||
|
LOG.debug("Updating snapshot name. snapshotId: %s, snapshotName: %s, newName: %s", snapshotId, snapshotName, hedvigSnapshotName)
|
||||||
|
self.db.snapshot_update(ctxt, snapshotId, {'display_name': str(hedvigSnapshotName)})
|
||||||
|
except Exception as e:
|
||||||
|
LOG.error(_LE('Failed to create snapshot. volName: %(volName)s, snapshotName: %(snapshotName)s, project: %(project)s, snapshotId: %(snapshotId)s'), {'volName': volName, 'snapshotName': snapshotName, 'project': project, 'snapshotId': snapshotId})
|
||||||
|
raise exception.HedvigDriverException()
|
||||||
|
|
||||||
|
def detach_volume(self, context, volume, attachment):
|
||||||
|
LOG.info(_LI('Detaching volume. context: %(context)s, volume: %(volume)s, attachment: %(attachment)s'), {'context': context, 'volume': volume, 'attachment': attachment})
|
||||||
|
return
|
||||||
|
|
||||||
|
def hedvigCreateSnapshot(self, vDiskName):
|
||||||
|
"""
|
||||||
|
Hedvig call to create snapshot of vdisk.
|
||||||
|
"""
|
||||||
|
hedvigDescribeVirtualDiskOp = HDescribeVirtualDiskOpCb(vDiskName)
|
||||||
|
vDiskInfo = hedvigDescribeVirtualDiskOp.describeVirtualDisk()
|
||||||
|
snapshotName = None
|
||||||
|
LOG.debug("Creating snapshot. mount location: %s", vDiskInfo.mntLocation)
|
||||||
|
if vDiskInfo.mntLocation == "":
|
||||||
|
LOG.debug("vDisk: %s is not mounted", vDiskName)
|
||||||
|
hedvigSnapshotOp = HSnapshotOpCb(vDiskName)
|
||||||
|
snapInfo = hedvigSnapshotOp.snapshot()
|
||||||
|
snapshotName = snapInfo.snapshot
|
||||||
|
else:
|
||||||
|
tgtPort = HedvigConfig.getInstance().getHedvigControllerPort()
|
||||||
|
hedvigSnapshotFromTgtOp = HSnapshotFromTgtOpCb(tgtHost, tgtPort, vDiskName)
|
||||||
|
tgtHost = vDiskInfo.mntLocation.split(":")[0]
|
||||||
|
LOG.debug("vDisk: %s is mounted on tgtHost: %s", vDiskName, tgtHost)
|
||||||
|
snapshotName = hedvigSnapshotFromTgtOp.snapshotFromtgt()
|
||||||
|
return snapshotName
|
||||||
|
|
||||||
|
def delete_snapshot(self, snapshot):
|
||||||
|
"""
|
||||||
|
Driver entry point for deleting a snapshot.
|
||||||
|
"""
|
||||||
|
volName = snapshot['volume_name']
|
||||||
|
snapshotName = snapshot['display_name']
|
||||||
|
project = snapshot['project_id']
|
||||||
|
LOG.debug("Deleting snapshot. volName: %s, snapshotName: %s, project: %s", volName, snapshotName, project)
|
||||||
|
try:
|
||||||
|
hedvigDeleteSnapshotOp = HDeleteSnapshotOpCb(snapshotName)
|
||||||
|
hedvigDeleteSnapshotOp.deleteSnapshot()
|
||||||
|
except Exception as e:
|
||||||
|
LOG.error(_LE('Failed to delete snapshot. volName: %(volName)s, snapshotName: %(snapshotName)s, project: %(project)s'), {'volName': volName, 'snapshotName': snapshotName, 'project': project})
|
||||||
|
raise exception.HedvigDriverException()
|
||||||
|
|
||||||
|
def create_volume_from_snapshot(self, volume, snapshot):
|
||||||
|
"""
|
||||||
|
Driver entry point for creating a new volume from a snapshot.
|
||||||
|
This is the same as cloning.
|
||||||
|
"""
|
||||||
|
name, description, size = self.hedvigGetVolumeDetails(volume)
|
||||||
|
snapshotname = snapshot['display_name']
|
||||||
|
try:
|
||||||
|
LOG.debug("Creating volume from snapshot. snapshotName: %s, name: %s, description: %s, size: %s", snapshotname, name, description, size)
|
||||||
|
self.hedvigCloneSnapshot(snapshotname, name, description, size)
|
||||||
|
except Exception as e:
|
||||||
|
LOG.error(_LE('Failed to create volume from snapshot. snapshotName: %(snapshotName)s, name: %(name)s, description: %(description)s, size: %(size)s'), {'snapshotName': snapshotName, 'name': name, 'description': description, 'size': size})
|
||||||
|
raise exception.HedvigDriverException()
|
||||||
|
|
||||||
|
def check_for_export(self, context, volume_id):
|
||||||
|
"""
|
||||||
|
Not relevant to Hedvig
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
def extend_volume(self, volume, newSize):
|
||||||
|
"""
|
||||||
|
Resizes virtual disk.
|
||||||
|
newSize should be greater than current size.
|
||||||
|
"""
|
||||||
|
name, description, size = self.hedvigGetVolumeDetails(volume)
|
||||||
|
newSize = int(newSize) * HedvigISCSIDriver.toGB_
|
||||||
|
LOG.info(_LI('Resizing virtual disk. name: %(name)s, newSize: %(newSize)s'), {'name': name, 'newSize': newSize})
|
||||||
|
try:
|
||||||
|
hedvigDescribeVirtualDiskOp = HDescribeVirtualDiskOpCb(name)
|
||||||
|
vDiskInfo = hedvigDescribeVirtualDiskOp.describeVirtualDisk()
|
||||||
|
if vDiskInfo.size > newSize:
|
||||||
|
LOG.error(_LE('Cannot reduce virtual disk size. currentSize: %(currentSize)s, newSize: %(newSize)s'), {'currentSize': vDiskInfo.size, 'newSize': newSize})
|
||||||
|
raise Exception("Cannot reduce virtual disk size. currentSize: %s, newSize: %s" % (vDiskInfo.size, newSize))
|
||||||
|
size = vDiskInfo.size
|
||||||
|
vDiskInfo.size = newSize
|
||||||
|
hedvigResizeVirtualDiskOp = HResizeVirtualDiskOpCb(vDiskInfo)
|
||||||
|
hedvigResizeVirtualDiskOp.resizeVirtualDisk()
|
||||||
|
except Exception as e:
|
||||||
|
LOG.error(_LE('Cannot reduce virtual disk size. currentSize: %(currentSize)s, newSize: %(newSize)s'), {'currentSize': size, 'newSize': newSize})
|
||||||
|
raise exception.HedvigDriverException()
|
||||||
|
|
||||||
|
def hedvigCreateVirtualDisk(self, name, description, size, volumeType):
|
||||||
|
LOG.info(_LI('Creating virtual disk. name: %(name)s, description: %(description)s, size: %(size)s'), {'name': name, 'description': description, 'size': size})
|
||||||
|
vDiskInfo = hc.VDiskInfo()
|
||||||
|
vDiskInfo.vDiskName = str(name)
|
||||||
|
vDiskInfo.blockSize = HedvigISCSIDriver.defaultVolumeBlkSize_
|
||||||
|
vDiskInfo.size = size
|
||||||
|
vDiskInfo.createdBy = str(HedvigISCSIDriver.defaultCreatedBy_)
|
||||||
|
vDiskInfo.description = str(description)
|
||||||
|
vDiskInfo.residence = HedvigConfig.getInstance().getCinderDiskResidence()
|
||||||
|
vDiskInfo.replicationFactor = HedvigConfig.getInstance().getCinderReplicationFactor()
|
||||||
|
vDiskInfo.replicationPolicy = HedvigConfig.getInstance().getCinderReplicationPolicy()
|
||||||
|
vDiskInfo.clusteredfilesystem = False
|
||||||
|
vDiskInfo.exportedBlockSize = HedvigISCSIDriver.defaultExportedBlkSize_
|
||||||
|
vDiskInfo.cacheEnable = HedvigConfig.getInstance().isCinderCacheEnabled()
|
||||||
|
vDiskInfo.diskType = hc.DiskType.BLOCK
|
||||||
|
vDiskInfo.immutable = False
|
||||||
|
vDiskInfo.dedup = HedvigConfig.getInstance().isCinderDedupEnabled()
|
||||||
|
vDiskInfo.compressed = HedvigConfig.getInstance().isCinderCompressEnabled()
|
||||||
|
vDiskInfo.cloudEnabled = False
|
||||||
|
vDiskInfo.cloudProvider = 0
|
||||||
|
vDiskInfo.isClone = False
|
||||||
|
vDiskInfo.consistency = hc.Consistency.STRONG
|
||||||
|
if "extra_specs" in volumeType:
|
||||||
|
key = volumeType["extra_specs"]
|
||||||
|
if "qos:dedup_enable" in key:
|
||||||
|
entry = key["qos:dedup_enable"]
|
||||||
|
val = HedvigConfig.parseAndGetBooleanEntry(entry)
|
||||||
|
if val != None:
|
||||||
|
vDiskInfo.dedup = val
|
||||||
|
if "qos:compress_enable" in key:
|
||||||
|
entry = key["qos:compress_enable"]
|
||||||
|
val = HedvigConfig.parseAndGetBooleanEntry(entry)
|
||||||
|
if val != None:
|
||||||
|
vDiskInfo.compressed = val
|
||||||
|
if "qos:cache_enable" in key:
|
||||||
|
entry = key["qos:cache_enable"]
|
||||||
|
val = HedvigConfig.parseAndGetBooleanEntry(entry)
|
||||||
|
if val != None:
|
||||||
|
vDiskInfo.cacheEnable = val
|
||||||
|
if "qos:replication_factor" in key:
|
||||||
|
val = key["qos:replication_factor"]
|
||||||
|
val = int(val)
|
||||||
|
if val > 0:
|
||||||
|
vDiskInfo.replicationFactor = val
|
||||||
|
if "qos:replication_policy" in key:
|
||||||
|
entry = key["qos:replication_policy"]
|
||||||
|
val = HedvigConfig.parseAndGetReplicationPolicy(entry)
|
||||||
|
if val != None:
|
||||||
|
vDiskInfo.replicationPolicy = val
|
||||||
|
if "qos:disk_residence" in key:
|
||||||
|
entry = key["qos:disk_residence"]
|
||||||
|
val = HedvigConfig.parseAndGetDiskResidence(entry)
|
||||||
|
if val != None:
|
||||||
|
vDiskInfo.residence = val
|
||||||
|
hedvigCreateVirtualDiskOp = HCreateVirtualDiskOpCb(vDiskInfo)
|
||||||
|
hedvigCreateVirtualDiskOp.createVirtualDisk()
|
||||||
|
|
||||||
|
def hedvigDeleteVirtualDisk(self, name):
|
||||||
|
LOG.info(_LI('Deleting virtual disk. name - %s'), name)
|
||||||
|
hedvigDeleteVirtualDiskOp = HDeleteVirtualDiskOpCb(name)
|
||||||
|
hedvigDeleteVirtualDiskOp.deleteVirtualDisk()
|
||||||
|
|
||||||
|
def hedvigCloneSnapshot(self, snapshotname, name, description, size):
|
||||||
|
LOG.debug("Cloning a snapshot. snapshotName: %s, name: %s, description: %s, size: %s", snapshotname, name, description, size)
|
||||||
|
LOG.info(_LI('Cloning a snapshot. snapshotName: %(snapshotName)s, name: %(name)s, description: %(description)s, size: %(size)s'), {'snapshotName': snapshotName, 'name': name, 'description': description, 'size': size})
|
||||||
|
vDiskInfo = hc.VDiskInfo()
|
||||||
|
cloneInfo = hc.CloneInfo()
|
||||||
|
baseDisk = snapshotname.split("$")[0]
|
||||||
|
baseVersion = snapshotname.split("$")[2]
|
||||||
|
hedvigDescribeVirtualDiskOp = HDescribeVirtualDiskOpCb(vDiskName)
|
||||||
|
parentVDiskInfo = hedvigDescribeVirtualDiskOp.describeVirtualDisk()
|
||||||
|
vDiskInfo.vDiskName = name
|
||||||
|
cloneInfo.typeOfClone = TypeOfClone.Shallow
|
||||||
|
vDiskInfo.clusteredfilesystem = parentVDiskInfo.clusteredfilesystem
|
||||||
|
vDiskInfo.blockSize = parentVDiskInfo.blockSize
|
||||||
|
vDiskInfo.exportedBlockSize = parentVDiskInfo.exportedBlockSize
|
||||||
|
if parentVDiskInfo.size > size:
|
||||||
|
LOG.error(_LE('Failed to clone snapshot. Size of the clone: %(cloneSize)s is less than the parent virtual disk size: %(parentSize)s'), {'cloneSize': size, 'parentSize': parentVDiskInfo.size})
|
||||||
|
raise Exception("Specified size: %s is less than parent virtual disk size: %s" % (size, parentVDiskInfo.size))
|
||||||
|
vDiskInfo.size = size
|
||||||
|
vDiskInfo.createdBy = parentVDiskInfo.createdBy
|
||||||
|
vDiskInfo.description = description
|
||||||
|
vDiskInfo.residence = parentVDiskInfo.residence
|
||||||
|
vDiskInfo.replicationFactor = parentVDiskInfo.replicationFactor
|
||||||
|
vDiskInfo.replicationPolicy = parentVDiskInfo.replicationPolicy
|
||||||
|
cloneInfo.snapshot = snapshotname
|
||||||
|
cloneInfo.baseVersion = int(baseVersion)
|
||||||
|
cloneInfo.baseDisk = baseDisk
|
||||||
|
vDiskInfo.cloneInfo = cloneInfo
|
||||||
|
vDiskInfo.isClone = True
|
||||||
|
vDiskInfo.scsisn = 0
|
||||||
|
vDiskInfo.cacheEnable = parentVDiskInfo.cacheEnable
|
||||||
|
vDiskInfo.diskType = parentVDiskInfo.diskType
|
||||||
|
vDiskInfo.cloudProvider = parentVDiskInfo.cloudProvider
|
||||||
|
vDiskInfo.cloudEnabled = parentVDiskInfo.cloudEnabled
|
||||||
|
vDiskInfo.dedup = parentVDiskInfo.dedup
|
||||||
|
vDiskInfo.consistency = Consistency.STRONG
|
||||||
|
hedvigCreateVirtualDiskOp = HCreateVirtualDiskOpCb(vDiskInfo)
|
||||||
|
hedvigCreateVirtualDiskOp.createVirtualDisk()
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
Binary file not shown.
|
@ -0,0 +1,8 @@
|
||||||
|
class plugin_hedvig_cinder
|
||||||
|
{
|
||||||
|
if($::operatingsystem == 'Ubuntu') {
|
||||||
|
include plugin_hedvig_cinder::ubuntu
|
||||||
|
}else {
|
||||||
|
include plugin_hedvig_cinder::centos
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,152 @@
|
||||||
|
class plugin_hedvig_cinder::ubuntu
|
||||||
|
{
|
||||||
|
$services = ['cinder-volume']
|
||||||
|
|
||||||
|
$metadata_server = $plugin_settings['hedvig_metadata_server']
|
||||||
|
$volume_type = "hedvig"
|
||||||
|
|
||||||
|
file { "/usr/lib/python2.7/dist-packages/cinder/volume/drivers/hedvig/":
|
||||||
|
ensure => directory,
|
||||||
|
}
|
||||||
|
|
||||||
|
file { "/usr/lib/python2.7/dist-packages/_hedvigpyc.so":
|
||||||
|
source => 'puppet:///modules/plugin_hedvig_cinder/pythonlibs/_hedvigpyc.so',
|
||||||
|
mode => '644',
|
||||||
|
owner => 'root',
|
||||||
|
group => 'root',
|
||||||
|
}
|
||||||
|
|
||||||
|
file { "/usr/local/lib/libhedvig.so":
|
||||||
|
source => 'puppet:///modules/plugin_hedvig_cinder/libs/libhedvig.so',
|
||||||
|
mode => '644',
|
||||||
|
owner => 'root',
|
||||||
|
group => 'root',
|
||||||
|
}
|
||||||
|
|
||||||
|
file { "/usr/local/lib/libcrcutil.so":
|
||||||
|
source => 'puppet:///modules/plugin_hedvig_cinder/libs/libcrcutil.so',
|
||||||
|
mode => '644',
|
||||||
|
owner => 'root',
|
||||||
|
group => 'root',
|
||||||
|
}
|
||||||
|
|
||||||
|
file { "/usr/local/lib/libthrift-0.9.0.so":
|
||||||
|
source => 'puppet:///modules/plugin_hedvig_cinder/libs/libthrift-0.9.0.so',
|
||||||
|
mode => '644',
|
||||||
|
owner => 'root',
|
||||||
|
group => 'root',
|
||||||
|
}
|
||||||
|
|
||||||
|
file { "/usr/local/lib/libthriftnb-0.9.0.so":
|
||||||
|
source => 'puppet:///modules/plugin_hedvig_cinder/libs/libthriftnb-0.9.0.so',
|
||||||
|
mode => '644',
|
||||||
|
owner => 'root',
|
||||||
|
group => 'root',
|
||||||
|
}
|
||||||
|
|
||||||
|
file { "/usr/local/lib/libunwind.so.8":
|
||||||
|
source => 'puppet:///modules/plugin_hedvig_cinder/libs/libunwind.so.8',
|
||||||
|
mode => '644',
|
||||||
|
owner => 'root',
|
||||||
|
group => 'root',
|
||||||
|
}
|
||||||
|
|
||||||
|
file { "/usr/lib/python2.7/dist-packages/cinder/volume/drivers/hedvig/hedvig-cinder.py":
|
||||||
|
source => 'puppet:///modules/plugin_hedvig_cinder/python/hedvig-cinder.py',
|
||||||
|
mode => '644',
|
||||||
|
owner => 'root',
|
||||||
|
group => 'root',
|
||||||
|
}
|
||||||
|
|
||||||
|
file { "/usr/lib/python2.7/dist-packages/cinder/volume/drivers/hedvig/hedvigpyc.py":
|
||||||
|
source => 'puppet:///modules/plugin_hedvig_cinder/python/hedvigpyc.py',
|
||||||
|
mode => '644',
|
||||||
|
owner => 'root',
|
||||||
|
group => 'root',
|
||||||
|
}
|
||||||
|
|
||||||
|
file { "/usr/lib/python2.7/dist-packages/cinder/volume/drivers/hedvig/__init__.py":
|
||||||
|
source => 'puppet:///modules/plugin_hedvig_cinder/python/__init__.py',
|
||||||
|
mode => '644',
|
||||||
|
owner => 'root',
|
||||||
|
group => 'root',
|
||||||
|
}
|
||||||
|
|
||||||
|
file { "/usr/lib/python2.7/dist-packages/cinder/volume/drivers/hedvig/HedvigConfig.py":
|
||||||
|
source => 'puppet:///modules/plugin_hedvig_cinder/python/HedvigConfig.py',
|
||||||
|
mode => '644',
|
||||||
|
owner => 'root',
|
||||||
|
group => 'root',
|
||||||
|
}
|
||||||
|
|
||||||
|
file { "/usr/lib/python2.7/dist-packages/cinder/volume/drivers/hedvig/Helper.py":
|
||||||
|
source => 'puppet:///modules/plugin_hedvig_cinder/python/Helper.py',
|
||||||
|
mode => '644',
|
||||||
|
owner => 'root',
|
||||||
|
group => 'root',
|
||||||
|
}
|
||||||
|
|
||||||
|
file { "/usr/lib/python2.7/dist-packages/cinder/volume/drivers/hedvig/HedvigOpCb.py":
|
||||||
|
source => 'puppet:///modules/plugin_hedvig_cinder/python/HedvigOpCb.py',
|
||||||
|
mode => '644',
|
||||||
|
owner => 'root',
|
||||||
|
group => 'root',
|
||||||
|
}
|
||||||
|
|
||||||
|
package {'libboost-all-dev':
|
||||||
|
ensure => installed ,
|
||||||
|
}->
|
||||||
|
|
||||||
|
package {'libsnappy-dev':
|
||||||
|
ensure => installed ,
|
||||||
|
}->
|
||||||
|
|
||||||
|
package {'libgoogle-glog-dev':
|
||||||
|
ensure => installed ,
|
||||||
|
}->
|
||||||
|
|
||||||
|
ini_setting { 'cinder_conf_enabled_backends':
|
||||||
|
ensure => present,
|
||||||
|
path => '/etc/cinder/cinder.conf',
|
||||||
|
section => 'DEFAULT',
|
||||||
|
setting => 'enabled_backends',
|
||||||
|
value => 'hedvig',
|
||||||
|
before => Ini_setting['cinder_conf_volume_driver'],
|
||||||
|
} ->
|
||||||
|
|
||||||
|
ini_setting { 'cinder_conf_volume_driver':
|
||||||
|
ensure => present,
|
||||||
|
path => '/etc/cinder/cinder.conf',
|
||||||
|
section => 'hedvig',
|
||||||
|
setting => 'volume_driver',
|
||||||
|
value => 'cinder.volume.drivers.hedvig.hedvig-cinder.HedvigISCSIDriver',
|
||||||
|
before => Ini_setting['cinder_conf_hedvig_metadata_server'],
|
||||||
|
} ->
|
||||||
|
|
||||||
|
ini_setting { 'cinder_conf_hedvig_metadata_server':
|
||||||
|
ensure => present,
|
||||||
|
path => '/etc/cinder/cinder.conf',
|
||||||
|
section => 'hedvig',
|
||||||
|
setting => 'hedvig_metadata_server',
|
||||||
|
value => $metadata_server,
|
||||||
|
} ->
|
||||||
|
|
||||||
|
service { $services:
|
||||||
|
ensure => running,
|
||||||
|
}->
|
||||||
|
exec { "Create Cinder volume type \'${volume_type}\'":
|
||||||
|
command => "bash -c 'source /root/openrc; cinder type-create ${volume_type}'",
|
||||||
|
path => ['/usr/bin', '/bin'],
|
||||||
|
unless => "bash -c 'source /root/openrc; cinder type-list |grep -q \" ${volume_type} \"'",
|
||||||
|
}
|
||||||
|
|
||||||
|
exec { "ldconfig /usr/local/lib":
|
||||||
|
command => 'ldconfig /usr/local/lib',
|
||||||
|
path => ['/usr/local/sbin','/usr/local/bin','/usr/sbin','/usr/bin','/sbin','/bin'],
|
||||||
|
} ->
|
||||||
|
|
||||||
|
exec { "ReStart Cinder volume ":
|
||||||
|
command => 'service cinder-volume restart',
|
||||||
|
path => ['/usr/local/sbin','/usr/local/bin','/usr/sbin','/usr/bin','/sbin','/bin'],
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
attributes:
|
||||||
|
multibackend:
|
||||||
|
value: 'true'
|
||||||
|
label: 'Multi-backend enabled'
|
||||||
|
description: 'Hedvig will be used in a multi-backend environment'
|
||||||
|
weight: 10
|
||||||
|
type: "checkbox"
|
||||||
|
hedvig_metadata_server:
|
||||||
|
value: ''
|
||||||
|
label: 'Hedvig cluster node(s)'
|
||||||
|
description: 'Comma separated list of hostname (or IP address) for Hedvig cluster node(s)'
|
||||||
|
weight: 20
|
||||||
|
type: "text"
|
||||||
|
regex:
|
||||||
|
source: '\S'
|
||||||
|
error: "This field cannot be empty"
|
Binary file not shown.
|
@ -0,0 +1,35 @@
|
||||||
|
# Plugin name
|
||||||
|
name: fuel-plugin-hedvig-cinder
|
||||||
|
# Human-readable name for your plugin
|
||||||
|
title: Fuel plugin for Hedvig cinder driver
|
||||||
|
# Plugin version
|
||||||
|
version: '1.0.0'
|
||||||
|
# Description
|
||||||
|
description: Enable to use Hedvig as a cinder backend
|
||||||
|
# Required fuel version
|
||||||
|
fuel_version: ['7.0', '8.0']
|
||||||
|
# Specify license of your plugin
|
||||||
|
licenses: ['Apache License Version 2.0']
|
||||||
|
# Specify author or company name
|
||||||
|
authors: ['abhjith shenoy(ashenoy@hedviginc.com), suhani gupta(suhani@hedviginc.com)']
|
||||||
|
# A link to the plugin's page
|
||||||
|
homepage: 'https://github.com/openstack/fuel-plugin-hedvig-cinder'
|
||||||
|
# Specify a group which your plugin implements, possible options:
|
||||||
|
# network, storage, storage::cinder, storage::glance, hypervisor
|
||||||
|
groups: ['storage::cinder']
|
||||||
|
|
||||||
|
# The plugin is compatible with releases in the list
|
||||||
|
releases:
|
||||||
|
- os: ubuntu
|
||||||
|
version: 2015.1.0-7.0
|
||||||
|
mode: ['ha']
|
||||||
|
deployment_scripts_path: deployment_scripts/
|
||||||
|
repository_path: repositories/ubuntu
|
||||||
|
- os: ubuntu
|
||||||
|
version: 2015.1.0-8.0
|
||||||
|
mode: ['ha']
|
||||||
|
deployment_scripts_path: deployment_scripts/
|
||||||
|
repository_path: repositories/ubuntu
|
||||||
|
|
||||||
|
# Version of plugin package
|
||||||
|
package_version: '1.0.0'
|
|
@ -0,0 +1,5 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Add here any the actions which are required before plugin build
|
||||||
|
# like packages building, packages downloading from mirrors and so on.
|
||||||
|
# The script should return 0 if there were no errors.
|
|
@ -0,0 +1,11 @@
|
||||||
|
# These tasks will be merged into deployment graph. Here you
|
||||||
|
# can specify new tasks for any roles, even built-in ones.
|
||||||
|
|
||||||
|
- id: hedvig-cinder
|
||||||
|
type: puppet
|
||||||
|
role: ['cinder']
|
||||||
|
stage: post_deployment
|
||||||
|
parameters:
|
||||||
|
puppet_manifest: puppet/manifests/controller.pp
|
||||||
|
puppet_modules: "puppet/modules/:/etc/puppet/modules/"
|
||||||
|
timeout: 360
|
Loading…
Reference in New Issue