Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_fake.py @ 98c98ab9

History | View | Annotate | Download (7.8 kB)

1
#
2
#
3

    
4
# Copyright (C) 2006, 2007, 2008 Google Inc.
5
#
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.
10
#
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.
15
#
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
19
# 02110-1301, USA.
20

    
21

    
22
"""Fake hypervisor
23

24
"""
25

    
26
import os
27
import os.path
28
import logging
29

    
30
from ganeti import utils
31
from ganeti import constants
32
from ganeti import errors
33
from ganeti.hypervisor import hv_base
34

    
35

    
36
class FakeHypervisor(hv_base.BaseHypervisor):
37
  """Fake hypervisor interface.
38

39
  This can be used for testing the ganeti code without having to have
40
  a real virtualisation software installed.
41

42
  """
43
  CAN_MIGRATE = True
44

    
45
  _ROOT_DIR = constants.RUN_DIR + "/ganeti-fake-hypervisor"
46

    
47
  def __init__(self):
48
    hv_base.BaseHypervisor.__init__(self)
49
    utils.EnsureDirs([(self._ROOT_DIR, constants.RUN_DIRS_MODE)])
50

    
51
  def ListInstances(self):
52
    """Get the list of running instances.
53

54
    """
55
    return os.listdir(self._ROOT_DIR)
56

    
57
  def GetInstanceInfo(self, instance_name):
58
    """Get instance properties.
59

60
    @param instance_name: the instance name
61

62
    @return: tuple of (name, id, memory, vcpus, stat, times)
63

64
    """
65
    file_name = self._InstanceFile(instance_name)
66
    if not os.path.exists(file_name):
67
      return None
68
    try:
69
      fh = open(file_name, "r")
70
      try:
71
        inst_id = fh.readline().strip()
72
        memory = utils.TryConvert(int, fh.readline().strip())
73
        vcpus = utils.TryConvert(int, fh.readline().strip())
74
        stat = "---b-"
75
        times = "0"
76
        return (instance_name, inst_id, memory, vcpus, stat, times)
77
      finally:
78
        fh.close()
79
    except IOError, err:
80
      raise errors.HypervisorError("Failed to list instance %s: %s" %
81
                                   (instance_name, err))
82

    
83
  def GetAllInstancesInfo(self):
84
    """Get properties of all instances.
85

86
    @return: list of tuples (name, id, memory, vcpus, stat, times)
87

88
    """
89
    data = []
90
    for file_name in os.listdir(self._ROOT_DIR):
91
      try:
92
        fh = open(utils.PathJoin(self._ROOT_DIR, file_name), "r")
93
        inst_id = "-1"
94
        memory = 0
95
        vcpus = 1
96
        stat = "-----"
97
        times = "-1"
98
        try:
99
          inst_id = fh.readline().strip()
100
          memory = utils.TryConvert(int, fh.readline().strip())
101
          vcpus = utils.TryConvert(int, fh.readline().strip())
102
          stat = "---b-"
103
          times = "0"
104
        finally:
105
          fh.close()
106
        data.append((file_name, inst_id, memory, vcpus, stat, times))
107
      except IOError, err:
108
        raise errors.HypervisorError("Failed to list instances: %s" % err)
109
    return data
110

    
111
  @classmethod
112
  def _InstanceFile(cls, instance_name):
113
    """Compute the instance file for an instance name.
114

115
    """
116
    return utils.PathJoin(cls._ROOT_DIR, instance_name)
117

    
118
  def _IsAlive(self, instance_name):
119
    """Checks if an instance is alive.
120

121
    """
122
    file_name = self._InstanceFile(instance_name)
123
    return os.path.exists(file_name)
124

    
125
  def _MarkUp(self, instance):
126
    """Mark the instance as running.
127

128
    This does no checks, which should be done by its callers.
129

130
    """
131
    file_name = self._InstanceFile(instance.name)
132
    fh = file(file_name, "w")
133
    try:
134
      fh.write("0\n%d\n%d\n" %
135
               (instance.beparams[constants.BE_MEMORY],
136
                instance.beparams[constants.BE_VCPUS]))
137
    finally:
138
      fh.close()
139

    
140
  def _MarkDown(self, instance_name):
141
    """Mark the instance as running.
142

143
    This does no checks, which should be done by its callers.
144

145
    """
146
    file_name = self._InstanceFile(instance_name)
147
    utils.RemoveFile(file_name)
148

    
149
  def StartInstance(self, instance, block_devices):
150
    """Start an instance.
151

152
    For the fake hypervisor, it just creates a file in the base dir,
153
    creating an exception if it already exists. We don't actually
154
    handle race conditions properly, since these are *FAKE* instances.
155

156
    """
157
    if self._IsAlive(instance.name):
158
      raise errors.HypervisorError("Failed to start instance %s: %s" %
159
                                   (instance.name, "already running"))
160
    try:
161
      self._MarkUp(instance)
162
    except IOError, err:
163
      raise errors.HypervisorError("Failed to start instance %s: %s" %
164
                                   (instance.name, err))
165

    
166
  def StopInstance(self, instance, force=False, retry=False, name=None):
167
    """Stop an instance.
168

169
    For the fake hypervisor, this just removes the file in the base
170
    dir, if it exist, otherwise we raise an exception.
171

172
    """
173
    if name is None:
174
      name = instance.name
175
    if not self._IsAlive(name):
176
      raise errors.HypervisorError("Failed to stop instance %s: %s" %
177
                                   (name, "not running"))
178
    self._MarkDown(name)
179

    
180
  def RebootInstance(self, instance):
181
    """Reboot an instance.
182

183
    For the fake hypervisor, this does nothing.
184

185
    """
186
    return
187

    
188
  def GetNodeInfo(self):
189
    """Return information about the node.
190

191
    This is just a wrapper over the base GetLinuxNodeInfo method.
192

193
    @return: a dict with the following keys (values in MiB):
194
          - memory_total: the total memory size on the node
195
          - memory_free: the available memory on the node for instances
196
          - memory_dom0: the memory used by the node itself, if available
197

198
    """
199
    result = self.GetLinuxNodeInfo()
200
    # substract running instances
201
    all_instances = self.GetAllInstancesInfo()
202
    result['memory_free'] -= min(result['memory_free'],
203
                                 sum([row[2] for row in all_instances]))
204
    return result
205

    
206
  @classmethod
207
  def GetShellCommandForConsole(cls, instance, hvparams, beparams):
208
    """Return a command for connecting to the console of an instance.
209

210
    """
211
    return "echo Console not available for fake hypervisor"
212

    
213
  def Verify(self):
214
    """Verify the hypervisor.
215

216
    For the fake hypervisor, it just checks the existence of the base
217
    dir.
218

219
    """
220
    if not os.path.exists(self._ROOT_DIR):
221
      return "The required directory '%s' does not exist." % self._ROOT_DIR
222

    
223
  @classmethod
224
  def PowercycleNode(cls):
225
    """Fake hypervisor powercycle, just a wrapper over Linux powercycle.
226

227
    """
228
    cls.LinuxPowercycle()
229

    
230
  def AcceptInstance(self, instance, info, target):
231
    """Prepare to accept an instance.
232

233
    @type instance: L{objects.Instance}
234
    @param instance: instance to be accepted
235
    @type info: string
236
    @param info: instance info, not used
237
    @type target: string
238
    @param target: target host (usually ip), on this node
239

240
    """
241
    if self._IsAlive(instance.name):
242
      raise errors.HypervisorError("Can't accept instance, already running")
243

    
244
  def MigrateInstance(self, instance, target, live):
245
    """Migrate an instance.
246

247
    @type instance: L{objects.Instance}
248
    @param instance: the instance to be migrated
249
    @type target: string
250
    @param target: hostname (usually ip) of the target node
251
    @type live: boolean
252
    @param live: whether to do a live or non-live migration
253

254
    """
255
    logging.debug("Fake hypervisor migrating %s to %s (live=%s)",
256
                  instance, target, live)
257

    
258
    self._MarkDown(instance.name)
259

    
260
  def FinalizeMigration(self, instance, info, success):
261
    """Finalize an instance migration.
262

263
    For the fake hv, this just marks the instance up.
264

265
    @type instance: L{objects.Instance}
266
    @param instance: instance whose migration is being finalized
267

268
    """
269
    if success:
270
      self._MarkUp(instance)
271
    else:
272
      # ensure it's down
273
      self._MarkDown(instance.name)