Statistics
| Branch: | Revision:

root / shared-filer / detach @ 68abdf0d

History | View | Annotate | Download (4.7 kB)

1
#!/usr/bin/env python
2
#
3
# Copyright (C) 2012 Greek Research and Technology Network
4
#
5
# This program is free software; you can redistribute it and/or modify
6
# it under the terms of the GNU General Public License as published by
7
# the Free Software Foundation; either version 2 of the License, or
8
# (at your option) any later version.
9
#
10
# This program is distributed in the hope that it will be useful, but
11
# WITHOUT ANY WARRANTY; without even the implied warranty of
12
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13
# General Public License for more details.
14
#
15
# You should have received a copy of the GNU General Public License
16
# along with this program; if not, write to the Free Software
17
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18
# 02110-1301, USA.
19

    
20
"""Detach the Image file from the loop device
21

    
22
This program detaches an Image file from the loop device it attached to.
23
It is idempotent, if the file isn't losetup at all.
24

    
25
It takes it's input from environment variables. Specifically the
26
following variable should be present:
27

    
28
 - VOL_NAME: The name of the Image file to which the device points
29

    
30
Returns O upon successfull unmapping, 1 upon failure
31

    
32
"""
33

    
34
import os
35
import sys
36

    
37
sys.path.insert(0, "/etc/ganeti/share")
38

    
39
from ganeti import utils
40

    
41

    
42
# Default shared directory
43
SHARED_DIR = "/srv/ganeti/shared-file-storage"
44

    
45

    
46
def ReadEnv():
47
  """Read the mandatory enviromental variables
48

    
49
  """
50
  name = os.getenv("VOL_NAME")
51
  if name is None:
52
    sys.stderr.write('The environment variable VOL_NAME is missing.\n')
53
    return None
54
  shared_dir_param = os.getenv("EXTP_SHARED_DIR")
55
  if shared_dir_param is not None:
56
    sys.stderr.write('Found shared dir param, value: %s\n' % shared_dir_param)
57

    
58
  return (name, shared_dir_param)
59

    
60

    
61
def _ParseLosetupOutput(output, filename):
62
  """Parse the output of `losetup -j <filename>`
63

    
64
  This method parses the output of `losetup -j <filename>` and returns
65
  the corresponding loop device path for this filename
66
  (e.g. /dev/loop0)
67

    
68
  @type output: string
69
  @param output: the whole output of `losetup -j filename`
70
  @type filename: string
71
  @param filename: the complete file path to the file we search for
72
  @rtype: string or None
73
  @return: loop device path if the file is losetup, else None
74

    
75
  """
76
  # `losetup -j file1` output looks like this
77
  #   /dev/loop0: [X]:Y (/path/to/file1)
78
  # if the file has been losetup. If not there is no output.
79
  # If the file has been losetup more than once, then there will be
80
  # multiple lines like the one above.
81
  #
82
  # We assume the following format (space is the seperator):
83
  # field0: field1 (field2)
84

    
85
  field0 = 0
86
  field_sep = " "
87
  
88
  lines = output.splitlines()
89
  splitted_lines = map(lambda l: l.split(field_sep), lines)
90

    
91
  # Check empty output. If empty, the file is not losetup
92
  if not splitted_lines:
93
    return None
94

    
95
  # Check if we have more than one lines in the output
96
  if len(splitted_lines) > 1:
97
    sys.stderr.write("The file %s is losetup more than once" % filename)
98
    sys.exit(1)
99

    
100
  # The file is losetup only once
101
  # Take field0, remove the ":" at the end and we have our path
102
  dev_path = splitted_lines[0][field0].split(":")[0]
103

    
104
  return dev_path
105

    
106

    
107
def main():
108
  sys.stderr.write('Detaching started: reading environment...\n')
109

    
110
  # Read environment
111
  env = ReadEnv()
112
  if env is None:
113
    sys.stderr.write('Wrong environment. Aborting\n')
114
    return 1
115

    
116
  file_name, shared_dir_param = env
117

    
118
  if shared_dir_param is None:
119
    shared_dir_param = SHARED_DIR
120

    
121
  file_path = utils.PathJoin(shared_dir_param, file_name)
122

    
123
  sys.stderr.write('Read environment successfully: file name: %s\n' % file_path)
124

    
125
  # Check if the file exists
126
  if not os.path.exists(file_path):
127
    sys.stderr.write('File %s does not exist. Aborting\n' % file_path)
128
    return 1
129

    
130
  # Check if the file is losetup
131
  cmd1 = ["losetup", "-j", "%s" % file_path]
132
  result = utils.RunCmd(cmd1)
133
  if result.failed:
134
    sys.stderr.write('losetup -j %s failed (%s): %s' %
135
                     (dev_path, result.fail_reason, result.output))
136
    return 1
137
  else:
138
    # Parse the result's output
139
    dev_path = _ParseLosetupOutput(result.output, file_path)
140

    
141
    if dev_path is None:
142
      # The file is not losetup (device is not attached). Return.
143
      sys.stderr.write('File %s successfully detached\n' % file_path)
144
      return 0
145
    else:
146
      # The file is losetup (device attached). Detach it.
147
      cmd2 = ["losetup", "-d", "%s" % dev_path]
148
      result = utils.RunCmd(cmd2)
149
      if result.failed:
150
        sys.stderr.write('Cannot `losetup -d` device: %s, detachment failed '
151
                         '(%s): %s\n' %
152
                          (dev_path, result.fail_reason, result.output))
153
        return 1
154

    
155
      sys.stderr.write('File %s successfully detached\n' % file_path)
156
      return 0
157

    
158

    
159
if __name__ == "__main__":
160
    sys.exit(main())