/** @test */ public function it_parses_repo_name_correctly() { $repo = new Repo('ashleyhindle/rocks'); $this->assertEquals('ashleyhindle', $repo->getUsername()); $this->assertEquals('rocks', $repo->getRepoName()); $this->assertEquals('ashleyhindle/rocks', $repo->getName()); }
public function view(Request $request, $repo = false) { try { $repo = new Repo($repo); } catch (\Exception $e) { $request->session()->flash(str_random(4), ['type' => 'danger', 'message' => $e->getMessage()]); return redirect('/?ohno'); } $fullRepo = $repo->getName(); $request->session()->set('intendedRepo', $repo->getName()); $github = new Github($this->getGithubClient(), $repo); $json = $github->getFodorJson(); // TODO: Consider: should this be $repo->getFodorConfig() or getConfig or getFodorJson, and pass Github into Repo? if (empty($json)) { $request->session()->flash(str_random(4), ['type' => 'warning', 'message' => 'This repo or repo\'s fodor.json is non-existent']); return redirect(url('/')); } $fodorJson = new Config($json); try { $fodorJson->valid(); } catch (InvalidRepoException $e) { $request->session()->flash(str_random(4), ['type' => 'danger', 'message' => $e->getMessage()]); return redirect('/?ohno'); } $fodorJsonUndecoded = $fodorJson->getJson(); // string of json // Has to be less than 1mb $provisioner = $github->getFileContents($fodorJson->provisioner); if (empty($provisioner)) { $request->session()->flash(str_random(4), ['type' => 'warning', 'message' => 'This repo\'s provisioner was invalid or empty']); return redirect(url('/?ohno')); } $timeEstimate = 0; if (config('fodor.enable_time_estimates')) { $timeEstimate = \DB::select('select AVG(unix_timestamp(dateready)-unix_timestamp(datestarted)) as timeEstimate from provisions where repo=? and datestarted > ? and dateready is not null', [$fullRepo, (new \DateTime())->sub(new \DateInterval('P6M'))->format('Y-m-d H:i:s')]); $timeEstimate = $timeEstimate === null ? 0 : floor($timeEstimate[0]->timeEstimate); } return view('provision.view', ['repo' => $fullRepo, 'description' => $fodorJson->description, 'imageUrl' => $this->getValidUrl($fodorJson, 'image'), 'homepage' => $this->getValidUrl($fodorJson, 'homepage'), 'fodorJson' => $fodorJsonUndecoded, 'provisionerScript' => $provisioner, 'timeEstimate' => $timeEstimate]); }
/** * Execute the job. * * @return void */ public function handle() { $this->log = new Logger('LOG'); $this->log->pushHandler(new StreamHandler(storage_path('logs/provision/' . $this->provision->uuid . '.log'), Logger::INFO)); $logProvisionerOutput = new Logger('OUTPUT'); $logProvisionerOutput->pushHandler(new StreamHandler(storage_path('logs/provision/' . $this->provision->uuid . '.output'), Logger::INFO)); $this->log->addInfo("Provisioning started"); $uuid = $this->provision->uuid; $sshKeys = new \App\Fodor\Ssh\Keys($uuid); //TODO: This should be a beanstalk job with AJAX updating //DO ALL THE PROVISIONING HERE - GET GITHUB FODOR.JSON, SSH IN, DO IT ALL, $this->provision->status = 'provision'; $this->provision->save(); $this->log->addInfo("Set status to provision"); $repo = new Repo($this->provision->repo); $branch = $repo->getBranch(); $username = $repo->getUsername(); $client = new \Github\Client(); $client->authenticate(env('GITHUB_API_TOKEN'), false, \Github\Client::AUTH_HTTP_TOKEN); $github = new Github($client, $repo); $json = $github->getFodorJson(); $this->log->addInfo("Fetched fodor.json from GitHub: {$json}"); $fodorJson = new Config($json); try { $fodorJson->valid(); } catch (\Exception $e) { $this->log->addError('Fodor.json invalid'); } $baseScript = \View::make('provision-base.ubuntu-14-04-x64', ['installpath' => $fodorJson->installpath, 'name' => $this->provision->repo, 'domain' => $this->provision->subdomain . '.fodor.xyz', 'ipv4' => $this->provision->ipv4, 'inputs' => $this->inputs])->render(); // Has to be less than 1mb $providedScript = $github->getFileContents($fodorJson->provisioner); if (empty($providedScript)) { $this->log->addError('Provisioner invalid'); } $this->log->addInfo("Fetched provisioner script from GitHub: {$providedScript}"); $remoteProvisionScriptPath = '/tmp/fodor-provision-script-' . $this->provision->uuid; if ($ssh = ssh2_connect($this->provision->ipv4, 22, [], ['disconnect' => [$this, 'tidyUp']])) { $this->log->addInfo("Successfully connected to the server via SSH: {$this->provision->ipv4}"); if (ssh2_auth_pubkey_file($ssh, 'root', storage_path('app/' . $sshKeys->getPublicKeyPath()), storage_path('app/' . $sshKeys->getPrivateKeyPath()))) { $this->log->addInfo("Successfully authenticated"); $this->log->addInfo("Running: /bin/bash '{$remoteProvisionScriptPath}'"); $sftp = ssh2_sftp($ssh); //TODO error check and refactor all of the code we've written so far $stream = fopen("ssh2.sftp://{$sftp}{$remoteProvisionScriptPath}", 'w'); $fullScript = $baseScript . PHP_EOL . $providedScript . PHP_EOL; fwrite($stream, $fullScript); fclose($stream); $this->log->addInfo("Transferred provisioner-combined script"); // TODO: Investigate setting environment variables here instead of with export $stream = ssh2_exec($ssh, '(/bin/bash ' . escapeshellarg($remoteProvisionScriptPath) . ' 2>&1); echo -e "\\n$?"'); stream_set_blocking($stream, true); $lastString = ''; while (($string = fgets($stream)) !== false) { $logProvisionerOutput->addInfo($string); echo $string; $lastString = $string; } $this->log->addInfo('EXIT CODE: ' . $lastString); $this->exitCode = (int) trim($lastString); fclose($stream); } else { $this->log->addError("Failed to authenticate to SSH"); exit(1); } } else { $this->log->addError("Failed to connect to SSH"); $this->release(2); // Delay x seconds to retry as SSH isn't ready yet exit(1); } $this->tidyUp(); }