Statistics
| Branch: | Revision:

root / shared-filer / attach @ master

History | View | Annotate | Download (5.2 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
"""Map an existing file Image to a loop device
21

    
22
This program maps an existing file Image to a block device
23
e.g. /dev/loop{X} and returns the device path. If the mapping
24
already exists, it returns the corresponding device path.
25

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

    
29
 - VOL_NAME: The name of the Image to map
30

    
31
Returns the block device path (which maps the Image) as a string
32
upon success, or 1 upon failure
33

    
34
"""
35

    
36
import os
37
import sys
38

    
39
sys.path.insert(0, "/etc/ganeti/share")
40

    
41
from ganeti import utils
42

    
43

    
44
# Default shared directory
45
SHARED_DIR = "/srv/ganeti/shared-file-storage"
46
#SHARED_DIR = "/mnt/okeanos/shared_dir"
47

    
48

    
49
def ReadEnv():
50
  """Read the mandatory enviromental variables
51

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

    
61
  return (name, shared_dir_param)
62

    
63

    
64
def _ParseLosetupOutput(output, filename):
65
  """Parse the output of `losetup -j <filename>`
66

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

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

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

    
88
  field0 = 0
89
  field_sep = " "
90
  
91
  lines = output.splitlines()
92
  splitted_lines = map(lambda l: l.split(field_sep), lines)
93

    
94
  # Check empty output. If empty, the file is not losetup
95
  if not splitted_lines:
96
    return None
97

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

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

    
107
  return dev_path
108

    
109

    
110
def main():
111
  sys.stderr.write('Attaching started: reading environment...\n')
112

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

    
119
  file_name, shared_dir_param = env
120

    
121
  if shared_dir_param is None:
122
    shared_dir_param = SHARED_DIR
123

    
124
  file_path = utils.PathJoin(shared_dir_param, file_name)
125

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

    
128
  # Check if the file exists
129
  if not os.path.exists(file_path):
130
    sys.stderr.write("File %s does not exist. Aborting\n" % file_path)
131
    return 1
132

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

    
144
    if dev_path is None:
145
      # The file is not attached. Attach it
146
      cmd2 = ["losetup", "-f", "--show", "%s" % file_path]
147
      result = utils.RunCmd(cmd2)
148
      if result.failed:
149
        sys.stderr.write('Cannot losetup file %s, attachment failed (%s): %s' %
150
                         file_path, result.fail_reason, result.output)
151
        return 1
152

    
153
      # The '--show' option returns an EOL at the end. Remove it.
154
      dev_path = result.output.split("\n")[0]
155

    
156
      # The file was losetup successfully. Return the loop device.
157
      sys.stderr.write('File %s successfully attached at %s\n' %
158
                       (file_path, dev_path))
159
      sys.stdout.write("%s" % str(dev_path))
160
      return 0
161

    
162
    else:
163
      # The file is already losetup. Return the loop device path
164
      sys.stderr.write('File %s successfully attached at %s\n' %
165
                       (file_path, dev_path))
166
      sys.stdout.write("%s" % str(dev_path))
167
      return 0
168

    
169

    
170
if __name__ == "__main__":
171
    sys.exit(main())