5.0_boot_devices.rb

EOLE Team, 08/19/2016 02:33 PM

Download (6.15 KB)

 
1
# coding: utf-8
2
# -------------------------------------------------------------------------- #
3
# Copyright 2002-2016, OpenNebula Project, OpenNebula Systems                #
4
#                                                                            #
5
# Licensed under the Apache License, Version 2.0 (the "License"); you may    #
6
# not use this file except in compliance with the License. You may obtain    #
7
# a copy of the License at                                                   #
8
#                                                                            #
9
# http://www.apache.org/licenses/LICENSE-2.0                                 #
10
#                                                                            #
11
# Unless required by applicable law or agreed to in writing, software        #
12
# distributed under the License is distributed on an "AS IS" BASIS,          #
13
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   #
14
# See the License for the specific language governing permissions and        #
15
# limitations under the License.                                             #
16
#--------------------------------------------------------------------------- #
17

    
18
require 'nokogiri'
19

    
20
module OneDBPatch
21
  VERSION = "4.90.0"
22
  LOCAL_VERSION = "4.90.0"
23

    
24
  IMAGE_TYPE = %w[hd cdrom]
25

    
26
  class NoImageError < StandardError
27
  end
28

    
29
  def is_hot_patch(ops)
30
    return false
31
  end
32

    
33
  def check_db_version(ops)
34
    db_version = read_db_version()
35

    
36
    if ( db_version[:version] != VERSION ||
37
         db_version[:local_version] != LOCAL_VERSION )
38

    
39
      raise <<-EOT
40
Version mismatch: patch file is for version
41
Shared: #{VERSION}, Local: #{LOCAL_VERSION}
42

43
Current database is version
44
Shared: #{db_version[:version]}, Local: #{db_version[:local_version]}
45
EOT
46
    end
47
  end
48

    
49
  # Modify template boot order to match disk# and nic# instead of HD, CDROM and NETWORK
50
  # Params:
51
  # +ops+:: Options
52
  def patch(ops)
53
    init_log_time()
54

    
55
    #
56

    
57
    @db.transaction do
58
      @db.fetch("SELECT oid,body FROM template_pool") do |row|
59
        doc = Nokogiri::XML(row[:body],nil,NOKOGIRI_ENCODING){|c| c.default_xml.noblanks}
60
        template_name = doc.root.at_css("NAME").content
61

    
62
        # Rename VMMMAD -> VM_MAD and TMMAD -> TM_MAD
63
        boot = doc.root.at_xpath("TEMPLATE/OS/BOOT")
64
        if boot.nil?
65
          # No boot entry for template
66
          next
67
        end
68

    
69
        # Convert each boot device
70
        # Skip template if:
71
        # * the image referenced by a DISK is not found
72
        # * a boot device in BOOT does not match any DISK
73
        devs=[]
74
        nic_id=0
75

    
76
        begin
77
          boot.content.split(",").each do |dev|
78
            case dev.downcase
79

    
80
              when "hd", "cdrom"
81
                id = get_first_disk_id(dev, doc)
82
                if id.nil?
83
                  puts "Warning template #{row[:oid]} #{template_name}: skip nonexistent boot device '#{dev}'"
84
                  next
85
                end
86
                devs.push("disk#{id}")
87

    
88
              when "network"
89
                devs.push("nic#{nic_id}")
90
                nic_id += 1
91

    
92
              when /^(?:nic|disk)[0-9]+/
93
                devs.push(dev)
94

    
95
            end
96
          end
97
        rescue NoImageError => error
98
          puts "Skipping template #{row[:oid]} #{template_name}: #{error.message}"
99
          next
100
        end
101

    
102
        if boot.content != devs.join(",")
103
          # Avoid updating unchanged lines
104
          new_boot = devs.join(",")
105

    
106
          if ops[:verbose]
107
            puts "Template #{row[:oid]} #{template_name}: '#{boot.content}' -> '#{new_boot}'"
108
          end
109

    
110
          boot.content = new_boot
111

    
112
          @db[:template_pool].where(:oid => row[:oid]).update(
113
            :body => doc.root.to_s)
114

    
115
        end
116
      end
117

    
118
    end
119

    
120
    log_time()
121

    
122
    return true
123
  end
124

    
125
  # Returns the ID of the first disk of a type
126
  # Params:
127
  # +type+:: type name of the disk, can be “hd” or “cdrom”
128
  # +doc+:: Nokogiri::XML::Node describing the VM template
129
  def get_first_disk_id(type, doc)
130
    doc.root.xpath("TEMPLATE/DISK").each_with_index do |disk, index|
131
      id = disk.at_css("IMAGE_ID")
132
      if ! id.nil?
133
        image = get_image_from_id(id.content)
134
      else
135
        image = get_image_from_name(disk)
136
      end
137

    
138
      if is_image_type_matching?(image.at_css("TYPE").content, type)
139
        return index
140
      end
141
    end
142
    return nil # Skip this type of device
143
  end
144

    
145
  # Returns a Nokogiri::XML::Node describing an image
146
  # Params:
147
  # +id+:: ID of the image
148
  def get_image_from_id(id)
149
    @db.transaction do
150
      row = @db.fetch("SELECT body from image_pool where oid=#{id}").first
151
      # No image found, so unable to get image TYPE
152
      raise NoImageError, "No image with ID '#{id}'" if row.nil?
153
      image = Nokogiri::XML(row[:body], nil,NOKOGIRI_ENCODING){|c| c.default_xml.noblanks}
154
      return image
155
    end
156
  end
157

    
158
  # Returns a Nokogiri::XML::Node describing an image
159
  # Params:
160
  # +disk+:: Nokogiri::XML::Node describing a disk used by a template
161
  def get_image_from_name(disk)
162
    name = disk.at_css("IMAGE").content # always defined
163
    uid = disk.at_css("IMAGE_UID")
164
    uname = disk.at_css("IMAGE_UNAME")
165

    
166
    if ! name.nil? and (! uid.nil? or ! uname.nil?)
167
      if uid.nil?
168
        uid = get_user_id(uname.content)
169
      else
170
        uid = uid.content
171
      end
172

    
173
      @db.transaction do
174
        row = @db.fetch("SELECT body from image_pool where name=\"#{name}\" and uid=#{uid}").first
175
        # No image found, so unable to get image TYPE
176
        raise NoImageError, "No image named '#{name}' for uid '#{uid}'" if row.nil?
177
        image = Nokogiri::XML(row[:body], nil,NOKOGIRI_ENCODING){|c| c.default_xml.noblanks}
178
        return image
179
      end
180
    end
181
  end
182

    
183
  # Returns the ID of a user name
184
  # Params:
185
  # +name+:: name of a user
186
  def get_user_id(name)
187
    @db.transaction do
188
      row = @db.fetch("SELECT uid from user_pool where name=\"#{name}\"").first
189
      return row[:uid]
190
    end
191
  end
192

    
193
  # Check if an image type match the type used in template BOOT
194
  # Params:
195
  # +image_type+:: numerical type of an image
196
  # +wanted_type+:: string type extracted from VM template BOOT
197
  def is_image_type_matching?(image_type, wanted_type)
198
    Integer(image_type) == IMAGE_TYPE.index(wanted_type.downcase)
199
  end
200

    
201
end