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") |