github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/cloudconfig/cloudinit/progress.go (about)

     1  // Copyright 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package cloudinit
     5  
     6  import (
     7  	"fmt"
     8  
     9  	"github.com/juju/utils"
    10  )
    11  
    12  // progressFdEnvVar is the name of the environment variable set for
    13  // the duration of the cloud-init script, identifying the file
    14  // descriptor to which progress is logged. This is necessary so that
    15  // we can redirect all non-progress related stderr away for interactive
    16  // sessions (bootstrap, manual add-machine).
    17  const progressFdEnvVar = "JUJU_PROGRESS_FD"
    18  
    19  // InitProgressCmd will return a command to initialise progress
    20  // reporting, sending messages to stderr. If LogProgressCmd is
    21  // used in a script, InitProgressCmd MUST be executed beforehand.
    22  //
    23  // The returned commands are idempotent; this is important, to
    24  // allow a script to be embedded in another with stderr redirected,
    25  // in which case InitProgressCmd must precede the redirection.
    26  func InitProgressCmd() string {
    27  	// This command may be run by either bash or /bin/sh, the
    28  	// latter of which does not support named file descriptors.
    29  	// When running under /bin/sh we don't care about progress
    30  	// logging, so we can allow it to go to FD 2.
    31  	return fmt.Sprintf(
    32  		`test -n "$%s" || `+
    33  			`(exec {%s}>&2) 2>/dev/null && exec {%s}>&2 || `+
    34  			`%s=2`,
    35  		progressFdEnvVar,
    36  		progressFdEnvVar,
    37  		progressFdEnvVar,
    38  		progressFdEnvVar,
    39  	)
    40  }
    41  
    42  // LogProgressCmd will return a command to log the specified progress
    43  // message to stderr; the resultant command should be added to the
    44  // configuration as a runcmd or bootcmd as appropriate.
    45  //
    46  // If there are any uses of LogProgressCmd in a configuration, the
    47  // configuration MUST precede the command with the result of
    48  // InitProgressCmd.
    49  func LogProgressCmd(format string, args ...interface{}) string {
    50  	msg := utils.ShQuote(fmt.Sprintf(format, args...))
    51  	return fmt.Sprintf("echo %s >&$%s", msg, progressFdEnvVar)
    52  }