Revision 7432d332 lib/ovf.py

b/lib/ovf.py
80 80
RASD_TYPE = {
81 81
  "vcpus": "3",
82 82
  "memory": "4",
83
  "scsi-controller": "6",
84
  "ethernet-adapter": "10",
85
  "disk": "17",
83 86
}
84 87

  
85 88
# AllocationUnits values and conversion
......
107 110
TAGS = "tags"
108 111
VERSION = "version"
109 112

  
113
# Instance IDs of System and SCSI controller
114
SYSTEM_ID = 0
115
SCSI_ID = 3
116

  
117
# Disk format descriptions
118
DISK_FORMAT = {
119
  "raw": "http://en.wikipedia.org/wiki/Byte",
120
  "vmdk": "http://www.vmware.com/interfaces/specifications/vmdk.html"
121
          "#monolithicSparse",
122
  "cow": "http://www.gnome.org/~markmc/qcow-image-format.html",
123
}
124

  
110 125

  
111 126
def LinkFile(old_path, prefix=None, suffix=None, directory=None):
112 127
  """Create link with a given prefix and suffix.
......
539 554
    return results
540 555

  
541 556

  
557
def SubElementText(parent, tag, text, attrib={}, **extra):
558
# pylint: disable=W0102
559
  """This is just a wrapper on ET.SubElement that always has text content.
560

  
561
  """
562
  if text is None:
563
    return None
564
  elem = ET.SubElement(parent, tag, attrib=attrib, **extra)
565
  elem.text = str(text)
566
  return elem
567

  
568

  
542 569
class OVFWriter(object):
543 570
  """Writer class for OVF files.
544 571

  
545 572
  @type tree: ET.ElementTree
546 573
  @ivar tree: XML tree that we are constructing
574
  @type hardware_list: list
575
  @ivar hardware_list: list of items prepared for VirtualHardwareSection
547 576

  
548 577
  """
549 578
  def __init__(self, has_gnt_section):
......
565 594
    if has_gnt_section:
566 595
      env_attribs["xmlns:gnt"] = GANETI_SCHEMA
567 596
    self.tree = ET.Element("Envelope", attrib=env_attribs)
597
    self.hardware_list = []
598

  
599
  def SaveDisksData(self, disks):
600
    """Convert disk information to certain OVF sections.
601

  
602
    @type disks: list
603
    @param disks: list of dictionaries of disk options from config.ini
604

  
605
    """
606
    references = ET.SubElement(self.tree, "References")
607
    disk_section = ET.SubElement(self.tree, "DiskSection")
608
    for counter, disk in enumerate(disks):
609
      file_id = "file%s" % counter
610
      disk_id = "disk%s" % counter
611
      file_attribs = {
612
        "ovf:href": disk["path"],
613
        "ovf:size": str(disk["real-size"]),
614
        "ovf:id": file_id,
615
      }
616
      disk_attribs = {
617
        "ovf:capacity": str(disk["virt-size"]),
618
        "ovf:diskId": disk_id,
619
        "ovf:fileRef": file_id,
620
        "ovf:format": DISK_FORMAT.get(disk["format"], disk["format"]),
621
      }
622
      if "compression" in disk:
623
        file_attribs["ovf:compression"] = disk["compression"]
624
      ET.SubElement(references, "File", attrib=file_attribs)
625
      ET.SubElement(disk_section, "Disk", attrib=disk_attribs)
626

  
627
      # Item in VirtualHardwareSection creation
628
      disk_item = ET.Element("Item")
629
      SubElementText(disk_item, "rasd:ElementName", disk_id)
630
      SubElementText(disk_item, "rasd:ResourceType", RASD_TYPE["disk"])
631
      SubElementText(disk_item, "rasd:HostResource", "ovf:/disk/%s" % disk_id)
632
      SubElementText(disk_item, "rasd:Parent", SCSI_ID)
633
      self.hardware_list.append(disk_item)
634

  
635
  def SaveNetworksData(self, networks):
636
    """Convert network information to NetworkSection.
637

  
638
    @type networks: list
639
    @param networks: list of dictionaries of network options form config.ini
640

  
641
    """
642
    network_section = ET.SubElement(self.tree, "NetworkSection")
643
    for counter, network in enumerate(networks):
644
      network_name = "%s%s" % (network["mode"], counter)
645
      network_attrib = {"ovf:name": network_name}
646
      ET.SubElement(network_section, "Network", attrib=network_attrib)
647

  
648
      # Item in VirtualHardwareSection creation
649
      network_item = ET.Element("Item")
650
      SubElementText(network_item, "rasd:ElementName", network_name)
651
      SubElementText(network_item, "rasd:ResourceType",
652
        RASD_TYPE["ethernet-adapter"])
653
      SubElementText(network_item, "rasd:Connection", network_name)
654
      SubElementText(network_item, "rasd:Address", network["mac"])
655
      self.hardware_list.append(network_item)
656

  
657
  @staticmethod
658
  def _SaveNameAndParams(root, data):
659
    """Save name and parameters information under root using data.
660

  
661
    @type root: ET.Element
662
    @param root: root element for the Name and Parameters
663
    @type data: dict
664
    @param data: data from which we gather the values
665

  
666
    """
667
    assert(data.get("name"))
668
    name = SubElementText(root, "gnt:Name", data["name"])
669
    params = ET.SubElement(root, "gnt:Parameters")
670
    for name, value in data.iteritems():
671
      if name != "name":
672
        SubElementText(params, "gnt:%s" % name, value)
673

  
674
  def SaveGanetiData(self, ganeti, networks):
675
    """Convert Ganeti-specific information to GanetiSection.
676

  
677
    @type ganeti: dict
678
    @param ganeti: dictionary of Ganeti-specific options from config.ini
679
    @type networks: list
680
    @param networks: list of dictionaries of network options form config.ini
681

  
682
    """
683
    ganeti_section = ET.SubElement(self.tree, "gnt:GanetiSection")
684

  
685
    SubElementText(ganeti_section, "gnt:Version", ganeti.get("version"))
686
    SubElementText(ganeti_section, "gnt:DiskTemplate",
687
      ganeti.get("disk_template"))
688
    SubElementText(ganeti_section, "gnt:AutoBalance",
689
      ganeti.get("auto_balance"))
690
    SubElementText(ganeti_section, "gnt:Tags", ganeti.get("tags"))
691

  
692
    osys = ET.SubElement(ganeti_section, "gnt:OperatingSystem")
693
    self._SaveNameAndParams(osys, ganeti["os"])
694

  
695
    hypervisor = ET.SubElement(ganeti_section, "gnt:Hypervisor")
696
    self._SaveNameAndParams(hypervisor, ganeti["hypervisor"])
697

  
698
    network_section = ET.SubElement(ganeti_section, "gnt:Network")
699
    for counter, network in enumerate(networks):
700
      network_name = "%s%s" % (network["mode"], counter)
701
      nic_attrib = {"ovf:name": network_name}
702
      nic = ET.SubElement(network_section, "gnt:Nic", attrib=nic_attrib)
703
      SubElementText(nic, "gnt:Mode", network["mode"])
704
      SubElementText(nic, "gnt:MACAddress", network["mac"])
705
      SubElementText(nic, "gnt:IPAddress", network["ip"])
706
      SubElementText(nic, "gnt:Link", network["link"])
707

  
708
  def SaveVirtualSystemData(self, name, vcpus, memory):
709
    """Convert virtual system information to OVF sections.
710

  
711
    @type name: string
712
    @param name: name of the instance
713
    @type vcpus: int
714
    @param vcpus: number of VCPUs
715
    @type memory: int
716
    @param memory: RAM memory in MB
717

  
718
    """
719
    assert(vcpus > 0)
720
    assert(memory > 0)
721
    vs_attrib = {"ovf:id": name}
722
    virtual_system = ET.SubElement(self.tree, "VirtualSystem", attrib=vs_attrib)
723

  
724
    name_section = ET.SubElement(virtual_system, "Name")
725
    name_section.text = name
726
    os_attrib = {"ovf:id": "0"}
727
    ET.SubElement(virtual_system, "OperatingSystemSection",
728
      attrib=os_attrib)
729
    hardware_section = ET.SubElement(virtual_system, "VirtualHardwareSection")
730

  
731
    # System description
732
    system = ET.SubElement(hardware_section, "System")
733
    SubElementText(system, "vssd:ElementName", "Virtual Hardware Family")
734
    SubElementText(system, "vssd:InstanceId", SYSTEM_ID)
735
    SubElementText(system, "vssd:VirtualSystemIdentifier", name)
736
    SubElementText(system, "vssd:VirtualSystemType", "ganeti-ovf")
737

  
738
    # Item for vcpus
739
    vcpus_item = ET.SubElement(hardware_section, "Item")
740
    SubElementText(vcpus_item, "rasd:ElementName",
741
      "%s virtual CPU(s)" % vcpus)
742
    SubElementText(vcpus_item, "rasd:InstanceID", "1")
743
    SubElementText(vcpus_item, "rasd:ResourceType", RASD_TYPE["vcpus"])
744
    SubElementText(vcpus_item, "rasd:VirtualQuantity", vcpus)
745

  
746
    # Item for memory
747
    memory_item = ET.SubElement(hardware_section, "Item")
748
    SubElementText(memory_item, "rasd:AllocationUnits", "byte * 2^20")
749
    SubElementText(memory_item, "rasd:ElementName", "%sMB of memory" % memory)
750
    SubElementText(memory_item, "rasd:InstanceID", "2")
751
    SubElementText(memory_item, "rasd:ResourceType", RASD_TYPE["memory"])
752
    SubElementText(memory_item, "rasd:VirtualQuantity", memory)
753

  
754
    # Item for scsi controller
755
    scsi_item = ET.SubElement(hardware_section, "Item")
756
    SubElementText(scsi_item, "rasd:Address", SYSTEM_ID)
757
    SubElementText(scsi_item, "rasd:ElementName", "scsi_controller0")
758
    SubElementText(scsi_item, "rasd:ResourceType", RASD_TYPE["scsi-controller"])
759
    SubElementText(scsi_item, "rasd:InstanceId", "3")
760

  
761
    # Other items - from self.hardware_list
762
    for counter, item in enumerate(self.hardware_list):
763
      SubElementText(item, "rasd:InstanceID", counter + 4)
764
      hardware_section.append(item)
568 765

  
569 766
  def PrettyXmlDump(self):
570 767
    """Formatter of the XML file.
......
1241 1438
  @ivar output_path: complete path to .ovf file
1242 1439
  @type config_parser: L{ConfigParserWithDefaults}
1243 1440
  @ivar config_parser: parser for the config.ini file
1441
  @type reference_files: list
1442
  @ivar reference_files: files referenced in the ovf file
1244 1443
  @type results_disk: list
1245 1444
  @ivar results_disk: list of dictionaries of disk options from config.ini
1246 1445
  @type results_network: list
......
1528 1727
    self.output_path = utils.PathJoin(self.output_dir, output_file)
1529 1728
    files_list = [self.output_path]
1530 1729

  
1730
    self.ovf_writer.SaveDisksData(self.results_disk)
1731
    self.ovf_writer.SaveNetworksData(self.results_network)
1732
    if not self.options.ext_usage:
1733
      self.ovf_writer.SaveGanetiData(self.results_ganeti, self.results_network)
1734

  
1735
    self.ovf_writer.SaveVirtualSystemData(self.results_name, self.results_vcpus,
1736
      self.results_memory)
1737

  
1531 1738
    data = self.ovf_writer.PrettyXmlDump()
1532 1739
    utils.WriteFile(self.output_path, data=data)
1533 1740

  

Also available in: Unified diff