Пример #1
0
 /**
  * @param $name
  */
 public function dockerInspect($name)
 {
     $containerName = $this->getContainerName($name);
     $command = ['docker', 'inspect', $containerName];
     echo 'command | ';
     echo \Peanut\Console\Color::text(implode(' ', $command), 'white') . PHP_EOL . PHP_EOL;
     echo $this->process($command, ['print' => false]);
 }
Пример #2
0
 /**
  * @param $name
  * @param $cmd
  */
 public function dockerSsh($name, $cmd = '')
 {
     $containerName = $this->getContainerName($name);
     if (!$cmd) {
         $cmd = '/bin/bash';
     }
     $command = ['docker', 'exec', '-it', $containerName, $cmd];
     echo 'command | ';
     echo \Peanut\Console\Color::text(implode(' ', $command), 'white') . PHP_EOL . PHP_EOL;
     $this->process($command, ['print' => false, 'tty' => true]);
 }
Пример #3
0
 /**
  * @param $name
  * @param $force
  */
 public function dockerRm($name, $force = false)
 {
     $containerName = $this->getContainerName($name);
     $command = ['docker', 'rm'];
     if ($force) {
         $command[] = '-f';
     }
     $command[] = $containerName;
     echo 'command | ';
     echo \Peanut\Console\Color::text(implode(' ', $command), 'white') . PHP_EOL . PHP_EOL;
     $this->process($command, ['print' => true]);
 }
Пример #4
0
 /**
  * @param $name
  */
 public function dockerLog($name, $isFollow = false)
 {
     $containerName = $this->getContainerName($name);
     $command = ['docker', 'logs'];
     if ($isFollow) {
         $command[] = '-f';
     }
     $command[] = $containerName;
     echo 'command | ';
     echo \Peanut\Console\Color::text(implode(' ', $command), 'white') . PHP_EOL . PHP_EOL;
     //echo shell_exec(implode(' ', $command));
     $this->process($command, ['print' => true]);
 }
Пример #5
0
 /**
  * @param \Peanut\Console\Application $app
  * @param array                       $config
  */
 public function exec(\Peanut\Console\Application $app, array $config)
 {
     $this->process('sudo -v', ['print' => false]);
     $mode = $app->getOption('attach') ? 'attach' : 'detach';
     $ispull = $app->getOption('pull') ? true : false;
     if ('attach' == $mode) {
         if (false === function_exists('pcntl_fork')) {
             $mode = 'detach';
             echo \Peanut\Console\Color::text('attach mode is not support, start detach mode', 'red', '') . PHP_EOL;
         }
         $this->loop = \React\EventLoop\Factory::create();
         try {
             $this->run();
             $pcntl = new \MKraemer\ReactPCNTL\PCNTL($this->loop);
             $pcntl->on(SIGTERM, function () {
                 // kill
                 echo 'SIGTERM' . PHP_EOL;
                 exit;
             });
             $pcntl->on(SIGHUP, function () {
                 // logout
                 echo 'SIGHUP' . PHP_EOL;
                 exit;
             });
             $pcntl->on(SIGINT, function () {
                 // ctrl+c
                 echo 'Terminated by console' . PHP_EOL;
                 posix_kill(posix_getpid(), SIGUSR1);
                 echo $this->process('docker rm -f $(docker ps -q)');
                 exit;
             });
             echo 'Started as PID ' . getmypid() . PHP_EOL;
             $this->loop->run();
         } catch (\Exception $e) {
             throw new \Peanut\Console\Exception($e);
         }
     } else {
         $this->run($mode, $ispull);
         echo PHP_EOL;
         $this->dockerLs();
     }
 }
Пример #6
0
 /**
  * @param $task
  * @param $action
  */
 public function dockerTask($task, $action)
 {
     $containerName = $this->getContainerName($task['container']);
     $command = ['docker', 'exec'];
     if (true === isset($task['user'])) {
         $command[] = '--user='******'user'];
     }
     $command[] = '-it';
     $command[] = $containerName;
     $command[] = 'sh -c';
     $command[] = '"';
     if (true === isset($task['working_dir'])) {
         $command[] = 'cd ' . $task['working_dir'];
         $command[] = '&&';
     }
     $command[] = $task['cmd'];
     if ($action) {
         $command[] = $action;
     }
     $command[] = '"';
     echo 'command | ';
     echo \Peanut\Console\Color::text(implode(' ', $command), 'white') . PHP_EOL . PHP_EOL;
     $this->process($command, ['print' => true, 'tty' => true]);
 }
Пример #7
0
 /**
  * @param $config
  * TODO : Run before container creation
  */
 public function setCert()
 {
     $stageName = $this->getStageName();
     $serviceList = [];
     $stageService = isset($this->config['stages'][$stageName]['services']) ? $this->config['stages'][$stageName]['services'] : [];
     foreach ($this->config['services'] + $stageService as $key => $value) {
         $serviceList[] = $this->getContainerName($key);
     }
     $command = ['docker', 'inspect', '--format="name={{.Name}}&ip={{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}&service={{index .Config.Labels \\"com.docker.bootapp.service\\"}}&id={{.Id}}&env={{json .Config.Env}}"', '$(docker ps -q)'];
     $inspectList = $this->process($command, ['print' => false])->toArray();
     $machineName = $this->getMachineName();
     $projectName = $this->getProjectName();
     $id = $machineName . '_' . $projectName;
     $domainList = [];
     foreach ($inspectList as $str) {
         parse_str($str, $b);
         $envs = json_decode($b['env'], true);
         $name = ltrim($b['name'], '/');
         $env = [];
         if (true === in_array($name, $serviceList)) {
             foreach ($envs as $envstring) {
                 list($key, $value) = explode('=', $envstring, 2);
                 $env[$key] = $value;
             }
             if (isset($env['DOMAIN']) && isset($env['USE_SSL'])) {
                 $domainList[$b['ip']] = $env['DOMAIN'];
             }
         }
     }
     if ($domainList) {
         $SSL_DIR = getcwd() . '/var/certs';
         if (false === is_dir(getcwd() . '/var')) {
             mkdir(getcwd() . '/var');
         }
         if (false === is_dir(getcwd() . '/var/certs')) {
             mkdir(getcwd() . '/var/certs');
         }
         shell_exec('mkdir -p ' . $SSL_DIR);
         $dump = $this->process('sudo security dump-trust-settings -d', ['print' => false]);
         $certList = [];
         if (preg_match_all('#Cert (?P<key>[0-9]+): (?P<domain>[^\\n]+)#', $dump, $matches)) {
             $certList = $matches['domain'];
         } else {
         }
         foreach ($domainList as $ip => $domain) {
             $sslname = $SSL_DIR . '/' . $domain;
             $this->message(\Peanut\Console\Color::text('cert    | ', 'white') . 'domain ' . $domain);
             //$this->message(\Peanut\Console\Color::text('        | ', 'white').'key     ./var/certs/'.$domain.'.key');
             $certfile = './var/certs/' . $domain . '.cert';
             if (false === file_exists($certfile)) {
                 $command = ['openssl', 'genrsa', '-out', $sslname . '.key', '2048'];
                 $this->process($command, ['print' => false]);
                 $command = ['openssl', 'req', '-new', '-x509', '-key', $sslname . '.key', '-out', $sslname . '.cert', '-days', '3650', '-subj', '/CN=' . $domain];
                 $this->process($command, ['print' => false]);
             } else {
             }
             if (true === file_exists($certfile) && false === in_array($domain, $certList)) {
                 $this->process('sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain ' . $certfile, ['print' => false]);
                 $this->message(\Peanut\Console\Color::text('        | ', 'white') . 'trusted ./var/certs/' . $domain . '.cert');
             } else {
                 $this->message(\Peanut\Console\Color::text('        | ', 'white') . 'cert    ./var/certs/' . $domain . '.cert');
             }
         }
         $this->message();
         $this->message('# Run this command to configure your ssl certificate:');
         $this->message(\Peanut\Console\Color::text('open /Applications/Utilities/Keychain\\ Access.app', 'white'));
     }
 }
Пример #8
0
 /**
  * @param $name
  * @param $command
  */
 public function childProcess($name, $command)
 {
     $process = new \React\ChildProcess\Process($command);
     $process->on('exit', function ($exitCode, $termSignal) {
         // ...
         $this->message($exitCode, 'exit');
         $this->message($termSignal, 'exit');
     });
     if (!$this->color) {
         $tmp = \Peanut\Console\Color::$foregroundColors;
         unset($tmp['black'], $tmp['default'], $tmp['white'], $tmp['light_gray']);
         $this->color = array_keys($tmp);
     }
     $color = array_shift($this->color);
     $this->loop->addTimer(0.001, function ($timer) use($process, $name, $color) {
         $process->start($timer->getLoop());
         $callback = function ($output) use($name, $color) {
             $lines = explode(PHP_EOL, $output);
             $i = 0;
             foreach ($lines as $line) {
                 if ($line) {
                     $tmp = '';
                     if ($name) {
                         $tmp .= \Peanut\Console\Color::text(str_pad($name, 16, ' ', STR_PAD_RIGHT) . ' | ', $color);
                     }
                     $tmp .= \Peanut\Console\Color::text($line, 'light_gray');
                     $this->message($tmp);
                 }
                 $i++;
             }
         };
         $process->stdout->on('data', $callback);
         $process->stderr->on('data', $callback);
     });
 }
Пример #9
0
 /**
  * @param $stageName
  */
 public function Containers($mode, $isPull)
 {
     $machineName = $this->getMachineName();
     $projectName = $this->getProjectName();
     if (!$projectName) {
         echo PHP_EOL;
         while (true) {
             $inputProjectName = $this->ask('Please project a name : ');
             $command = ['docker', 'ps', '-aq', '--filter="label=com.docker.bootapp.project=' . $inputProjectName . '"'];
             $existsCount = count($this->process($command, ['print' => false])->toArray());
             if (0 == $existsCount) {
                 break;
             } else {
                 echo 'Name invalid. ';
             }
         }
         $this->config = ['project_name' => $inputProjectName] + $this->config;
         \App\Helpers\Yaml::dumpFile($this->configFileName, $this->config);
         $projectName = $this->getProjectName();
     }
     $stageName = $this->getStageName();
     $machineName = $this->getMachineName();
     $compose = \App\Helpers\Yaml::parseFile(getcwd() . '/docker-compose.' . $stageName . '.yml');
     echo \Peanut\Console\Color::text('machine | ', 'white') . $machineName . PHP_EOL;
     echo \Peanut\Console\Color::text('project | ', 'white') . $projectName . PHP_EOL;
     echo \Peanut\Console\Color::text('stage   | ', 'white') . $stageName . PHP_EOL;
     $checkBuild = false;
     $checkPull = false;
     foreach ($compose['services'] as $serviceName => &$service) {
         if (true === isset($service['name'])) {
             $name = $service['name'];
         } else {
             $name = $serviceName;
         }
         $service['org_name'] = $name;
         $service['name'] = $this->getContainerName($name);
         if (true === isset($service['build'])) {
             $checkBuild = true;
         } elseif (true === isset($service['image'])) {
             $checkPull = true;
         }
     }
     // break the reference with the last element
     unset($service);
     if ($checkPull && $isPull) {
         echo \Peanut\Console\Color::text('pull    | ', 'white');
         foreach ($compose['services'] as $serviceName => $service) {
             if (true === isset($service['image'])) {
                 $command = ['docker', 'pull', $service['image']];
                 //$this->message('build '.$service['name']);
                 echo $service['org_name'] . ' ';
                 $this->process($command, ['print' => false]);
             }
         }
         echo PHP_EOL;
     }
     if ($checkBuild) {
         echo \Peanut\Console\Color::text('build   | ', 'white');
         foreach ($compose['services'] as $serviceName => $service) {
             if (true === isset($service['build'])) {
                 $buildOpts = [];
                 $buildOpts[] = 'docker';
                 $buildOpts[] = 'build';
                 $buildOpts[] = '--tag=' . $service['name'];
                 if (true === is_array($service['build'])) {
                     if (true === isset($service['build']['args'])) {
                         foreach ($service['build']['args'] as $argKey => $argValue) {
                             $buildOpts[] = '--build-arg ' . $argKey . '=' . escapeshellarg($argValue);
                         }
                     }
                     if (true === isset($service['build']['context'])) {
                         $buildOpts[] = $service['build']['context'];
                     } else {
                         throw new \Console\Exception('build context not found');
                     }
                 } else {
                     $buildOpts[] = $service['build'];
                 }
                 //$this->message('build '.$service['name']);
                 echo $service['org_name'] . ' ';
                 $this->process($buildOpts, ['print' => true]);
             }
         }
         echo PHP_EOL;
     }
     echo \Peanut\Console\Color::text('remove  | ', 'white');
     foreach ($compose['services'] as $serviceName => $service) {
         echo $service['org_name'] . ' ';
         $rmCommand = ['docker', 'rm', '-f', $service['name'], '2>&1'];
         $this->process($rmCommand, ['print' => false]);
     }
     echo PHP_EOL;
     if (true === isset($compose['networks'])) {
     } else {
         // default network setting
         $compose['networks'] = ['default' => ['ipam' => ['config' => [['subnet']]]]];
     }
     if (true === isset($compose['networks'])) {
         $defaultName = $projectName;
         foreach ($compose['networks'] as $networkName => $network) {
             $dockerNetworks = $this->getNetworkList();
             if ('default' == $networkName) {
                 $networkName = 'default[' . $defaultName . ']';
             }
             //$this->networkName[] = $networkName; // --net 은 배열이 아니다.
             $this->networkName = [$networkName];
             if (true === isset($dockerNetworks[$networkName])) {
                 $networkRmcommand = ['docker', 'network', 'rm', $networkName, '2>&1'];
                 $this->process($networkRmcommand, ['print' => false]);
                 unset($dockerNetworks[$networkName]);
             }
             foreach ($dockerNetworks as $dockerNetworkName => $dockerNetworkSubnet) {
                 foreach ($network['ipam']['config'] as $configSubnet) {
                     if (true === isset($configSubnet['subnet']) && $configSubnet['subnet'] == $dockerNetworkSubnet) {
                         $this->message(\Peanut\Console\Color::text($networkName . ' conflicts with network ' . $dockerNetworkName . ', subnet ' . $dockerNetworkSubnet, 'red'));
                         echo 'delete? [y/N]: ';
                         $handle = fopen('php://stdin', 'r');
                         $line = fgets($handle);
                         fclose($handle);
                         if (false === in_array(trim($line), ['y', 'Y'])) {
                             throw new \Peanut\Console\Exception($networkName . ' conflicts with network ' . $dockerNetworkName . ', subnet ' . $dockerNetworkSubnet);
                         } else {
                             $networkRmCommand = ['docker', 'network', 'rm', $dockerNetworkName];
                             $this->process($networkRmCommand, ['print' => false]);
                         }
                     }
                 }
             }
             $subnet = [];
             foreach ($network['ipam']['config'] as $configSubnet) {
                 if (true === isset($configSubnet['subnet']) && $configSubnet['subnet']) {
                     $subnet[] = $configSubnet['subnet'];
                 }
             }
             $networkCreateCommand = ['docker', 'network', 'create', '--driver=bridge'];
             if ($subnet) {
                 $networkCreateCommand[] = '--subnet=' . implode(' --subnet=', $subnet);
             } else {
                 $subnetFile = $this->process('echo $HOME', ['print' => false])->toString() . '/.docker/docker-machine-subnet.yaml';
                 if (false === is_file($subnetFile)) {
                     $this->process('touch ' . $subnetFile, ['print' => false]);
                 }
                 $subnets = \App\Helpers\Yaml::parseFile($subnetFile);
                 if (false === is_array($subnets)) {
                     $subnets = [];
                 }
                 if (true === isset($subnets[$machineName][$projectName])) {
                     $subnet = $subnets[$machineName][$projectName];
                 } else {
                     $bridge = $this->process("docker network inspect --format='{{range .IPAM.Config}}{{.Subnet}}{{end}}' bridge", ['print' => false])->toString();
                     $subnetIps = [];
                     foreach ($subnets as $machines) {
                         if (true === is_array($machines)) {
                             foreach ($machines as $projectIp) {
                                 $subnetIps[] = $projectIp;
                             }
                         }
                     }
                     while (1) {
                         $subnet = '172.' . rand(0, 255) . '.0.0/16';
                         if ($subnet == $bridge) {
                             continue;
                         }
                         if (false == in_array($subnet, $subnetIps)) {
                             break;
                         }
                     }
                     $subnets[$machineName][$projectName] = $subnet;
                     \App\Helpers\Yaml::dumpFile($subnetFile, $subnets);
                 }
                 $networkCreateCommand[] = '--subnet=' . $subnet;
             }
             $networkCreateCommand[] = $networkName;
             $networkCreateCommand[] = '2>&1';
             $this->process($networkCreateCommand, ['print' => false]);
             $networkInspectCommand = ['docker', 'network', 'inspect', '--format="{{range .IPAM.Config}}{{.Subnet}}{{end}}"', $networkName, '2>&1'];
             $subnet = $this->process($networkInspectCommand, ['print' => false])->toArray();
             if (!$subnet) {
                 throw new \Peanut\Console\Exception('network ' . $networkName . ' not found');
             }
             echo \Peanut\Console\Color::text('network | ', 'white') . 'recreate ' . $networkName . ', subnet ' . implode(' ', $subnet) . PHP_EOL;
         }
     }
     if ('attach' == $mode) {
         echo \Peanut\Console\Color::text('create  | ', 'white');
     } else {
         echo \Peanut\Console\Color::text('run     | ', 'white');
     }
     $runCommands = [];
     foreach ($compose['services'] as $serviceName => $service) {
         $command = [];
         if ('attach' == $mode) {
             $command[] = 'docker create';
             $command[] = '-a STDIN';
             $command[] = '-a STDOUT';
             $command[] = '-a STDERR';
             $command[] = '-i';
         } else {
             $command[] = 'docker run';
             $command[] = '-d';
             $command[] = '-i';
             if (true === isset($service['tty'])) {
                 $command[] = '--tty';
             }
         }
         if (true === isset($service['privileged'])) {
             $command[] = '--privileged';
         }
         if ($this->networkName) {
             foreach ($this->networkName as $networkName) {
                 $command[] = '--net=' . $networkName;
             }
         }
         if (true === isset($service['networks'])) {
             foreach ($service['networks'] as $name => $conf) {
                 if (true === isset($conf['ipv4_address'])) {
                     $command[] = '--ip=' . $conf['ipv4_address'];
                 }
                 if (true === isset($conf['ipv6_address'])) {
                     $command[] = '--ip6=' . $conf['ipv6_address'];
                 }
             }
         }
         if (true === isset($service['dns'])) {
             foreach ($service['dns'] as $value) {
                 $command[] = '--dns=' . $value;
             }
         }
         if (true === isset($service['env-file'])) {
             foreach ($service['env-file'] as $value) {
                 $command[] = '--env-file=' . $value;
             }
         }
         $command[] = '-e TERM=xterm';
         if (true === isset($service['environment'])) {
             foreach ($service['environment'] as $key => $value) {
                 if (true === is_array($value)) {
                     $value = "'" . json_encode($value, JSON_UNESCAPED_SLASHES) . "'";
                 }
                 $command[] = '-e ' . $key . '=' . escapeshellarg($value);
             }
         }
         if (true === isset($service['expose'])) {
             foreach ($service['expose'] as $key => $value) {
                 $command[] = '--expose=' . $value;
             }
         }
         if (true === isset($service['user'])) {
             $command[] = '--user='******'user'];
         }
         if (true === isset($service['hostname'])) {
             $command[] = '--hostname=' . $service['hostname'];
         }
         $addHost = [];
         if (true === isset($service['links'])) {
             foreach ($service['links'] as $key => $value) {
                 foreach ($this->networkName as $networkName) {
                     $inspectCommand = ['docker', 'inspect', '--format="service={{index .Config.Labels \\"com.docker.bootapp.service\\"}}&&ip={{with index .NetworkSettings.Networks \\"' . $networkName . '\\"}}{{.IPAddress}}{{end}}"', $this->getContainerName($value)];
                     $str = $this->process($inspectCommand, ['print' => false])->toString();
                     parse_str($str, $out);
                     if (true === isset($out['ip']) && true === isset($out['service'])) {
                         $ip = $out['ip'];
                         $serviceName = $out['service'];
                         $addHost[$ip] = $serviceName . ' ' . $this->getContainerName($value);
                     }
                 }
                 $command[] = '--link=' . $this->getContainerName($value);
             }
         }
         foreach ($addHost as $ip => $host) {
             $command[] = '--add-host="' . $host . '":' . $ip;
         }
         if (true === isset($service['net'])) {
             $command[] = '--net=' . $service['net'];
         }
         if (true === isset($service['working_dir'])) {
             $command[] = '--workdir=' . $service['working_dir'];
         }
         if (true === isset($service['ports'])) {
             foreach ($service['ports'] as $value) {
                 $command[] = '--publish=' . $value;
             }
         } else {
             //$command[] = '-P';
         }
         if (true === isset($service['restart'])) {
             $command[] = '--restart=' . $service['restart'];
         }
         if (true === isset($service['volumes'])) {
             foreach ($service['volumes'] as $value) {
                 $command[] = '-v ' . $this->volumeRealPath($value);
             }
         }
         if (true === isset($service['volumes_from'])) {
             foreach ($service['volumes_from'] as $value) {
                 $command[] = '--volumes-from=' . ($projectName ? $projectName . '-' . $value : $value);
             }
         }
         if (true === isset($service['entrypoint'])) {
             $command[] = '--entrypoint=' . $service['entrypoint'];
         }
         $command[] = '--name=' . $service['name'];
         if (true === isset($service['labels'])) {
             foreach ($service['labels'] as $labelName => $labelValue) {
                 $command[] = '--label ' . $labelName . '="' . $labelValue . '"';
             }
         }
         if (true === isset($service['environment']['DOMAIN'])) {
             if (false === strpos($service['environment']['DOMAIN'], ' ')) {
                 $command[] = '--label com.docker.bootapp.domain="' . $service['environment']['DOMAIN'] . '"';
             } else {
                 throw new \Peanut\Console\Exception('domain name not valid');
             }
         }
         if (true === isset($service['image'])) {
             $command[] = $service['image'];
         }
         if (true === isset($service['build'])) {
             $command[] = $service['name'];
         }
         if (true === isset($service['command'])) {
             $command[] = $service['command'];
         }
         $runCommands[] = implode(' ', $command);
         $this->process($command, ['print' => false]);
         // create
         echo $service['org_name'] . ' ';
     }
     echo PHP_EOL;
     if ('attach' == $mode) {
         echo \Peanut\Console\Color::text('start   | ', 'white');
         foreach ($compose['services'] as $serviceName => $service) {
             echo $service['org_name'] . ' ';
             $command = ['docker', 'start', $service['name']];
             $this->process($command, ['print' => false]);
         }
         echo PHP_EOL;
         echo 'attach  | ';
         foreach ($compose['services'] as $serviceName => $service) {
             echo $service['org_name'] . ' ';
             $command = ['docker', 'logs', $service['name'], '&&', 'docker', 'attach', '--sig-proxy=true', $service['name']];
             $this->childProcess($service['name'], implode(' ', $command));
         }
         echo PHP_EOL;
     } else {
     }
 }