1 <?php
2 3 4 5
6
7 namespace Fluxsauce\Switchboard;
8
9 10 11 12
13 class ProviderPantheon extends Provider {
14 15 16
17 protected $name = 'pantheon';
18
19 20 21
22 protected $label = 'Pantheon';
23
24 25 26
27 protected $homepage = 'https://www.getpantheon.com/';
28
29 30 31
32 protected $endpoint = 'https://terminus.getpantheon.com';
33
34 35 36 37 38 39 40 41 42 43 44 45 46
47 public function siteGetField($site_name, $field) {
48 switch ($field) {
49
50 case 'name':
51 case 'provider':
52 break;
53
54 case 'vcsUrl':
55 case 'vcsType':
56 case 'vcsProtocol':
57 case 'sshPort':
58 $this->apiGetSite($site_name);
59 break;
60
61 case 'unixUsername':
62 case 'realm':
63 case 'uuid':
64 $this->apiGetSites();
65 break;
66
67 case 'title':
68 $this->apiGetSiteName($site_name);
69 case 'environments':
70 $this->apiGetSiteEnvironments($site_name);
71 break;
72
73 default:
74 throw new \Exception('Unknown field ' . $field . ' in ' . __CLASS__);
75 }
76 return $this->sites[$site_name]->$field;
77 }
78
79 80 81 82 83 84
85 public function apiGetSite($site_name) {
86 $site = new Site('pantheon', $site_name);
87
88 $repository = 'codeserver.dev.' . $site->uuid;
89 $repository .= '@codeserver.dev.' . $site->uuid;
90 $repository .= '.drush.in:2222/~/repository.git';
91
92 $site->update(array(
93 'vcsUrl' => $repository,
94 'vcsType' => 'git',
95 'vcsProtocol' => 'ssh',
96 'sshPort' => 2222,
97 ));
98 $this->sites[$site_name] = $site;
99 }
100
101 102 103
104 public function apiGetSites() {
105 $user_uuid = drush_cache_get('user_uuid', $this->drushCacheBinAuthName());
106 $result = switchboard_request($this, array(
107 'method' => 'GET',
108 'realm' => 'sites',
109 'resource' => 'user',
110 'uuid' => $user_uuid->data,
111 ));
112 $site_metadata = json_decode($result->body);
113
114 $sites = array();
115
116 foreach ($site_metadata as $uuid => $data) {
117 $site = new Site($this->name, $data->information->name);
118 $site->uuid = $uuid;
119 $site->realm = $data->information->preferred_zone;
120 $site->unixUsername = '';
121 $site->update();
122 $this->sites[$site->name] = $site;
123 }
124 }
125
126 127 128 129 130 131
132 public function apiGetSiteName($site_name) {
133 $site =& $this->sites[$site_name];
134 $result = switchboard_request($this, array(
135 'method' => 'GET',
136 'realm' => 'attributes',
137 'resource' => 'site',
138 'uuid' => $site->uuid,
139 ));
140 $site_attributes = json_decode($result->body);
141 $site->title = $site_attributes->label;
142 $site->update();
143 $this->sites[$site->name] = $site;
144 }
145
146 147 148 149 150 151
152 public function requestsOptionsCustom() {
153 $options = array();
154 $cookies = drush_cache_get('session', $this->drushCacheBinAuthName());
155 if (isset($cookies->data)) {
156 $options = array(
157 'cookies' => array($cookies->data),
158 );
159 }
160 return $options;
161 }
162
163 164 165 166 167 168 169 170 171 172 173
174 public function authLogin($email, $password) {
175 $url = $this->endpoint . '/login';
176
177
178 try {
179 $response = \Requests::post($url);
180 }
181 catch (\Requests_Exception $e) {
182 return drush_set_error('SWITCHBOARD_AUTH_LOGIN_PANTHEON_ENDPOINT_UNAVAILABLE', dt('Pantheon endpoint unavailable: @error', array(
183 '@error' => $e->getMessage(),
184 )));
185 }
186 $form_build_id = $this->authLoginGetFormBuildId($response->body);
187 if (!$form_build_id) {
188 return drush_set_error('SWITCHBOARD_AUTH_LOGIN_PANTHEON_LOGIN_UNAVAILABLE', dt('Pantheon login unavailable.'));
189 }
190
191
192 try {
193 $response = \Requests::post($url, array(), array(
194 'email' => $email,
195 'password' => $password,
196 'form_build_id' => $form_build_id,
197 'form_id' => 'atlas_login_form',
198 'op' => 'Login',
199 ), $this->requestsOptions(array('follow_redirects' => FALSE)));
200 }
201 catch (\Requests_Exception $e) {
202 return drush_set_error('SWITCHBOARD_AUTH_LOGIN_PANTHEON_LOGIN_FAILURE', dt('Pantheon login failure: @error', array(
203 '@error' => $e->getMessage(),
204 )));
205 }
206
207 $session = $this->authLoginGetSessionFromHeaders($response->headers->getValues('set-cookie'));
208
209 if (!$session) {
210 return drush_set_error('SWITCHBOARD_AUTH_LOGIN_PANTHEON_NO_SESSION', dt('Pantheon Session not found; please check your credentials and try again.'));
211 }
212
213
214 $user_uuid = array_pop(explode('/', $response->headers->offsetGet('Location')));
215 if (!switchboard_validate_uuid($user_uuid)) {
216 return drush_set_error('SWITCHBOARD_AUTH_LOGIN_PANTHEON_NO_UUID', dt('Pantheon User UUID not found; please check your credentials and try again.'));
217 }
218
219 drush_cache_clear_all('*', $this->drushCacheBinAuthName(), TRUE);
220 drush_cache_set('user_uuid', $user_uuid, $this->drushCacheBinAuthName());
221 drush_cache_set('session', $session, $this->drushCacheBinAuthName());
222 drush_cache_set('email', $email, $this->drushCacheBinAuthName());
223 return TRUE;
224 }
225
226 227 228 229 230 231
232 public function authIsLoggedIn() {
233 $session = drush_cache_get('session', $this->drushCacheBinAuthName());
234 return isset($session->data) ? TRUE : FALSE;
235 }
236
237 238 239 240 241 242 243 244 245 246 247
248 public function ($headers) {
249 $session = FALSE;
250 foreach ($headers as $header) {
251 foreach (explode('; ', $header) as $cookie) {
252 if (strpos($cookie, 'SSESS') === 0) {
253 $session = $cookie;
254 }
255 }
256 }
257 return $session;
258 }
259
260 261 262 263 264 265 266 267 268
269 public function authLoginGetFormBuildId($html) {
270 if (!$html) {
271 return FALSE;
272 }
273
274 $dom = new \DOMDocument();
275 @$dom->loadHTML($html);
276 $login_form = $dom->getElementById('atlas-login-form');
277 if (!$login_form) {
278 return FALSE;
279 }
280
281 foreach ($login_form->getElementsByTagName('input') as $input) {
282 if ($input->getAttribute('name') == 'form_build_id') {
283 return $input->getAttribute('value');
284 }
285 }
286 return FALSE;
287 }
288
289 290 291 292 293 294
295 public function apiGetSiteEnvironments($site_name) {
296 $site =& $this->sites[$site_name];
297 $result = switchboard_request($this, array(
298 'method' => 'GET',
299 'realm' => 'environments',
300 'resource' => 'site',
301 'uuid' => $site->uuid,
302 ));
303 $environment_data = json_decode($result->body);
304 foreach ($environment_data as $environment_name => $environment) {
305 $new_environment = new Environment($site->id, $environment_name);
306 $new_environment->branch = 'master';
307 $new_environment->host = "appserver.$environment_name.{$site->uuid}.drush.in";
308 $new_environment->username = "$environment_name.$site_name";
309 $new_environment->update();
310 $site->environmentAdd($new_environment);
311 }
312 }
313
314 315 316 317 318 319 320 321
322 public function apiGetSiteEnvDbs($site_name, $env_name) {
323 $site =& $this->sites[$site_name];
324 $env =& $site->environments[$env_name];
325 $new_db = new EnvDb($env->id, 'pantheon');
326 $new_db->update();
327 $env->dbAdd($new_db);
328 }
329
330 331 332 333 334 335 336 337 338 339 340 341 342 343 344
345 public function apiGetSiteEnvDbBackups($site_name, $env_name) {
346 $site = $this->sites[$site_name];
347 $result = switchboard_request($this, array(
348 'method' => 'GET',
349 'resource' => 'site',
350 'realm' => 'environments/' . $env_name . '/backups/catalog',
351 'uuid' => $site->uuid,
352 ));
353 $backups = array();
354 $backup_data = json_decode($result->body);
355 foreach ($backup_data as $id => $backup) {
356 $parts = explode('_', $id);
357 if (!isset($backup->filename) || $parts[2] != 'database') {
358 continue;
359 }
360 $backups[$backup->timestamp] = array(
361 'filename' => $backup->filename,
362 'url' => '',
363 'bucket' => $parts[0] . '_' . $parts[1],
364 'timestamp' => $backup->timestamp,
365 );
366 }
367 arsort($backups);
368 return $backups;
369 }
370
371 372 373 374 375 376 377 378 379 380 381
382 public function getSiteEnvDbBackupLatest($site_name, $env_name) {
383 $backup = parent::getSiteEnvDbBackupLatest($site_name, $env_name);
384 $backup['url'] = $this->apiGetBackupDownloadUrl($site_name, $env_name, $backup['bucket'], 'database');
385 unset($backup['bucket']);
386 return $backup;
387 }
388
389 390 391 392 393 394 395 396 397 398 399 400 401 402 403
404 public function apiGetBackupDownloadUrl($site_name, $env_name, $bucket, $element) {
405 $site = $this->sites[$site_name];
406 $result = switchboard_request($this, array(
407 'method' => 'POST',
408 'resource' => 'site',
409 'realm' => 'environments/' . $env_name . '/backups/catalog/' . $bucket . '/' . $element . '/s3token',
410 'uuid' => $site->uuid,
411 'data' => array('method' => 'GET'),
412 ));
413 $token = json_decode($result->body);
414 return $token->url;
415 }
416
417 418 419 420 421 422 423 424 425 426 427
428 public function apiDownloadBackup($backup, $destination) {
429
430 $destination_path = $destination . DIRECTORY_SEPARATOR . $backup['filename'];
431 $path = _drush_download_file($backup['url'], $destination_path, 31556926);
432 if ($path || drush_get_context('DRUSH_SIMULATE')) {
433 return $destination_path;
434 }
435 else {
436 return drush_set_error('SWITCHBOARD_PANTHEON_BACKUP_DL_FAIL', dt('Unable to download!'));
437 }
438 }
439
440 441 442 443 444 445 446 447 448 449 450
451 public function getFilesPath($site_name, $env_name) {
452 return 'files';
453 }
454 }
455