@@ -21,7 +21,6 @@ import {
2121 pluralizeNodes ,
2222 startOrNowOption ,
2323 yesOption ,
24- zoneOption ,
2524} from "./utils.ts" ;
2625import { handleNodesError , nodesClient } from "../../nodesClient.ts" ;
2726import { logAndQuit } from "../../helpers/errors.ts" ;
@@ -82,7 +81,18 @@ const create = new Command("create")
8281 "[Required: names or --count] Number of nodes to create with auto-generated names" ,
8382 validateCount ,
8483 )
85- . addOption ( zoneOption )
84+ . addOption (
85+ new Option (
86+ "-z, --zone <zone>" ,
87+ "[Required: zone or --any-zone if --auto is provided] Zone for your nodes" ,
88+ ) . conflicts ( "any-zone" ) ,
89+ )
90+ . addOption (
91+ new Option (
92+ "--any-zone" ,
93+ "Use any zone that meets requirements" ,
94+ ) . conflicts ( "zone" ) ,
95+ )
8696 . addOption ( maxPriceOption )
8797 . addOption (
8898 new Option (
@@ -125,41 +135,42 @@ const create = new Command("create")
125135 . addOption ( jsonOption )
126136 . hook ( "preAction" , ( command ) => {
127137 const names = command . args ;
128- const { count, start, duration, end, auto, reserved } = command
129- . opts ( ) ;
138+ const { count, start, duration, end, auto, reserved, anyZone, zone } =
139+ command
140+ . opts ( ) ;
130141
131142 // Validate arguments
132143 if ( names . length === 0 && ! count ) {
133- console . error (
144+ command . error (
134145 red ( "Must specify either node names or use \`--count\` option\n" ) ,
135146 ) ;
136- command . help ( ) ;
137- process . exit ( 1 ) ;
138147 }
139148
140149 if ( names . length > 0 && count ) {
141150 if ( names . length !== count ) {
142- console . error ( red (
151+ command . error ( red (
143152 `You specified ${ names . length } ${
144153 names . length === 1 ? "node name" : "node names"
145154 } but \`--count\` is set to ${ count } . The number of names must match the \`count\`.\n`,
146155 ) ) ;
147- command . help ( ) ;
148- process . exit ( 1 ) ;
149156 }
150157 }
151158
159+ if ( auto && ! anyZone && ! zone ) {
160+ command . error ( red (
161+ "If --auto is provided, you must specify a zone or use --any-zone\n" ,
162+ ) ) ;
163+ }
164+
152165 if ( reserved && auto ) {
153- console . error ( red ( "Specify either --reserved or --auto, but not both\n" ) ) ;
154- command . help ( ) ;
155- process . exit ( 1 ) ;
166+ command . error ( red (
167+ "Specify either --reserved or --auto, but not both\n" ,
168+ ) ) ;
156169 }
157170
158171 // Validate duration/end like buy command
159172 if ( typeof end !== "undefined" && typeof duration !== "undefined" ) {
160- console . error ( red ( "Specify either --duration or --end, but not both\n" ) ) ;
161- command . help ( ) ;
162- process . exit ( 1 ) ;
173+ command . error ( red ( "Specify either --duration or --end, but not both\n" ) ) ;
163174 }
164175
165176 // Validate that timing flags are only used with reserved nodes
@@ -168,25 +179,21 @@ const create = new Command("create")
168179 ( start !== "NOW" || typeof duration !== "undefined" ||
169180 typeof end !== "undefined" )
170181 ) {
171- console . error (
182+ command . error (
172183 red (
173184 "Auto-reserved nodes start immediately and cannot have a start time, duration, or end time.\n" ,
174185 ) ,
175186 ) ;
176- command . help ( ) ;
177- process . exit ( 1 ) ;
178187 }
179188
180189 if (
181190 ! auto && typeof duration === "undefined" && typeof end === "undefined"
182191 ) {
183- console . error (
192+ command . error (
184193 red (
185194 "You must specify either --duration or --end to create a reserved node.\n" ,
186195 ) ,
187196 ) ;
188- command . help ( ) ;
189- process . exit ( 1 ) ;
190197 }
191198 } )
192199 . addHelpText (
@@ -250,6 +257,7 @@ async function createNodesAction(
250257 desired_count : count ,
251258 max_price_per_node_hour : options . maxPrice * 100 ,
252259 names : names . length > 0 ? names : undefined ,
260+ any_zone : options . anyZone ?? false ,
253261 zone : options . zone ,
254262 cloud_init_user_data : encodedUserData ,
255263 image_id : options . image ,
@@ -393,10 +401,13 @@ async function createNodesAction(
393401 confirmationMessage += ` for ~$${
394402 pricePerNodeHour . toFixed ( 2 )
395403 } /node/hr`;
404+ if ( "zone" in quote ) {
405+ confirmationMessage += ` on ${ cyan ( quote . zone ) } ` ;
406+ }
396407 } else {
397408 logAndQuit (
398409 red (
399- "No nodes available matching your requirements. This is likely due to insufficient capacity ." ,
410+ "No capacity available matching your hardware and pricing requirements. You can view zone capacity at https://sfcompute.com/dashboard/zones ." ,
400411 ) ,
401412 ) ;
402413 }
@@ -405,6 +416,11 @@ async function createNodesAction(
405416 confirmationMessage += ` for up to $${
406417 options . maxPrice . toFixed ( 2 )
407418 } /node/hr`;
419+ if ( options . zone ) {
420+ confirmationMessage += ` on ${ cyan ( options . zone ) } ` ;
421+ } else {
422+ confirmationMessage += ` on any matching zone` ;
423+ }
408424 }
409425
410426 // Add node names at the end after a colon
0 commit comments