<commit_before>// Copyright 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package manual

import (
	"encoding/base64"
	"fmt"
	"os"
	"strings"

	"launchpad.net/juju-core/agent"
	corecloudinit "launchpad.net/juju-core/cloudinit"
	"launchpad.net/juju-core/constraints"
	"launchpad.net/juju-core/environs"
	"launchpad.net/juju-core/environs/cloudinit"
	"launchpad.net/juju-core/environs/config"
	"launchpad.net/juju-core/provider"
	"launchpad.net/juju-core/state"
	"launchpad.net/juju-core/state/api"
	"launchpad.net/juju-core/tools"
	"launchpad.net/juju-core/utils"
)

type provisionMachineAgentArgs struct {
	host          string
	dataDir       string
	bootstrap     bool
	environConfig *config.Config
	machineId     string
	nonce         string
	stateFileURL  string
	stateInfo     *state.Info
	apiInfo       *api.Info
	tools         *tools.Tools

	// agentEnv is an optional map of
	// arbitrary key/value pairs to pass
	// into the machine agent.
	agentEnv map[string]string
}

// provisionMachineAgent connects to a machine over SSH,
// copies across the tools, and installs a machine agent.
func provisionMachineAgent(args provisionMachineAgentArgs) error {
	logger.Infof("Provisioning machine agent on %s", args.host)
	script, err := provisionMachineAgentScript(args)
	if err != nil {
		return err
	}
	scriptBase64 := base64.StdEncoding.EncodeToString([]byte(script))
	script = fmt.Sprintf(`F=$(mktemp); echo %s | base64 -d > $F; . $F`, scriptBase64)
	cmd := sshCommand(
		args.host,
		fmt.Sprintf("sudo bash -c '%s'", script),
		allocateTTY,
	)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	cmd.Stdin = os.Stdin
	return cmd.Run()
}

// provisionMachineAgentScript generates the script necessary
// to install a machine agent on the specified host.
func provisionMachineAgentScript(args provisionMachineAgentArgs) (string, error) {
	// We generate a cloud-init config, which we'll then pull the runcmds
	// and prerequisite packages out of. Rather than generating a cloud-config,
	// we'll just generate a shell script.
	var mcfg *cloudinit.MachineConfig
	if args.bootstrap {
		mcfg = environs.NewBootstrapMachineConfig(args.machineId, args.nonce)
	} else {
		mcfg = environs.NewMachineConfig(args.machineId, args.nonce, args.stateInfo, args.apiInfo)
	}
	if args.dataDir != "" {
		mcfg.DataDir = args.dataDir
	}
	mcfg.Tools = args.tools
	err := environs.FinishMachineConfig(mcfg, args.environConfig, constraints.Value{})
	if err != nil {
		return "", err
	}
	mcfg.AgentEnvironment[agent.ProviderType] = provider.Null
	for k, v := range args.agentEnv {
		mcfg.AgentEnvironment[k] = v
	}
	cloudcfg := corecloudinit.New()
	if cloudcfg, err = cloudinit.Configure(mcfg, cloudcfg); err != nil {
		return "", err
	}

	// TODO(axw): 2013-08-23 bug 1215777
	// Carry out configuration for ssh-keys-per-user,<commit_msg>Fixup manual bootstrapping, also referencing the same tech-debt bug #1231313<commit_after>// Copyright 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package manual

import (
	"encoding/base64"
	"fmt"
	"os"
	"strings"

	"launchpad.net/juju-core/agent"
	corecloudinit "launchpad.net/juju-core/cloudinit"
	"launchpad.net/juju-core/constraints"
	"launchpad.net/juju-core/environs"
	"launchpad.net/juju-core/environs/cloudinit"
	"launchpad.net/juju-core/environs/config"
	"launchpad.net/juju-core/provider"
	"launchpad.net/juju-core/state"
	"launchpad.net/juju-core/state/api"
	"launchpad.net/juju-core/tools"
	"launchpad.net/juju-core/utils"
)

type provisionMachineAgentArgs struct {
	host          string
	dataDir       string
	bootstrap     bool
	environConfig *config.Config
	machineId     string
	nonce         string
	stateFileURL  string
	stateInfo     *state.Info
	apiInfo       *api.Info
	tools         *tools.Tools

	// agentEnv is an optional map of
	// arbitrary key/value pairs to pass
	// into the machine agent.
	agentEnv map[string]string
}

// provisionMachineAgent connects to a machine over SSH,
// copies across the tools, and installs a machine agent.
func provisionMachineAgent(args provisionMachineAgentArgs) error {
	logger.Infof("Provisioning machine agent on %s", args.host)
	script, err := provisionMachineAgentScript(args)
	if err != nil {
		return err
	}
	scriptBase64 := base64.StdEncoding.EncodeToString([]byte(script))
	script = fmt.Sprintf(`F=$(mktemp); echo %s | base64 -d > $F; . $F`, scriptBase64)
	cmd := sshCommand(
		args.host,
		fmt.Sprintf("sudo bash -c '%s'", script),
		allocateTTY,
	)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	cmd.Stdin = os.Stdin
	return cmd.Run()
}

// provisionMachineAgentScript generates the script necessary
// to install a machine agent on the specified host.
func provisionMachineAgentScript(args provisionMachineAgentArgs) (string, error) {
	// We generate a cloud-init config, which we'll then pull the runcmds
	// and prerequisite packages out of. Rather than generating a cloud-config,
	// we'll just generate a shell script.
	var mcfg *cloudinit.MachineConfig
	// TODO(jam): 2013-09-26 http://pad.lv/1231313
	// We should have a test about what the right value of
	// disableSSLHostnameVerification should be
	disableSSLHostnameVerification := false
	if args.bootstrap {
		mcfg = environs.NewBootstrapMachineConfig(args.machineId, args.nonce, disableSSLHostnameVerification)
	} else {
		mcfg = environs.NewMachineConfig(args.machineId, args.nonce, args.stateInfo, args.apiInfo, disableSSLHostnameVerification)
	}
	if args.dataDir != "" {
		mcfg.DataDir = args.dataDir
	}
	mcfg.Tools = args.tools
	err := environs.FinishMachineConfig(mcfg, args.environConfig, constraints.Value{})
	if err != nil {
		return "", err
	}
	mcfg.AgentEnvironment[agent.ProviderType] = provider.Null
	for k, v := range args.agentEnv {
		mcfg.AgentEnvironment[k] = v
	}
	cloudcfg := corecloudinit.New()
	if cloudcfg, err = cloudinit.Configure(mcfg, cloudcfg); err != nil {
		return "", err
	}

	// TODO(axw): 2013-08-23 bug 1215777
	// Carry out configuration for ssh-keys-per-user,
{'fraction_non_alphanumeric': 0.11243979405414382, 'fraction_numerical': 0.013619000166085369, 'mean_word_length': 3.9933665008291874, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1745965', 'n_tokens_mistral': 2152, 'n_tokens_neox': 1980, 'n_words': 507}