Revision 1862d460

b/lib/cmdlib.py
2837 2837
  HTYPE = constants.HTYPE_INSTANCE
2838 2838
  _OP_REQP = ["instance_name", "mem_size", "disk_size", "pnode",
2839 2839
              "disk_template", "swap_size", "mode", "start", "vcpus",
2840
              "wait_for_sync", "ip_check"]
2840
              "wait_for_sync", "ip_check", "mac"]
2841 2841

  
2842 2842
  def BuildHooksEnv(self):
2843 2843
    """Build hooks env.
......
3013 3013
        raise errors.OpPrereqError("IP %s of instance %s already in use" %
3014 3014
                                   (hostname1.ip, instance_name))
3015 3015

  
3016
    # MAC address verification
3017
    if self.op.mac != "auto":
3018
      if not utils.IsValidMac(self.op.mac.lower()):
3019
        raise errors.OpPrereqError("invalid MAC address specified: %s" %
3020
                                   self.op.mac)
3021

  
3016 3022
    # bridge verification
3017 3023
    bridge = getattr(self.op, "bridge", None)
3018 3024
    if bridge is None:
......
3037 3043
    instance = self.op.instance_name
3038 3044
    pnode_name = self.pnode.name
3039 3045

  
3040
    nic = objects.NIC(bridge=self.op.bridge, mac=self.cfg.GenerateMAC())
3046
    if self.op.mac == "auto":
3047
      mac_address=self.cfg.GenerateMAC()
3048
    else:
3049
      mac_address=self.op.mac
3050

  
3051
    nic = objects.NIC(bridge=self.op.bridge, mac=mac_address)
3041 3052
    if self.inst_ip is not None:
3042 3053
      nic.ip = self.inst_ip
3043 3054

  
......
4073 4084
    self.mem = getattr(self.op, "mem", None)
4074 4085
    self.vcpus = getattr(self.op, "vcpus", None)
4075 4086
    self.ip = getattr(self.op, "ip", None)
4087
    self.mac = getattr(self.op, "mac", None)
4076 4088
    self.bridge = getattr(self.op, "bridge", None)
4077
    if [self.mem, self.vcpus, self.ip, self.bridge].count(None) == 4:
4089
    if [self.mem, self.vcpus, self.ip, self.bridge, self.mac].count(None) == 5:
4078 4090
      raise errors.OpPrereqError("No changes submitted")
4079 4091
    if self.mem is not None:
4080 4092
      try:
......
4096 4108
    else:
4097 4109
      self.do_ip = False
4098 4110
    self.do_bridge = (self.bridge is not None)
4111
    if self.mac is not None:
4112
      if self.cfg.IsMacInUse(self.mac):
4113
        raise errors.OpPrereqError('MAC address %s already in use in cluster' %
4114
                                   self.mac)
4115
      if not utils.IsValidMac(self.mac):
4116
        raise errors.OpPrereqError('Invalid MAC address %s' % self.mac)
4099 4117

  
4100 4118
    instance = self.cfg.GetInstanceInfo(
4101 4119
      self.cfg.ExpandInstanceName(self.op.instance_name))
......
4125 4143
    if self.bridge:
4126 4144
      instance.nics[0].bridge = self.bridge
4127 4145
      result.append(("bridge", self.bridge))
4146
    if self.mac:
4147
      instance.nics[0].mac = self.mac
4148
      result.append(("mac", self.mac))
4128 4149

  
4129 4150
    self.cfg.AddInstance(instance)
4130 4151

  
b/lib/config.py
96 96
      raise errors.ConfigurationError("Can't generate unique MAC")
97 97
    return mac
98 98

  
99
  def IsMacInUse(self, mac):
100
    """Predicate: check if the specified MAC is in use in the Ganeti cluster.
101

  
102
    This only checks instances managed by this cluster, it does not
103
    check for potential collisions elsewhere.
104

  
105
    """
106
    self._OpenConfig()
107
    self._ReleaseLock()
108
    all_macs = self._AllMACs()
109
    return mac in all_macs
110

  
99 111
  def _ComputeAllLVs(self):
100 112
    """Compute the list of all LVs.
101 113

  
b/lib/opcodes.py
160 160
  __slots__ = ["instance_name", "mem_size", "disk_size", "os_type", "pnode",
161 161
               "disk_template", "snode", "swap_size", "mode",
162 162
               "vcpus", "ip", "bridge", "src_node", "src_path", "start",
163
               "wait_for_sync", "ip_check"]
163
               "wait_for_sync", "ip_check", "mac"]
164 164

  
165 165

  
166 166
class OpReinstallInstance(OpCode):
......
257 257
class OpSetInstanceParms(OpCode):
258 258
  """Change the parameters of an instance."""
259 259
  OP_ID = "OP_INSTANCE_SET_PARMS"
260
  __slots__ = ["instance_name", "mem", "vcpus", "ip", "bridge"]
260
  __slots__ = ["instance_name", "mem", "vcpus", "ip", "bridge", "mac"]
261 261

  
262 262

  
263 263
# OS opcodes
b/lib/utils.py
1055 1055
  """
1056 1056
  seen = set()
1057 1057
  return [i for i in seq if i not in seen and not seen.add(i)]
1058

  
1059

  
1060
def IsValidMac(mac):
1061
  """Predicate to check if a MAC address is valid.
1062

  
1063
  Checks wether the supplied MAC address is formally correct, only
1064
  accepts colon separated format.
1065
  """
1066
  mac_check = re.compile("^([0-9a-f]{2}(:|$)){6}$")
1067
  return mac_check.match(mac) is not None
b/scripts/gnt-instance
226 226
                                snode=snode, vcpus=opts.vcpus,
227 227
                                ip=opts.ip, bridge=opts.bridge,
228 228
                                start=opts.start, ip_check=opts.ip_check,
229
                                wait_for_sync=opts.wait_for_sync)
229
                                wait_for_sync=opts.wait_for_sync, mac=opts.mac)
230 230
  SubmitOpCode(op)
231 231
  return 0
232 232

  
......
624 624
  Opts used:
625 625
    memory - the new memory size
626 626
    vcpus - the new number of cpus
627
    mac - the new MAC address of the instance
627 628

  
628 629
  """
629
  if not opts.mem and not opts.vcpus and not opts.ip and not opts.bridge:
630
  if not (opts.mem or opts.vcpus or opts.ip or opts.bridge or opts.mac):
630 631
    logger.ToStdout("Please give at least one of the parameters.")
631 632
    return 1
632 633

  
633 634
  op = opcodes.OpSetInstanceParms(instance_name=args[0], mem=opts.mem,
634 635
                                  vcpus=opts.vcpus, ip=opts.ip,
635
                                  bridge=opts.bridge)
636
                                  bridge=opts.bridge, mac=opts.mac)
636 637
  result = SubmitOpCode(op)
637 638

  
638 639
  if result:
......
701 702
  make_option("-i", "--ip", dest="ip",
702 703
              help="IP address ('none' [default], 'auto', or specify address)",
703 704
              default='none', type="string", metavar="<ADDRESS>"),
705
  make_option("--mac", dest="mac",
706
              help="MAC address ('auto' [default], or specify address)",
707
              default='auto', type="string", metavar="<MACADDRESS>"),
704 708
  make_option("--no-wait-for-sync", dest="wait_for_sync", default=True,
705 709
              action="store_false", help="Don't wait for sync (DANGEROUS!)"),
706 710
  make_option("-b", "--bridge", dest="bridge",
......
808 812
              make_option("-b", "--bridge", dest="bridge",
809 813
                          help="Bridge to connect this instance to",
810 814
                          default=None, type="string", metavar="<bridge>"),
815
              make_option("--mac", dest="mac",
816
                          help="MAC address", default=None,
817
                          type="string", metavar="<MACADDRESS>"),
811 818
              ],
812 819
             "<instance>", "Alters the parameters of an instance"),
813 820
  'shutdown': (ShutdownInstance, ARGS_ANY,

Also available in: Unified diff