@@ -270,31 +270,30 @@ func (c *MssqlBase) AddFlags(
270270// If the EULA has not been accepted, it prints an error message with suggestions for how to proceed,
271271// and exits the program.
272272func (c * MssqlBase ) Run () {
273- output := c .Cmd .Output ()
274-
275273 var imageName string
276274
275+ output := c .Cmd .Output ()
276+
277277 if ! c .acceptEula && viper .GetString ("ACCEPT_EULA" ) == "" {
278278 output .FatalWithHints (
279279 []string {"Either, add the --accept-eula flag to the command-line" ,
280- fmt .Sprintf ("Or, set the environment variable i.e. %s SQLCMD_ACCEPT_EULA=YES " , pal .CreateEnvVarKeyword ())},
280+ fmt .Sprintf (
281+ "Or, set the environment variable i.e. %s SQLCMD_ACCEPT_EULA=YES " ,
282+ pal .CreateEnvVarKeyword ())},
281283 "EULA not accepted" )
282284 }
283285
284- imageName = fmt .Sprintf (
285- "%s/%s:%s" ,
286- c .registry ,
287- c .repo ,
288- c .tag )
286+ imageName = fmt .Sprintf ("%s/%s:%s" , c .registry , c .repo , c .tag )
289287
288+ // If no context name provided, set it to the default (e.g. mssql or edge)
290289 if c .contextName == "" {
291290 c .contextName = c .defaultContextName
292291 }
293292
294293 c .createContainer (imageName , c .contextName )
295294}
296295
297- // createContainer installs an image for a SQL Server container. The image
296+ // createContainer creates a SQL Server container for an image . The image
298297// is specified by imageName, and the container will be given the name contextName.
299298// If the useCached flag is set, the function will skip downloading the image
300299// from the internet. The function outputs progress messages to the command-line
@@ -305,25 +304,19 @@ func (c *MssqlBase) createContainer(imageName string, contextName string) {
305304 controller := container .NewController ()
306305 saPassword := c .generatePassword ()
307306
308- env := []string {
309- "ACCEPT_EULA=Y" ,
310- fmt .Sprintf ("MSSQL_SA_PASSWORD=%s" , saPassword ),
311- fmt .Sprintf ("MSSQL_COLLATION=%s" , c .collation ),
312- }
313-
314307 if c .port == 0 {
315308 c .port = config .FindFreePortForTds ()
316309 }
317310
318311 // Do an early exit if url doesn't exist
319312 var useDatabase ingest.Ingest
320313 if c .useDatabaseUrl != "" {
321- useDatabase = c .verifyUseSourceFileExists (useDatabase , controller , output )
314+ useDatabase = c .verifyUseSourceFileExists (controller , output )
322315 }
323316
324317 if c .defaultDatabase != "" {
325318 if ! c .validateDbName (c .defaultDatabase ) {
326- output .Fatalf ("--user- database %q contains non-ASCII chars and/or quotes" , c .defaultDatabase )
319+ output .Fatalf ("--database %q contains non-ASCII chars and/or quotes" , c .defaultDatabase )
327320 }
328321 }
329322
@@ -332,38 +325,34 @@ func (c *MssqlBase) createContainer(imageName string, contextName string) {
332325 }
333326
334327 runOptions := container.RunOptions {
335- Env : env ,
336328 Port : c .port ,
337329 Name : c .name ,
338330 Hostname : c .hostname ,
339331 Architecture : c .architecture ,
340- Os : c .os ,
341- Command : []string {},
342- }
332+ Os : c .os }
333+
334+ runOptions .Env = []string {
335+ "ACCEPT_EULA=Y" ,
336+ fmt .Sprintf ("MSSQL_SA_PASSWORD=%s" , saPassword ),
337+ fmt .Sprintf ("MSSQL_COLLATION=%s" , c .collation )}
343338
344339 output .Infof ("Starting %v" , imageName )
345340 containerId := controller .ContainerRun (imageName , runOptions )
346341 previousContextName := config .CurrentContextName ()
347342
348- userName := pal .UserName ()
349- password := c .generatePassword ()
350-
351343 // Save the config now, so user can uninstall/delete, even if mssql in the container
352344 // fails to start
353-
354345 contextOptions := config.ContextOptions {
355346 ImageName : imageName ,
356347 PortNumber : c .port ,
357348 ContainerId : containerId ,
358- Username : userName ,
359- Password : password ,
360- PasswordEncryption : c .passwordEncryption ,
361- }
362-
349+ Username : pal .UserName (),
350+ Password : c .generatePassword (),
351+ PasswordEncryption : c .passwordEncryption }
363352 config .AddContextWithContainer (contextName , contextOptions )
364353
365354 output .Infof (
366- "Created context %q in \" %s\" , configuring user account... " ,
355+ "Created context %q in \" %s\" , configuring user account" ,
367356 config .CurrentContextName (),
368357 config .GetConfigFileUsed ())
369358
@@ -372,7 +361,7 @@ func (c *MssqlBase) createContainer(imageName string, contextName string) {
372361 output .Infof ("Disabled %q account (and rotated %q password). Creating user %q" ,
373362 "sa" ,
374363 "sa" ,
375- userName )
364+ contextOptions . Username )
376365
377366 endpoint , _ := config .CurrentContext ()
378367
@@ -384,7 +373,7 @@ func (c *MssqlBase) createContainer(imageName string, contextName string) {
384373 if c .errorLogEntryToWaitFor == "Hello from Docker!" {
385374 sqlOptions .UnitTesting = true
386375 }
387- c .sql = sql .New (sqlOptions )
376+ c .sql = sql .NewSql (sqlOptions )
388377
389378 saUser := & sqlconfig.User {
390379 AuthenticationType : "basic" ,
@@ -394,27 +383,34 @@ func (c *MssqlBase) createContainer(imageName string, contextName string) {
394383 Password : secret .Encode (saPassword , c .passwordEncryption )},
395384 Name : "sa" }
396385
397- c .sql .Connect (endpoint , saUser , sql.ConnectOptions {Database : "master" , Interactive : false })
398- c .createNonSaUser (userName , password )
386+ // Connect to master database on SQL Server in the container as `sa`
387+ c .sql .Connect (endpoint , saUser , sql.ConnectOptions {Database : "master" })
388+
389+ // Create a new (non-sa) SQL Server user
390+ c .createUser (contextOptions .Username , contextOptions .Password )
399391
400- // Download and restore DB if asked
392+ // Download and restore/attach etc. DB if asked
401393 if useDatabase != nil {
402- output .Infof ("Copying to container" )
394+ if useDatabase .IsRemoteUrl () {
395+ output .Infof ("Downloading %q to container" , useDatabase .UrlFilename ())
396+ } else {
397+ output .Infof ("Copying %q to container" , useDatabase .UrlFilename ())
398+ }
403399 useDatabase .CopyToContainer (containerId )
404400
405401 if useDatabase .IsExtractionNeeded () {
406- output .Infof ("Extracting files from archive" )
402+ output .Infof ("Extracting files from %q archive" , useDatabase . UrlFilename () )
407403 useDatabase .Extract ()
408404 }
409405
410- output .Infof ("Bringing database online" )
411- useDatabase .BringOnline (c .sql .Query , userName , password )
406+ output .Infof ("Bringing database %q online" , useDatabase . DatabaseName () )
407+ useDatabase .BringOnline (c .sql .Query , contextOptions . Username , contextOptions . Password )
412408 }
413409
414410 if c .openTool == "" {
415411 hints := [][]string {}
416412
417- // TODO: sqlcmd open ads only support on Windows right now, add Mac support
413+ // TODO: sqlcmd open ads only support on Windows/Mac right now, add Linux support
418414 if runtime .GOOS == "windows" || runtime .GOOS == "darwin" {
419415 hints = append (hints , []string {"Open in Azure Data Studio" , "sqlcmd open ads" })
420416 }
@@ -452,10 +448,10 @@ func (c *MssqlBase) createContainer(imageName string, contextName string) {
452448 user := & sqlconfig.User {
453449 AuthenticationType : "basic" ,
454450 BasicAuth : & sqlconfig.BasicAuthDetails {
455- Username : userName ,
451+ Username : contextOptions . Username ,
456452 PasswordEncryption : c .passwordEncryption ,
457- Password : secret .Encode (password , c .passwordEncryption )},
458- Name : userName }
453+ Password : secret .Encode (contextOptions . Password , c .passwordEncryption )},
454+ Name : contextOptions . Username }
459455
460456 ads .PersistCredentialForAds (endpoint .EndpointDetails .Address , endpoint , user )
461457
@@ -466,7 +462,7 @@ func (c *MssqlBase) createContainer(imageName string, contextName string) {
466462 c .port ))}
467463
468464 args = append (args , fmt .Sprintf ("--user=%s" ,
469- strings .Replace (userName , `"` , `\"` , - 1 )))
465+ strings .Replace (contextOptions . Username , `"` , `\"` , - 1 )))
470466
471467 tool := tools .NewTool ("ads" )
472468 if ! tool .IsInstalled () {
@@ -478,7 +474,10 @@ func (c *MssqlBase) createContainer(imageName string, contextName string) {
478474 }
479475}
480476
481- func (c * MssqlBase ) verifyUseSourceFileExists (useDatabase ingest.Ingest , controller * container.Controller , output * output.Output ) ingest.Ingest {
477+ func (c * MssqlBase ) verifyUseSourceFileExists (
478+ controller * container.Controller ,
479+ output * output.Output ,
480+ ) (useDatabase ingest.Ingest ) {
482481 useDatabase = ingest .NewIngest (c .useDatabaseUrl , controller , ingest.IngestOptions {
483482 Mechanism : c .useMechanism ,
484483 })
@@ -487,44 +486,52 @@ func (c *MssqlBase) verifyUseSourceFileExists(useDatabase ingest.Ingest, control
487486 output .FatalfWithHints (
488487 []string {
489488 fmt .Sprintf (
490- "--using must be a path to a file with a %q extension" ,
489+ "--use must be a path to a file with a %q extension" ,
491490 ingest .ValidFileExtensions (),
492491 ),
493492 },
494- "%q is not a valid file extension for --using flag" , useDatabase .UserProvidedFileExt ())
493+ "%q is not a valid file extension for --use flag" , useDatabase .UserProvidedFileExt ())
495494 }
496495
497496 if useDatabase .IsRemoteUrl () && ! useDatabase .IsValidScheme () {
498497 output .FatalfWithHints (
499498 []string {
500499 fmt .Sprintf (
501- "--using URL must one of %q" ,
500+ "--use URL must one of %q" ,
502501 strings .Join (useDatabase .ValidSchemes (), ", " ),
503502 ),
504503 },
505- "%q is not a valid URL for --using flag" , c .useDatabaseUrl )
504+ "%q is not a valid URL for --use flag" , c .useDatabaseUrl )
506505 }
507506
508507 if ! useDatabase .SourceFileExists () {
509508 output .FatalfWithHints (
510509 []string {fmt .Sprintf ("File does not exist at URL %q" , c .useDatabaseUrl )},
511510 "Unable to download file" )
512511 }
513- return useDatabase
512+ return
514513}
515514
516- // createNonSaUser creates a user (non-sa) and assigns the sysadmin role
515+ // createUser creates a user (non-sa) and assigns the sysadmin role
517516// to the user. It also creates a default database with the provided name
518517// and assigns the default database to the user. Finally, it disables
519518// the sa account and rotates the sa password for security reasons.
520- func (c * MssqlBase ) createNonSaUser (
519+ func (c * MssqlBase ) createUser (
521520 userName string ,
522521 password string ,
523522) {
523+ const createLogin = `CREATE LOGIN [%s]
524+ WITH PASSWORD=N'%s',
525+ DEFAULT_DATABASE=[%s],
526+ CHECK_EXPIRATION=OFF,
527+ CHECK_POLICY=OFF`
528+ const addSrvRoleMember = `EXEC master..sp_addsrvrolemember
529+ @loginame = N'%s',
530+ @rolename = N'sysadmin'`
531+
524532 output := c .Cmd .Output ()
525533
526534 defaultDatabase := "master"
527-
528535 if c .defaultDatabase != "" {
529536 defaultDatabase = c .defaultDatabase
530537
@@ -533,15 +540,6 @@ func (c *MssqlBase) createNonSaUser(
533540 c .sql .Query (fmt .Sprintf ("CREATE DATABASE [%s]" , defaultDatabase ))
534541 }
535542
536- const createLogin = `CREATE LOGIN [%s]
537- WITH PASSWORD=N'%s',
538- DEFAULT_DATABASE=[%s],
539- CHECK_EXPIRATION=OFF,
540- CHECK_POLICY=OFF`
541- const addSrvRoleMember = `EXEC master..sp_addsrvrolemember
542- @loginame = N'%s',
543- @rolename = N'sysadmin'`
544-
545543 c .sql .Query (fmt .Sprintf (createLogin , userName , password , defaultDatabase ))
546544 c .sql .Query (fmt .Sprintf (addSrvRoleMember , userName ))
547545
0 commit comments