2016-12-18 05:21:29 +00:00
package cli
import (
2017-02-06 05:29:34 +00:00
"time"
2016-12-18 05:21:29 +00:00
"github.com/portainer/portainer"
"os"
2017-10-26 09:17:45 +00:00
"path/filepath"
2016-12-18 05:21:29 +00:00
"strings"
2016-12-25 20:34:02 +00:00
"gopkg.in/alecthomas/kingpin.v2"
2016-12-18 05:21:29 +00:00
)
// Service implements the CLIService interface
type Service struct { }
const (
2018-07-20 09:02:06 +00:00
errInvalidEndpointProtocol = portainer . Error ( "Invalid endpoint protocol: Portainer only supports unix://, npipe:// or tcp://" )
errSocketOrNamedPipeNotFound = portainer . Error ( "Unable to locate Unix socket or named pipe" )
2017-09-25 16:13:56 +00:00
errEndpointsFileNotFound = portainer . Error ( "Unable to locate external endpoints file" )
2018-07-03 18:31:02 +00:00
errTemplateFileNotFound = portainer . Error ( "Unable to locate template file on disk" )
2017-09-25 16:13:56 +00:00
errInvalidSyncInterval = portainer . Error ( "Invalid synchronization interval" )
2018-07-11 08:39:20 +00:00
errInvalidSnapshotInterval = portainer . Error ( "Invalid snapshot interval" )
2017-09-25 16:13:56 +00:00
errEndpointExcludeExternal = portainer . Error ( "Cannot use the -H flag mutually with --external-endpoints" )
errNoAuthExcludeAdminPassword = portainer . Error ( "Cannot use --no-auth with --admin-password or --admin-password-file" )
errAdminPassExcludeAdminPassFile = portainer . Error ( "Cannot use --admin-password with --admin-password-file" )
2016-12-18 05:21:29 +00:00
)
// ParseFlags parse the CLI flags and return a portainer.Flags struct
func ( * Service ) ParseFlags ( version string ) ( * portainer . CLIFlags , error ) {
kingpin . Version ( version )
flags := & portainer . CLIFlags {
2017-02-06 05:29:34 +00:00
Addr : kingpin . Flag ( "bind" , "Address and port to serve Portainer" ) . Default ( defaultBindAddress ) . Short ( 'p' ) . String ( ) ,
Assets : kingpin . Flag ( "assets" , "Path to the assets" ) . Default ( defaultAssetsDirectory ) . Short ( 'a' ) . String ( ) ,
Data : kingpin . Flag ( "data" , "Path to the folder where the data is stored" ) . Default ( defaultDataDirectory ) . Short ( 'd' ) . String ( ) ,
2018-05-19 14:25:11 +00:00
EndpointURL : kingpin . Flag ( "host" , "Endpoint URL" ) . Short ( 'H' ) . String ( ) ,
2018-01-15 18:34:07 +00:00
ExternalEndpoints : kingpin . Flag ( "external-endpoints" , "Path to a file defining available endpoints" ) . String ( ) ,
2017-02-06 05:29:34 +00:00
NoAuth : kingpin . Flag ( "no-auth" , "Disable authentication" ) . Default ( defaultNoAuth ) . Bool ( ) ,
2017-09-10 08:00:48 +00:00
NoAnalytics : kingpin . Flag ( "no-analytics" , "Disable Analytics in app" ) . Default ( defaultNoAnalytics ) . Bool ( ) ,
2018-05-19 14:25:11 +00:00
TLS : kingpin . Flag ( "tlsverify" , "TLS support" ) . Default ( defaultTLS ) . Bool ( ) ,
2018-05-06 07:15:57 +00:00
TLSSkipVerify : kingpin . Flag ( "tlsskipverify" , "Disable TLS server verification" ) . Default ( defaultTLSSkipVerify ) . Bool ( ) ,
2017-02-06 05:29:34 +00:00
TLSCacert : kingpin . Flag ( "tlscacert" , "Path to the CA" ) . Default ( defaultTLSCACertPath ) . String ( ) ,
TLSCert : kingpin . Flag ( "tlscert" , "Path to the TLS certificate file" ) . Default ( defaultTLSCertPath ) . String ( ) ,
TLSKey : kingpin . Flag ( "tlskey" , "Path to the TLS key" ) . Default ( defaultTLSKeyPath ) . String ( ) ,
2017-04-25 09:51:22 +00:00
SSL : kingpin . Flag ( "ssl" , "Secure Portainer instance using SSL" ) . Default ( defaultSSL ) . Bool ( ) ,
SSLCert : kingpin . Flag ( "sslcert" , "Path to the SSL certificate used to secure the Portainer instance" ) . Default ( defaultSSLCertPath ) . String ( ) ,
SSLKey : kingpin . Flag ( "sslkey" , "Path to the SSL key used to secure the Portainer instance" ) . Default ( defaultSSLKeyPath ) . String ( ) ,
2018-01-15 18:34:07 +00:00
SyncInterval : kingpin . Flag ( "sync-interval" , "Duration between each synchronization via the external endpoints source" ) . Default ( defaultSyncInterval ) . String ( ) ,
2018-07-11 08:39:20 +00:00
Snapshot : kingpin . Flag ( "snapshot" , "Start a background job to create endpoint snapshots" ) . Default ( defaultSnapshot ) . Bool ( ) ,
SnapshotInterval : kingpin . Flag ( "snapshot-interval" , "Duration between each endpoint snapshot job" ) . Default ( defaultSnapshotInterval ) . String ( ) ,
2017-04-16 07:54:51 +00:00
AdminPassword : kingpin . Flag ( "admin-password" , "Hashed admin password" ) . String ( ) ,
2017-09-25 16:13:56 +00:00
AdminPasswordFile : kingpin . Flag ( "admin-password-file" , "Path to the file containing the password for the admin user" ) . String ( ) ,
2018-01-24 20:58:58 +00:00
Labels : pairs ( kingpin . Flag ( "hide-label" , "Hide containers with a specific label in the UI" ) . Short ( 'l' ) ) ,
Logo : kingpin . Flag ( "logo" , "URL for the logo displayed in the UI" ) . String ( ) ,
2018-07-03 18:31:02 +00:00
Templates : kingpin . Flag ( "templates" , "URL to the templates definitions." ) . Short ( 't' ) . String ( ) ,
TemplateFile : kingpin . Flag ( "template-file" , "Path to the templates (app) definitions on the filesystem" ) . Default ( defaultTemplateFile ) . String ( ) ,
2016-12-18 05:21:29 +00:00
}
kingpin . Parse ( )
2017-10-26 09:17:45 +00:00
if ! filepath . IsAbs ( * flags . Assets ) {
ex , err := os . Executable ( )
if err != nil {
panic ( err )
}
* flags . Assets = filepath . Join ( filepath . Dir ( ex ) , * flags . Assets )
}
2016-12-18 05:21:29 +00:00
return flags , nil
}
// ValidateFlags validates the values of the flags.
func ( * Service ) ValidateFlags ( flags * portainer . CLIFlags ) error {
2017-02-07 03:26:12 +00:00
2018-05-19 14:25:11 +00:00
if * flags . EndpointURL != "" && * flags . ExternalEndpoints != "" {
2017-02-07 03:26:12 +00:00
return errEndpointExcludeExternal
}
2018-07-03 18:31:02 +00:00
err := validateTemplateFile ( * flags . TemplateFile )
if err != nil {
return err
}
err = validateEndpointURL ( * flags . EndpointURL )
2017-02-07 03:26:12 +00:00
if err != nil {
return err
}
err = validateExternalEndpoints ( * flags . ExternalEndpoints )
if err != nil {
return err
}
err = validateSyncInterval ( * flags . SyncInterval )
if err != nil {
return err
}
2018-07-11 08:39:20 +00:00
err = validateSnapshotInterval ( * flags . SnapshotInterval )
if err != nil {
return err
}
2017-09-25 16:13:56 +00:00
if * flags . NoAuth && ( * flags . AdminPassword != "" || * flags . AdminPasswordFile != "" ) {
2017-05-23 19:01:19 +00:00
return errNoAuthExcludeAdminPassword
}
2017-04-16 07:54:51 +00:00
2017-09-25 16:13:56 +00:00
if * flags . AdminPassword != "" && * flags . AdminPasswordFile != "" {
return errAdminPassExcludeAdminPassFile
}
2017-02-07 03:26:12 +00:00
return nil
}
2018-05-19 14:25:11 +00:00
func validateEndpointURL ( endpointURL string ) error {
if endpointURL != "" {
2018-07-20 09:02:06 +00:00
if ! strings . HasPrefix ( endpointURL , "unix://" ) && ! strings . HasPrefix ( endpointURL , "tcp://" ) && ! strings . HasPrefix ( endpointURL , "npipe://" ) {
2017-04-16 07:54:51 +00:00
return errInvalidEndpointProtocol
2016-12-25 20:34:02 +00:00
}
2016-12-18 05:21:29 +00:00
2018-07-20 09:02:06 +00:00
if strings . HasPrefix ( endpointURL , "unix://" ) || strings . HasPrefix ( endpointURL , "npipe://" ) {
2018-05-19 14:25:11 +00:00
socketPath := strings . TrimPrefix ( endpointURL , "unix://" )
2018-07-20 09:02:06 +00:00
socketPath = strings . TrimPrefix ( socketPath , "npipe://" )
2016-12-25 20:34:02 +00:00
if _ , err := os . Stat ( socketPath ) ; err != nil {
if os . IsNotExist ( err ) {
2018-07-20 09:02:06 +00:00
return errSocketOrNamedPipeNotFound
2016-12-25 20:34:02 +00:00
}
return err
2016-12-18 05:21:29 +00:00
}
}
}
2017-02-07 03:26:12 +00:00
return nil
}
2016-12-18 05:21:29 +00:00
2017-02-07 03:26:12 +00:00
func validateExternalEndpoints ( externalEndpoints string ) error {
if externalEndpoints != "" {
if _ , err := os . Stat ( externalEndpoints ) ; err != nil {
2017-02-06 05:29:34 +00:00
if os . IsNotExist ( err ) {
return errEndpointsFileNotFound
}
return err
}
}
2017-02-07 03:26:12 +00:00
return nil
}
2017-02-06 05:29:34 +00:00
2018-07-03 18:31:02 +00:00
func validateTemplateFile ( templateFile string ) error {
if _ , err := os . Stat ( templateFile ) ; err != nil {
if os . IsNotExist ( err ) {
return errTemplateFileNotFound
}
return err
}
return nil
}
2017-02-07 03:26:12 +00:00
func validateSyncInterval ( syncInterval string ) error {
if syncInterval != defaultSyncInterval {
_ , err := time . ParseDuration ( syncInterval )
2017-02-06 05:29:34 +00:00
if err != nil {
return errInvalidSyncInterval
}
}
2016-12-18 05:21:29 +00:00
return nil
}
2018-07-11 08:39:20 +00:00
func validateSnapshotInterval ( snapshotInterval string ) error {
if snapshotInterval != defaultSnapshotInterval {
_ , err := time . ParseDuration ( snapshotInterval )
if err != nil {
return errInvalidSnapshotInterval
}
}
return nil
}