Revision 4b97f902

b/Makefile.am
712 712
	  echo "XEN_INITRD = '$(XEN_INITRD)'"; \
713 713
	  echo "FILE_STORAGE_DIR = '$(FILE_STORAGE_DIR)'"; \
714 714
	  echo "ENABLE_FILE_STORAGE = $(ENABLE_FILE_STORAGE)"; \
715
	  echo "SHARED_FILE_STORAGE_DIR = '$(SHARED_FILE_STORAGE_DIR)'"; \
716
	  echo "ENABLE_SHARED_FILE_STORAGE = $(ENABLE_SHARED_FILE_STORAGE)"; \
715 717
	  echo "IALLOCATOR_SEARCH_PATH = [$(IALLOCATOR_SEARCH_PATH)]"; \
716 718
	  echo "KVM_PATH = '$(KVM_PATH)'"; \
717 719
	  echo "SOCAT_PATH = '$(SOCAT)'"; \
b/configure.ac
115 115
AC_SUBST(FILE_STORAGE_DIR, $file_storage_dir)
116 116
AC_SUBST(ENABLE_FILE_STORAGE, $enable_file_storage)
117 117

  
118
# --with-shared-file-storage-dir=...
119
AC_ARG_WITH([shared-file-storage-dir],
120
  [AS_HELP_STRING([--with-shared-file-storage-dir=PATH],
121
    [directory to store files for shared file-based backend]
122
    [ (default is /srv/ganeti/shared-file-storage)]
123
  )],
124
  [[shared_file_storage_dir="$withval";
125
    if test "$withval" != no; then
126
      enable_shared_file_storage=True
127
    else
128
      enable_shared_file_storage=False
129
    fi
130
  ]],
131
  [[shared_file_storage_dir="/srv/ganeti/shared-file-storage"; enable_shared_file_storage="True"]])
132
AC_SUBST(SHARED_FILE_STORAGE_DIR, $shared_file_storage_dir)
133
AC_SUBST(ENABLE_SHARED_FILE_STORAGE, $enable_shared_file_storage)
134

  
118 135
# --with-kvm-path=...
119 136
AC_ARG_WITH([kvm-path],
120 137
  [AS_HELP_STRING([--with-kvm-path=PATH],
b/lib/backend.py
2404 2404
    _Fail("; ".join(msgs))
2405 2405

  
2406 2406

  
2407
def _TransformFileStorageDir(file_storage_dir):
2407
def _TransformFileStorageDir(fs_dir):
2408 2408
  """Checks whether given file_storage_dir is valid.
2409 2409

  
2410
  Checks wheter the given file_storage_dir is within the cluster-wide
2411
  default file_storage_dir stored in SimpleStore. Only paths under that
2412
  directory are allowed.
2410
  Checks wheter the given fs_dir is within the cluster-wide default
2411
  file_storage_dir or the shared_file_storage_dir, which are stored in
2412
  SimpleStore. Only paths under those directories are allowed.
2413 2413

  
2414
  @type file_storage_dir: str
2415
  @param file_storage_dir: the path to check
2414
  @type fs_dir: str
2415
  @param fs_dir: the path to check
2416 2416

  
2417 2417
  @return: the normalized path if valid, None otherwise
2418 2418

  
......
2420 2420
  if not constants.ENABLE_FILE_STORAGE:
2421 2421
    _Fail("File storage disabled at configure time")
2422 2422
  cfg = _GetConfig()
2423
  file_storage_dir = os.path.normpath(file_storage_dir)
2424
  base_file_storage_dir = cfg.GetFileStorageDir()
2425
  if (os.path.commonprefix([file_storage_dir, base_file_storage_dir]) !=
2426
      base_file_storage_dir):
2423
  fs_dir = os.path.normpath(fs_dir)
2424
  base_fstore = cfg.GetFileStorageDir()
2425
  base_shared = cfg.GetSharedFileStorageDir()
2426
  if ((os.path.commonprefix([fs_dir, base_fstore]) != base_fstore) and
2427
      (os.path.commonprefix([fs_dir, base_shared]) != base_shared)):
2427 2428
    _Fail("File storage directory '%s' is not under base file"
2428
          " storage directory '%s'", file_storage_dir, base_file_storage_dir)
2429
  return file_storage_dir
2429
          " storage directory '%s' or shared storage directory '%s'",
2430
          fs_dir, base_fstore, base_shared)
2431
  return fs_dir
2430 2432

  
2431 2433

  
2432 2434
def CreateFileStorageDir(file_storage_dir):
b/lib/bdev.py
1 1
#
2 2
#
3 3

  
4
# Copyright (C) 2006, 2007, 2010 Google Inc.
4
# Copyright (C) 2006, 2007, 2010, 2011 Google Inc.
5 5
#
6 6
# This program is free software; you can redistribute it and/or modify
7 7
# it under the terms of the GNU General Public License as published by
......
2074 2074
  constants.LD_DRBD8: DRBD8,
2075 2075
  }
2076 2076

  
2077
if constants.ENABLE_FILE_STORAGE:
2077
if constants.ENABLE_FILE_STORAGE or constants.ENABLE_SHARED_FILE_STORAGE:
2078 2078
  DEV_MAP[constants.LD_FILE] = FileStorage
2079 2079

  
2080 2080

  
b/lib/bootstrap.py
410 410
    master_netdev=master_netdev,
411 411
    cluster_name=clustername.name,
412 412
    file_storage_dir=file_storage_dir,
413
    shared_file_storage_dir=shared_file_storage_dir,
413 414
    enabled_hypervisors=enabled_hypervisors,
414 415
    beparams={constants.PP_DEFAULT: beparams},
415 416
    nicparams={constants.PP_DEFAULT: nicparams},
b/lib/cli.py
79 79
  "FORCE_VARIANT_OPT",
80 80
  "GLOBAL_FILEDIR_OPT",
81 81
  "HID_OS_OPT",
82
  "GLOBAL_SHARED_FILEDIR_OPT",
82 83
  "HVLIST_OPT",
83 84
  "HVOPTS_OPT",
84 85
  "HYPERVISOR_OPT",
......
972 973
                                metavar="DIR",
973 974
                                default=constants.DEFAULT_FILE_STORAGE_DIR)
974 975

  
976
GLOBAL_SHARED_FILEDIR_OPT = cli_option("--shared-file-storage-dir",
977
                            dest="shared_file_storage_dir",
978
                            help="Specify the default directory (cluster-"
979
                            "wide) for storing the shared file-based"
980
                            " disks [%s]" %
981
                            constants.DEFAULT_SHARED_FILE_STORAGE_DIR,
982
                            metavar="SHAREDDIR",
983
                            default=constants.DEFAULT_SHARED_FILE_STORAGE_DIR)
984

  
975 985
NOMODIFY_ETCHOSTS_OPT = cli_option("--no-etc-hosts", dest="modify_etc_hosts",
976 986
                                   help="Don't modify /etc/hosts",
977 987
                                   action="store_false", default=True)
b/lib/client/gnt_cluster.py
352 352
  ToStdout("  - lvm reserved volumes: %s", reserved_lvs)
353 353
  ToStdout("  - drbd usermode helper: %s", result["drbd_usermode_helper"])
354 354
  ToStdout("  - file storage path: %s", result["file_storage_dir"])
355
  ToStdout("  - shared file storage path: %s",
356
           result["shared_file_storage_dir"])
355 357
  ToStdout("  - maintenance of node health: %s",
356 358
           result["maintain_node_health"])
357 359
  ToStdout("  - uid pool: %s",
b/lib/cmdlib.py
1036 1036
  # Special case for file storage
1037 1037
  if storage_type == constants.ST_FILE:
1038 1038
    # storage.FileStorage wants a list of storage directories
1039
    return [[cfg.GetFileStorageDir()]]
1039
    return [[cfg.GetFileStorageDir(), cfg.GetSharedFileStorageDir()]]
1040 1040

  
1041 1041
  return []
1042 1042

  
......
4696 4696
      "volume_group_name": cluster.volume_group_name,
4697 4697
      "drbd_usermode_helper": cluster.drbd_usermode_helper,
4698 4698
      "file_storage_dir": cluster.file_storage_dir,
4699
      "shared_file_storage_dir": cluster.shared_file_storage_dir,
4699 4700
      "maintain_node_health": cluster.maintain_node_health,
4700 4701
      "ctime": cluster.ctime,
4701 4702
      "mtime": cluster.mtime,
......
5542 5543
    old_name = inst.name
5543 5544

  
5544 5545
    rename_file_storage = False
5545
    if (inst.disk_template == constants.DT_FILE and
5546
    if (inst.disk_template in (constants.DT_FILE, constants.DT_SHARED_FILE) and
5546 5547
        self.op.new_name != inst.name):
5547 5548
      old_file_storage_dir = os.path.dirname(inst.disks[0].logical_id[1])
5548 5549
      rename_file_storage = True
......
6635 6636
                                                         disk_index)),
6636 6637
                              mode=disk["mode"])
6637 6638
      disks.append(disk_dev)
6639
  elif template_name == constants.DT_SHARED_FILE:
6640
    if len(secondary_nodes) != 0:
6641
      raise errors.ProgrammerError("Wrong template configuration")
6642

  
6643
    opcodes.RequireSharedFileStorage()
6644

  
6645
    for idx, disk in enumerate(disk_info):
6646
      disk_index = idx + base_index
6647
      disk_dev = objects.Disk(dev_type=constants.LD_FILE, size=disk["size"],
6648
                              iv_name="disk/%d" % disk_index,
6649
                              logical_id=(file_driver,
6650
                                          "%s/disk%d" % (file_storage_dir,
6651
                                                         disk_index)),
6652
                              mode=disk["mode"])
6653
      disks.append(disk_dev)
6638 6654
  else:
6639 6655
    raise errors.ProgrammerError("Invalid disk template '%s'" % template_name)
6640 6656
  return disks
......
6744 6760
    pnode = target_node
6745 6761
    all_nodes = [pnode]
6746 6762

  
6747
  if instance.disk_template == constants.DT_FILE:
6763
  if instance.disk_template in (constants.DT_FILE, constants.DT_SHARED_FILE):
6748 6764
    file_storage_dir = os.path.dirname(instance.disks[0].logical_id[1])
6749 6765
    result = lu.rpc.call_file_storage_dir_create(pnode, file_storage_dir)
6750 6766

  
......
6834 6850
    # 128 MB are added for drbd metadata for each disk
6835 6851
    constants.DT_DRBD8: _compute(disks, 128),
6836 6852
    constants.DT_FILE: {},
6853
    constants.DT_SHARED_FILE: {},
6837 6854
  }
6838 6855

  
6839 6856
  if disk_template not in req_size_dict:
......
6854 6871
    # 128 MB are added for drbd metadata for each disk
6855 6872
    constants.DT_DRBD8: sum(d["size"] + 128 for d in disks),
6856 6873
    constants.DT_FILE: None,
6874
    constants.DT_SHARED_FILE: 0,
6857 6875
  }
6858 6876

  
6859 6877
  if disk_template not in req_size_dict:
......
7657 7675
    else:
7658 7676
      network_port = None
7659 7677

  
7660
    if constants.ENABLE_FILE_STORAGE:
7678
    if constants.ENABLE_FILE_STORAGE or constants.ENABLE_SHARED_FILE_STORAGE:
7661 7679
      # this is needed because os.path.join does not accept None arguments
7662 7680
      if self.op.file_storage_dir is None:
7663 7681
        string_file_storage_dir = ""
......
7665 7683
        string_file_storage_dir = self.op.file_storage_dir
7666 7684

  
7667 7685
      # build the full file storage dir path
7668
      file_storage_dir = utils.PathJoin(self.cfg.GetFileStorageDir(),
7686
      if self.op.disk_template == constants.DT_SHARED_FILE:
7687
        get_fsd_fn = self.cfg.GetSharedFileStorageDir
7688
      else:
7689
        get_fsd_fn = self.cfg.GetFileStorageDir
7690

  
7691
      file_storage_dir = utils.PathJoin(get_fsd_fn(),
7669 7692
                                        string_file_storage_dir, instance)
7670 7693
    else:
7671 7694
      file_storage_dir = ""
......
8811 8834

  
8812 8835
    self.disk = instance.FindDisk(self.op.disk)
8813 8836

  
8814
    if instance.disk_template != constants.DT_FILE:
8815
      # TODO: check the free disk space for file, when that feature
8816
      # will be supported
8837
    if instance.disk_template not in (constants.DT_FILE,
8838
                                      constants.DT_SHARED_FILE):
8839
      # TODO: check the free disk space for file, when that feature will be
8840
      # supported
8817 8841
      _CheckNodesFreeDiskPerVG(self, nodenames,
8818 8842
                               self.disk.ComputeGrowth(self.op.amount))
8819 8843

  
......
9554 9578
        result.append(("disk/%d" % device_idx, "remove"))
9555 9579
      elif disk_op == constants.DDM_ADD:
9556 9580
        # add a new disk
9557
        if instance.disk_template == constants.DT_FILE:
9581
        if instance.disk_template in (constants.DT_FILE,
9582
                                        constants.DT_SHARED_FILE):
9558 9583
          file_driver, file_path = instance.disks[0].logical_id
9559 9584
          file_path = os.path.dirname(file_path)
9560 9585
        else:
b/lib/config.py
878 878
    return self._config_data.cluster.file_storage_dir
879 879

  
880 880
  @locking.ssynchronized(_config_lock, shared=1)
881
  def GetSharedFileStorageDir(self):
882
    """Get the shared file storage dir for this cluster.
883

  
884
    """
885
    return self._config_data.cluster.shared_file_storage_dir
886

  
887
  @locking.ssynchronized(_config_lock, shared=1)
881 888
  def GetHypervisorType(self):
882 889
    """Get the hypervisor type for this cluster.
883 890

  
......
1738 1745
      constants.SS_CLUSTER_NAME: cluster.cluster_name,
1739 1746
      constants.SS_CLUSTER_TAGS: cluster_tags,
1740 1747
      constants.SS_FILE_STORAGE_DIR: cluster.file_storage_dir,
1748
      constants.SS_SHARED_FILE_STORAGE_DIR: cluster.shared_file_storage_dir,
1741 1749
      constants.SS_MASTER_CANDIDATES: mc_data,
1742 1750
      constants.SS_MASTER_CANDIDATES_IPS: mc_ips_data,
1743 1751
      constants.SS_MASTER_IP: cluster.master_ip,
b/lib/constants.py
144 144
KVM_IFUP = _autoconf.PKGLIBDIR + "/kvm-ifup"
145 145
ETC_HOSTS = "/etc/hosts"
146 146
DEFAULT_FILE_STORAGE_DIR = _autoconf.FILE_STORAGE_DIR
147
DEFAULT_SHARED_FILE_STORAGE_DIR = _autoconf.SHARED_FILE_STORAGE_DIR
147 148
ENABLE_FILE_STORAGE = _autoconf.ENABLE_FILE_STORAGE
149
ENABLE_SHARED_FILE_STORAGE = _autoconf.ENABLE_SHARED_FILE_STORAGE
148 150
SYSCONFDIR = _autoconf.SYSCONFDIR
149 151
TOOLSDIR = _autoconf.TOOLSDIR
150 152
CONF_DIR = SYSCONFDIR + "/ganeti"
......
360 362
DT_PLAIN = "plain"
361 363
DT_DRBD8 = "drbd"
362 364
DT_FILE = "file"
365
DT_SHARED_FILE = "sharedfile"
363 366

  
364 367
# the set of network-mirrored disk templates
365 368
DTS_NET_MIRROR = frozenset([DT_DRBD8])
366 369

  
370
# the set of externally mirrored disk templates
371
DTS_EXT_MIRROR = frozenset([DT_SHARED_FILE])
372

  
367 373
# the set of non-lvm-based disk templates
368
DTS_NOT_LVM = frozenset([DT_DISKLESS, DT_FILE])
374
DTS_NOT_LVM = frozenset([DT_DISKLESS, DT_FILE, DT_SHARED_FILE])
369 375

  
370 376
# the set of disk templates which can be grown
371
DTS_GROWABLE = frozenset([DT_PLAIN, DT_DRBD8, DT_FILE])
377
DTS_GROWABLE = frozenset([DT_PLAIN, DT_DRBD8, DT_FILE, DT_SHARED_FILE])
372 378

  
373 379
# the set of disk templates that allow adoption
374 380
DTS_MAY_ADOPT = frozenset([DT_PLAIN])
......
449 455
#: Give child process up to 5 seconds to exit after sending a signal
450 456
CHILD_LINGER_TIMEOUT = 5.0
451 457

  
452
DISK_TEMPLATES = frozenset([DT_DISKLESS, DT_PLAIN,
453
                            DT_DRBD8, DT_FILE])
458
DISK_TEMPLATES = frozenset([DT_DISKLESS, DT_PLAIN, DT_DRBD8,
459
                            DT_FILE, DT_SHARED_FILE])
454 460

  
455 461
FILE_DRIVER = frozenset([FD_LOOP, FD_BLKTAP])
456 462

  
......
1077 1083
SS_CLUSTER_NAME = "cluster_name"
1078 1084
SS_CLUSTER_TAGS = "cluster_tags"
1079 1085
SS_FILE_STORAGE_DIR = "file_storage_dir"
1086
SS_SHARED_FILE_STORAGE_DIR = "shared_file_storage_dir"
1080 1087
SS_MASTER_CANDIDATES = "master_candidates"
1081 1088
SS_MASTER_CANDIDATES_IPS = "master_candidates_ips"
1082 1089
SS_MASTER_IP = "master_ip"
b/lib/objects.py
558 558
    actual algorithms from bdev.
559 559

  
560 560
    """
561
    if self.dev_type == constants.LD_LV or self.dev_type == constants.LD_FILE:
561
    if self.dev_type in (constants.LD_LV, constants.LD_FILE):
562 562
      self.size += amount
563 563
    elif self.dev_type == constants.LD_DRBD8:
564 564
      if self.children:
......
1066 1066
    "master_netdev",
1067 1067
    "cluster_name",
1068 1068
    "file_storage_dir",
1069
    "shared_file_storage_dir",
1069 1070
    "enabled_hypervisors",
1070 1071
    "hvparams",
1071 1072
    "os_hvp",
b/lib/opcodes.py
162 162
                               errors.ECODE_INVAL)
163 163

  
164 164

  
165
def RequireSharedFileStorage():
166
  """Checks that shared file storage is enabled.
167

  
168
  While it doesn't really fit into this module, L{utils} was deemed too large
169
  of a dependency to be imported for just one or two functions.
170

  
171
  @raise errors.OpPrereqError: when shared file storage is disabled
172

  
173
  """
174
  if not constants.ENABLE_SHARED_FILE_STORAGE:
175
    raise errors.OpPrereqError("Shared file storage disabled at"
176
                               " configure time", errors.ECODE_INVAL)
177

  
178

  
165 179
@ht.WithDesc("CheckFileStorage")
166 180
def _CheckFileStorage(value):
167 181
  """Ensures file storage is enabled if used.
......
169 183
  """
170 184
  if value == constants.DT_FILE:
171 185
    RequireFileStorage()
186
  elif value == constants.DT_SHARED_FILE:
187
    RequireSharedFileStorage()
172 188
  return True
173 189

  
174 190

  
b/lib/ssconf.py
155 155
  def GetFileStorageDir(self):
156 156
    return self._config_data["cluster"]["file_storage_dir"]
157 157

  
158
  def GetSharedFileStorageDir(self):
159
    return self._config_data["cluster"]["shared_file_storage_dir"]
160

  
158 161
  def GetNodeList(self):
159 162
    return self._config_data["nodes"].keys()
160 163

  
......
272 275
    constants.SS_CLUSTER_NAME,
273 276
    constants.SS_CLUSTER_TAGS,
274 277
    constants.SS_FILE_STORAGE_DIR,
278
    constants.SS_SHARED_FILE_STORAGE_DIR,
275 279
    constants.SS_MASTER_CANDIDATES,
276 280
    constants.SS_MASTER_CANDIDATES_IPS,
277 281
    constants.SS_MASTER_IP,
......
369 373
    """
370 374
    return self._ReadFile(constants.SS_FILE_STORAGE_DIR)
371 375

  
376
  def GetSharedFileStorageDir(self):
377
    """Get the shared file storage dir.
378

  
379
    """
380
    return self._ReadFile(constants.SS_SHARED_FILE_STORAGE_DIR)
381

  
372 382
  def GetMasterCandidates(self):
373 383
    """Return the list of master candidates.
374 384

  

Also available in: Unified diff