00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 import random
00019 import tempfile
00020 import os
00021 import time
00022 import sqlite3
00023
00024
00025 from lsm import (size_human_2_size_bytes)
00026 from lsm import (System, Volume, Disk, Pool, FileSystem, AccessGroup,
00027 FsSnapshot, NfsExport, md5, LsmError, TargetPort,
00028 ErrorNumber, JobStatus)
00029
00030
00031 def _handle_errors(method):
00032 def wrapper(*args, **kargs):
00033 try:
00034 return method(*args, **kargs)
00035 except sqlite3.OperationalError as sql_error:
00036 if type(args[0]) is SimArray and hasattr(args[0], 'bs_obj'):
00037 args[0].bs_obj.trans_rollback()
00038 if str(sql_error) == 'database is locked':
00039 raise LsmError(
00040 ErrorNumber.TIMEOUT,
00041 "Timeout to require lock on state file")
00042 raise LsmError(
00043 ErrorNumber.PLUGIN_BUG,
00044 "Got unexpected error from sqlite3: %s" % str(sql_error))
00045 except LsmError:
00046 if type(args[0]) is SimArray and hasattr(args[0], 'bs_obj'):
00047 args[0].bs_obj.trans_rollback()
00048 raise
00049 except Exception as base_error:
00050 if type(args[0]) is SimArray and hasattr(args[0], 'bs_obj'):
00051 args[0].bs_obj.trans_rollback()
00052 raise LsmError(
00053 ErrorNumber.PLUGIN_BUG,
00054 "Got unexpected error: %s" % str(base_error))
00055 return wrapper
00056
00057
00058 def _random_vpd():
00059 """
00060 Generate a random VPD83 NAA_Type3 ID
00061 """
00062 vpd = ['60']
00063 for _ in range(0, 15):
00064 vpd.append(str('%02x' % (random.randint(0, 255))))
00065 return "".join(vpd)
00066
00067
00068 class PoolRAID(object):
00069 _RAID_DISK_CHK = {
00070 Volume.RAID_TYPE_JBOD: lambda x: x > 0,
00071 Volume.RAID_TYPE_RAID0: lambda x: x > 0,
00072 Volume.RAID_TYPE_RAID1: lambda x: x == 2,
00073 Volume.RAID_TYPE_RAID3: lambda x: x >= 3,
00074 Volume.RAID_TYPE_RAID4: lambda x: x >= 3,
00075 Volume.RAID_TYPE_RAID5: lambda x: x >= 3,
00076 Volume.RAID_TYPE_RAID6: lambda x: x >= 4,
00077 Volume.RAID_TYPE_RAID10: lambda x: x >= 4 and x % 2 == 0,
00078 Volume.RAID_TYPE_RAID15: lambda x: x >= 6 and x % 2 == 0,
00079 Volume.RAID_TYPE_RAID16: lambda x: x >= 8 and x % 2 == 0,
00080 Volume.RAID_TYPE_RAID50: lambda x: x >= 6 and x % 2 == 0,
00081 Volume.RAID_TYPE_RAID60: lambda x: x >= 8 and x % 2 == 0,
00082 Volume.RAID_TYPE_RAID51: lambda x: x >= 6 and x % 2 == 0,
00083 Volume.RAID_TYPE_RAID61: lambda x: x >= 8 and x % 2 == 0,
00084 }
00085
00086 _RAID_PARITY_DISK_COUNT_FUNC = {
00087 Volume.RAID_TYPE_JBOD: lambda x: x,
00088 Volume.RAID_TYPE_RAID0: lambda x: x,
00089 Volume.RAID_TYPE_RAID1: lambda x: 1,
00090 Volume.RAID_TYPE_RAID3: lambda x: x - 1,
00091 Volume.RAID_TYPE_RAID4: lambda x: x - 1,
00092 Volume.RAID_TYPE_RAID5: lambda x: x - 1,
00093 Volume.RAID_TYPE_RAID6: lambda x: x - 2,
00094 Volume.RAID_TYPE_RAID10: lambda x: x / 2,
00095 Volume.RAID_TYPE_RAID15: lambda x: x / 2 - 1,
00096 Volume.RAID_TYPE_RAID16: lambda x: x / 2 - 2,
00097 Volume.RAID_TYPE_RAID50: lambda x: x - 2,
00098 Volume.RAID_TYPE_RAID60: lambda x: x - 4,
00099 Volume.RAID_TYPE_RAID51: lambda x: x / 2 - 1,
00100 Volume.RAID_TYPE_RAID61: lambda x: x / 2 - 2,
00101 }
00102
00103 @staticmethod
00104 def data_disk_count(raid_type, disk_count):
00105 """
00106 Return a integer indicating how many disks should be used as
00107 real data(not mirrored or parity) disks.
00108 Treating RAID 5 and 6 using fixed parity disk.
00109 """
00110 if raid_type not in PoolRAID._RAID_DISK_CHK.keys():
00111 raise LsmError(
00112 ErrorNumber.PLUGIN_BUG,
00113 "data_disk_count(): Got unsupported raid type(%d)" %
00114 raid_type)
00115
00116 if PoolRAID._RAID_DISK_CHK[raid_type](disk_count) is False:
00117 raise LsmError(
00118 ErrorNumber.PLUGIN_BUG,
00119 "data_disk_count(): Illegal disk count"
00120 "(%d) for raid type(%d)" % (disk_count, raid_type))
00121 return PoolRAID._RAID_PARITY_DISK_COUNT_FUNC[raid_type](disk_count)
00122
00123
00124 class BackStore(object):
00125 VERSION = "3.4"
00126 VERSION_SIGNATURE = 'LSM_SIMULATOR_DATA_%s_%s' % (VERSION, md5(VERSION))
00127 JOB_DEFAULT_DURATION = 1
00128 JOB_DATA_TYPE_VOL = 1
00129 JOB_DATA_TYPE_FS = 2
00130 JOB_DATA_TYPE_FS_SNAP = 3
00131
00132 SYS_ID = "sim-01"
00133 SYS_NAME = "LSM simulated storage plug-in"
00134 BLK_SIZE = 512
00135 DEFAULT_STRIP_SIZE = 128 * 1024
00136
00137 _LIST_SPLITTER = '#'
00138
00139 SYS_KEY_LIST = ['id', 'name', 'status', 'status_info', 'version']
00140
00141 POOL_KEY_LIST = [
00142 'id', 'name', 'status', 'status_info',
00143 'element_type', 'unsupported_actions', 'raid_type',
00144 'member_type', 'parent_pool_id', 'total_space', 'free_space',
00145 'strip_size']
00146
00147 DISK_KEY_LIST = [
00148 'id', 'name', 'total_space', 'disk_type', 'status',
00149 'owner_pool_id', 'role']
00150
00151 VOL_KEY_LIST = [
00152 'id', 'vpd83', 'name', 'total_space', 'consumed_size',
00153 'pool_id', 'admin_state', 'thinp', 'is_hw_raid_vol']
00154
00155 TGT_KEY_LIST = [
00156 'id', 'port_type', 'service_address', 'network_address',
00157 'physical_address', 'physical_name']
00158
00159 AG_KEY_LIST = ['id', 'name', 'init_type', 'init_ids_str']
00160
00161 JOB_KEY_LIST = ['id', 'duration', 'timestamp', 'data_type', 'data_id']
00162
00163 FS_KEY_LIST = [
00164 'id', 'name', 'total_space', 'free_space', 'consumed_size',
00165 'pool_id']
00166
00167 FS_SNAP_KEY_LIST = [
00168 'id', 'fs_id', 'name', 'timestamp']
00169
00170 EXP_KEY_LIST = [
00171 'id', 'fs_id', 'exp_path', 'auth_type', 'anon_uid', 'anon_gid',
00172 'options', 'exp_root_hosts_str', 'exp_rw_hosts_str',
00173 'exp_ro_hosts_str']
00174
00175 SUPPORTED_VCR_RAID_TYPES = [
00176 Volume.RAID_TYPE_RAID0, Volume.RAID_TYPE_RAID1,
00177 Volume.RAID_TYPE_RAID5, Volume.RAID_TYPE_RAID6,
00178 Volume.RAID_TYPE_RAID10, Volume.RAID_TYPE_RAID50,
00179 Volume.RAID_TYPE_RAID60]
00180
00181 SUPPORTED_VCR_STRIP_SIZES = [
00182 8 * 1024, 16 * 1024, 32 * 1024, 64 * 1024, 128 * 1024, 256 * 1024,
00183 512 * 1024, 1024 * 1024]
00184
00185 def __init__(self, statefile, timeout):
00186 if not os.path.exists(statefile):
00187 os.close(os.open(statefile, os.O_WRONLY | os.O_CREAT))
00188
00189 os.chmod(statefile, 0o666)
00190
00191 self.statefile = statefile
00192 self.lastrowid = None
00193 self.sql_conn = sqlite3.connect(
00194 statefile, timeout=int(timeout/1000), isolation_level="IMMEDIATE")
00195
00196
00197 sql_cmd = "PRAGMA foreign_keys = ON;\n"
00198
00199 sql_cmd += (
00200 """
00201 CREATE TABLE systems (
00202 id TEXT PRIMARY KEY,
00203 name TEXT NOT NULL,
00204 status INTEGER NOT NULL,
00205 status_info TEXT,
00206 version TEXT NOT NULL);
00207 """)
00208
00209
00210 sql_cmd += (
00211 "CREATE TABLE tgts ("
00212 "id INTEGER PRIMARY KEY, "
00213 "port_type INTEGER NOT NULL, "
00214 "service_address TEXT NOT NULL, "
00215 "network_address TEXT NOT NULL, "
00216 "physical_address TEXT NOT NULL, "
00217 "physical_name TEXT NOT NULL);\n")
00218
00219 sql_cmd += (
00220 "CREATE TABLE pools ("
00221 "id INTEGER PRIMARY KEY, "
00222 "name TEXT UNIQUE NOT NULL, "
00223 "status INTEGER NOT NULL, "
00224 "status_info TEXT, "
00225 "element_type INTEGER NOT NULL, "
00226 "unsupported_actions INTEGER, "
00227 "raid_type INTEGER NOT NULL, "
00228 "parent_pool_id INTEGER, "
00229
00230 "member_type INTEGER, "
00231 "strip_size INTEGER, "
00232 "total_space LONG);\n")
00233
00234
00235 sql_cmd += (
00236 "CREATE TABLE disks ("
00237 "id INTEGER PRIMARY KEY, "
00238 "total_space LONG NOT NULL, "
00239 "disk_type INTEGER NOT NULL, "
00240 "status INTEGER NOT NULL, "
00241 "disk_prefix TEXT NOT NULL, "
00242 "owner_pool_id INTEGER, "
00243
00244 "role TEXT,"
00245 "FOREIGN KEY(owner_pool_id) "
00246 "REFERENCES pools(id) ON DELETE CASCADE );\n")
00247
00248 sql_cmd += (
00249 "CREATE TABLE volumes ("
00250 "id INTEGER PRIMARY KEY, "
00251 "vpd83 TEXT NOT NULL, "
00252 "name TEXT UNIQUE NOT NULL, "
00253 "total_space LONG NOT NULL, "
00254 "consumed_size LONG NOT NULL, "
00255
00256 "admin_state INTEGER, "
00257 "thinp INTEGER NOT NULL, "
00258 "is_hw_raid_vol INTEGER, "
00259
00260
00261
00262 "pool_id INTEGER NOT NULL, "
00263 "FOREIGN KEY(pool_id) "
00264 "REFERENCES pools(id) ON DELETE CASCADE);\n")
00265
00266 sql_cmd += (
00267 "CREATE TABLE ags ("
00268 "id INTEGER PRIMARY KEY, "
00269 "name TEXT UNIQUE NOT NULL);\n")
00270
00271 sql_cmd += (
00272 "CREATE TABLE inits ("
00273 "id TEXT UNIQUE NOT NULL, "
00274 "init_type INTEGER NOT NULL, "
00275 "owner_ag_id INTEGER NOT NULL, "
00276 "FOREIGN KEY(owner_ag_id) "
00277 "REFERENCES ags(id) ON DELETE CASCADE);\n")
00278
00279 sql_cmd += (
00280 "CREATE TABLE vol_masks ("
00281 "vol_id INTEGER NOT NULL, "
00282 "ag_id INTEGER NOT NULL, "
00283 "FOREIGN KEY(vol_id) REFERENCES volumes(id) ON DELETE CASCADE, "
00284 "FOREIGN KEY(ag_id) REFERENCES ags(id) ON DELETE CASCADE);\n")
00285
00286 sql_cmd += (
00287 "CREATE TABLE vol_reps ("
00288 "rep_type INTEGER, "
00289 "src_vol_id INTEGER NOT NULL, "
00290 "dst_vol_id INTEGER NOT NULL, "
00291 "FOREIGN KEY(src_vol_id) "
00292 "REFERENCES volumes(id) ON DELETE CASCADE, "
00293 "FOREIGN KEY(dst_vol_id) "
00294 "REFERENCES volumes(id) ON DELETE CASCADE);\n")
00295
00296 sql_cmd += (
00297 "CREATE TABLE fss ("
00298 "id INTEGER PRIMARY KEY, "
00299 "name TEXT UNIQUE NOT NULL, "
00300 "total_space LONG NOT NULL, "
00301 "consumed_size LONG NOT NULL, "
00302 "free_space LONG, "
00303 "pool_id INTEGER NOT NULL, "
00304 "FOREIGN KEY(pool_id) "
00305 "REFERENCES pools(id) ON DELETE CASCADE);\n")
00306
00307 sql_cmd += (
00308 "CREATE TABLE fs_snaps ("
00309 "id INTEGER PRIMARY KEY, "
00310 "name TEXT UNIQUE NOT NULL, "
00311 "fs_id INTEGER NOT NULL, "
00312 "timestamp LONG NOT NULL, "
00313 "FOREIGN KEY(fs_id) "
00314 "REFERENCES fss(id) ON DELETE CASCADE);\n")
00315
00316 sql_cmd += (
00317 "CREATE TABLE fs_clones ("
00318 "src_fs_id INTEGER NOT NULL, "
00319 "dst_fs_id INTEGER NOT NULL, "
00320 "FOREIGN KEY(src_fs_id) "
00321 "REFERENCES fss(id) ON DELETE CASCADE, "
00322 "FOREIGN KEY(dst_fs_id) "
00323 "REFERENCES fss(id) ON DELETE CASCADE);\n")
00324
00325 sql_cmd += (
00326 "CREATE TABLE exps ("
00327 "id INTEGER PRIMARY KEY, "
00328 "fs_id INTEGER NOT NULL, "
00329 "exp_path TEXT UNIQUE NOT NULL, "
00330 "auth_type TEXT, "
00331 "anon_uid INTEGER, "
00332 "anon_gid INTEGER, "
00333 "options TEXT, "
00334 "FOREIGN KEY(fs_id) "
00335 "REFERENCES fss(id) ON DELETE CASCADE);\n")
00336
00337 sql_cmd += (
00338 "CREATE TABLE exp_root_hosts("
00339 "host TEXT NOT NULL, "
00340 "exp_id INTEGER NOT NULL, "
00341 "FOREIGN KEY(exp_id) "
00342 "REFERENCES exps(id) ON DELETE CASCADE);\n")
00343
00344 sql_cmd += (
00345 "CREATE TABLE exp_rw_hosts("
00346 "host TEXT NOT NULL, "
00347 "exp_id INTEGER NOT NULL, "
00348 "FOREIGN KEY(exp_id) "
00349 "REFERENCES exps(id) ON DELETE CASCADE);\n")
00350
00351 sql_cmd += (
00352 "CREATE TABLE exp_ro_hosts("
00353 "host TEXT NOT NULL, "
00354 "exp_id INTEGER NOT NULL, "
00355 "FOREIGN KEY(exp_id) "
00356 "REFERENCES exps(id) ON DELETE CASCADE);\n")
00357
00358 sql_cmd += (
00359 "CREATE TABLE jobs ("
00360 "id INTEGER PRIMARY KEY, "
00361 "duration INTEGER NOT NULL, "
00362 "timestamp TEXT NOT NULL, "
00363 "data_type INTEGER, "
00364 "data_id TEXT);\n")
00365
00366
00367 sql_cmd += (
00368 """
00369 CREATE VIEW pools_view AS
00370 SELECT
00371 pool0.id,
00372 pool0.name,
00373 pool0.status,
00374 pool0.status_info,
00375 pool0.element_type,
00376 pool0.unsupported_actions,
00377 pool0.raid_type,
00378 pool0.member_type,
00379 pool0.parent_pool_id,
00380 pool0.strip_size,
00381 pool1.total_space total_space,
00382 pool1.total_space -
00383 pool2.vol_consumed_size -
00384 pool3.fs_consumed_size -
00385 pool4.sub_pool_consumed_size free_space
00386 FROM
00387 pools pool0
00388 LEFT JOIN (
00389 SELECT
00390 pool.id,
00391 ifnull(pool.total_space,
00392 ifnull(SUM(disk.total_space), 0))
00393 total_space
00394 FROM pools pool
00395 LEFT JOIN disks disk
00396 ON pool.id = disk.owner_pool_id AND
00397 disk.role = 'DATA'
00398 GROUP BY
00399 pool.id
00400 ) pool1 ON pool0.id = pool1.id
00401
00402 LEFT JOIN (
00403 SELECT
00404 pool.id,
00405 ifnull(SUM(volume.consumed_size), 0)
00406 vol_consumed_size
00407 FROM pools pool
00408 LEFT JOIN volumes volume
00409 ON volume.pool_id = pool.id
00410 GROUP BY
00411 pool.id
00412 ) pool2 ON pool0.id = pool2.id
00413
00414 LEFT JOIN (
00415 SELECT
00416 pool.id,
00417 ifnull(SUM(fs.consumed_size), 0)
00418 fs_consumed_size
00419 FROM pools pool
00420 LEFT JOIN fss fs
00421 ON fs.pool_id = pool.id
00422 GROUP BY
00423 pool.id
00424 ) pool3 ON pool0.id = pool3.id
00425
00426 LEFT JOIN (
00427 SELECT
00428 pool.id,
00429 ifnull(SUM(sub_pool.total_space), 0)
00430 sub_pool_consumed_size
00431 FROM pools pool
00432 LEFT JOIN pools sub_pool
00433 ON sub_pool.parent_pool_id = pool.id
00434 GROUP BY
00435 pool.id
00436 ) pool4 ON pool0.id = pool4.id
00437
00438 GROUP BY
00439 pool0.id;
00440 """)
00441 sql_cmd += (
00442 """
00443 CREATE VIEW disks_view AS
00444 SELECT
00445 id,
00446 disk_prefix || '_' || id
00447 name,
00448 total_space,
00449 disk_type,
00450 role,
00451 status,
00452 owner_pool_id
00453 FROM
00454 disks
00455 ;
00456 """)
00457 sql_cmd += (
00458 """
00459 CREATE VIEW volumes_by_ag_view AS
00460 SELECT
00461 vol.id,
00462 vol.vpd83,
00463 vol.name,
00464 vol.total_space,
00465 vol.consumed_size,
00466 vol.pool_id,
00467 vol.admin_state,
00468 vol.thinp,
00469 vol.is_hw_raid_vol,
00470 vol_mask.ag_id ag_id
00471 FROM
00472 volumes vol
00473 LEFT JOIN vol_masks vol_mask
00474 ON vol_mask.vol_id = vol.id
00475 ;
00476 """)
00477
00478 sql_cmd += (
00479 """
00480 CREATE VIEW ags_view AS
00481 SELECT
00482 ag.id,
00483 ag.name,
00484 CASE
00485 WHEN count(DISTINCT init.init_type) = 1
00486 THEN init.init_type
00487 WHEN count(DISTINCT init.init_type) = 2
00488 THEN %s
00489 ELSE %s
00490 END
00491 init_type,
00492 group_concat(init.id, '%s') init_ids_str
00493 FROM
00494 ags ag
00495 LEFT JOIN inits init
00496 ON ag.id = init.owner_ag_id
00497 GROUP BY
00498 ag.id
00499 ORDER BY
00500 init.init_type
00501 ;
00502 """ % (
00503 AccessGroup.INIT_TYPE_ISCSI_WWPN_MIXED,
00504 AccessGroup.INIT_TYPE_UNKNOWN, BackStore._LIST_SPLITTER))
00505
00506 sql_cmd += (
00507 """
00508 CREATE VIEW ags_by_vol_view AS
00509 SELECT
00510 ag_new.id,
00511 ag_new.name,
00512 ag_new.init_type,
00513 ag_new.init_ids_str,
00514 vol_mask.vol_id vol_id
00515 FROM
00516 (
00517 SELECT
00518 ag.id,
00519 ag.name,
00520 CASE
00521 WHEN count(DISTINCT init.init_type) = 1
00522 THEN init.init_type
00523 WHEN count(DISTINCT init.init_type) = 2
00524 THEN %s
00525 ELSE %s
00526 END
00527 init_type,
00528 group_concat(init.id, '%s') init_ids_str
00529 FROM
00530 ags ag
00531 LEFT JOIN inits init
00532 ON ag.id = init.owner_ag_id
00533 GROUP BY
00534 ag.id
00535 ORDER BY
00536 init.init_type
00537 ) ag_new
00538 LEFT JOIN vol_masks vol_mask
00539 ON vol_mask.ag_id = ag_new.id
00540 ;
00541 """ % (
00542 AccessGroup.INIT_TYPE_ISCSI_WWPN_MIXED,
00543 AccessGroup.INIT_TYPE_UNKNOWN, BackStore._LIST_SPLITTER))
00544
00545 sql_cmd += (
00546 """
00547 CREATE VIEW exps_view AS
00548 SELECT
00549 exp.id,
00550 exp.fs_id,
00551 exp.exp_path,
00552 exp.auth_type,
00553 exp.anon_uid,
00554 exp.anon_gid,
00555 exp.options,
00556 exp2.exp_root_hosts_str,
00557 exp3.exp_rw_hosts_str,
00558 exp4.exp_ro_hosts_str
00559 FROM
00560 exps exp
00561 LEFT JOIN (
00562 SELECT
00563 exp_t2.id,
00564 group_concat(
00565 exp_root_host.host, '%s')
00566 exp_root_hosts_str
00567 FROM
00568 exps exp_t2
00569 LEFT JOIN exp_root_hosts exp_root_host
00570 ON exp_t2.id = exp_root_host.exp_id
00571 GROUP BY
00572 exp_t2.id
00573 ) exp2
00574 ON exp.id = exp2.id
00575 LEFT JOIN (
00576 SELECT
00577 exp_t3.id,
00578 group_concat(
00579 exp_rw_host.host, '%s')
00580 exp_rw_hosts_str
00581 FROM
00582 exps exp_t3
00583 LEFT JOIN exp_rw_hosts exp_rw_host
00584 ON exp_t3.id = exp_rw_host.exp_id
00585 GROUP BY
00586 exp_t3.id
00587 ) exp3
00588 ON exp.id = exp3.id
00589 LEFT JOIN (
00590 SELECT
00591 exp_t4.id,
00592 group_concat(
00593 exp_ro_host.host, '%s')
00594 exp_ro_hosts_str
00595 FROM
00596 exps exp_t4
00597 LEFT JOIN exp_ro_hosts exp_ro_host
00598 ON exp_t4.id = exp_ro_host.exp_id
00599 GROUP BY
00600 exp_t4.id
00601 ) exp4
00602 ON exp.id = exp4.id
00603 GROUP BY
00604 exp.id;
00605 ;
00606 """ % (
00607 BackStore._LIST_SPLITTER, BackStore._LIST_SPLITTER,
00608 BackStore._LIST_SPLITTER))
00609
00610 sql_cur = self.sql_conn.cursor()
00611 try:
00612 sql_cur.executescript(sql_cmd)
00613 except sqlite3.OperationalError as sql_error:
00614 if 'already exists' in str(sql_error):
00615 pass
00616 else:
00617 raise sql_error
00618 except sqlite3.DatabaseError as sql_error:
00619 raise LsmError(
00620 ErrorNumber.INVALID_ARGUMENT,
00621 "Stored simulator state incompatible with "
00622 "simulator, please move or delete %s" % self.statefile)
00623
00624 def _check_version(self):
00625 sim_syss = self.sim_syss()
00626 if len(sim_syss) == 0 or not sim_syss[0]:
00627 return False
00628 else:
00629 if 'version' in sim_syss[0] and \
00630 sim_syss[0]['version'] == BackStore.VERSION_SIGNATURE:
00631 return True
00632
00633 raise LsmError(
00634 ErrorNumber.INVALID_ARGUMENT,
00635 "Stored simulator state incompatible with "
00636 "simulator, please move or delete %s" % self.statefile)
00637
00638 def check_version_and_init(self):
00639 """
00640 Raise error if version not match.
00641 If empty database found, initiate.
00642 """
00643
00644
00645 self.trans_begin()
00646 if self._check_version():
00647 self.trans_commit()
00648 return
00649 else:
00650 self._data_add(
00651 'systems',
00652 {
00653 'id': BackStore.SYS_ID,
00654 'name': BackStore.SYS_NAME,
00655 'status': System.STATUS_OK,
00656 'status_info': "",
00657 'version': BackStore.VERSION_SIGNATURE,
00658 })
00659
00660 size_bytes_2t = size_human_2_size_bytes('2TiB')
00661 size_bytes_512g = size_human_2_size_bytes('512GiB')
00662
00663 pool_1_disks = []
00664 for _ in range(0, 2):
00665 self._data_add(
00666 'disks',
00667 {
00668 'disk_prefix': "2TiB SATA Disk",
00669 'total_space': size_bytes_2t,
00670 'disk_type': Disk.TYPE_SATA,
00671 'status': Disk.STATUS_OK,
00672 })
00673 pool_1_disks.append(self.lastrowid)
00674
00675 test_pool_disks = []
00676
00677 for _ in range(0, 6):
00678 self._data_add(
00679 'disks',
00680 {
00681 'disk_prefix': "2TiB SAS Disk",
00682 'total_space': size_bytes_2t,
00683 'disk_type': Disk.TYPE_SAS,
00684 'status': Disk.STATUS_OK,
00685 })
00686 if len(test_pool_disks) < 2:
00687 test_pool_disks.append(self.lastrowid)
00688
00689 ssd_pool_disks = []
00690
00691 for _ in range(0, 5):
00692 self._data_add(
00693 'disks',
00694 {
00695 'disk_prefix': "512GiB SSD Disk",
00696 'total_space': size_bytes_512g,
00697 'disk_type': Disk.TYPE_SSD,
00698 'status': Disk.STATUS_OK,
00699 })
00700 if len(ssd_pool_disks) < 2:
00701 ssd_pool_disks.append(self.lastrowid)
00702
00703
00704 for _ in range(0, 7):
00705 self._data_add(
00706 'disks',
00707 {
00708 'disk_prefix': "2TiB SSD Disk",
00709 'total_space': size_bytes_2t,
00710 'disk_type': Disk.TYPE_SSD,
00711 'status': Disk.STATUS_OK,
00712 })
00713
00714 pool_1_id = self.sim_pool_create_from_disk(
00715 name='Pool 1',
00716 raid_type=Volume.RAID_TYPE_RAID1,
00717 sim_disk_ids=pool_1_disks,
00718 element_type=Pool.ELEMENT_TYPE_POOL |
00719 Pool.ELEMENT_TYPE_FS |
00720 Pool.ELEMENT_TYPE_VOLUME |
00721 Pool.ELEMENT_TYPE_DELTA |
00722 Pool.ELEMENT_TYPE_SYS_RESERVED,
00723 unsupported_actions=Pool.UNSUPPORTED_VOLUME_GROW |
00724 Pool.UNSUPPORTED_VOLUME_SHRINK)
00725
00726 self.sim_pool_create_sub_pool(
00727 name='Pool 2(sub pool of Pool 1)',
00728 parent_pool_id=pool_1_id,
00729 element_type=Pool.ELEMENT_TYPE_FS |
00730 Pool.ELEMENT_TYPE_VOLUME |
00731 Pool.ELEMENT_TYPE_DELTA,
00732 size=size_bytes_512g)
00733
00734 self.sim_pool_create_from_disk(
00735 name='Pool 3',
00736 raid_type=Volume.RAID_TYPE_RAID1,
00737 sim_disk_ids=ssd_pool_disks,
00738 element_type=Pool.ELEMENT_TYPE_FS |
00739 Pool.ELEMENT_TYPE_VOLUME |
00740 Pool.ELEMENT_TYPE_DELTA)
00741
00742 self.sim_pool_create_from_disk(
00743 name='lsm_test_aggr',
00744 element_type=Pool.ELEMENT_TYPE_FS |
00745 Pool.ELEMENT_TYPE_VOLUME |
00746 Pool.ELEMENT_TYPE_DELTA,
00747 raid_type=Volume.RAID_TYPE_RAID0,
00748 sim_disk_ids=test_pool_disks)
00749
00750 self._data_add(
00751 'tgts',
00752 {
00753 'port_type': TargetPort.TYPE_FC,
00754 'service_address': '50:0a:09:86:99:4b:8d:c5',
00755 'network_address': '50:0a:09:86:99:4b:8d:c5',
00756 'physical_address': '50:0a:09:86:99:4b:8d:c5',
00757 'physical_name': 'FC_a_0b',
00758 })
00759
00760 self._data_add(
00761 'tgts',
00762 {
00763 'port_type': TargetPort.TYPE_FCOE,
00764 'service_address': '50:0a:09:86:99:4b:8d:c6',
00765 'network_address': '50:0a:09:86:99:4b:8d:c6',
00766 'physical_address': '50:0a:09:86:99:4b:8d:c6',
00767 'physical_name': 'FCoE_b_0c',
00768 })
00769 self._data_add(
00770 'tgts',
00771 {
00772 'port_type': TargetPort.TYPE_ISCSI,
00773 'service_address': 'iqn.1986-05.com.example:sim-tgt-03',
00774 'network_address': 'sim-iscsi-tgt-3.example.com:3260',
00775 'physical_address': 'a4:4e:31:47:f4:e0',
00776 'physical_name': 'iSCSI_c_0d',
00777 })
00778 self._data_add(
00779 'tgts',
00780 {
00781 'port_type': TargetPort.TYPE_ISCSI,
00782 'service_address': 'iqn.1986-05.com.example:sim-tgt-03',
00783 'network_address': '10.0.0.1:3260',
00784 'physical_address': 'a4:4e:31:47:f4:e1',
00785 'physical_name': 'iSCSI_c_0e',
00786 })
00787 self._data_add(
00788 'tgts',
00789 {
00790 'port_type': TargetPort.TYPE_ISCSI,
00791 'service_address': 'iqn.1986-05.com.example:sim-tgt-03',
00792 'network_address': '[2001:470:1f09:efe:a64e:31ff::1]:3260',
00793 'physical_address': 'a4:4e:31:47:f4:e1',
00794 'physical_name': 'iSCSI_c_0e',
00795 })
00796
00797 self.trans_commit()
00798 return
00799
00800 def _sql_exec(self, sql_cmd, key_list=None):
00801 """
00802 Execute sql command and get all output.
00803 If key_list is not None, will convert returned sql data to a list of
00804 dictionaries.
00805 """
00806 sql_cur = self.sql_conn.cursor()
00807 sql_cur.execute(sql_cmd)
00808 self.lastrowid = sql_cur.lastrowid
00809 sql_output = sql_cur.fetchall()
00810 if key_list and sql_output:
00811 return list(
00812 dict(zip(key_list, value_list))
00813 for value_list in sql_output
00814 if value_list)
00815 else:
00816 return sql_output
00817
00818 def _get_table(self, table_name, key_list):
00819 sql_cmd = "SELECT %s FROM %s" % (",".join(key_list), table_name)
00820 return self._sql_exec(sql_cmd, key_list)
00821
00822 def trans_begin(self):
00823 self.sql_conn.execute("BEGIN IMMEDIATE TRANSACTION;")
00824
00825 def trans_commit(self):
00826 self.sql_conn.commit()
00827
00828 def trans_rollback(self):
00829 self.sql_conn.rollback()
00830
00831 def _data_add(self, table_name, data_dict):
00832 keys = data_dict.keys()
00833 values = ['' if v is None else str(v) for v in data_dict.values()]
00834
00835 sql_cmd = "INSERT INTO %s (%s) VALUES (%s);" % \
00836 (table_name,
00837 "'%s'" % ("', '".join(keys)),
00838 "'%s'" % ("', '".join(values)))
00839 self._sql_exec(sql_cmd)
00840
00841 def _data_find(self, table, condition, key_list, flag_unique=False):
00842 sql_cmd = "SELECT %s FROM %s WHERE %s" % (
00843 ",".join(key_list), table, condition)
00844 sim_datas = self._sql_exec(sql_cmd, key_list)
00845 if flag_unique:
00846 if len(sim_datas) == 0:
00847 return None
00848 elif len(sim_datas) == 1:
00849 return sim_datas[0]
00850 else:
00851 raise LsmError(
00852 ErrorNumber.PLUGIN_BUG,
00853 "_data_find(): Got non-unique data: %s" % locals())
00854 else:
00855 return sim_datas
00856
00857 def _data_update(self, table, data_id, column_name, value):
00858 if value is None:
00859 value = ''
00860
00861 sql_cmd = "UPDATE %s SET %s='%s' WHERE id='%s'" % \
00862 (table, column_name, value, data_id)
00863
00864 self._sql_exec(sql_cmd)
00865
00866 def _data_delete(self, table, condition):
00867 sql_cmd = "DELETE FROM %s WHERE %s;" % (table, condition)
00868 self._sql_exec(sql_cmd)
00869
00870 def sim_job_create(self, job_data_type=None, data_id=None):
00871 """
00872 Return a job id(Integer)
00873 """
00874 self._data_add(
00875 "jobs",
00876 {
00877 "duration": os.getenv(
00878 "LSM_SIM_TIME", BackStore.JOB_DEFAULT_DURATION),
00879 "timestamp": time.time(),
00880 "data_type": job_data_type,
00881 "data_id": data_id,
00882 })
00883 return self.lastrowid
00884
00885 def sim_job_delete(self, sim_job_id):
00886 self._data_delete('jobs', 'id="%s"' % sim_job_id)
00887
00888 def sim_job_status(self, sim_job_id):
00889 """
00890 Return (progress, data_type, data) tuple.
00891 progress is the integer of percent.
00892 """
00893 sim_job = self._data_find(
00894 'jobs', 'id=%s' % sim_job_id, BackStore.JOB_KEY_LIST,
00895 flag_unique=True)
00896 if sim_job is None:
00897 raise LsmError(
00898 ErrorNumber.NOT_FOUND_JOB, "Job not found")
00899
00900 progress = int(
00901 (time.time() - float(sim_job['timestamp'])) /
00902 sim_job['duration'] * 100)
00903
00904 data = None
00905 data_type = None
00906
00907 if progress >= 100:
00908 progress = 100
00909 if sim_job['data_type'] == BackStore.JOB_DATA_TYPE_VOL:
00910 data = self.sim_vol_of_id(sim_job['data_id'])
00911 data_type = sim_job['data_type']
00912 elif sim_job['data_type'] == BackStore.JOB_DATA_TYPE_FS:
00913 data = self.sim_fs_of_id(sim_job['data_id'])
00914 data_type = sim_job['data_type']
00915 elif sim_job['data_type'] == BackStore.JOB_DATA_TYPE_FS_SNAP:
00916 data = self.sim_fs_snap_of_id(sim_job['data_id'])
00917 data_type = sim_job['data_type']
00918
00919 return (progress, data_type, data)
00920
00921 def sim_syss(self):
00922 """
00923 Return a list of sim_sys dict.
00924 """
00925 return self._get_table('systems', BackStore.SYS_KEY_LIST)
00926
00927 def sim_disk_ids_of_pool(self, sim_pool_id):
00928 return list(
00929 d['id']
00930 for d in self._data_find(
00931 'disks', 'owner_pool_id="%s"' % sim_pool_id, ['id']))
00932
00933 def sim_disks(self):
00934 """
00935 Return a list of sim_disk dict.
00936 """
00937 return self._get_table('disks_view', BackStore.DISK_KEY_LIST)
00938
00939 def sim_pools(self):
00940 """
00941 Return a list of sim_pool dict.
00942 """
00943 return self._get_table('pools_view', BackStore.POOL_KEY_LIST)
00944
00945 def sim_pool_of_id(self, sim_pool_id):
00946 return self._sim_data_of_id(
00947 "pools_view", sim_pool_id, BackStore.POOL_KEY_LIST,
00948 ErrorNumber.NOT_FOUND_POOL, "Pool")
00949
00950 def sim_pool_create_from_disk(self, name, sim_disk_ids, raid_type,
00951 element_type, unsupported_actions=0,
00952 strip_size=0):
00953 if strip_size == 0:
00954 strip_size = BackStore.DEFAULT_STRIP_SIZE
00955
00956 self._data_add(
00957 'pools',
00958 {
00959 'name': name,
00960 'status': Pool.STATUS_OK,
00961 'status_info': '',
00962 'element_type': element_type,
00963 'unsupported_actions': unsupported_actions,
00964 'raid_type': raid_type,
00965 'member_type': Pool.MEMBER_TYPE_DISK,
00966 'strip_size': strip_size,
00967 })
00968
00969 data_disk_count = PoolRAID.data_disk_count(
00970 raid_type, len(sim_disk_ids))
00971
00972
00973 sim_pool_id = self.lastrowid
00974 for sim_disk_id in sim_disk_ids[:data_disk_count]:
00975 self._data_update(
00976 'disks', sim_disk_id, 'owner_pool_id', sim_pool_id)
00977 self._data_update(
00978 'disks', sim_disk_id, 'role', 'DATA')
00979
00980 for sim_disk_id in sim_disk_ids[data_disk_count:]:
00981 self._data_update(
00982 'disks', sim_disk_id, 'owner_pool_id', sim_pool_id)
00983 self._data_update(
00984 'disks', sim_disk_id, 'role', 'PARITY')
00985
00986 return sim_pool_id
00987
00988 def sim_pool_create_sub_pool(self, name, parent_pool_id, size,
00989 element_type, unsupported_actions=0):
00990 self._data_add(
00991 'pools',
00992 {
00993 'name': name,
00994 'status': Pool.STATUS_OK,
00995 'status_info': '',
00996 'element_type': element_type,
00997 'unsupported_actions': unsupported_actions,
00998 'raid_type': Volume.RAID_TYPE_OTHER,
00999 'member_type': Pool.MEMBER_TYPE_POOL,
01000 'parent_pool_id': parent_pool_id,
01001 'total_space': size,
01002 })
01003 return self.lastrowid
01004
01005 def sim_pool_disks_count(self, sim_pool_id):
01006 return self._sql_exec(
01007 "SELECT COUNT(id) FROM disks WHERE owner_pool_id=%s;" %
01008 sim_pool_id)[0][0]
01009
01010 def sim_pool_data_disks_count(self, sim_pool_id=None):
01011 return self._sql_exec(
01012 "SELECT COUNT(id) FROM disks WHERE "
01013 "owner_pool_id=%s and role='DATA';" % sim_pool_id)[0][0]
01014
01015 def sim_vols(self, sim_ag_id=None):
01016 """
01017 Return a list of sim_vol dict.
01018 """
01019 if sim_ag_id:
01020 return self._data_find(
01021 'volumes_by_ag_view', 'ag_id=%s' % sim_ag_id,
01022 BackStore.VOL_KEY_LIST)
01023 else:
01024 return self._get_table('volumes', BackStore.VOL_KEY_LIST)
01025
01026 def _sim_data_of_id(self, table_name, data_id, key_list, lsm_error_no,
01027 data_name):
01028 sim_data = self._data_find(
01029 table_name, 'id=%s' % data_id, key_list, flag_unique=True)
01030 if sim_data is None:
01031 if lsm_error_no:
01032 raise LsmError(
01033 lsm_error_no, "%s not found" % data_name)
01034 else:
01035 return None
01036 return sim_data
01037
01038 def sim_vol_of_id(self, sim_vol_id):
01039 """
01040 Return sim_vol if found. Raise error if not found.
01041 """
01042 return self._sim_data_of_id(
01043 "volumes", sim_vol_id, BackStore.VOL_KEY_LIST,
01044 ErrorNumber.NOT_FOUND_VOLUME,
01045 "Volume")
01046
01047 def _check_pool_free_space(self, sim_pool_id, size_bytes):
01048 sim_pool = self.sim_pool_of_id(sim_pool_id)
01049
01050 if (sim_pool['free_space'] < size_bytes):
01051 raise LsmError(ErrorNumber.NOT_ENOUGH_SPACE,
01052 "Insufficient space in pool")
01053
01054 @staticmethod
01055 def _block_rounding(size_bytes):
01056 return (size_bytes + BackStore.BLK_SIZE - 1) / \
01057 BackStore.BLK_SIZE * BackStore.BLK_SIZE
01058
01059 def sim_vol_create(self, name, size_bytes, sim_pool_id, thinp,
01060 is_hw_raid_vol=0):
01061
01062 size_bytes = BackStore._block_rounding(size_bytes)
01063 self._check_pool_free_space(sim_pool_id, size_bytes)
01064 sim_vol = dict()
01065 sim_vol['vpd83'] = _random_vpd()
01066 sim_vol['name'] = name
01067 sim_vol['thinp'] = thinp
01068 sim_vol['pool_id'] = sim_pool_id
01069 sim_vol['total_space'] = size_bytes
01070 sim_vol['consumed_size'] = size_bytes
01071 sim_vol['admin_state'] = Volume.ADMIN_STATE_ENABLED
01072 sim_vol['is_hw_raid_vol'] = is_hw_raid_vol
01073
01074 try:
01075 self._data_add("volumes", sim_vol)
01076 except sqlite3.IntegrityError as sql_error:
01077 raise LsmError(
01078 ErrorNumber.NAME_CONFLICT,
01079 "Name '%s' is already in use by other volume" % name)
01080
01081 return self.lastrowid
01082
01083 def sim_vol_delete(self, sim_vol_id):
01084 """
01085 This does not check whether volume exist or not.
01086 """
01087
01088 sim_vol = self.sim_vol_of_id(sim_vol_id)
01089
01090 if self._sim_ag_ids_of_masked_vol(sim_vol_id):
01091 raise LsmError(
01092 ErrorNumber.IS_MASKED,
01093 "Volume is masked to access group")
01094
01095 dst_sim_vol_ids = self.dst_sim_vol_ids_of_src(sim_vol_id)
01096 if len(dst_sim_vol_ids) >= 1:
01097 for dst_sim_vol_id in dst_sim_vol_ids:
01098 if dst_sim_vol_id != sim_vol_id:
01099
01100 raise LsmError(
01101 ErrorNumber.PLUGIN_BUG,
01102 "Requested volume is a replication source")
01103 if sim_vol['is_hw_raid_vol']:
01104
01105 self._data_delete("pools", 'id="%s"' % sim_vol['pool_id'])
01106 else:
01107 self._data_delete("volumes", 'id="%s"' % sim_vol_id)
01108
01109 def sim_vol_mask(self, sim_vol_id, sim_ag_id):
01110 self.sim_vol_of_id(sim_vol_id)
01111 self.sim_ag_of_id(sim_ag_id)
01112 exist_mask = self._data_find(
01113 'vol_masks', 'ag_id="%s" AND vol_id="%s"' %
01114 (sim_ag_id, sim_vol_id), ['vol_id'])
01115 if exist_mask:
01116 raise LsmError(
01117 ErrorNumber.NO_STATE_CHANGE,
01118 "Volume is already masked to requested access group")
01119
01120 self._data_add(
01121 "vol_masks", {'ag_id': sim_ag_id, 'vol_id': sim_vol_id})
01122
01123 return None
01124
01125 def sim_vol_unmask(self, sim_vol_id, sim_ag_id):
01126 self.sim_vol_of_id(sim_vol_id)
01127 self.sim_ag_of_id(sim_ag_id)
01128 condition = 'ag_id="%s" AND vol_id="%s"' % (sim_ag_id, sim_vol_id)
01129 exist_mask = self._data_find('vol_masks', condition, ['vol_id'])
01130 if exist_mask:
01131 self._data_delete('vol_masks', condition)
01132 else:
01133 raise LsmError(
01134 ErrorNumber.NO_STATE_CHANGE,
01135 "Volume is not masked to requested access group")
01136 return None
01137
01138 def _sim_vol_ids_of_masked_ag(self, sim_ag_id):
01139 return list(
01140 m['vol_id'] for m in self._data_find(
01141 'vol_masks', 'ag_id="%s"' % sim_ag_id, ['vol_id']))
01142
01143 def _sim_ag_ids_of_masked_vol(self, sim_vol_id):
01144 return list(
01145 m['ag_id'] for m in self._data_find(
01146 'vol_masks', 'vol_id="%s"' % sim_vol_id, ['ag_id']))
01147
01148 def sim_vol_resize(self, sim_vol_id, new_size_bytes):
01149 org_new_size_bytes = new_size_bytes
01150 new_size_bytes = BackStore._block_rounding(new_size_bytes)
01151 sim_vol = self.sim_vol_of_id(sim_vol_id)
01152 if sim_vol['total_space'] == new_size_bytes:
01153 if org_new_size_bytes != new_size_bytes:
01154
01155
01156 return
01157 else:
01158 raise LsmError(
01159 ErrorNumber.NO_STATE_CHANGE,
01160 "Volume size is identical to requested")
01161
01162 sim_pool = self.sim_pool_of_id(sim_vol['pool_id'])
01163
01164 increment = new_size_bytes - sim_vol['total_space']
01165
01166 if increment > 0:
01167
01168 if sim_pool['unsupported_actions'] & Pool.UNSUPPORTED_VOLUME_GROW:
01169 raise LsmError(
01170 ErrorNumber.NO_SUPPORT,
01171 "Requested pool does not allow volume size grow")
01172
01173 if sim_pool['free_space'] < increment:
01174 raise LsmError(
01175 ErrorNumber.NOT_ENOUGH_SPACE, "Insufficient space in pool")
01176
01177 elif sim_pool['unsupported_actions'] & Pool.UNSUPPORTED_VOLUME_SHRINK:
01178 raise LsmError(
01179 ErrorNumber.NO_SUPPORT,
01180 "Requested pool does not allow volume size grow")
01181
01182
01183
01184 self._data_update(
01185 'volumes', sim_vol_id, "total_space", new_size_bytes)
01186 self._data_update(
01187 'volumes', sim_vol_id, "consumed_size", new_size_bytes)
01188
01189 def dst_sim_vol_ids_of_src(self, src_sim_vol_id):
01190 """
01191 Return a list of dst_vol_id for provided source volume ID.
01192 """
01193 self.sim_vol_of_id(src_sim_vol_id)
01194 return list(
01195 d['dst_vol_id'] for d in self._data_find(
01196 'vol_reps', 'src_vol_id="%s"' % src_sim_vol_id,
01197 ['dst_vol_id']))
01198
01199 def sim_vol_replica(self, src_sim_vol_id, dst_sim_vol_id, rep_type,
01200 blk_ranges=None):
01201 self.sim_vol_of_id(src_sim_vol_id)
01202 self.sim_vol_of_id(dst_sim_vol_id)
01203
01204
01205
01206 cur_src_sim_vol_ids = list(
01207 r['src_vol_id'] for r in self._data_find(
01208 'vol_reps', 'dst_vol_id="%s"' % dst_sim_vol_id,
01209 ['src_vol_id']))
01210 if len(cur_src_sim_vol_ids) == 1 and \
01211 cur_src_sim_vol_ids[0] == src_sim_vol_id:
01212
01213 pass
01214 elif len(cur_src_sim_vol_ids) == 0:
01215 pass
01216 else:
01217
01218 raise LsmError(
01219 ErrorNumber.PLUGIN_BUG,
01220 "Target volume is already a replication target for other "
01221 "source volume")
01222
01223 self._data_add(
01224 'vol_reps',
01225 {
01226 'src_vol_id': src_sim_vol_id,
01227 'dst_vol_id': dst_sim_vol_id,
01228 'rep_type': rep_type,
01229 })
01230
01231
01232
01233 def sim_vol_src_replica_break(self, src_sim_vol_id):
01234
01235 if not self.dst_sim_vol_ids_of_src(src_sim_vol_id):
01236 raise LsmError(
01237 ErrorNumber.NO_STATE_CHANGE,
01238 "Provided volume is not a replication source")
01239
01240 self._data_delete(
01241 'vol_reps', 'src_vol_id="%s"' % src_sim_vol_id)
01242
01243 def sim_vol_state_change(self, sim_vol_id, new_admin_state):
01244 sim_vol = self.sim_vol_of_id(sim_vol_id)
01245 if sim_vol['admin_state'] == new_admin_state:
01246 raise LsmError(
01247 ErrorNumber.NO_STATE_CHANGE,
01248 "Volume admin state is identical to requested")
01249
01250 self._data_update(
01251 'volumes', sim_vol_id, "admin_state", new_admin_state)
01252
01253 @staticmethod
01254 def _sim_ag_format(sim_ag):
01255 """
01256 Update 'init_type' and 'init_ids' of sim_ag
01257 """
01258 sim_ag['init_ids'] = sim_ag['init_ids_str'].split(
01259 BackStore._LIST_SPLITTER)
01260 del sim_ag['init_ids_str']
01261 return sim_ag
01262
01263 def sim_ags(self, sim_vol_id=None):
01264 if sim_vol_id:
01265 sim_ags = self._data_find(
01266 'ags_by_vol_view', 'vol_id=%s' % sim_vol_id,
01267 BackStore.AG_KEY_LIST)
01268 else:
01269 sim_ags = self._get_table('ags_view', BackStore.AG_KEY_LIST)
01270
01271 return [BackStore._sim_ag_format(a) for a in sim_ags]
01272
01273 def _sim_init_create(self, init_type, init_id, sim_ag_id):
01274 try:
01275 self._data_add(
01276 "inits",
01277 {
01278 'id': init_id,
01279 'init_type': init_type,
01280 'owner_ag_id': sim_ag_id
01281 })
01282 except sqlite3.IntegrityError as sql_error:
01283 raise LsmError(
01284 ErrorNumber.EXISTS_INITIATOR,
01285 "Initiator '%s' is already in use by other access group" %
01286 init_id)
01287
01288 def iscsi_chap_auth_set(self, init_id, in_user, in_pass, out_user,
01289 out_pass):
01290
01291 return None
01292
01293 def sim_ag_create(self, name, init_type, init_id):
01294 try:
01295 self._data_add("ags", {'name': name})
01296 sim_ag_id = self.lastrowid
01297 except sqlite3.IntegrityError as sql_error:
01298 raise LsmError(
01299 ErrorNumber.NAME_CONFLICT,
01300 "Name '%s' is already in use by other access group" %
01301 name)
01302
01303 self._sim_init_create(init_type, init_id, sim_ag_id)
01304
01305 return sim_ag_id
01306
01307 def sim_ag_delete(self, sim_ag_id):
01308 self.sim_ag_of_id(sim_ag_id)
01309 if self._sim_vol_ids_of_masked_ag(sim_ag_id):
01310 raise LsmError(
01311 ErrorNumber.IS_MASKED,
01312 "Access group has volume masked to")
01313
01314 self._data_delete('ags', 'id="%s"' % sim_ag_id)
01315
01316 def sim_ag_init_add(self, sim_ag_id, init_id, init_type):
01317 sim_ag = self.sim_ag_of_id(sim_ag_id)
01318 if init_id in sim_ag['init_ids']:
01319 raise LsmError(
01320 ErrorNumber.NO_STATE_CHANGE,
01321 "Initiator already in access group")
01322
01323 if init_type != AccessGroup.INIT_TYPE_ISCSI_IQN and \
01324 init_type != AccessGroup.INIT_TYPE_WWPN:
01325 raise LsmError(
01326 ErrorNumber.NO_SUPPORT,
01327 "Only support iSCSI IQN and WWPN initiator type")
01328
01329 self._sim_init_create(init_type, init_id, sim_ag_id)
01330 return None
01331
01332 def sim_ag_init_delete(self, sim_ag_id, init_id):
01333 sim_ag = self.sim_ag_of_id(sim_ag_id)
01334 if init_id not in sim_ag['init_ids']:
01335 raise LsmError(
01336 ErrorNumber.NO_STATE_CHANGE,
01337 "Initiator is not in defined access group")
01338 if len(sim_ag['init_ids']) == 1:
01339 raise LsmError(
01340 ErrorNumber.LAST_INIT_IN_ACCESS_GROUP,
01341 "Refused to remove the last initiator from access group")
01342
01343 self._data_delete('inits', 'id="%s"' % init_id)
01344
01345 def sim_ag_of_id(self, sim_ag_id):
01346 sim_ag = self._sim_data_of_id(
01347 "ags_view", sim_ag_id, BackStore.AG_KEY_LIST,
01348 ErrorNumber.NOT_FOUND_ACCESS_GROUP,
01349 "Access Group")
01350 BackStore._sim_ag_format(sim_ag)
01351 return sim_ag
01352
01353 def sim_fss(self):
01354 """
01355 Return a list of sim_fs dict.
01356 """
01357 return self._get_table('fss', BackStore.FS_KEY_LIST)
01358
01359 def sim_fs_of_id(self, sim_fs_id, raise_error=True):
01360 lsm_error_no = ErrorNumber.NOT_FOUND_FS
01361 if not raise_error:
01362 lsm_error_no = None
01363
01364 return self._sim_data_of_id(
01365 "fss", sim_fs_id, BackStore.FS_KEY_LIST, lsm_error_no,
01366 "File System")
01367
01368 def sim_fs_create(self, name, size_bytes, sim_pool_id):
01369 size_bytes = BackStore._block_rounding(size_bytes)
01370 self._check_pool_free_space(sim_pool_id, size_bytes)
01371 try:
01372 self._data_add(
01373 "fss",
01374 {
01375 'name': name,
01376 'total_space': size_bytes,
01377 'consumed_size': size_bytes,
01378 'free_space': size_bytes,
01379 'pool_id': sim_pool_id,
01380 })
01381 except sqlite3.IntegrityError as sql_error:
01382 raise LsmError(
01383 ErrorNumber.NAME_CONFLICT,
01384 "Name '%s' is already in use by other fs" % name)
01385 return self.lastrowid
01386
01387 def sim_fs_delete(self, sim_fs_id):
01388 self.sim_fs_of_id(sim_fs_id)
01389 if self.clone_dst_sim_fs_ids_of_src(sim_fs_id):
01390
01391
01392 raise LsmError(
01393 ErrorNumber.PLUGIN_BUG,
01394 "Requested file system is a clone source")
01395
01396 if self.sim_fs_snaps(sim_fs_id):
01397 raise LsmError(
01398 ErrorNumber.PLUGIN_BUG,
01399 "Requested file system has snapshot attached")
01400
01401 if self._data_find('exps', 'fs_id="%s"' % sim_fs_id, ['id']):
01402
01403
01404 raise LsmError(
01405 ErrorNumber.PLUGIN_BUG,
01406 "Requested file system is exported via NFS")
01407
01408 self._data_delete("fss", 'id="%s"' % sim_fs_id)
01409
01410 def sim_fs_resize(self, sim_fs_id, new_size_bytes):
01411 org_new_size_bytes = new_size_bytes
01412 new_size_bytes = BackStore._block_rounding(new_size_bytes)
01413 sim_fs = self.sim_fs_of_id(sim_fs_id)
01414
01415 if sim_fs['total_space'] == new_size_bytes:
01416 if new_size_bytes != org_new_size_bytes:
01417 return
01418 else:
01419 raise LsmError(
01420 ErrorNumber.NO_STATE_CHANGE,
01421 "File System size is identical to requested")
01422
01423
01424
01425
01426 sim_pool = self.sim_pool_of_id(sim_fs['pool_id'])
01427
01428 if new_size_bytes > sim_fs['total_space'] and \
01429 sim_pool['free_space'] < new_size_bytes - sim_fs['total_space']:
01430 raise LsmError(
01431 ErrorNumber.NOT_ENOUGH_SPACE, "Insufficient space in pool")
01432
01433 self._data_update(
01434 'fss', sim_fs_id, "total_space", new_size_bytes)
01435 self._data_update(
01436 'fss', sim_fs_id, "consumed_size", new_size_bytes)
01437 self._data_update(
01438 'fss', sim_fs_id, "free_space", new_size_bytes)
01439
01440 def sim_fs_snaps(self, sim_fs_id):
01441 self.sim_fs_of_id(sim_fs_id)
01442 return self._data_find(
01443 'fs_snaps', 'fs_id="%s"' % sim_fs_id, BackStore.FS_SNAP_KEY_LIST)
01444
01445 def sim_fs_snap_of_id(self, sim_fs_snap_id, sim_fs_id=None):
01446 sim_fs_snap = self._sim_data_of_id(
01447 'fs_snaps', sim_fs_snap_id, BackStore.FS_SNAP_KEY_LIST,
01448 ErrorNumber.NOT_FOUND_FS_SS, 'File system snapshot')
01449 if sim_fs_id and sim_fs_snap['fs_id'] != sim_fs_id:
01450 raise LsmError(
01451 ErrorNumber.NOT_FOUND_FS_SS,
01452 "Defined file system snapshot ID is not belong to requested "
01453 "file system")
01454 return sim_fs_snap
01455
01456 def sim_fs_snap_create(self, sim_fs_id, name):
01457 self.sim_fs_of_id(sim_fs_id)
01458 try:
01459 self._data_add(
01460 'fs_snaps',
01461 {
01462 'name': name,
01463 'fs_id': sim_fs_id,
01464 'timestamp': int(time.time()),
01465 })
01466 except sqlite3.IntegrityError as sql_error:
01467 raise LsmError(
01468 ErrorNumber.NAME_CONFLICT,
01469 "The name is already used by other file system snapshot")
01470 return self.lastrowid
01471
01472 def sim_fs_snap_restore(self, sim_fs_id, sim_fs_snap_id, files,
01473 restore_files, flag_all_files):
01474
01475
01476 self.sim_fs_of_id(sim_fs_id)
01477 if sim_fs_snap_id:
01478 self.sim_fs_snap_of_id(sim_fs_snap_id, sim_fs_id)
01479 return
01480
01481 def sim_fs_snap_delete(self, sim_fs_snap_id, sim_fs_id):
01482 self.sim_fs_of_id(sim_fs_id)
01483 self.sim_fs_snap_of_id(sim_fs_snap_id, sim_fs_id)
01484 self._data_delete('fs_snaps', 'id="%s"' % sim_fs_snap_id)
01485
01486 def sim_fs_snap_del_by_fs(self, sim_fs_id):
01487 sql_cmd = "DELETE FROM fs_snaps WHERE fs_id='%s';" % sim_fs_id
01488 self._sql_exec(sql_cmd)
01489
01490 def sim_fs_clone(self, src_sim_fs_id, dst_sim_fs_id, sim_fs_snap_id):
01491 self.sim_fs_of_id(src_sim_fs_id)
01492 self.sim_fs_of_id(dst_sim_fs_id)
01493
01494 if sim_fs_snap_id:
01495
01496
01497
01498 self.sim_fs_snap_of_id(sim_fs_snap_id, src_sim_fs_id)
01499
01500 self._data_add(
01501 'fs_clones',
01502 {
01503 'src_fs_id': src_sim_fs_id,
01504 'dst_fs_id': dst_sim_fs_id,
01505 })
01506
01507 def sim_fs_file_clone(self, sim_fs_id, src_fs_name, dst_fs_name,
01508 sim_fs_snap_id):
01509
01510
01511 self.sim_fs_of_id(sim_fs_id)
01512 if sim_fs_snap_id:
01513 self.sim_fs_snap_of_id(sim_fs_snap_id, sim_fs_id)
01514 return
01515
01516 def clone_dst_sim_fs_ids_of_src(self, src_sim_fs_id):
01517 """
01518 Return a list of dst_fs_id for provided clone source fs ID.
01519 """
01520 self.sim_fs_of_id(src_sim_fs_id)
01521 return list(
01522 d['dst_fs_id'] for d in self._data_find(
01523 'fs_clones', 'src_fs_id="%s"' % src_sim_fs_id,
01524 ['dst_fs_id']))
01525
01526 def sim_fs_src_clone_break(self, src_sim_fs_id):
01527 self._data_delete('fs_clones', 'src_fs_id="%s"' % src_sim_fs_id)
01528
01529 def _sim_exp_format(self, sim_exp):
01530 for key_name in ['root_hosts', 'rw_hosts', 'ro_hosts']:
01531 table_name = "exp_%s_str" % key_name
01532 if sim_exp[table_name]:
01533 sim_exp[key_name] = sim_exp[table_name].split(
01534 BackStore._LIST_SPLITTER)
01535 else:
01536 sim_exp[key_name] = []
01537 del sim_exp[table_name]
01538 return sim_exp
01539
01540 def sim_exps(self):
01541 return list(
01542 self._sim_exp_format(e)
01543 for e in self._get_table('exps_view', BackStore.EXP_KEY_LIST))
01544
01545 def sim_exp_of_id(self, sim_exp_id):
01546 return self._sim_exp_format(
01547 self._sim_data_of_id(
01548 'exps_view', sim_exp_id, BackStore.EXP_KEY_LIST,
01549 ErrorNumber.NOT_FOUND_NFS_EXPORT, 'NFS Export'))
01550
01551 def sim_exp_create(self, sim_fs_id, exp_path, root_hosts, rw_hosts,
01552 ro_hosts, anon_uid, anon_gid, auth_type, options):
01553 if exp_path is None:
01554 exp_path = "/nfs_exp_%s" % _random_vpd()[:8]
01555 self.sim_fs_of_id(sim_fs_id)
01556
01557 try:
01558 self._data_add(
01559 'exps',
01560 {
01561 'fs_id': sim_fs_id,
01562 'exp_path': exp_path,
01563 'anon_uid': anon_uid,
01564 'anon_gid': anon_gid,
01565 'auth_type': auth_type,
01566 'options': options,
01567 })
01568 except sqlite3.IntegrityError as sql_error:
01569
01570
01571 raise LsmError(
01572 ErrorNumber.NAME_CONFLICT,
01573 "Export path is already used by other NFS export")
01574
01575 sim_exp_id = self.lastrowid
01576
01577 for root_host in root_hosts:
01578 self._data_add(
01579 'exp_root_hosts',
01580 {
01581 'host': root_host,
01582 'exp_id': sim_exp_id,
01583 })
01584 for rw_host in rw_hosts:
01585 self._data_add(
01586 'exp_rw_hosts',
01587 {
01588 'host': rw_host,
01589 'exp_id': sim_exp_id,
01590 })
01591 for ro_host in ro_hosts:
01592 self._data_add(
01593 'exp_ro_hosts',
01594 {
01595 'host': ro_host,
01596 'exp_id': sim_exp_id,
01597 })
01598
01599 return sim_exp_id
01600
01601 def sim_exp_delete(self, sim_exp_id):
01602 self.sim_exp_of_id(sim_exp_id)
01603 self._data_delete('exps', 'id="%s"' % sim_exp_id)
01604
01605 def sim_tgts(self):
01606 """
01607 Return a list of sim_tgt dict.
01608 """
01609 return self._get_table('tgts', BackStore.TGT_KEY_LIST)
01610
01611
01612 class SimArray(object):
01613 SIM_DATA_FILE = os.getenv("LSM_SIM_DATA",
01614 tempfile.gettempdir() + '/lsm_sim_data')
01615
01616 ID_FMT = 5
01617
01618 @staticmethod
01619 def _sim_id_to_lsm_id(sim_id, prefix):
01620 return "%s_ID_%0*d" % (prefix, SimArray.ID_FMT, sim_id)
01621
01622 @staticmethod
01623 def _lsm_id_to_sim_id(lsm_id, lsm_error):
01624 try:
01625 return int(lsm_id[-SimArray.ID_FMT:])
01626 except ValueError:
01627 raise lsm_error
01628
01629 @staticmethod
01630 def _sim_job_id_of(job_id):
01631 return SimArray._lsm_id_to_sim_id(
01632 job_id, LsmError(ErrorNumber.NOT_FOUND_JOB, "Job not found"))
01633
01634 @staticmethod
01635 def _sim_pool_id_of(pool_id):
01636 return SimArray._lsm_id_to_sim_id(
01637 pool_id, LsmError(ErrorNumber.NOT_FOUND_POOL, "Pool not found"))
01638
01639 @staticmethod
01640 def _sim_vol_id_of(vol_id):
01641 return SimArray._lsm_id_to_sim_id(
01642 vol_id, LsmError(
01643 ErrorNumber.NOT_FOUND_VOLUME, "Volume not found"))
01644
01645 @staticmethod
01646 def _sim_fs_id_of(fs_id):
01647 return SimArray._lsm_id_to_sim_id(
01648 fs_id, LsmError(
01649 ErrorNumber.NOT_FOUND_FS, "File system not found"))
01650
01651 @staticmethod
01652 def _sim_fs_snap_id_of(snap_id):
01653 return SimArray._lsm_id_to_sim_id(
01654 snap_id, LsmError(
01655 ErrorNumber.NOT_FOUND_FS_SS,
01656 "File system snapshot not found"))
01657
01658 @staticmethod
01659 def _sim_exp_id_of(exp_id):
01660 return SimArray._lsm_id_to_sim_id(
01661 exp_id, LsmError(
01662 ErrorNumber.NOT_FOUND_NFS_EXPORT,
01663 "File system export not found"))
01664
01665 @staticmethod
01666 def _sim_ag_id_of(ag_id):
01667 return SimArray._lsm_id_to_sim_id(
01668 ag_id, LsmError(
01669 ErrorNumber.NOT_FOUND_NFS_EXPORT,
01670 "File system export not found"))
01671
01672 @_handle_errors
01673 def __init__(self, statefile, timeout):
01674 if statefile is None:
01675 statefile = SimArray.SIM_DATA_FILE
01676
01677 self.bs_obj = BackStore(statefile, timeout)
01678 self.bs_obj.check_version_and_init()
01679 self.statefile = statefile
01680 self.timeout = timeout
01681
01682 def _job_create(self, data_type=None, sim_data_id=None):
01683 sim_job_id = self.bs_obj.sim_job_create(
01684 data_type, sim_data_id)
01685 return SimArray._sim_id_to_lsm_id(sim_job_id, 'JOB')
01686
01687 @_handle_errors
01688 def job_status(self, job_id, flags=0):
01689 sim_job_id = SimArray._sim_job_id_of(job_id)
01690
01691 (progress, data_type, sim_data) = self.bs_obj.sim_job_status(
01692 sim_job_id)
01693 status = JobStatus.INPROGRESS
01694 if progress == 100:
01695 status = JobStatus.COMPLETE
01696
01697 data = None
01698 if data_type == BackStore.JOB_DATA_TYPE_VOL:
01699 data = SimArray._sim_vol_2_lsm(sim_data)
01700 elif data_type == BackStore.JOB_DATA_TYPE_FS:
01701 data = SimArray._sim_fs_2_lsm(sim_data)
01702 elif data_type == BackStore.JOB_DATA_TYPE_FS_SNAP:
01703 data = SimArray._sim_fs_snap_2_lsm(sim_data)
01704
01705 return (status, progress, data)
01706
01707 @_handle_errors
01708 def job_free(self, job_id, flags=0):
01709 self.bs_obj.trans_begin()
01710 self.bs_obj.sim_job_delete(SimArray._sim_job_id_of(job_id))
01711 self.bs_obj.trans_commit()
01712 return None
01713
01714 @_handle_errors
01715 def time_out_set(self, ms, flags=0):
01716 self.bs_obj = BackStore(self.statefile, int(ms/1000))
01717 self.timeout = ms
01718 return None
01719
01720 @_handle_errors
01721 def time_out_get(self, flags=0):
01722 return self.timeout
01723
01724 @staticmethod
01725 def _sim_sys_2_lsm(sim_sys):
01726 return System(
01727 sim_sys['id'], sim_sys['name'], sim_sys['status'],
01728 sim_sys['status_info'])
01729
01730 @_handle_errors
01731 def systems(self):
01732 return list(
01733 SimArray._sim_sys_2_lsm(sim_sys)
01734 for sim_sys in self.bs_obj.sim_syss())
01735
01736 @staticmethod
01737 def _sim_vol_2_lsm(sim_vol):
01738 vol_id = SimArray._sim_id_to_lsm_id(sim_vol['id'], 'VOL')
01739 pool_id = SimArray._sim_id_to_lsm_id(sim_vol['pool_id'], 'POOL')
01740 return Volume(vol_id, sim_vol['name'], sim_vol['vpd83'],
01741 BackStore.BLK_SIZE,
01742 int(sim_vol['total_space'] / BackStore.BLK_SIZE),
01743 sim_vol['admin_state'], BackStore.SYS_ID,
01744 pool_id)
01745
01746 @_handle_errors
01747 def volumes(self):
01748 return list(
01749 SimArray._sim_vol_2_lsm(v) for v in self.bs_obj.sim_vols())
01750
01751 @staticmethod
01752 def _sim_pool_2_lsm(sim_pool):
01753 pool_id = SimArray._sim_id_to_lsm_id(sim_pool['id'], 'POOL')
01754 name = sim_pool['name']
01755 total_space = sim_pool['total_space']
01756 free_space = sim_pool['free_space']
01757 status = sim_pool['status']
01758 status_info = sim_pool['status_info']
01759 sys_id = BackStore.SYS_ID
01760 element_type = sim_pool['element_type']
01761 unsupported_actions = sim_pool['unsupported_actions']
01762 return Pool(
01763 pool_id, name, element_type, unsupported_actions, total_space,
01764 free_space, status, status_info, sys_id)
01765
01766 @_handle_errors
01767 def pools(self, flags=0):
01768 self.bs_obj.trans_begin()
01769 sim_pools = self.bs_obj.sim_pools()
01770 self.bs_obj.trans_rollback()
01771 return list(
01772 SimArray._sim_pool_2_lsm(sim_pool) for sim_pool in sim_pools)
01773
01774 @staticmethod
01775 def _sim_disk_2_lsm(sim_disk):
01776 disk_status = Disk.STATUS_OK
01777 if sim_disk['role'] is None:
01778 disk_status |= Disk.STATUS_FREE
01779
01780 return Disk(
01781 SimArray._sim_id_to_lsm_id(sim_disk['id'], 'DISK'),
01782 sim_disk['name'],
01783 sim_disk['disk_type'], BackStore.BLK_SIZE,
01784 int(sim_disk['total_space'] / BackStore.BLK_SIZE),
01785 disk_status, BackStore.SYS_ID)
01786
01787 @_handle_errors
01788 def disks(self):
01789 return list(
01790 SimArray._sim_disk_2_lsm(sim_disk)
01791 for sim_disk in self.bs_obj.sim_disks())
01792
01793 @_handle_errors
01794 def volume_create(self, pool_id, vol_name, size_bytes, thinp, flags=0,
01795 _internal_use=False, _is_hw_raid_vol=0):
01796 """
01797 The '_internal_use' parameter is only for SimArray internal use.
01798 This method will return the new sim_vol id instead of job_id when
01799 '_internal_use' marked as True.
01800 """
01801 if _internal_use is False:
01802 self.bs_obj.trans_begin()
01803
01804 new_sim_vol_id = self.bs_obj.sim_vol_create(
01805 vol_name, size_bytes, SimArray._sim_pool_id_of(pool_id),
01806 thinp, is_hw_raid_vol=_is_hw_raid_vol)
01807
01808 if _internal_use:
01809 return new_sim_vol_id
01810
01811 job_id = self._job_create(
01812 BackStore.JOB_DATA_TYPE_VOL, new_sim_vol_id)
01813 self.bs_obj.trans_commit()
01814
01815 return job_id, None
01816
01817 @_handle_errors
01818 def volume_delete(self, vol_id, flags=0):
01819 self.bs_obj.trans_begin()
01820 self.bs_obj.sim_vol_delete(SimArray._sim_vol_id_of(vol_id))
01821 job_id = self._job_create()
01822 self.bs_obj.trans_commit()
01823 return job_id
01824
01825 @_handle_errors
01826 def volume_resize(self, vol_id, new_size_bytes, flags=0):
01827 self.bs_obj.trans_begin()
01828
01829 sim_vol_id = SimArray._sim_vol_id_of(vol_id)
01830 self.bs_obj.sim_vol_resize(sim_vol_id, new_size_bytes)
01831 job_id = self._job_create(
01832 BackStore.JOB_DATA_TYPE_VOL, sim_vol_id)
01833 self.bs_obj.trans_commit()
01834
01835 return job_id, None
01836
01837 @_handle_errors
01838 def volume_replicate(self, dst_pool_id, rep_type, src_vol_id, new_vol_name,
01839 flags=0):
01840 self.bs_obj.trans_begin()
01841
01842 src_sim_vol_id = SimArray._sim_pool_id_of(src_vol_id)
01843
01844 src_sim_vol = self.bs_obj.sim_vol_of_id(src_sim_vol_id)
01845
01846 dst_sim_vol_id = self.volume_create(
01847 dst_pool_id, new_vol_name, src_sim_vol['total_space'],
01848 src_sim_vol['thinp'], _internal_use=True)
01849
01850 self.bs_obj.sim_vol_replica(src_sim_vol_id, dst_sim_vol_id, rep_type)
01851
01852 job_id = self._job_create(
01853 BackStore.JOB_DATA_TYPE_VOL, dst_sim_vol_id)
01854 self.bs_obj.trans_commit()
01855
01856 return job_id, None
01857
01858 @_handle_errors
01859 def volume_replicate_range_block_size(self, sys_id, flags=0):
01860 if sys_id != BackStore.SYS_ID:
01861 raise LsmError(
01862 ErrorNumber.NOT_FOUND_SYSTEM,
01863 "System not found")
01864 return BackStore.BLK_SIZE
01865
01866 @_handle_errors
01867 def volume_replicate_range(self, rep_type, src_vol_id, dst_vol_id, ranges,
01868 flags=0):
01869 self.bs_obj.trans_begin()
01870
01871
01872
01873
01874
01875 self.bs_obj.sim_vol_replica(
01876 SimArray._sim_pool_id_of(src_vol_id),
01877 SimArray._sim_pool_id_of(dst_vol_id), rep_type, ranges)
01878
01879 job_id = self._job_create()
01880
01881 self.bs_obj.trans_commit()
01882 return job_id
01883
01884 @_handle_errors
01885 def volume_enable(self, vol_id, flags=0):
01886 self.bs_obj.trans_begin()
01887 self.bs_obj.sim_vol_state_change(
01888 SimArray._sim_vol_id_of(vol_id), Volume.ADMIN_STATE_ENABLED)
01889 self.bs_obj.trans_commit()
01890 return None
01891
01892 @_handle_errors
01893 def volume_disable(self, vol_id, flags=0):
01894 self.bs_obj.trans_begin()
01895 self.bs_obj.sim_vol_state_change(
01896 SimArray._sim_vol_id_of(vol_id), Volume.ADMIN_STATE_DISABLED)
01897 self.bs_obj.trans_commit()
01898 return None
01899
01900 @_handle_errors
01901 def volume_child_dependency(self, vol_id, flags=0):
01902
01903
01904
01905
01906
01907
01908
01909
01910
01911
01912
01913
01914
01915
01916
01917
01918
01919
01920 src_sim_vol_id = SimArray._sim_vol_id_of(vol_id)
01921 dst_sim_vol_ids = self.bs_obj.dst_sim_vol_ids_of_src(src_sim_vol_id)
01922 for dst_sim_fs_id in dst_sim_vol_ids:
01923 if dst_sim_fs_id != src_sim_vol_id:
01924 return True
01925 return False
01926
01927 @_handle_errors
01928 def volume_child_dependency_rm(self, vol_id, flags=0):
01929 self.bs_obj.trans_begin()
01930
01931 self.bs_obj.sim_vol_src_replica_break(
01932 SimArray._sim_vol_id_of(vol_id))
01933
01934 job_id = self._job_create()
01935 self.bs_obj.trans_commit()
01936 return job_id
01937
01938 @staticmethod
01939 def _sim_fs_2_lsm(sim_fs):
01940 fs_id = SimArray._sim_id_to_lsm_id(sim_fs['id'], 'FS')
01941 pool_id = SimArray._sim_id_to_lsm_id(sim_fs['id'], 'POOL')
01942 return FileSystem(fs_id, sim_fs['name'],
01943 sim_fs['total_space'], sim_fs['free_space'],
01944 pool_id, BackStore.SYS_ID)
01945
01946 @_handle_errors
01947 def fs(self):
01948 return list(SimArray._sim_fs_2_lsm(f) for f in self.bs_obj.sim_fss())
01949
01950 @_handle_errors
01951 def fs_create(self, pool_id, fs_name, size_bytes, flags=0,
01952 _internal_use=False):
01953
01954 if not _internal_use:
01955 self.bs_obj.trans_begin()
01956
01957 new_sim_fs_id = self.bs_obj.sim_fs_create(
01958 fs_name, size_bytes, SimArray._sim_pool_id_of(pool_id))
01959
01960 if _internal_use:
01961 return new_sim_fs_id
01962
01963 job_id = self._job_create(
01964 BackStore.JOB_DATA_TYPE_FS, new_sim_fs_id)
01965 self.bs_obj.trans_commit()
01966
01967 return job_id, None
01968
01969 @_handle_errors
01970 def fs_delete(self, fs_id, flags=0):
01971 self.bs_obj.trans_begin()
01972 self.bs_obj.sim_fs_delete(SimArray._sim_fs_id_of(fs_id))
01973 job_id = self._job_create()
01974 self.bs_obj.trans_commit()
01975 return job_id
01976
01977 @_handle_errors
01978 def fs_resize(self, fs_id, new_size_bytes, flags=0):
01979 sim_fs_id = SimArray._sim_fs_id_of(fs_id)
01980 self.bs_obj.trans_begin()
01981 self.bs_obj.sim_fs_resize(sim_fs_id, new_size_bytes)
01982 job_id = self._job_create(BackStore.JOB_DATA_TYPE_FS, sim_fs_id)
01983 self.bs_obj.trans_commit()
01984 return job_id, None
01985
01986 @_handle_errors
01987 def fs_clone(self, src_fs_id, dst_fs_name, snap_id, flags=0):
01988 self.bs_obj.trans_begin()
01989
01990 sim_fs_snap_id = None
01991 if snap_id:
01992 sim_fs_snap_id = SimArray._sim_fs_snap_id_of(snap_id)
01993
01994 src_sim_fs_id = SimArray._sim_fs_id_of(src_fs_id)
01995 src_sim_fs = self.bs_obj.sim_fs_of_id(src_sim_fs_id)
01996 pool_id = SimArray._sim_id_to_lsm_id(src_sim_fs['pool_id'], 'POOL')
01997
01998 dst_sim_fs_id = self.fs_create(
01999 pool_id, dst_fs_name, src_sim_fs['total_space'],
02000 _internal_use=True)
02001
02002 self.bs_obj.sim_fs_clone(src_sim_fs_id, dst_sim_fs_id, sim_fs_snap_id)
02003
02004 job_id = self._job_create(
02005 BackStore.JOB_DATA_TYPE_FS, dst_sim_fs_id)
02006 self.bs_obj.trans_commit()
02007
02008 return job_id, None
02009
02010 @_handle_errors
02011 def fs_file_clone(self, fs_id, src_fs_name, dst_fs_name, snap_id, flags=0):
02012 self.bs_obj.trans_begin()
02013 sim_fs_snap_id = None
02014 if snap_id:
02015 sim_fs_snap_id = SimArray._sim_fs_snap_id_of(snap_id)
02016
02017 self.bs_obj.sim_fs_file_clone(
02018 SimArray._sim_fs_id_of(fs_id), src_fs_name, dst_fs_name,
02019 sim_fs_snap_id)
02020
02021 job_id = self._job_create()
02022 self.bs_obj.trans_commit()
02023 return job_id
02024
02025 @staticmethod
02026 def _sim_fs_snap_2_lsm(sim_fs_snap):
02027 snap_id = SimArray._sim_id_to_lsm_id(sim_fs_snap['id'], 'FS_SNAP')
02028 return FsSnapshot(
02029 snap_id, sim_fs_snap['name'], sim_fs_snap['timestamp'])
02030
02031 @_handle_errors
02032 def fs_snapshots(self, fs_id, flags=0):
02033 return list(
02034 SimArray._sim_fs_snap_2_lsm(s)
02035 for s in self.bs_obj.sim_fs_snaps(
02036 SimArray._sim_fs_id_of(fs_id)))
02037
02038 @_handle_errors
02039 def fs_snapshot_create(self, fs_id, snap_name, flags=0):
02040 self.bs_obj.trans_begin()
02041 sim_fs_snap_id = self.bs_obj.sim_fs_snap_create(
02042 SimArray._sim_fs_id_of(fs_id), snap_name)
02043 job_id = self._job_create(
02044 BackStore.JOB_DATA_TYPE_FS_SNAP, sim_fs_snap_id)
02045 self.bs_obj.trans_commit()
02046 return job_id, None
02047
02048 @_handle_errors
02049 def fs_snapshot_delete(self, fs_id, snap_id, flags=0):
02050 self.bs_obj.trans_begin()
02051 self.bs_obj.sim_fs_snap_delete(
02052 SimArray._sim_fs_snap_id_of(snap_id),
02053 SimArray._sim_fs_id_of(fs_id))
02054 job_id = self._job_create()
02055 self.bs_obj.trans_commit()
02056 return job_id
02057
02058 @_handle_errors
02059 def fs_snapshot_restore(self, fs_id, snap_id, files, restore_files,
02060 flag_all_files, flags):
02061 self.bs_obj.trans_begin()
02062 sim_fs_snap_id = None
02063 if snap_id:
02064 sim_fs_snap_id = SimArray._sim_fs_snap_id_of(snap_id)
02065
02066 self.bs_obj.sim_fs_snap_restore(
02067 SimArray._sim_fs_id_of(fs_id),
02068 sim_fs_snap_id, files, restore_files, flag_all_files)
02069
02070 job_id = self._job_create()
02071 self.bs_obj.trans_commit()
02072 return job_id
02073
02074 @_handle_errors
02075 def fs_child_dependency(self, fs_id, files, flags=0):
02076 sim_fs_id = SimArray._sim_fs_id_of(fs_id)
02077 self.bs_obj.trans_begin()
02078 if self.bs_obj.clone_dst_sim_fs_ids_of_src(sim_fs_id) == [] and \
02079 self.bs_obj.sim_fs_snaps(sim_fs_id) == []:
02080 self.bs_obj.trans_rollback()
02081 return False
02082 self.bs_obj.trans_rollback()
02083 return True
02084
02085 @_handle_errors
02086 def fs_child_dependency_rm(self, fs_id, files, flags=0):
02087 """
02088 Assuming API defination is break all clone relationship and remove
02089 all snapshot of this source file system.
02090 """
02091 self.bs_obj.trans_begin()
02092 if self.fs_child_dependency(fs_id, files) is False:
02093 raise LsmError(
02094 ErrorNumber.NO_STATE_CHANGE,
02095 "No snapshot or fs clone target found for this file system")
02096
02097 src_sim_fs_id = SimArray._sim_fs_id_of(fs_id)
02098 self.bs_obj.sim_fs_src_clone_break(src_sim_fs_id)
02099 self.bs_obj.sim_fs_snap_del_by_fs(src_sim_fs_id)
02100 job_id = self._job_create()
02101 self.bs_obj.trans_begin()
02102 return job_id
02103
02104 @staticmethod
02105 def _sim_exp_2_lsm(sim_exp):
02106 exp_id = SimArray._sim_id_to_lsm_id(sim_exp['id'], 'EXP')
02107 fs_id = SimArray._sim_id_to_lsm_id(sim_exp['fs_id'], 'FS')
02108 return NfsExport(exp_id, fs_id, sim_exp['exp_path'],
02109 sim_exp['auth_type'], sim_exp['root_hosts'],
02110 sim_exp['rw_hosts'], sim_exp['ro_hosts'],
02111 sim_exp['anon_uid'], sim_exp['anon_gid'],
02112 sim_exp['options'])
02113
02114 @_handle_errors
02115 def exports(self, flags=0):
02116 return [SimArray._sim_exp_2_lsm(e) for e in self.bs_obj.sim_exps()]
02117
02118 @_handle_errors
02119 def fs_export(self, fs_id, exp_path, root_hosts, rw_hosts, ro_hosts,
02120 anon_uid, anon_gid, auth_type, options, flags=0):
02121 self.bs_obj.trans_begin()
02122 sim_exp_id = self.bs_obj.sim_exp_create(
02123 SimArray._sim_fs_id_of(fs_id), exp_path, root_hosts, rw_hosts,
02124 ro_hosts, anon_uid, anon_gid, auth_type, options)
02125 sim_exp = self.bs_obj.sim_exp_of_id(sim_exp_id)
02126 self.bs_obj.trans_commit()
02127 return SimArray._sim_exp_2_lsm(sim_exp)
02128
02129 @_handle_errors
02130 def fs_unexport(self, exp_id, flags=0):
02131 self.bs_obj.trans_begin()
02132 self.bs_obj.sim_exp_delete(SimArray._sim_exp_id_of(exp_id))
02133 self.bs_obj.trans_commit()
02134 return None
02135
02136 @staticmethod
02137 def _sim_ag_2_lsm(sim_ag):
02138 ag_id = SimArray._sim_id_to_lsm_id(sim_ag['id'], 'AG')
02139 return AccessGroup(ag_id, sim_ag['name'], sim_ag['init_ids'],
02140 sim_ag['init_type'], BackStore.SYS_ID)
02141
02142 @_handle_errors
02143 def ags(self):
02144 return list(SimArray._sim_ag_2_lsm(a) for a in self.bs_obj.sim_ags())
02145
02146 @_handle_errors
02147 def access_group_create(self, name, init_id, init_type, sys_id, flags=0):
02148 if sys_id != BackStore.SYS_ID:
02149 raise LsmError(
02150 ErrorNumber.NOT_FOUND_SYSTEM,
02151 "System not found")
02152 self.bs_obj.trans_begin()
02153 new_sim_ag_id = self.bs_obj.sim_ag_create(name, init_type, init_id)
02154 new_sim_ag = self.bs_obj.sim_ag_of_id(new_sim_ag_id)
02155 self.bs_obj.trans_commit()
02156 return SimArray._sim_ag_2_lsm(new_sim_ag)
02157
02158 @_handle_errors
02159 def access_group_delete(self, ag_id, flags=0):
02160 self.bs_obj.trans_begin()
02161 self.bs_obj.sim_ag_delete(SimArray._sim_ag_id_of(ag_id))
02162 self.bs_obj.trans_commit()
02163 return None
02164
02165 @_handle_errors
02166 def access_group_initiator_add(self, ag_id, init_id, init_type, flags=0):
02167 sim_ag_id = SimArray._sim_ag_id_of(ag_id)
02168 self.bs_obj.trans_begin()
02169 self.bs_obj.sim_ag_init_add(sim_ag_id, init_id, init_type)
02170 new_sim_ag = self.bs_obj.sim_ag_of_id(sim_ag_id)
02171 self.bs_obj.trans_commit()
02172 return SimArray._sim_ag_2_lsm(new_sim_ag)
02173
02174 @_handle_errors
02175 def access_group_initiator_delete(self, ag_id, init_id, init_type,
02176 flags=0):
02177 sim_ag_id = SimArray._sim_ag_id_of(ag_id)
02178 self.bs_obj.trans_begin()
02179 self.bs_obj.sim_ag_init_delete(sim_ag_id, init_id)
02180 sim_ag = self.bs_obj.sim_ag_of_id(sim_ag_id)
02181 self.bs_obj.trans_commit()
02182 return SimArray._sim_ag_2_lsm(sim_ag)
02183
02184 @_handle_errors
02185 def volume_mask(self, ag_id, vol_id, flags=0):
02186 self.bs_obj.trans_begin()
02187 self.bs_obj.sim_vol_mask(
02188 SimArray._sim_vol_id_of(vol_id),
02189 SimArray._sim_ag_id_of(ag_id))
02190 self.bs_obj.trans_commit()
02191 return None
02192
02193 @_handle_errors
02194 def volume_unmask(self, ag_id, vol_id, flags=0):
02195 self.bs_obj.trans_begin()
02196 self.bs_obj.sim_vol_unmask(
02197 SimArray._sim_vol_id_of(vol_id),
02198 SimArray._sim_ag_id_of(ag_id))
02199 self.bs_obj.trans_commit()
02200 return None
02201
02202 @_handle_errors
02203 def volumes_accessible_by_access_group(self, ag_id, flags=0):
02204 self.bs_obj.trans_begin()
02205
02206 sim_vols = self.bs_obj.sim_vols(
02207 sim_ag_id=SimArray._sim_ag_id_of(ag_id))
02208
02209 self.bs_obj.trans_rollback()
02210 return [SimArray._sim_vol_2_lsm(v) for v in sim_vols]
02211
02212 @_handle_errors
02213 def access_groups_granted_to_volume(self, vol_id, flags=0):
02214 self.bs_obj.trans_begin()
02215 sim_ags = self.bs_obj.sim_ags(
02216 sim_vol_id=SimArray._sim_vol_id_of(vol_id))
02217 self.bs_obj.trans_rollback()
02218 return [SimArray._sim_ag_2_lsm(a) for a in sim_ags]
02219
02220 @_handle_errors
02221 def iscsi_chap_auth(self, init_id, in_user, in_pass, out_user, out_pass,
02222 flags=0):
02223 self.bs_obj.trans_begin()
02224 self.bs_obj.iscsi_chap_auth_set(
02225 init_id, in_user, in_pass, out_user, out_pass)
02226 self.bs_obj.trans_commit()
02227 return None
02228
02229 @staticmethod
02230 def _sim_tgt_2_lsm(sim_tgt):
02231 tgt_id = "TGT_PORT_ID_%0*d" % (SimArray.ID_FMT, sim_tgt['id'])
02232 return TargetPort(
02233 tgt_id, sim_tgt['port_type'], sim_tgt['service_address'],
02234 sim_tgt['network_address'], sim_tgt['physical_address'],
02235 sim_tgt['physical_name'],
02236 BackStore.SYS_ID)
02237
02238 @_handle_errors
02239 def target_ports(self):
02240 return list(SimArray._sim_tgt_2_lsm(t) for t in self.bs_obj.sim_tgts())
02241
02242 @_handle_errors
02243 def volume_raid_info(self, lsm_vol):
02244 sim_pool = self.bs_obj.sim_pool_of_id(
02245 SimArray._lsm_id_to_sim_id(
02246 lsm_vol.pool_id,
02247 LsmError(ErrorNumber.NOT_FOUND_POOL, "Pool not found")))
02248
02249 raid_type = sim_pool['raid_type']
02250 strip_size = Volume.STRIP_SIZE_UNKNOWN
02251 min_io_size = BackStore.BLK_SIZE
02252 opt_io_size = Volume.OPT_IO_SIZE_UNKNOWN
02253 disk_count = Volume.DISK_COUNT_UNKNOWN
02254
02255 if sim_pool['member_type'] == Pool.MEMBER_TYPE_POOL:
02256 parent_sim_pool = self.bs_obj.sim_pool_of_id(
02257 sim_pool['parent_pool_id'])
02258 raid_type = parent_sim_pool['raid_type']
02259
02260 disk_count = self.bs_obj.sim_pool_disks_count(
02261 parent_sim_pool['id'])
02262 data_disk_count = self.bs_obj.sim_pool_data_disks_count(
02263 parent_sim_pool['id'])
02264 else:
02265 disk_count = self.bs_obj.sim_pool_disks_count(
02266 sim_pool['id'])
02267 data_disk_count = self.bs_obj.sim_pool_data_disks_count(
02268 sim_pool['id'])
02269
02270 if raid_type == Volume.RAID_TYPE_UNKNOWN or \
02271 raid_type == Volume.RAID_TYPE_OTHER:
02272 return [
02273 raid_type, strip_size, disk_count, min_io_size,
02274 opt_io_size]
02275
02276 if raid_type == Volume.RAID_TYPE_MIXED:
02277 raise LsmError(
02278 ErrorNumber.PLUGIN_BUG,
02279 "volume_raid_info(): Got unsupported RAID_TYPE_MIXED pool "
02280 "%s" % sim_pool['id'])
02281
02282 if raid_type == Volume.RAID_TYPE_RAID1 or \
02283 raid_type == Volume.RAID_TYPE_JBOD:
02284 strip_size = BackStore.BLK_SIZE
02285 min_io_size = BackStore.BLK_SIZE
02286 opt_io_size = BackStore.BLK_SIZE
02287 else:
02288 strip_size = sim_pool['strip_size']
02289 min_io_size = strip_size
02290 opt_io_size = int(data_disk_count * strip_size)
02291
02292 return [raid_type, strip_size, disk_count, min_io_size, opt_io_size]
02293
02294 @_handle_errors
02295 def pool_member_info(self, lsm_pool):
02296 sim_pool = self.bs_obj.sim_pool_of_id(
02297 SimArray._lsm_id_to_sim_id(
02298 lsm_pool.id,
02299 LsmError(ErrorNumber.NOT_FOUND_POOL, "Pool not found")))
02300 member_type = sim_pool['member_type']
02301 member_ids = []
02302 if member_type == Pool.MEMBER_TYPE_POOL:
02303 member_ids = [
02304 SimArray._sim_id_to_lsm_id(
02305 sim_pool['parent_pool_id'], 'POOL')]
02306 elif member_type == Pool.MEMBER_TYPE_DISK:
02307 member_ids = list(
02308 SimArray._sim_id_to_lsm_id(sim_disk_id, 'DISK')
02309 for sim_disk_id in self.bs_obj.sim_disk_ids_of_pool(
02310 sim_pool['id']))
02311 else:
02312 member_type = Pool.MEMBER_TYPE_UNKNOWN
02313
02314 return sim_pool['raid_type'], member_type, member_ids
02315
02316 @_handle_errors
02317 def volume_raid_create_cap_get(self, system):
02318 if system.id != BackStore.SYS_ID:
02319 raise LsmError(
02320 ErrorNumber.NOT_FOUND_SYSTEM,
02321 "System not found")
02322 return (
02323 BackStore.SUPPORTED_VCR_RAID_TYPES,
02324 BackStore.SUPPORTED_VCR_STRIP_SIZES)
02325
02326 @_handle_errors
02327 def volume_raid_create(self, name, raid_type, disks, strip_size):
02328 if raid_type not in BackStore.SUPPORTED_VCR_RAID_TYPES:
02329 raise LsmError(
02330 ErrorNumber.NO_SUPPORT,
02331 "Provided 'raid_type' is not supported")
02332
02333 if strip_size == Volume.VCR_STRIP_SIZE_DEFAULT:
02334 strip_size = BackStore.DEFAULT_STRIP_SIZE
02335 elif strip_size not in BackStore.SUPPORTED_VCR_STRIP_SIZES:
02336 raise LsmError(
02337 ErrorNumber.NO_SUPPORT,
02338 "Provided 'strip_size' is not supported")
02339
02340 self.bs_obj.trans_begin()
02341 pool_name = "Pool for volume %s" % name
02342 sim_disk_ids = [
02343 SimArray._lsm_id_to_sim_id(
02344 d.id,
02345 LsmError(ErrorNumber.NOT_FOUND_DISK, "Disk not found"))
02346 for d in disks]
02347
02348 for disk in disks:
02349 if not disk.status & Disk.STATUS_FREE:
02350 raise LsmError(
02351 ErrorNumber.DISK_NOT_FREE,
02352 "Disk %s is not in DISK.STATUS_FREE mode" % disk.id)
02353 try:
02354 sim_pool_id = self.bs_obj.sim_pool_create_from_disk(
02355 name=pool_name,
02356 raid_type=raid_type,
02357 sim_disk_ids=sim_disk_ids,
02358 element_type=Pool.ELEMENT_TYPE_VOLUME,
02359 unsupported_actions=Pool.UNSUPPORTED_VOLUME_GROW |
02360 Pool.UNSUPPORTED_VOLUME_SHRINK,
02361 strip_size=strip_size)
02362 except sqlite3.IntegrityError as sql_error:
02363 raise LsmError(
02364 ErrorNumber.NAME_CONFLICT,
02365 "Name '%s' is already in use by other volume" % name)
02366
02367 sim_pool = self.bs_obj.sim_pool_of_id(sim_pool_id)
02368 sim_vol_id = self.volume_create(
02369 SimArray._sim_id_to_lsm_id(sim_pool_id, 'POOL'), name,
02370 sim_pool['free_space'], Volume.PROVISION_FULL,
02371 _internal_use=True, _is_hw_raid_vol=1)
02372 sim_vol = self.bs_obj.sim_vol_of_id(sim_vol_id)
02373 self.bs_obj.trans_commit()
02374 return SimArray._sim_vol_2_lsm(sim_vol)