4 # Copyright (C) 2006, 2007 Google Inc.
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 2 of the License, or
9 # (at your option) any later version.
11 # This program is distributed in the hope that it will be useful, but
12 # WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 # General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
28 from ganeti import constants
29 from ganeti import cli
30 from ganeti import logger
31 from ganeti import errors
32 from ganeti import utils
33 from ganeti import config
34 from ganeti import ssh
38 """Simple function that prints out its argument.
45 def LogIndented(level, msg):
46 """Log a message indented."""
47 for line in msg.splitlines():
48 Log(" " * 4 * level + line)
51 def CheckInstanceConfig(instance):
52 """Check if the instance has a correct configuration.
54 This checks that MD devices have only one child (the single DRBD
58 if instance.disk_template != constants.DT_REMOTE_RAID1:
60 for disk in instance.disks:
61 if len(disk.children) != 1:
62 raise errors.ConfigurationError("Instance %s drive %s has >1 mirrors" %
63 (instance.name, disk.iv_name))
65 def CheckNodeStatus(node):
68 This checks that there are no active DRBD devices on the node
71 result = ssh.SSHCall(node.name, "root", "cat /proc/drbd")
73 raise errors.OpExecError("Can't read /proc/drbd on node %s" % node.name)
74 for line in result.stdout.splitlines():
75 if "cs:" in line and "cs:Unconfigured" not in line:
76 raise errors.OpExecError("Active drbd? /proc/drbd entry: %s" % line)
78 result = ssh.SSHCall(node.name, "root", "drbdmeta")
80 raise errors.OpExecError("Failed to run drbdmeta on node %s" % node.name)
83 def ConvertMetaOnNode(node, meta_dev):
84 """Convert a meta device on a node."""
86 LogIndented(2, "Updating %s:%s" % (node, meta_dev))
87 lv_name = meta_dev.replace("/dev/", "").replace("/", "_")
89 result = ssh.SSHCall(node, "root",
90 "drbdmeta /dev/drbd0 v07 %s 0 dump-md" % meta_dev)
93 raise errors.OpExecError("Can't dump meta device %s" % meta_dev)
95 bk_fh = open("metadump-%s-%s" % (node, lv_name), "w")
96 bk_fh.write(result.stdout)
98 except EnvironmentError:
99 Log("Can't write meta dump!")
101 result = ssh.SSHCall(node, "root", "drbdmeta --force /dev/drbd0 v08 %s 0"
102 " create-md" % meta_dev)
104 raise errors.OpExecError("upgrading metadata for %s failed: %s" %
105 (meta_dev, result.output))
106 LogIndented(2, "Updated metadata:")
107 LogIndented(3, "%s%s" % (result.stderr, result.stdout))
110 def ConvertDiskStorage(disk):
111 """Convert disk storage for a drbd disk.
114 for node in disk.logical_id[:2]:
115 meta_disk = disk.children[1]
116 meta_dev = meta_disk.StaticDevPath()
118 raise errors.OpPrereqError("Can't upgrade disk %s: can't find meta in"
119 " config?" % meta_disk)
120 ConvertMetaOnNode(node, meta_dev)
121 disk.dev_type = constants.LD_DRBD8
124 def ConvertInstance(instance):
125 """Conver the instance to drbd8.
128 if instance.disk_template != constants.DT_REMOTE_RAID1:
130 Log("Working on %s" % instance.name)
132 for disk in instance.disks:
133 LogIndented(1, "Disk %s" % disk.iv_name)
134 drbd_disk = disk.children[0]
135 ConvertDiskStorage(drbd_disk)
136 drbd_disk.iv_name = disk.iv_name
137 new_disks.append(drbd_disk)
138 instance.disk_template = constants.DT_DRBD8
139 instance.disks = new_disks
143 """Main under lock."""
145 cfg = config.ConfigWriter()
146 ilist = [cfg.GetInstanceInfo(name) for name in cfg.GetInstanceList()]
147 for instance in ilist:
148 CheckInstanceConfig(instance)
149 nlist = [cfg.GetNodeInfo(name) for name in cfg.GetNodeList()]
151 CheckNodeStatus(node)
152 bkname = utils.CreateBackup(constants.CLUSTER_CONF_FILE)
153 Log("Created initial backup as %s" % bkname)
156 for instance in ilist:
157 ConvertInstance(instance)
165 logger.SetupLogging(debug=False, program="ganeti/drbd8-upgrade")
167 utils.Lock('cmd', max_retries=15, debug=True)
168 except errors.LockError, err:
169 logger.ToStderr(str(err))
173 retval = LockedMain()
174 except errors.GenericError, err:
175 retval, msg = cli.FormatError(err)
183 if __name__ == "__main__":