public function start(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'); } $request->session()->set('intendedRepo', $repo); if ($request->session()->has('digitalocean') === false) { return redirect(url('/do/start')); } $request->session()->forget('intendedRepo'); $provision = new Provision(); $provision->repo = $repo->getName(); // Before it gets contaminated $github = new Github($this->getGithubClient(), $repo); $json = $github->getFodorJson(); 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 (\Exception $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')); } // We have a valid provisioner $size = '512mb'; // TODO: Config variable for default size $suggestedSize = false; $requiredSize = false; if (array_key_exists('required', $fodorJson->size) === true) { $size = $fodorJson->size['required']; $requiredSize = $size; } // Suggested size overrides the default and required size if (array_key_exists('suggested', $fodorJson->size) === true) { $size = $fodorJson->size['suggested']; $suggestedSize = $size; } if (array_key_exists($size, config('digitalocean.sizes')) === false) { // Invalid size $size = '512mb'; // TODO: Config variable for default size } $isDistroInvalid = !in_array($fodorJson->distro, config('digitalocean.distros')); if (empty($fodorJson->distro) || $isDistroInvalid) { $fodorJson->distro = 'ubuntu-14-04-x64'; } $adapter = new GuzzleHttpAdapter($request->session()->get('digitalocean')['token']); $digitalocean = new DigitalOceanV2($adapter); $keysCached = false; $cacheKey = sha1($request->session()->get('digitalocean')['token'] . '-sshkeys'); $keys = Cache::get($cacheKey, []); if (empty($keys)) { $keysFromDo = $digitalocean->key()->getAll(); if (empty($keysFromDo)) { $request->session()->flash(str_random(4), ['type' => 'danger', 'message' => 'You must have SSH keys attached to your DigitalOcean account to continue - https://cloud.digitalocean.com/settings/security']); return redirect(url('/provision/' . $provision->repo)); } foreach ($keysFromDo as $key) { if (strpos($key->name, 'fodor-') !== 0) { $keys[$key->id] = $key->name; } } if (empty($keys)) { $request->session()->flash(str_random(4), ['type' => 'danger', 'message' => 'You must have SSH keys attached to your DigitalOcean account to continue - https://cloud.digitalocean.com/settings/security']); return redirect(url('/provision/' . $provision->repo)); } Cache::put($cacheKey, $keys, 5); // Cache SSH keys for 5 minutes } else { $keysCached = true; } $requiredMemory = 0; if (!empty($requiredSize)) { $requiredMemory = array_key_exists($requiredSize, config('digitalocean.sizes')) ? config('digitalocean.sizes')[$requiredSize]['memory'] : 0; } $inputs = is_null($fodorJson->inputs) === false ? $fodorJson->inputs : []; array_walk($inputs, function (&$input) { $input['value'] = ''; $input = new Input($input); }); //get account email, and digitalocean_uuid //generate our own uuid //store in DB $provision->uuid = Uuid::uuid4()->toString(); $provision->email = $request->session()->get('digitalocean')['email']; $provision->digitalocean_uuid = $request->session()->get('digitalocean')['uuid']; $provision->size = $size; // Default, can be overriden in next step $provision->distro = $fodorJson->distro; $provision->region = 'xxx'; // Default, can be overriden in next step $provision->datestarted = (new \DateTime('now', new \DateTimeZone('UTC')))->format('c'); $validatingInputs = $request->input('uuid') !== null ? true : false; if ($validatingInputs) { $provision = \App\Provision::where('id', $request->input('provisionid'))->where('uuid', $request->input('uuid'))->first(); /** * @var Input $input */ $invalidInputs = []; foreach ($inputs as $input) { $value = $request->input('inputs')[$input->getName()]; $input->value($value); $valid = $input->validate($value); if ($valid === false) { $invalidInputs[] = ucwords($input->getName()); } } $selectedKeys = $request->input('keys'); $keysChosen = count($selectedKeys) > 0; if ($keysChosen === false) { $request->session()->now(str_random(4), ['type' => 'warning', 'message' => 'You must select an SSH key to add to the server']); } elseif (count($invalidInputs) === 0 && $keysChosen) { return $this->doit($request); } else { $request->session()->now(str_random(4), ['type' => 'warning', 'message' => 'Input value was invalid for ' . implode(', ', $invalidInputs)]); } } else { try { $saved = $provision->save(); } catch (\Exception $e) { $saved = false; } if (empty($saved)) { // Failed to save $request->session()->flash(str_random(4), ['type' => 'danger', 'message' => 'Failed to save the provision data to the database, please destroy your droplet']); return redirect(url('/provision/' . $provision->repo)); } } return view('provision.start', ['repo' => $repo->getRepoName(), 'size' => ['default' => $size, 'suggested' => $suggestedSize, 'required' => $requiredSize], 'requiredMemory' => $requiredMemory, 'description' => $fodorJson->description, 'distro' => $fodorJson->distro, 'keys' => $keys, 'provisionid' => $provision->id, 'provision' => $provision, 'id' => $provision->id, 'uuid' => $provision->uuid, 'inputs' => $inputs, 'keysCached' => $keysCached]); }