github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/cmd/juju/application/series_selector.go (about) 1 // Copyright 2016 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package application 5 6 import ( 7 "github.com/juju/utils/series" 8 "gopkg.in/juju/charm.v6-unstable" 9 ) 10 11 const ( 12 msgUserRequestedSeries = "with the user specified series %q" 13 msgBundleSeries = "with the series %q defined by the bundle" 14 msgDefaultCharmSeries = "with the default charm metadata series %q" 15 msgDefaultModelSeries = "with the configured model default series %q" 16 msgLatestLTSSeries = "with the latest LTS series %q" 17 ) 18 19 type modelConfig interface { 20 DefaultSeries() (string, bool) 21 } 22 23 // seriesSelector is a helper type that determines what series the charm should 24 // be deployed to. 25 type seriesSelector struct { 26 // seriesFlag is the series passed to the --series flag on the command line. 27 seriesFlag string 28 // charmURLSeries is the series specified as part of the charm URL, i.e. 29 // cs:trusty/ubuntu. 30 charmURLSeries string 31 // conf is the configuration for the model we're deploying to. 32 conf modelConfig 33 // supportedSeries is the list of series the charm supports. 34 supportedSeries []string 35 // force indicates the user explicitly wants to deploy to a requested 36 // series, regardless of whether the charm says it supports that series. 37 force bool 38 // from bundle specifies the deploy request comes from a bundle spec. 39 fromBundle bool 40 } 41 42 // charmSeries determines what series to use with a charm. 43 // Order of preference is: 44 // - user requested with --series or defined by bundle when deploying 45 // - user requested in charm's url (e.g. juju deploy precise/ubuntu) 46 // - model default (if it matches supported series) 47 // - default from charm metadata supported series / series in url 48 // - default LTS 49 func (s seriesSelector) charmSeries() (selectedSeries string, err error) { 50 // User has requested a series with --series. 51 if s.seriesFlag != "" { 52 return s.userRequested(s.seriesFlag) 53 } 54 55 // User specified a series in the charm URL, e.g. 56 // juju deploy precise/ubuntu. 57 if s.charmURLSeries != "" { 58 return s.userRequested(s.charmURLSeries) 59 } 60 61 // No series explicitly requested by the user. 62 // Use model default series, if explicitly set and supported by the charm. 63 if defaultSeries, explicit := s.conf.DefaultSeries(); explicit { 64 if isSeriesSupported(defaultSeries, s.supportedSeries) { 65 logger.Infof(msgDefaultModelSeries, defaultSeries) 66 return defaultSeries, nil 67 } 68 } 69 70 // Use the charm's perferred series, if it has one. In a multi-series 71 // charm, the first series in the list is the preferred one. 72 if len(s.supportedSeries) > 0 { 73 logger.Infof(msgDefaultCharmSeries, s.supportedSeries[0]) 74 return s.supportedSeries[0], nil 75 } 76 77 // Charm hasn't specified a default (likely due to being a local charm 78 // deployed by path). Last chance, best we can do is default to LTS. 79 80 // At this point, because we have no idea what series the charm supports, 81 // *everything* requires --force. 82 if !s.force { 83 return "", s.unsupportedSeries(series.LatestLts()) 84 } 85 86 latestLTS := series.LatestLts() 87 logger.Infof(msgLatestLTSSeries, latestLTS) 88 return latestLTS, nil 89 } 90 91 // userRequested checks the series the user has requested, and returns it if it 92 // is supported, or if they used --force. 93 func (s seriesSelector) userRequested(series string) (selectedSeries string, err error) { 94 if !s.force && !isSeriesSupported(series, s.supportedSeries) { 95 return "", s.unsupportedSeries(series) 96 } 97 98 // either it's a supported series or the user used --force, so just 99 // give them what they asked for. 100 if s.fromBundle { 101 logger.Infof(msgBundleSeries, series) 102 return series, nil 103 } 104 logger.Infof(msgUserRequestedSeries, series) 105 return series, nil 106 } 107 108 func (s seriesSelector) unsupportedSeries(series string) error { 109 supp := s.supportedSeries 110 if len(supp) == 0 { 111 supp = []string{"<none defined>"} 112 } 113 return charm.NewUnsupportedSeriesError(series, supp) 114 }