Skip to content

Commit 325c264

Browse files
committed
Support SSH to a specific instance of an app
1 parent e64d379 commit 325c264

1 file changed

Lines changed: 74 additions & 30 deletions

File tree

src/Model/Environment.php

Lines changed: 74 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -100,32 +100,76 @@ public function getHeadCommit()
100100
/**
101101
* Get the SSH URL for the environment.
102102
*
103-
* @param string $app An application name. If there is no published URL for
104-
* this app name, the 'legacy' URL (without an app name)
105-
* will be returned.
103+
* @param string $app
104+
* An application or worker name. If there is no published URL for this
105+
* app name, the 'legacy' URL (without an app name) will be returned.
106+
* @param string|null $instance
107+
* An instance ID. This is usually numeric starting with 0. Some legacy
108+
* dedicated environments have their instances starting from 1. If the
109+
* app does not have multiple instances, leave this as an empty string
110+
* or null.
106111
*
107112
* @throws EnvironmentStateException
108113
* @throws OperationUnavailableException
114+
* @throws \InvalidArgumentException if the $instance is not found
109115
*
110116
* @return string
111117
*/
112-
public function getSshUrl($app = '')
118+
public function getSshUrl($app = '', $instance = '')
113119
{
114120
$urls = $this->getSshUrls();
121+
if ($instance !== '' && $instance !== null) {
122+
$instances = $this->getSshInstanceURLs($app, $urls);
123+
if (isset($instances[$instance])) {
124+
return $instances[$instance];
125+
}
126+
$message = \sprintf("SSH URL not found for instance '%s' of '%s'.", $instance, $app);
127+
if (count($instances)) {
128+
$message .= \sprintf(' Available instances: %s', implode(', ', array_keys($instances)));
129+
}
130+
throw new \InvalidArgumentException($message);
131+
}
115132
if (isset($urls[$app])) {
116133
return $urls[$app];
117134
}
118135

119-
// Look for the first URL whose key starts with "$app:".
120-
\ksort($urls, SORT_NATURAL);
136+
// Fall back to the legacy SSH URL.
137+
return $this->constructLegacySshUrl();
138+
}
139+
140+
/**
141+
* List instance URLs for a specific app.
142+
*
143+
* @param string $app The app name.
144+
* @param ?array $sshUrls
145+
*
146+
* @return array<mixed, string>
147+
* An array of SSH URLs for the given app, keyed by instance ID.
148+
*/
149+
public function getSshInstanceURLs($app, $sshUrls = null)
150+
{
151+
$urls = $sshUrls === null ? $this->getSshUrls() : $sshUrls;
152+
$instances = [];
121153
foreach ($urls as $key => $url) {
122-
if (\strpos($key, $app . ':') === 0) {
123-
return $url;
154+
if (\strpos($key, "$app:") === 0) {
155+
$parts = explode(':', $key, 3);
156+
if (isset($parts[1])) {
157+
$instances[$parts[1]] = $url;
158+
}
124159
}
125160
}
126161

127-
// Fall back to the legacy SSH URL.
128-
return $this->constructLegacySshUrl();
162+
if ($instances === []) {
163+
// Handle legacy dedicated instance URLs.
164+
foreach ($urls as $key => $url) {
165+
if (strpos($key, 'ent-') === 0) {
166+
$instances[substr($key, 4)] = $url;
167+
}
168+
}
169+
}
170+
171+
natsort($instances);
172+
return $instances;
129173
}
130174

131175
/**
@@ -134,25 +178,13 @@ public function getSshUrl($app = '')
134178
* Workers themselves can be listed via getCurrentDeployment()->workers.
135179
*
136180
* @param Worker $worker
181+
* @param string $instance
137182
*
138183
* @return string
139184
*/
140-
public function getWorkerSshUrl(Worker $worker)
185+
public function getWorkerSshUrl(Worker $worker, $instance = '')
141186
{
142-
list($app, $worker) = explode('--', $worker->name, 2);
143-
144-
$prefix = 'pf:ssh:';
145-
foreach ($this->data['_links'] as $rel => $link) {
146-
if ($rel === $prefix . $app && isset($link['href'])) {
147-
return $this->convertSshUrl($link['href'], '--' . $worker);
148-
}
149-
}
150-
151-
throw new \RuntimeException(sprintf(
152-
'Unable to find the SSH URL for the app "%s" containing the worker "%s"',
153-
$app,
154-
$worker
155-
));
187+
return $this->getSshUrl($worker->name, $instance);
156188
}
157189

158190
/**
@@ -174,21 +206,33 @@ private function constructLegacySshUrl()
174206
}
175207

176208
/**
177-
* Convert a full SSH URL (with schema) into a normal SSH connection string.
209+
* Convert a full SSH URL (with scheme) into a normal SSH connection string.
210+
*
211+
* This can then be used with tools such as scp, etc.
178212
*
179-
* @param string $url The URL (starting with ssh://).
180-
* @param string $username_suffix A suffix to append to the username.
213+
* Only the username, host and path will be preserved (the port, password,
214+
* query and fragment will be dropped).
215+
*
216+
* @param string $url The URL (starting with ssh://).
181217
*
182218
* @return string
183219
*/
184-
private function convertSshUrl($url, $username_suffix = '')
220+
private function convertSshUrl($url)
185221
{
186222
$parsed = parse_url($url);
187223
if (!$parsed) {
188224
throw new \InvalidArgumentException('Invalid URL: ' . $url);
189225
}
226+
$str = '';
227+
if (!empty($parsed['user'])) {
228+
$str .= $parsed['user'] . '@';
229+
}
230+
$str .= $parsed['host'];
231+
if (!empty($parsed['path'])) {
232+
$str .= ':' . $parsed['path'];
233+
}
190234

191-
return $parsed['user'] . $username_suffix . '@' . $parsed['host'];
235+
return $str;
192236
}
193237

194238
/**

0 commit comments

Comments
 (0)