@@ -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