Implements: hedvig fuel cinder plugin

Change-Id: I294de1df8df88ef57a42d5712f6e825f1e991e6d
This commit is contained in:
hedvig-ci 2016-02-04 19:06:29 -08:00 committed by suhanigupta
parent 1eabe89f91
commit d1829eaa79
27 changed files with 2831 additions and 0 deletions

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
.tox
.build
*.pyc

202
LICENSE Normal file
View File

@ -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.

4
README.md Normal file
View File

@ -0,0 +1,4 @@
fuel-plugin-hedvig-cinder
============
Plugin description

View File

@ -0,0 +1,4 @@
#!/bin/bash
# It's a script which deploys your plugin
echo fuel-plugin-hedvig-cinder > /tmp/fuel-plugin-hedvig-cinder

View File

@ -0,0 +1,2 @@
$plugin_settings = hiera('fuel-plugin-hedvig-cinder')
class {'plugin_hedvig_cinder': }

View File

@ -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_

View File

@ -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

View File

@ -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 *

View File

@ -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

View File

@ -0,0 +1,8 @@
class plugin_hedvig_cinder
{
if($::operatingsystem == 'Ubuntu') {
include plugin_hedvig_cinder::ubuntu
}else {
include plugin_hedvig_cinder::centos
}
}

View File

@ -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'],
}
}

16
environment_config.yaml Normal file
View File

@ -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.

35
metadata.yaml Normal file
View File

@ -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'

5
pre_build_hook Normal file
View File

@ -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.

View File

View File

11
tasks.yaml Normal file
View File

@ -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