Merge branch 'maintenance-0.20.x' into yandex-prod
[racktables] / scripts / syncdomain.php
CommitLineData
94929d74 1#!/usr/bin/env php
46f2c279
DO
2<?php
3
cddbb9fd
DO
4# This file is a part of RackTables, a datacenter and server room management
5# framework. See accompanying file "COPYING" for the full copyright and
6# licensing information.
7
46f2c279
DO
8$script_mode = TRUE;
9require 'inc/init.php';
10
1b2aae6c 11function usage ($rc)
46f2c279
DO
12{
13 echo "Usage: <this file> <options>\n";
14 echo "\t\t--vdid=<VLAN domain ID>\n";
15 echo "\t\t--mode=pull\n";
16 echo "\t\t--mode=pullall\n";
17 echo "\t\t--mode=push\n";
18 echo "\t\t[--max=<max_to_do>]\n";
0eb16817 19 echo "\t\t[--verbose]\n";
9f694dda
DO
20 echo "\t\t[--nolock]\n";
21 echo "\t\t[--stderr]\n";
1b2aae6c
DO
22 echo "\t\t--help\n";
23 exit ($rc);
46f2c279
DO
24}
25
9f694dda
DO
26define ('PML_VERBOSE', 1 << 0); // display message only if --verbose option specified
27define ('PML_NOTICE', 1 << 1); // the message is informational, do not write to STDERR
28function print_message_line($text, $flags = 0)
ac936aaa 29{
9f694dda
DO
30 global $options;
31 if (! array_key_exists ('verbose', $options) and $flags & PML_VERBOSE)
32 return;
33 $buff = date (DATE_RFC1123) . ": ${text}\n";
34 echo $buff;
35 if (array_key_exists ('stderr', $options) and ! ($flags & PML_NOTICE))
36 fwrite (STDERR, $buff);
ac936aaa
DO
37}
38
1b2aae6c
DO
39$options = getopt ('', array ('vdid:', 'max::', 'mode:', 'verbose', 'nolock', 'stderr', 'help'));
40if (array_key_exists ('help', $options))
41 usage (0);
f1cdc9f1 42if (!array_key_exists ('mode', $options))
1b2aae6c 43 usage (1);
46f2c279
DO
44
45switch ($options['mode'])
46{
47case 'pullall':
48 $do_push = FALSE;
49 break;
50case 'pull':
51 $do_push = FALSE;
52 break;
53case 'push':
54 $do_push = TRUE;
55 break;
56default:
1b2aae6c 57 usage (1);
46f2c279
DO
58}
59
a4c3d979 60$max = array_fetch ($options, 'max', 0);
9f694dda 61$nolock = array_key_exists ('nolock', $options);
46f2c279 62
46f2c279
DO
63$todo = array
64(
611b5e46 65 'pull' => array ('sync_ready', 'resync_ready'),
089e6bfe 66 'push' => array ('sync_ready', 'resync_ready'),
611b5e46 67 'pullall' => array ('sync_ready', 'resync_ready', 'sync_aging', 'resync_aging', 'done'),
46f2c279
DO
68);
69
9f694dda 70if (! $nolock)
fc81b88e 71{
9f694dda
DO
72 $domain_key = isset ($options['vdid']) ? $options['vdid'] : 0;
73 $filename = '/var/tmp/RackTables-syncdomain-' . $domain_key . '.pid';
74 if (FALSE === $fp = @fopen ($filename, 'c+'))
a50d3f2b 75 {
9f694dda 76 print_message_line ("Failed to open ${filename}");
a50d3f2b
DO
77 exit (1);
78 }
9f694dda
DO
79 $wouldblock = 0;
80 if (! flock ($fp, LOCK_EX|LOCK_NB, $wouldblock) || $wouldblock)
a50d3f2b 81 {
9f694dda
DO
82 $current_time = time();
83 $stat = fstat ($fp);
84 if (! isset ($stat['mtime']))
85 {
86 print_message_line ("Failed to obtain mtime of ${filename}");
87 exit (1);
88 }
89 $pidfile_mtime = $stat['mtime'];
90 if ($current_time < $pidfile_mtime)
91 {
92 print_message_line ("Warning: pidfile ${filename} mtime is in future!");
93 exit (1);
94 }
95 // don't indicate failure unless the pidfile is 15 minutes or more old
96 if ($current_time < $pidfile_mtime + 15 * 60)
97 exit (0);
98 print_message_line ("Failed to lock ${filename}, already locked by PID " . trim (fgets ($fp, 10)));
a50d3f2b
DO
99 exit (1);
100 }
fc81b88e 101
9f694dda
DO
102 ftruncate ($fp, 0);
103 fwrite ($fp, getmypid() . "\n");
104 // don't close $fp yet: we need to keep an flock
105}
fc81b88e 106
61e79d63 107// fetch all the needed data from DB (preparing for DB connection loss)
993dd5c5
AA
108$vswitch_filter = array();
109if (isset ($options['vdid']))
110 $vswitch_filter['domain_id'] = $options['vdid'];
111$switch_list = getVLANSwitchInfoRows ($vswitch_filter);
112$enabled_switches = listConstraint ('object', 'SYNC_802Q_LISTSRC');
113
61e79d63 114$switch_queue = array();
993dd5c5 115foreach ($switch_list as $vswitch)
de9c0396 116{
993dd5c5
AA
117 $object_id = $vswitch['object_id'];
118 $new_disabled = ! isset ($enabled_switches[$object_id]);
b1ca8279
AA
119 $queue = detectVLANSwitchQueue ($vswitch);
120 if ($queue != 'disabled' && $new_disabled)
121 {
122 setVLANSwitchError ($object_id, E_8021Q_SYNC_DISABLED);
123 continue;
124 }
125 elseif ($queue == 'disabled' && ! $new_disabled)
126 {
127 $vswitch['last_errno'] = E_8021Q_NOERROR;
128 setVLANSwitchError ($object_id, $vswitch['last_errno']);
129 $queue = detectVLANSwitchQueue ($vswitch);
130 }
131
132 if (in_array ($queue, $todo[$options['mode']]))
993dd5c5 133 $switch_queue[] = spotEntity ('object', $object_id);
de9c0396 134}
61e79d63
AA
135
136// YOU SHOULD NOT USE DB FUNCTIONS BELOW IN THE PARENT PROCESS
137// THE PARENT'S DB CONNECTION IS LOST DUE TO RECONNECTING IN THE CHILD
138$fork_slots = getConfigVar ('SYNCDOMAIN_MAX_PROCESSES');
139$do_fork = ($fork_slots > 1) and extension_loaded ('pcntl');
140if ($fork_slots > 1 and ! $do_fork)
141 throw new RackTablesError ('PHP extension \'pcntl\' not found, can not use childs', RackTablesError::MISCONFIGURED);
142$switches_working = 0;
143$switchesdone = 0;
144foreach ($switch_queue as $object)
145{
146 if ($do_fork)
147 {
148 // wait for the next free slot
149 while ($fork_slots <= $switches_working)
150 {
151 pcntl_waitpid (-1, $wait_status);
152 --$switches_working;
153 }
154 $i_am_child = (0 === $fork_res = pcntl_fork());
155 }
55eefced 156 if (! $do_fork || $i_am_child)
46f2c279 157 {
647635ad
DO
158 try
159 {
61e79d63
AA
160 // make a separate DB connection for correct concurrent transactions handling
161 if ($i_am_child)
162 connectDB();
163 $portsdone = exec8021QDeploy ($object['id'], $do_push);
9f694dda
DO
164 $flags = PML_NOTICE;
165 if (! $portsdone)
166 $flags |= PML_VERBOSE;
167 print_message_line ("Done '${object['dname']}': ${portsdone}", $flags);
647635ad
DO
168 }
169 catch (RackTablesError $e)
170 {
ac936aaa 171 print_message_line ("FAILED '${object['dname']}': " . $e->getMessage());
647635ad 172 }
61e79d63
AA
173 if ($i_am_child)
174 exit (0);
175 }
176 if (isset ($fork_res) and $fork_res > 0)
177 ++$switches_working;
178
179 if (++$switchesdone == $max)
180 {
9f694dda 181 print_message_line ("Maximum of ${max} items reached, terminating", PML_NOTICE|PML_VERBOSE);
61e79d63 182 break;
46f2c279 183 }
61e79d63
AA
184}
185
186// wait for all childs to exit
187while ($switches_working > 0)
188{
189 --$switches_working;
190 pcntl_waitpid (-1, $wait_status);
191}
46f2c279 192
9f694dda 193if (! $nolock)
fc81b88e 194{
9f694dda
DO
195 flock ($fp, LOCK_UN); // explicitly unlock file as PHP 5.3.2 made it mandatory
196 if (FALSE === unlink ($filename))
197 {
198 print_message_line ("Failed removing pidfile ${filename}");
199 exit (1);
200 }
fc81b88e 201}
46f2c279
DO
202exit (0);
203?>