3
A brief file description
5
@section license License
7
Licensed to the Apache Software Foundation (ASF) under one
8
or more contributor license agreements. See the NOTICE file
9
distributed with this work for additional information
10
regarding copyright ownership. The ASF licenses this file
11
to you under the Apache License, Version 2.0 (the
12
"License"); you may not use this file except in compliance
13
with the License. You may obtain a copy of the License at
15
http://www.apache.org/licenses/LICENSE-2.0
17
Unless required by applicable law or agreed to in writing, software
18
distributed under the License is distributed on an "AS IS" BASIS,
19
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20
See the License for the specific language governing permissions and
21
limitations under the License.
24
/****************************************************************************
31
****************************************************************************/
36
// Fix wierd conflict with Tcl #define for panic
41
#include "sio_buffer.h"
43
#include "test_utils.h"
44
#include "test_exec.h"
46
#include "Tokenizer.h"
50
static const int SIZE_32K = 32768;
53
create_pipe_for_remote(const char *hostname, int *pipe_arg, int in_pipe)
59
} while (r < 0 && errno == EINTR);
62
TE_Error("Pipe creation for %s failed : %s", hostname, strerror(errno));
67
r = fcntl((in_pipe == true) ? pipe_arg[0] : pipe_arg[1], F_SETFL, O_NONBLOCK);
68
} while (r < 0 && errno == EINTR);
71
TE_Error("Failed to set non-block on %s pipe", hostname, strerror(errno));
81
start_remote_shell(const UserDirInfo * ud_info, const char *hostname, int *in_pipe, int *out_pipe)
84
int r = create_pipe_for_remote(hostname, in_pipe, true);
89
r = create_pipe_for_remote(hostname, out_pipe, false);
97
if (strcmp(hostname, "localhost") == 0) {
98
// The command we want is
99
// <shell> -c "bash -s"
100
sub_cmd = strdup("bash -s");
102
// The command we want is
103
// <shell> -c "ssh <hostname> -q -o "BatchMode yes" -o "StrictHostKeyChecking no" bash -s"
104
const char *sub_cmd_format = "ssh -q -o \"BatchMode yes\" -o \"StrictHostKeyChecking no\" %s bash -s";
105
sub_cmd = (char *) malloc(strlen(sub_cmd_format) + strlen(hostname) + 1);
106
sprintf(sub_cmd, sub_cmd_format, hostname);
109
char **argv = build_argv_v(ud_info->shell, "-c", sub_cmd, NULL);
113
pid_t new_pid = fork();
116
TE_Error("fork to contact %s failed : %s", hostname, strerror(errno));
123
} else if (new_pid == 0) {
125
r = dup2(in_pipe[0], 0);
127
Fatal("dup to stdin failed : %s", strerror(errno));
130
r = dup2(out_pipe[1], 1);
132
Fatal("dup to stdout failed : %s", strerror(errno));
135
r = dup2(out_pipe[1], 2);
137
Fatal("dup to stderr failed : %s", strerror(errno));
139
// FIX - use fd limit
140
for (int i = 3; i < 1024; i++) {
144
r = execv(ud_info->shell, argv);
147
Fatal("exec failed : %s", strerror(errno));
163
send_remote_cmd(sio_buffer * in_buf, int fd_in, sio_buffer * out_buf, int fd_out)
166
int timeout_ms = 60 * 1000;
167
const char *rmsg = write_buffer(fd_in, in_buf, &timeout_ms);
173
rmsg = read_until(fd_out, out_buf, '\n', &timeout_ms);
183
determine_arch(int fd_in, int fd_out, char **arch_out)
190
const char cmd[] = "uname -s\n";
191
in_buf.fill(cmd, sizeof(cmd) - 1);
193
const char *rmsg = send_remote_cmd(&in_buf, fd_in, &out_buf, fd_out);
198
char *start = out_buf.start();
199
char *end = out_buf.memchr('\n');
202
// Since determine arch is the first command executed after the
203
// ssh, it's entirely possible that output has garbage in from
204
// error messages in the .login or .profile/.cshrc. There error
205
// messages tend be of the form "<thing>: <msg>" Thus we
206
// will ignore any line message that has a colon in it
207
while (memchr(start, ':', end - start) != NULL) {
208
out_buf.consume((end - start) + 1);
210
// First check if we've got another complete line
211
end = out_buf.memchr('\n');
213
// We need to read more
214
int timeout_ms = 60 * 1000;
215
rmsg = read_until(fd_out, &out_buf, '\n', &timeout_ms);
219
end = out_buf.memchr('\n');
221
// At this point we've got another line and end is pointing
222
// to the '\n' terminating the line. So we just need
223
// to tidy up an loop around again
224
start = out_buf.start();
229
Debug("remote", "OS is %s", out_buf.start());
231
if (strcmp(out_buf.start(), "SunOS") == 0) {
232
// We need to get the processor type to distinguish between
233
// sparc & x86 solaris
237
const char pcmd[] = "uname -p\n";
238
in_buf.fill(pcmd, sizeof(pcmd) - 1);
240
if ((rmsg = send_remote_cmd(&in_buf, fd_in, &out_buf, fd_out)) != NULL) {
244
end = out_buf.memchr('\n');
247
Debug("remote", "Proc Type is %s", out_buf.start());
249
if (strcmp(out_buf.start(), "i386") == 0) {
250
*arch_out = strdup("SunOSx86");
252
*arch_out = strdup("SunOS");
255
*arch_out = strdup(out_buf.start());
261
// char* find_proc_manager_binary(const char* remote_arch)
263
// Caller frees return value
266
find_proc_manager_binary(const UserDirInfo * ud, const char *remote_arch)
269
char *my_arch = get_arch_str();
270
FreeOnDestruct freer(my_arch);
272
if (strcasecmp(remote_arch, my_arch) == 0) {
275
r = access("proc_manager", R_OK | X_OK);
276
} while (r < 0 && errno == EINTR);
279
Debug("remote", "Using local proc_manager");
280
return strdup("proc_manager");
284
char *pack_name = find_local_package("proc_manager", remote_arch);
286
if (pack_name == NULL) {
290
int len = strlen(ud->package_dir) + 1 + strlen(pack_name) + 1;
291
char *local_pm_path = (char *) malloc(len);
292
sprintf(local_pm_path, "%s/%s", ud->package_dir, pack_name);
295
return local_pm_path;
300
setup_remote_directories(int fd_in, int fd_out, UserDirInfo * ud)
306
const char check_path_format[] = "if [ -d %s ]; then\n" " echo ok\n" "else\n" " echo not found\n" "fi\n";
308
const char mkdir_format[] = "if mkdir %s\n" "then\n" " echo ok\n" "fi\n";
310
int len = sizeof(check_path_format) + strlen(ud->test_stuff_path) + 1;
311
char *cmd = (char *) malloc(len);
312
sprintf(cmd, check_path_format, ud->test_stuff_path);
314
in_buf.fill(cmd, strlen(cmd));
318
const char *rmsg = send_remote_cmd(&in_buf, fd_in, &out_buf, fd_out);
324
char *end = out_buf.memchr('\n');
326
Debug("remote", "Response to check stuff path: %s", out_buf.start());
328
if (strcmp(out_buf.start(), "ok") != 0) {
329
return "remote stuff_path dir does not exist";
335
len = sizeof(check_path_format) + strlen(ud->test_stuff_path_and_dir) + 1;
336
cmd = (char *) malloc(len);
337
sprintf(cmd, check_path_format, ud->test_stuff_path_and_dir);
339
in_buf.fill(cmd, strlen(cmd));
343
rmsg = send_remote_cmd(&in_buf, fd_in, &out_buf, fd_out);
349
end = out_buf.memchr('\n');
351
Debug("remote", "Response to check stuff dir: %s", out_buf.start());
353
if (strcmp(out_buf.start(), "ok") != 0) {
354
// Need to create the directory
358
int len = sizeof(mkdir_format) + strlen(ud->test_stuff_path_and_dir) + 1;
359
char *cmd = (char *) malloc(len);
360
sprintf(cmd, mkdir_format, ud->test_stuff_path_and_dir);
362
in_buf.fill(cmd, strlen(cmd));
366
rmsg = send_remote_cmd(&in_buf, fd_in, &out_buf, fd_out);
368
end = out_buf.memchr('\n');
370
Debug("remote", "Response to mkdir stuff dir: %s", out_buf.start());
372
if (strcmp(out_buf.start(), "ok") != 0) {
373
TE_Note("failed to create remote directory : %s", out_buf.start());
374
return "remote directory creation failed";
383
transfer_proc_manager_binary(int local_file_fd, int fd_in, int *timeout_ms)
386
sio_buffer file_buf(SIZE_32K);
388
bool read_done = false;
389
const char *rmsg = NULL;
391
while (read_done == false) {
394
rmsg = read_to_buffer(local_file_fd, &file_buf, SIZE_32K, &eof, timeout_ms);
404
rmsg = write_buffer(fd_in, &file_buf, timeout_ms);
414
check_remote_proc_manager(int fd_in, int fd_out,
415
UserDirInfo * ud, const char *remote_proc_mgr_name, const char *remote_arch, int *ok)
422
const char ls_check_format[] =
423
"if [ -x %s ]; then\n" " a=`ls -l %s`\n" " echo ${a:-error}\n" "else\n" " echo error\n" "fi\n";
425
int len = sizeof(ls_check_format) + (2 * strlen(remote_proc_mgr_name)) + 1;
426
char *cmd = (char *) malloc(len);
427
sprintf(cmd, ls_check_format, remote_proc_mgr_name, remote_proc_mgr_name);
429
in_buf.fill(cmd, strlen(cmd));
433
const char *rmsg = send_remote_cmd(&in_buf, fd_in, &out_buf, fd_out);
439
char *end = out_buf.memchr('\n');
441
Debug("remote", "Response to ls check cmd: %s", out_buf.start());
443
if (strcmp(out_buf.start(), "error") == 0) {
444
TE_Warning("error checking proc_manager; replacing : %s", out_buf.start());
448
Tokenizer ws_tok(" \t\r\n");
449
int num_tok = ws_tok.Initialize(out_buf.start());
452
TE_Warning("bad ls output on proc_manager check; replacing : %s", out_buf.start());
456
int remote_size = atoi(ws_tok[4]);
458
if (remote_size == 0) {
462
char *local_pm = find_proc_manager_binary(ud, remote_arch);
464
if (local_pm == NULL) {
465
// Since we don't a replacement, the exisiting one
467
TE_Warning("no process manager for arch %s found", remote_arch);
473
struct stat stat_info;
475
r = stat(local_pm, &stat_info);
476
} while (r < 0 && errno == EINTR);
479
// Can not get info on local one, leave exisitng
480
TE_Warning("stat on for proc_manager % : %s", local_pm, strerror(errno));
483
// Check to see if sizes match
485
// FIX: should also check to see if local package
486
// is newer than remote
487
if (stat_info.st_size == remote_size) {
499
// const char* start_remote_proc_manager
503
start_remote_proc_manager(int &fd_in, int &fd_out,
504
UserDirInfo * ud, const char *remote_proc_mgr_name, int remote_proc_mgr_killtm)
509
const char start_format[] = "./%s -r -q -d . -p %d%s%s -k %d\n";
511
int len = sizeof(start_format) + strlen(remote_proc_mgr_name) + 1;
512
if (ud->log_collator_arg) {
513
len += 3 + strlen(ud->log_collator_arg);
516
char *cmd = (char *) malloc(len);
517
sprintf(cmd, start_format, remote_proc_mgr_name, ud->port,
518
(ud->log_collator_arg == NULL) ? "" : " -L ",
519
(ud->log_collator_arg == NULL) ? "" : ud->log_collator_arg, remote_proc_mgr_killtm);
521
in_buf.fill(cmd, strlen(cmd));
525
const char *rmsg = send_remote_cmd(&in_buf, fd_in, &out_buf, fd_out);
531
char *end = out_buf.memchr('\n');
533
Debug("remote", "Response to start cmd: %s", out_buf.start());
535
if (strcmp(out_buf.start(), "liftoff") != 0) {
536
TE_Note("failed to start proc_manager : %s", out_buf.start());
537
return "remote start failed";
547
// const char* put_and_start_proc_manager()
551
put_and_start_proc_manager(int &fd_in, int &fd_out,
553
const char *remote_proc_mgr_name, const char *remote_arch, int remote_proc_mgr_killtm)
559
char *local_pm = find_proc_manager_binary(ud, remote_arch);
561
if (local_pm == NULL) {
562
TE_Error("no process manager for arch %s found", remote_arch);
563
return "no process manager for arch";
566
int local_file_fd = -1;
568
local_file_fd = open(local_pm, O_RDONLY);
569
} while (local_file_fd < 0 && errno == EINTR);
571
if (local_file_fd < 0) {
572
TE_Error("unable to open %s : %s", local_pm, strerror(errno));
574
return "open of proc_manager for transfer failed";
580
const char put_and_start_format[] = "cat - > %s; chmod 0755 %s; ./%s -r -q -d . -p %d%s%s -k %d\n";
582
int len = sizeof(put_and_start_format) + (3 * strlen(remote_proc_mgr_name)) + 32 + 1;
583
if (ud->log_collator_arg) {
584
len += 3 + strlen(ud->log_collator_arg);
587
char *cmd = (char *) malloc(len);
588
sprintf(cmd, put_and_start_format, remote_proc_mgr_name,
589
remote_proc_mgr_name, remote_proc_mgr_name, ud->port,
590
(ud->log_collator_arg == NULL) ? "" : " -L ",
591
(ud->log_collator_arg == NULL) ? "" : ud->log_collator_arg, remote_proc_mgr_killtm);
593
in_buf.fill(cmd, strlen(cmd));
597
int timeout_ms = 60 * 1000;
598
const char *rmsg = write_buffer(fd_in, &in_buf, &timeout_ms);
605
rmsg = transfer_proc_manager_binary(local_file_fd, fd_in, &timeout_ms);
613
rmsg = read_until(fd_out, &out_buf, '\n', &timeout_ms);
619
end = out_buf.memchr('\n');
621
Debug("remote", "Response to put and start: %s", out_buf.start());
623
if (strcmp(out_buf.start(), "liftoff") != 0) {
624
TE_Note("failed to push and start proc_manager : %s", out_buf.start());
625
return "remote push_and_start failed";
629
if (local_file_fd >= 0) {
630
close(local_file_fd);
634
TE_Error("put_and_start proc_manager failed %s", rmsg);
640
handle_proc_manager(int &fd_in, int &fd_out, UserDirInfo * ud, const char *arch, int kw)
646
const char proc_mgr_base[] = "proc_manager";
647
int len = strlen(proc_mgr_base) + 1 + strlen(arch);
649
char *proc_manager_name = (char *) malloc(len + 1);
650
sprintf(proc_manager_name, "%s-%s", proc_mgr_base, arch);
651
FreeOnDestruct pm_name_freer(proc_manager_name);
653
const char chdir_format[] = "if cd %s\n" "then\n" " echo ok\n" "fi\n";
655
const char check_file_format[] = "if [ -e %s ]; then\n" " echo ok\n" "else\n" " echo not found\n" "fi\n";
657
len = sizeof(chdir_format) + strlen(ud->test_stuff_path_and_dir) + 1;
658
char *cmd = (char *) malloc(len);
660
sprintf(cmd, chdir_format, ud->test_stuff_path_and_dir);
662
in_buf.fill(cmd, strlen(cmd));
666
const char *rmsg = send_remote_cmd(&in_buf, fd_in, &out_buf, fd_out);
672
char *end = out_buf.memchr('\n');
674
Debug("remote", "Response to cd: %s", out_buf.start());
676
if (strcmp(out_buf.start(), "ok") != 0) {
677
TE_Note("failed to change to remote directory : %s", out_buf.start());
678
return "chdir to remote stuff_path failed";
684
len = sizeof(check_file_format) + strlen(proc_manager_name) + 1;
685
cmd = (char *) malloc(len);
687
sprintf(cmd, check_file_format, proc_manager_name);
689
in_buf.fill(cmd, strlen(cmd));
693
rmsg = send_remote_cmd(&in_buf, fd_in, &out_buf, fd_out);
699
end = out_buf.memchr('\n');
701
Debug("remote", "Response to check for %s : %s", proc_manager_name, out_buf.start());
703
if (strcmp(out_buf.start(), "ok") == 0) {
705
rmsg = check_remote_proc_manager(fd_in, fd_out, ud, proc_manager_name, arch, &ok);
712
Debug("remote", "proc_manager is up to date on remote");
713
rmsg = start_remote_proc_manager(fd_in, fd_out, ud, proc_manager_name, kw);
715
Debug("remote", "proc_manager is out of date on remote");
716
rmsg = put_and_start_proc_manager(fd_in, fd_out, ud, proc_manager_name, arch, kw);
720
Debug("remote", "no proc_manager on remote");
721
rmsg = put_and_start_proc_manager(fd_in, fd_out, ud, proc_manager_name, arch, kw);
728
check_remote_isalive(unsigned int ip, int port, int retries = 20)
733
sio_buffer read_buffer;
735
request(0) = strdup("0");
736
request(1) = strdup("isalive");
738
const char *rmsg = "Unknown Error";
739
for (int i = 0; i < retries; i++) {
740
int timeout_ms = 10 * 1000;
741
int fd = SIO::make_client(ip, port);
742
bool success = false;
745
rmsg = send_raf_cmd(fd, &request, &timeout_ms);
747
rmsg = read_raf_resp(fd, &read_buffer, &response, &timeout_ms);
749
if (response.length() >= 2 && *(response[1]) == '0') {
752
rmsg = "bad raf reply";
757
rmsg = "connect failed";
763
Debug("remote", "remote passed 'isalive' check");
764
ink_debug_assert(rmsg == NULL);
767
Debug("remote", "remote failed 'isalive' check : %s", rmsg);
778
remote_start(const char *hostname, unsigned int ip, UserDirInfo * ud, int kw)
783
pid_t child_pid = start_remote_shell(ud, hostname, in_pipe, out_pipe);
789
int in_fd = in_pipe[1];
790
int out_fd = out_pipe[0];
791
int return_value = -1;
794
const char *rmsg = determine_arch(in_fd, out_fd, &arch);
798
TE_Error("remote start on %s failed : %s", hostname, rmsg);
801
Debug("remote", "Remote architecture for %s is %s", hostname, arch);
804
rmsg = setup_remote_directories(in_fd, out_fd, ud);
807
TE_Error("remote directory setup on %s failed : %s", hostname, rmsg);
811
rmsg = handle_proc_manager(in_fd, out_fd, ud, arch, kw);
814
TE_Error("proc_manager startup on %s failed %s", hostname, rmsg);
818
rmsg = check_remote_isalive(ip, ud->port);
820
TE_Error("proc_manager on %s failed isalive check : %s", hostname, rmsg);
828
int timeout_ms = 10000;
829
sio_buffer close_buf;
830
close_buf.fill("exit\n", 5);
831
write_buffer(in_fd, &close_buf, &timeout_ms);
841
reap_and_kill_child(child_pid, &exit_status);