syncdomain: don't do dummy SQL UPDATE's
[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
11function usage()
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";
46f2c279
DO
20 exit (1);
21}
22
ac936aaa
DO
23function print_message_line($text)
24{
25 echo gmdate (DATE_RFC1123) . ": ${text}\n";
26}
27
0eb16817 28$options = getopt ('', array ('vdid:', 'max::', 'mode:', 'verbose'));
f1cdc9f1 29if (!array_key_exists ('mode', $options))
46f2c279
DO
30 usage();
31
32switch ($options['mode'])
33{
34case 'pullall':
35 $do_push = FALSE;
36 break;
37case 'pull':
38 $do_push = FALSE;
39 break;
40case 'push':
41 $do_push = TRUE;
42 break;
43default:
44 usage();
45}
46
47$max = array_key_exists ('max', $options) ? $options['max'] : 0;
0eb16817 48$verbose = array_key_exists ('verbose', $options);
46f2c279 49
f1cdc9f1
AA
50$switch_list = array();
51if (! isset ($options['vdid']))
52 $switch_list = getVLANSwitches();
53else
54 try
55 {
56 $mydomain = getVLANDomain ($options['vdid']);
57 foreach ($mydomain['switchlist'] as $switch)
58 $switch_list[] = $switch['object_id'];
59 }
60 catch (RackTablesError $e)
61 {
ac936aaa
DO
62 print_message_line ("Cannot load domain data with ID ${options['vdid']}");
63 print_message_line ($e->getMessage());
f1cdc9f1
AA
64 exit (1);
65 }
46f2c279
DO
66
67$todo = array
68(
611b5e46 69 'pull' => array ('sync_ready', 'resync_ready'),
089e6bfe 70 'push' => array ('sync_ready', 'resync_ready'),
611b5e46 71 'pullall' => array ('sync_ready', 'resync_ready', 'sync_aging', 'resync_aging', 'done'),
46f2c279
DO
72);
73
f1cdc9f1
AA
74$domain_key = isset ($options['vdid']) ? $options['vdid'] : 0;
75$filename = '/var/tmp/RackTables-syncdomain-' . $domain_key . '.pid';
fc81b88e
DO
76if (FALSE === $fp = @fopen ($filename, 'x+'))
77{
a50d3f2b
DO
78 if (FALSE === $pidfile_mtime = filemtime ($filename))
79 {
ac936aaa 80 print_message_line ("Failed to obtain mtime of ${filename}");
a50d3f2b
DO
81 exit (1);
82 }
83 $current_time = time();
84 if ($current_time < $pidfile_mtime)
85 {
ac936aaa 86 print_message_line ("Warning: pidfile ${filename} mtime is in future!");
a50d3f2b
DO
87 exit (1);
88 }
89 // don't indicate failure unless the pidfile is 15 minutes or more old
1c638ec1 90 if ($current_time < $pidfile_mtime + 15 * 60)
a50d3f2b 91 exit (0);
ac936aaa 92 print_message_line ("Failed to lock ${filename}, already locked by PID " . mb_substr (file_get_contents ($filename), 0, 6));
fc81b88e
DO
93 exit (1);
94}
95
96ftruncate ($fp, 0);
97fwrite ($fp, getmypid() . "\n");
98fclose ($fp);
99
61e79d63
AA
100// fetch all the needed data from DB (preparing for DB connection loss)
101$switch_queue = array();
f1cdc9f1 102foreach ($switch_list as $object_id)
de9c0396
AA
103{
104 $queue = detectVLANSwitchQueue (getVLANSwitchInfo ($object_id));
105 if ($queue == 'disabled' || in_array ($queue, $todo[$options['mode']]))
f1cdc9f1
AA
106 {
107 $cell = spotEntity ('object', $object_id);
108 if (considerConfiguredConstraint ($cell, 'SYNC_802Q_LISTSRC'))
109 $switch_queue[] = $cell;
30456b1b 110 elseif ($vswitch['last_errno'] != E_8021Q_SYNC_DISABLED)
de9c0396
AA
111 usePreparedExecuteBlade
112 (
113 'UPDATE VLANSwitch SET out_of_sync="yes", last_error_ts=NOW(), last_errno=? WHERE object_id=?',
30456b1b 114 array (E_8021Q_SYNC_DISABLED, $object_id)
de9c0396 115 );
f1cdc9f1 116 }
de9c0396 117}
61e79d63
AA
118
119// YOU SHOULD NOT USE DB FUNCTIONS BELOW IN THE PARENT PROCESS
120// THE PARENT'S DB CONNECTION IS LOST DUE TO RECONNECTING IN THE CHILD
121$fork_slots = getConfigVar ('SYNCDOMAIN_MAX_PROCESSES');
122$do_fork = ($fork_slots > 1) and extension_loaded ('pcntl');
123if ($fork_slots > 1 and ! $do_fork)
124 throw new RackTablesError ('PHP extension \'pcntl\' not found, can not use childs', RackTablesError::MISCONFIGURED);
125$switches_working = 0;
126$switchesdone = 0;
127foreach ($switch_queue as $object)
128{
129 if ($do_fork)
130 {
131 // wait for the next free slot
132 while ($fork_slots <= $switches_working)
133 {
134 pcntl_waitpid (-1, $wait_status);
135 --$switches_working;
136 }
137 $i_am_child = (0 === $fork_res = pcntl_fork());
138 }
139 if (! $do_fork or $i_am_child)
46f2c279 140 {
647635ad
DO
141 try
142 {
61e79d63
AA
143 // make a separate DB connection for correct concurrent transactions handling
144 if ($i_am_child)
145 connectDB();
146 $portsdone = exec8021QDeploy ($object['id'], $do_push);
647635ad 147 if ($portsdone or $verbose)
ac936aaa 148 print_message_line ("Done '${object['dname']}': ${portsdone}");
647635ad
DO
149 }
150 catch (RackTablesError $e)
151 {
ac936aaa 152 print_message_line ("FAILED '${object['dname']}': " . $e->getMessage());
647635ad 153 }
61e79d63
AA
154 if ($i_am_child)
155 exit (0);
156 }
157 if (isset ($fork_res) and $fork_res > 0)
158 ++$switches_working;
159
160 if (++$switchesdone == $max)
161 {
162 if ($verbose)
ac936aaa 163 print_message_line ("Maximum of ${max} items reached, terminating");
61e79d63 164 break;
46f2c279 165 }
61e79d63
AA
166}
167
168// wait for all childs to exit
169while ($switches_working > 0)
170{
171 --$switches_working;
172 pcntl_waitpid (-1, $wait_status);
173}
46f2c279 174
fc81b88e
DO
175if (FALSE === unlink ($filename))
176{
ac936aaa 177 print_message_line ("Failed removing pidfile ${filename}");
fc81b88e
DO
178 exit (1);
179}
46f2c279
DO
180exit (0);
181?>