Package rtslib :: Module root
[hide private]
[frames] | no frames]

Source Code for Module rtslib.root

  1  ''' 
  2  Implements the RTSRoot class. 
  3   
  4  This file is part of RTSLib. 
  5  Copyright (c) 2011-2013 by Datera, Inc 
  6   
  7  Licensed under the Apache License, Version 2.0 (the "License"); you may 
  8  not use this file except in compliance with the License. You may obtain 
  9  a copy of the License at 
 10   
 11      http://www.apache.org/licenses/LICENSE-2.0 
 12   
 13  Unless required by applicable law or agreed to in writing, software 
 14  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 
 15  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 
 16  License for the specific language governing permissions and limitations 
 17  under the License. 
 18  ''' 
 19   
 20  import re 
 21  import os 
 22  import stat 
 23  import json 
 24   
 25  from node import CFSNode 
 26  from target import Target 
 27  from fabric import FabricModule 
 28  from tcm import (StorageObject, FileIOStorageObject, BlockStorageObject, 
 29                   PSCSIStorageObject, RDMCPStorageObject) 
 30  from utils import RTSLibError, RTSLibBrokenLink, modprobe, mount_configfs 
 31  from utils import dict_remove, set_attributes 
 32   
 33  storageobjects = dict( 
 34      fileio=FileIOStorageObject, 
 35      block=BlockStorageObject, 
 36      pscsi=PSCSIStorageObject, 
 37      ramdisk=RDMCPStorageObject, 
 38      ) 
 39   
 40  default_save_file = "/etc/target/saveconfig.json" 
 41   
42 -class RTSRoot(CFSNode):
43 ''' 44 This is an interface to the root of the configFS object tree. 45 Is allows one to start browsing Target and StorageObjects, 46 as well as helper methods to return arbitrary objects from the 47 configFS tree. 48 49 >>> import rtslib.root as root 50 >>> rtsroot = root.RTSRoot() 51 >>> rtsroot.path 52 '/sys/kernel/config/target' 53 >>> rtsroot.exists 54 True 55 >>> rtsroot.targets # doctest: +ELLIPSIS 56 [...] 57 >>> rtsroot.tpgs # doctest: +ELLIPSIS 58 [...] 59 >>> rtsroot.storage_objects # doctest: +ELLIPSIS 60 [...] 61 >>> rtsroot.network_portals # doctest: +ELLIPSIS 62 [...] 63 64 ''' 65 66 # RTSRoot private stuff
67 - def __init__(self):
68 ''' 69 Instantiate an RTSRoot object. Basically checks for configfs setup and 70 base kernel modules (tcm) 71 ''' 72 super(RTSRoot, self).__init__() 73 modprobe('configfs') 74 mount_configfs() 75 modprobe('target_core_mod') 76 self._create_in_cfs_ine('any')
77
78 - def _list_targets(self):
79 self._check_self() 80 for fabric_module in self.fabric_modules: 81 for target in fabric_module.targets: 82 yield target
83
84 - def _list_storage_objects(self):
85 self._check_self() 86 for so in StorageObject.all(): 87 yield so
88
89 - def _list_tpgs(self):
90 self._check_self() 91 for t in self.targets: 92 for tpg in t.tpgs: 93 yield tpg
94
95 - def _list_node_acls(self):
96 self._check_self() 97 for t in self.tpgs: 98 for node_acl in t.node_acls: 99 yield node_acl
100
101 - def _list_mapped_luns(self):
102 self._check_self() 103 for na in self.node_acls: 104 for mlun in na.mapped_luns: 105 yield mlun
106
107 - def _list_network_portals(self):
108 self._check_self() 109 for t in self.tpgs: 110 for p in t.network_portals: 111 yield p
112
113 - def _list_luns(self):
114 self._check_self() 115 for t in self.tpgs: 116 for lun in t.luns: 117 yield lun
118
119 - def _list_sessions(self):
120 self._check_self() 121 for na in self.node_acls: 122 if na.session: 123 yield na.session
124
125 - def _list_fabric_modules(self):
126 self._check_self() 127 for mod in FabricModule.all(): 128 yield mod
129
130 - def __str__(self):
131 return "rtslib"
132 133 # RTSRoot public stuff 134
135 - def dump(self):
136 ''' 137 Returns a dict representing the complete state of the target 138 config, suitable for serialization/deserialization, and then 139 handing to restore(). 140 ''' 141 d = super(RTSRoot, self).dump() 142 d['storage_objects'] = [so.dump() for so in self.storage_objects] 143 d['targets'] = [t.dump() for t in self.targets] 144 d['fabric_modules'] = [f.dump() for f in self.fabric_modules 145 if f.has_feature("discovery_auth") 146 if f.discovery_enable_auth] 147 return d
148
149 - def clear_existing(self, confirm=False):
150 ''' 151 Remove entire current configuration. 152 ''' 153 if not confirm: 154 raise RTSLibError("As a precaution, confirm=True needs to be set") 155 156 # Targets depend on storage objects, delete them first. 157 for t in self.targets: 158 t.delete() 159 for fm in (f for f in self.fabric_modules if f.has_feature("discovery_auth")): 160 fm.clear_discovery_auth_settings() 161 for so in self.storage_objects: 162 so.delete()
163
164 - def restore(self, config, clear_existing=False, abort_on_error=False):
165 ''' 166 Takes a dict generated by dump() and reconfigures the target to match. 167 Returns list of non-fatal errors that were encountered. 168 ''' 169 if clear_existing: 170 self.clear_existing(confirm=True) 171 elif list(self.storage_objects) or list(self.targets): 172 raise RTSLibError("storageobjects or targets present, not restoring." + 173 " Set clear_existing=True?") 174 175 errors = [] 176 177 if abort_on_error: 178 def err_func(err_str): 179 raise RTSLibError(err_str)
180 else: 181 def err_func(err_str): 182 errors.append(err_str + ", skipped")
183 184 for index, so in enumerate(config.get('storage_objects', [])): 185 if 'name' not in so: 186 err_func("'name' not defined in storage object %d" % index) 187 continue 188 try: 189 so_cls = storageobjects[so['plugin']] 190 except KeyError: 191 err_func("'plugin' not defined or invalid in storageobject %s" % so['name']) 192 continue 193 kwargs = so.copy() 194 dict_remove(kwargs, ('exists', 'attributes', 'plugin', 'buffered_mode')) 195 try: 196 so_obj = so_cls(**kwargs) 197 except (TypeError, ValueError): 198 err_func("Could not create StorageObject %s" % so['name']) 199 continue 200 201 # Custom err func to include block name 202 def so_err_func(x): 203 return err_func("Storage Object %s/%s: %s" % (so['plugin'], so['name'], x)) 204 205 set_attributes(so_obj, so.get('attributes', {}), so_err_func) 206 207 # Don't need to create fabric modules 208 for index, fm in enumerate(config.get('fabric_modules', [])): 209 if 'name' not in fm: 210 err_func("'name' not defined in fabricmodule %d" % index) 211 continue 212 for fm_obj in self.fabric_modules: 213 if fm['name'] == fm_obj.name: 214 fm_obj.setup(fm, err_func) 215 break 216 217 for index, t in enumerate(config.get('targets', [])): 218 if 'wwn' not in t: 219 err_func("'wwn' not defined in target %d" % index) 220 continue 221 if 'fabric' not in t: 222 err_func("target %s missing 'fabric' field" % t['wwn']) 223 continue 224 if t['fabric'] not in (f.name for f in self.fabric_modules): 225 err_func("Unknown fabric '%s'" % t['fabric']) 226 continue 227 228 fm_obj = FabricModule(t['fabric']) 229 230 # Instantiate target 231 Target.setup(fm_obj, t, err_func) 232 233 return errors 234
235 - def save_to_file(self, save_file=None):
236 ''' 237 Write the configuration in json format to a file. 238 ''' 239 if not save_file: 240 save_file = default_save_file 241 242 with open(save_file+".temp", "w+") as f: 243 os.fchmod(f.fileno(), stat.S_IRUSR | stat.S_IWUSR) 244 f.write(json.dumps(self.dump(), sort_keys=True, indent=2)) 245 f.write("\n") 246 os.fsync(f.fileno()) 247 248 os.rename(save_file+".temp", save_file)
249
250 - def restore_from_file(self, restore_file=None, clear_existing=True, abort_on_error=False):
251 ''' 252 Restore the configuration from a file in json format. 253 Returns a list of non-fatal errors. If abort_on_error is set, 254 it will raise the exception instead of continuing. 255 ''' 256 if not restore_file: 257 restore_file = default_save_file 258 259 with open(restore_file, "r") as f: 260 config = json.loads(f.read()) 261 return self.restore(config, clear_existing=clear_existing, 262 abort_on_error=abort_on_error)
263 264 targets = property(_list_targets, 265 doc="Get the list of Target objects.") 266 tpgs = property(_list_tpgs, 267 doc="Get the list of all the existing TPG objects.") 268 node_acls = property(_list_node_acls, 269 doc="Get the list of all the existing NodeACL objects.") 270 mapped_luns = property(_list_mapped_luns, 271 doc="Get the list of all the existing MappedLUN objects.") 272 sessions = property(_list_sessions, 273 doc="Get the list of all the existing sessions.") 274 network_portals = property(_list_network_portals, 275 doc="Get the list of all the existing Network Portal objects.") 276 storage_objects = property(_list_storage_objects, 277 doc="Get the list of all the existing Storage objects.") 278 luns = property(_list_luns, 279 doc="Get the list of all existing LUN objects.") 280 fabric_modules = property(_list_fabric_modules, 281 doc="Get the list of all FabricModule objects.") 282
283 -def _test():
284 '''Run the doctests.''' 285 import doctest 286 doctest.testmod()
287 288 if __name__ == "__main__": 289 _test() 290