159 lines
4.9 KiB
C
159 lines
4.9 KiB
C
#include "include/conf.h"
|
|
|
|
#include "include/proto.h"
|
|
#include "include/deploys.h"
|
|
|
|
#include <unistd.h>
|
|
#include <fcntl.h>
|
|
#include <sys/types.h>
|
|
#include <sys/wait.h>
|
|
#include <sys/stat.h>
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
#define DP_DEPLOY_PATH_MAX_LEN 1024
|
|
#define DP_DEPLOY_PIPE_READ 0
|
|
#define DP_DEPLOY_PIPE_WRITE 1
|
|
|
|
bool dp_trigger_online_deploy(SSL *ssl,
|
|
const char *domain,
|
|
size_t domain_len,
|
|
dp_Logger *logger,
|
|
dp_DeployCommand command,
|
|
bool is_unsafe) {
|
|
if (!ssl || !domain || strlen(domain) == 0 || !logger) {
|
|
return false;
|
|
}
|
|
|
|
char script_path[DP_DEPLOY_PATH_MAX_LEN] = {0};
|
|
|
|
/* Construct script path: DP_SCRIPTS_DIR + "/" + domain + ".deployer" */
|
|
const size_t dir_len = strlen(DP_SCRIPTS_DIR);
|
|
const size_t ext_len = strlen(".deployer");
|
|
|
|
if (dir_len + 1 + domain_len + ext_len >= DP_DEPLOY_PATH_MAX_LEN) {
|
|
dp_log(logger, DP_LOG_ERROR, DP_DEPLOYS_LOG "/online",
|
|
"Script path too long");
|
|
return false;
|
|
}
|
|
|
|
memcpy(script_path, DP_SCRIPTS_DIR, dir_len);
|
|
script_path[dir_len] = '/';
|
|
memcpy(script_path + dir_len + 1, domain, domain_len);
|
|
memcpy(script_path + dir_len + 1 + domain_len, ".deployer", ext_len);
|
|
|
|
/* Check if script is executable */
|
|
if (access(script_path, X_OK) != 0) {
|
|
perror("[deploy] Script is not executable or missing");
|
|
return false;
|
|
}
|
|
|
|
dp_logf(logger, DP_LOG_INFO, DP_DEPLOYS_LOG "/online",
|
|
"Starting online deploy %.*s", (int)domain_len, domain);
|
|
|
|
/* Set up pipe for capturing child output */
|
|
int pipe_fds[2];
|
|
if (pipe(pipe_fds) != 0) {
|
|
perror("[deploy] Failed to create pipe");
|
|
return false;
|
|
}
|
|
|
|
pid_t child_pid = fork();
|
|
if (child_pid < 0) {
|
|
perror("[deploy] Fork failed");
|
|
close(pipe_fds[DP_DEPLOY_PIPE_READ]);
|
|
close(pipe_fds[DP_DEPLOY_PIPE_WRITE]);
|
|
return false;
|
|
}
|
|
|
|
if (child_pid == 0) {
|
|
/* --- CHILD PROCESS --- */
|
|
close(pipe_fds[DP_DEPLOY_PIPE_READ]);
|
|
|
|
/* Redirect stdout and stderr to write end of pipe */
|
|
dup2(pipe_fds[DP_DEPLOY_PIPE_WRITE], STDOUT_FILENO);
|
|
dup2(pipe_fds[DP_DEPLOY_PIPE_WRITE], STDERR_FILENO);
|
|
|
|
/* Detach from stdin */
|
|
int dev_null = open("/dev/null", O_RDONLY);
|
|
if (dev_null >= 0) {
|
|
dup2(dev_null, STDIN_FILENO);
|
|
close(dev_null);
|
|
}
|
|
|
|
char *argv[5] = {script_path, NULL, NULL, NULL};
|
|
char **arg = NULL;
|
|
|
|
if (is_unsafe) {
|
|
argv[1] = "--unsafe";
|
|
arg = &argv[2];
|
|
} else {
|
|
arg = &argv[1];
|
|
}
|
|
|
|
switch (command) {
|
|
case dp_DeployCommand_trigger: break;
|
|
case dp_DeployCommand_teardown: *arg = "teardown"; break;
|
|
case dp_DeployCommand_deploy: *arg = "deploy"; break;
|
|
case dp_DeployCommand_rollback: *arg = "rollback"; break;
|
|
case dp_DeployCommand_cleanup: *arg = "cleanup"; break;
|
|
case dp_DeployCommand_restart: *arg = "restart"; break;
|
|
case dp_DeployCommand_sysadmin: *arg = "sysadmin"; break;
|
|
case dp_DeployCommand_logs: *arg = "logs"; break;
|
|
}
|
|
|
|
/* Execute the deployment script */
|
|
execv(script_path, argv);
|
|
|
|
/* If execl fails */
|
|
dp_err(logger, DP_LOG_FATAL, DP_DEPLOYS_LOG "/online",
|
|
"execv() failed");
|
|
_exit(127);
|
|
}
|
|
|
|
/* --- PARENT PROCESS --- */
|
|
close(pipe_fds[DP_DEPLOY_PIPE_WRITE]);
|
|
|
|
char buffer[1024] = {0};
|
|
ssize_t read_len = 0;
|
|
|
|
while ((read_len = read(pipe_fds[DP_DEPLOY_PIPE_READ], buffer,
|
|
sizeof(buffer))) > 0) {
|
|
if (!dp_proto_log_chunker(ssl, buffer, (size_t)read_len, logger)) {
|
|
return false;
|
|
}
|
|
|
|
if (!dp_proto_ping(ssl)) {
|
|
return false;
|
|
}
|
|
uint8_t ping_reply = 0x00;
|
|
if (SSL_read(ssl, &ping_reply, 1) != 1) {
|
|
dp_proto_error(ssl, dp_PacketError_internal,
|
|
"Unable to read PING_REPLY", logger);
|
|
return false;
|
|
}
|
|
if ((dp_PacketType)ping_reply != dp_PacketType_ping_reply) {
|
|
dp_proto_error(ssl, dp_PacketError_proto_packet_invalid,
|
|
"Invalid response to PING", logger);
|
|
return false;
|
|
}
|
|
|
|
sleep(1);
|
|
}
|
|
|
|
close(pipe_fds[DP_DEPLOY_PIPE_READ]);
|
|
|
|
/* Wait for child process to finish */
|
|
int exit_status = 0;
|
|
waitpid(child_pid, &exit_status, 0);
|
|
|
|
if (!dp_proto_log_end(ssl, logger)) {
|
|
return false;
|
|
}
|
|
|
|
dp_logf(logger, DP_LOG_INFO, DP_DEPLOYS_LOG "/online",
|
|
"Finished online deploy %.*s", (int)domain_len, domain);
|
|
|
|
return WIFEXITED(exit_status) && WEXITSTATUS(exit_status) == 0;
|
|
}
|