components/openstack/neutron/files/neutron-dhcp-agent
changeset 6382 ed601ca40b9c
parent 6031 1aaf20a19738
child 6848 8e252a37ed0d
equal deleted inserted replaced
6381:02b02527288b 6382:ed601ca40b9c
    17 import ConfigParser
    17 import ConfigParser
    18 import os
    18 import os
    19 import re
    19 import re
    20 import sys
    20 import sys
    21 
    21 
    22 from openstack_common import is_ml2_plugin
    22 from openstack_common import is_ml2_plugin, kill_contract
    23 import smf_include
    23 import smf_include
    24 
    24 
    25 from subprocess import CalledProcessError, Popen, PIPE, check_call
    25 from subprocess import CalledProcessError, Popen, PIPE, check_call
    26 
    26 
    27 
    27 
    43         print "failed to set ipadm hostmodel property to %s" % value
    43         print "failed to set ipadm hostmodel property to %s" % value
    44         return False
    44         return False
    45     return True
    45     return True
    46 
    46 
    47 
    47 
       
    48 def cleanup_dhcp_agent_datalinks():
       
    49     cmd = ["/usr/sbin/dladm", "show-link", "-p", "-o", "link"]
       
    50     p = Popen(cmd, stdout=PIPE, stderr=PIPE)
       
    51     output, error = p.communicate()
       
    52     if p.returncode != 0:
       
    53         print "failed to retrieve datalink names"
       
    54         return smf_include.SMF_EXIT_ERR_FATAL
       
    55 
       
    56     dlnames = output.splitlines()
       
    57     # DHCP agent datalinks are always 15 characters in length. They start with
       
    58     # 'dh', end with '_0', and in between they are hexadecimal digits.
       
    59     prog = re.compile('dh[0-9A-Fa-f\_]{11}_0')
       
    60     ret_code = smf_include.SMF_EXIT_OK
       
    61     ovs_bridge = None
       
    62     if is_ml2_plugin():
       
    63         ovs_bridge = get_ovs_bridge()
       
    64     for dlname in dlnames:
       
    65         if prog.search(dlname) is None:
       
    66             continue
       
    67         try:
       
    68             # first remove the IP
       
    69             check_call(["/usr/bin/pfexec", "/usr/sbin/ipadm", "delete-ip",
       
    70                         dlname])
       
    71         except:
       
    72             # It is possible that the IP was already deleted but not the
       
    73             # datalink. So we continue and try and delete the datalink.
       
    74             pass
       
    75         try:
       
    76             # next remove the VNIC
       
    77             check_call(["/usr/bin/pfexec", "/usr/sbin/dladm", "delete-vnic",
       
    78                         dlname])
       
    79             # remove the OVS Port
       
    80             if ovs_bridge:
       
    81                 check_call(["/usr/bin/pfexec", "/usr/sbin/ovs-vsctl", "--",
       
    82                             "--if-exists", "del-port", ovs_bridge, dlname])
       
    83         except CalledProcessError as err:
       
    84             print "failed to remove datalink '%s' used by DHCP agent: %s" % \
       
    85                 (dlname, err)
       
    86             ret_code = smf_include.SMF_EXIT_ERR_FATAL
       
    87     return ret_code
       
    88 
       
    89 
    48 def start():
    90 def start():
    49     # verify paths are valid
    91     # verify paths are valid
    50     for f in sys.argv[2:4]:
    92     for f in sys.argv[2:4]:
    51         if not os.path.exists(f) or not os.access(f, os.R_OK):
    93         if not os.path.exists(f) or not os.access(f, os.R_OK):
    52             print '%s does not exist or is not readable' % f
    94             print '%s does not exist or is not readable' % f
    53             return smf_include.SMF_EXIT_ERR_CONFIG
    95             return smf_include.SMF_EXIT_ERR_CONFIG
       
    96 
       
    97     # remove VNICs associated with DHCP agent if any were left over.
       
    98     ret_code = cleanup_dhcp_agent_datalinks()
       
    99     if ret_code != smf_include.SMF_EXIT_OK:
       
   100         return ret_code
    54 
   101 
    55     # set the hostmodel property if necessary
   102     # set the hostmodel property if necessary
    56     if not set_hostmodel("src-priority"):
   103     if not set_hostmodel("src-priority"):
    57         return smf_include.SMF_EXIT_ERR_FATAL
   104         return smf_include.SMF_EXIT_ERR_FATAL
    58 
   105 
    70         ovs_bridge = None
   117         ovs_bridge = None
    71     return ovs_bridge
   118     return ovs_bridge
    72 
   119 
    73 
   120 
    74 def stop():
   121 def stop():
    75     try:
   122     # Keep issuing SIGTERM until the contract is empty. This way we will catch
    76         # first kill the SMF contract
   123     # any child processes missed because they were getting forked.
    77         check_call(["/usr/bin/pkill", "-c", sys.argv[2]])
   124     # 50 attempts will be made at intervals of 2 seconds. Typically, we
    78     except CalledProcessError as err:
   125     # will only need 0 or 1 additional attempt before the contract is empty but
    79         print "failed to kill the SMF contract: %s" % err
   126     # we chose to err on the side of caution. In the worst case, we will use
       
   127     # 100 seconds in the below loop which will leave 500 seconds (timeout is
       
   128     # 600s) for the other cleanup tasks, after which the service will be put to
       
   129     # maintenance state if the contract was not killed successfully.
       
   130     if not kill_contract(50, 2, sys.argv[2]):
    80         return smf_include.SMF_EXIT_ERR_FATAL
   131         return smf_include.SMF_EXIT_ERR_FATAL
    81 
   132 
    82     cmd = ["/usr/sbin/ipadm", "show-if", "-p", "-o", "ifname"]
   133     # remove VNICs associated with DHCP agent
    83     p = Popen(cmd, stdout=PIPE, stderr=PIPE)
   134     ret_code = cleanup_dhcp_agent_datalinks()
    84     output, error = p.communicate()
       
    85     if p.returncode != 0:
       
    86         print "failed to retrieve IP interface names"
       
    87         return smf_include.SMF_EXIT_ERR_FATAL
       
    88 
       
    89     ifnames = output.splitlines()
       
    90     # DHCP agent datalinks are always 15 characters in length. They start with
       
    91     # 'dh', end with '_0', and in between they are hexadecimal digits.
       
    92     prog = re.compile('dh[0-9A-Fa-f\_]{11}_0')
       
    93     err_delete = False
       
    94     for ifname in ifnames:
       
    95         if prog.search(ifname) is None:
       
    96             continue
       
    97         try:
       
    98             # first remove the IP
       
    99             check_call(["/usr/bin/pfexec", "/usr/sbin/ipadm", "delete-ip",
       
   100                         ifname])
       
   101             # next remove the VNIC
       
   102             check_call(["/usr/bin/pfexec", "/usr/sbin/dladm", "delete-vnic",
       
   103                         ifname])
       
   104             # remove the OVS Port
       
   105             if is_ml2_plugin():
       
   106                 check_call(["/usr/bin/pfexec", "/usr/sbin/ovs-vsctl", "--",
       
   107                             "--if-exists", "del-port", get_ovs_bridge(),
       
   108                             ifname])
       
   109         except CalledProcessError as err:
       
   110             print "failed to remove datalink '%s' used by DHCP agent: %s" % \
       
   111                 (ifname, err)
       
   112             err_delete = True
       
   113 
   135 
   114     # finally reset the hostmodel property
   136     # finally reset the hostmodel property
   115     if not set_hostmodel("weak") or err_delete:
   137     if not set_hostmodel("weak") or ret_code != smf_include.SMF_EXIT_OK:
   116         return smf_include.SMF_EXIT_ERR_FATAL
   138         return smf_include.SMF_EXIT_ERR_FATAL
   117     return smf_include.SMF_EXIT_OK
   139     return smf_include.SMF_EXIT_OK
   118 
   140 
   119 if __name__ == "__main__":
   141 if __name__ == "__main__":
   120     os.putenv("LC_ALL", "C")
   142     os.putenv("LC_ALL", "C")