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

package application

import (
	"archive/zip"
	"fmt"
	"os"
	"path/filepath"
	"strings"

	"github.com/juju/cmd"
	"github.com/juju/errors"
	"gopkg.in/juju/charm.v6-unstable"
	charmresource "gopkg.in/juju/charm.v6-unstable/resource"
	"gopkg.in/juju/charmrepo.v2-unstable"
	csclientparams "gopkg.in/juju/charmrepo.v2-unstable/csclient/params"
	"gopkg.in/juju/names.v2"
	"gopkg.in/macaroon-bakery.v1/httpbakery"
	"gopkg.in/macaroon.v1"
	"launchpad.net/gnuflag"

	"github.com/juju/juju/api"
	apiannotations "github.com/juju/juju/api/annotations"
	"github.com/juju/juju/api/application"
	"github.com/juju/juju/charmstore"
	"github.com/juju/juju/cmd/juju/block"
	"github.com/juju/juju/cmd/modelcmd"
	"github.com/juju/juju/constraints"
	"github.com/juju/juju/environs/config"
	"github.com/juju/juju/instance"
	"github.com/juju/juju/resource/resourceadapters"
	"github.com/juju/juju/storage"
)

var planURL = "https://api.jujucharms.com/omnibus/v2"

// NewDeployCommand returns a command to deploy services.
func NewDeployCommand() cmd.Command {
	return modelcmd.Wrap(&DeployCommand{
		Steps: []DeployStep{
			&RegisterMeteredCharm{
				RegisterURL: planURL + "/plan/authorize",
				QueryURL:    planURL + "/charm",
			},
		}})
}

type DeployCommand struct {
	modelcmd.ModelCommandBase
	UnitCommandBase
	// CharmOrBundle is either a charm URL, a path where a charm can be found,
	// or a bundle name.
	CharmOrBundle string

	// Channel holds the charmstore channel to use when obtaining
	// the charm to be deployed.
	Channel csclientparams.Channel

	Series string

	// Force is used to allow a charm to be deployed onto a machine
	// running an unsupported series.
	Force bool

	ApplicationName string
	Config          cmd.FileVar
	Constraints     constraints.Value
	BindToSpaces    string

	// TODO(axw) move this to UnitCommandBase once we support --storage
	// on add-unit too.
	//
	// Storage is a map of storage constraints, keyed on the storage name
	// defined in charm storage metadata.
	Storage map[string]storage.Constraints

	// BundleStorage maps application names to maps of storage constraints keyed on
	// the storage name defined in that application's charm storage metadata.
	BundleStorage map[string]map[string]storage.Constraints

	// Resources is a map of resource name to filename to be uploaded on deploy.
	Resources map[string]string

	Bindings map[string]string
	Steps    []DeployStep

	flagSet *gnuflag.FlagSet
}

const deployDoc = `
<charm or bundle> can be a charm/bundle URL, or an unambiguously condensed
form of it; assuming a current series of "trusty", the following forms will be
accepted:

For cs:trusty/mysql
  mysql
  trusty/mysql

For cs:~user/trusty/mysql
  cs:~user/mysql

For cs:bundle/mediawiki-single
  mediawiki-single
  bundle/mediawiki-single

The current series for charms is determined first by the default-series model
setting, followed by the preferred series for the charm in the charm store.

In these cases, a versioned charm URL will be expanded as expected (for example,
mysql-33 becomes cs:precise/mysql-33).

Charms may also be deployed from a user specified path. In this case, the
path to the charm is specified along with an optional series.

   juju deploy /path/to/charm --series trusty

If series is not specified, the charm's default series is used. The default series
for a charm is the first one specified in the charm metadata. If the specified series
is not supported by the charm, this results in an error, unless --force is used.

   juju deploy /path/to/charm --series wily --force

Local bundles are specified with a direct path to a bundle.yaml file.
For example:

  juju deploy /path/to/bundle/openstack/bundle.yaml

<application name>, if omitted, will be derived from <charm name>.

Constraints can be specified when using deploy by specifying the --constraints
flag.  When used with deploy, application-specific constraints are set so that later
machines provisioned with add-unit will use the same constraints (unless changed
by set-constraints).

Resources may be uploaded at deploy time by specifying the --resource flag.
Following the resource flag should be name=filepath pair.  This flag may be
repeated more than once to upload more than one resource.

  juju deploy foo --resource bar=/some/file.tgz --resource baz=./docs/cfg.xml

Where bar and baz are resources named in the metadata for the foo charm.

Charms can be deployed to a specific machine using the --to argument.

In more complex scenarios, Juju's network spaces are used to partition the cloud
networking layer into sets of subnets. Instances hosting units inside the
same space can communicate with each other without any firewalls. Traffic
crossing space boundaries could be subject to firewall and access restrictions.
Using spaces as deployment targets, rather than their individual subnets allows
Juju to perform automatic distribution of units across availability zones to
support high availability for applications. Spaces help isolate applications and their
units, both for security purposes and to manage both traffic segregation and
congestion.

When deploying an application or adding machines, the "spaces" constraint can be
used to define a comma-delimited list of required and forbidden spaces
(the latter prefixed with "^", similar to the "tags" constraint).


Examples:
   juju deploy mysql --to 23       (deploy to machine 23)
   juju deploy mysql --to 24/lxd/3 (deploy to lxd container 3 on host machine 24)
   juju deploy mysql --to lxd:25   (deploy to a new lxd container on host machine 25)
   juju deploy mysql --to lxd      (deploy to a new lxd container on a new machine)

   juju deploy mysql -n 5 --constraints mem=8G
   (deploy 5 instances of mysql with at least 8 GB of RAM each)

   juju deploy haproxy -n 2 --constraints spaces=dmz,^cms,^database
   (deploy 2 instances of haproxy on cloud instances being part of the dmz
    space but not of the cmd and the database space)

See Also:
   juju help spaces
   juju help constraints
   juju help set-constraints
   juju help get-constraints
`

// DeployStep is an action that needs to be taken during charm deployment.
type DeployStep interface {<commit_msg>Improve deploy command documentation<commit_after>// Copyright 2012, 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package application

import (
	"archive/zip"
	"fmt"
	"os"
	"path/filepath"
	"strings"

	"github.com/juju/cmd"
	"github.com/juju/errors"
	"gopkg.in/juju/charm.v6-unstable"
	charmresource "gopkg.in/juju/charm.v6-unstable/resource"
	"gopkg.in/juju/charmrepo.v2-unstable"
	csclientparams "gopkg.in/juju/charmrepo.v2-unstable/csclient/params"
	"gopkg.in/juju/names.v2"
	"gopkg.in/macaroon-bakery.v1/httpbakery"
	"gopkg.in/macaroon.v1"
	"launchpad.net/gnuflag"

	"github.com/juju/juju/api"
	apiannotations "github.com/juju/juju/api/annotations"
	"github.com/juju/juju/api/application"
	"github.com/juju/juju/charmstore"
	"github.com/juju/juju/cmd/juju/block"
	"github.com/juju/juju/cmd/modelcmd"
	"github.com/juju/juju/constraints"
	"github.com/juju/juju/environs/config"
	"github.com/juju/juju/instance"
	"github.com/juju/juju/resource/resourceadapters"
	"github.com/juju/juju/storage"
)

var planURL = "https://api.jujucharms.com/omnibus/v2"

// NewDeployCommand returns a command to deploy services.
func NewDeployCommand() cmd.Command {
	return modelcmd.Wrap(&DeployCommand{
		Steps: []DeployStep{
			&RegisterMeteredCharm{
				RegisterURL: planURL + "/plan/authorize",
				QueryURL:    planURL + "/charm",
			},
		}})
}

type DeployCommand struct {
	modelcmd.ModelCommandBase
	UnitCommandBase
	// CharmOrBundle is either a charm URL, a path where a charm can be found,
	// or a bundle name.
	CharmOrBundle string

	// Channel holds the charmstore channel to use when obtaining
	// the charm to be deployed.
	Channel csclientparams.Channel

	Series string

	// Force is used to allow a charm to be deployed onto a machine
	// running an unsupported series.
	Force bool

	ApplicationName string
	Config          cmd.FileVar
	Constraints     constraints.Value
	BindToSpaces    string

	// TODO(axw) move this to UnitCommandBase once we support --storage
	// on add-unit too.
	//
	// Storage is a map of storage constraints, keyed on the storage name
	// defined in charm storage metadata.
	Storage map[string]storage.Constraints

	// BundleStorage maps application names to maps of storage constraints keyed on
	// the storage name defined in that application's charm storage metadata.
	BundleStorage map[string]map[string]storage.Constraints

	// Resources is a map of resource name to filename to be uploaded on deploy.
	Resources map[string]string

	Bindings map[string]string
	Steps    []DeployStep

	flagSet *gnuflag.FlagSet
}

const deployDoc = `
<charm or bundle> can be a charm/bundle URL, or an unambiguously condensed
form of it; assuming a current series of "trusty", the following forms will be
accepted:

For cs:trusty/mysql
  mysql
  trusty/mysql

For cs:~user/trusty/mysql
  ~user/mysql

For cs:bundle/mediawiki-single
  mediawiki-single
  bundle/mediawiki-single

The current series for charms is determined first by the 'default-series' model
setting, followed by the preferred series for the charm in the charm store.

In these cases, a versioned charm URL will be expanded as expected (for
example, mysql-33 becomes cs:precise/mysql-33).

Charms may also be deployed from a user specified path. In this case, the path
to the charm is specified along with an optional series.

  juju deploy /path/to/charm --series trusty

If '--series' is not specified, the charm's default series is used. The default
series for a charm is the first one specified in the charm metadata. If the
specified series is not supported by the charm, this results in an error,
unless '--force' is used.

  juju deploy /path/to/charm --series wily --force

Local bundles are specified with a direct path to a bundle.yaml file.
For example:

  juju deploy /path/to/bundle/openstack/bundle.yaml

If an 'application name' is not provided, the application name used is the
'charm or bundle' name.

Constraints can be specified by specifying the '--constraints' option. If the
application is later scaled out with ` + "`juju add-unit`" + `, provisioned machines
will use the same constraints (unless changed by ` + "`juju set-constraints`" + `).

Resources may be uploaded by specifying the '--resource' option followed by a
name=filepath pair. This option may be repeated more than once to upload more
than one resource.

  juju deploy foo --resource bar=/some/file.tgz --resource baz=./docs/cfg.xml

Where 'bar' and 'baz' are resources named in the metadata for the 'foo' charm.

When using a placement directive to deploy to an existing machine or container
('--to' option), the ` + "`juju status`" + ` command should be used for guidance. A few
placement directives are provider-dependent (e.g.: 'zone').

In more complex scenarios, Juju's network spaces are used to partition the
cloud networking layer into sets of subnets. Instances hosting units inside the
same space can communicate with each other without any firewalls. Traffic
crossing space boundaries could be subject to firewall and access restrictions.
Using spaces as deployment targets, rather than their individual subnets,
allows Juju to perform automatic distribution of units across availability zones
to support high availability for applications. Spaces help isolate applications
and their units, both for security purposes and to manage both traffic
segregation and congestion.

When deploying an application or adding machines, the 'spaces' constraint can
be used to define a comma-delimited list of required and forbidden spaces (the
latter prefixed with "^", similar to the 'tags' constraint).


Examples:
    juju deploy mysql --to 23       (deploy to machine 23)
    juju deploy mysql --to 24/lxd/3 (deploy to lxd container 3 on machine 24)
    juju deploy mysql --to lxd:25   (deploy to a new lxd container on machine 25)
    juju deploy mysql --to lxd      (deploy to a new lxd container on a new machine)

    juju deploy mysql --to zone=us-east-1a
    (provider-dependent; deploy to a specific AZ)

    juju deploy mysql --to host.maas
    (deploy to a specific MAAS node)

    juju deploy mysql -n 5 --constraints mem=8G
    (deploy 5 units to machines with at least 8 GB of memory)

    juju deploy haproxy -n 2 --constraints spaces=dmz,^cms,^database
    (deploy 2 units to machines that are part of the 'dmz' space but not of the
    'cmd' or the 'database' spaces)

See also:
    spaces
    constraints
    add-unit
    set-config
    get-config
    set-constraints
    get-constraints
`

// DeployStep is an action that needs to be taken during charm deployment.
type DeployStep interface {
{'fraction_non_alphanumeric': 0.07580220120911486, 'fraction_numerical': 0.006433111145558828, 'mean_word_length': 3.878260869565217, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 7, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 2}, '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': '3926223', 'n_tokens_mistral': 4078, 'n_tokens_neox': 3774, 'n_words': 1565}