github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/service/snap/app.go (about) 1 // Copyright 2021 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package snap 5 6 import ( 7 "fmt" 8 9 "github.com/juju/errors" 10 ) 11 12 // ConfinementPolicy describes the confinement policy for installing a given 13 // snap application. 14 type ConfinementPolicy string 15 16 const ( 17 // StrictPolicy confined snaps run in complete isolation, up to a minimal 18 // access level that’s deemed always safe. 19 StrictPolicy ConfinementPolicy = "strict" 20 // ClassicPolicy allows access to your system’s resources in much the same 21 // way traditional packages do 22 ClassicPolicy ConfinementPolicy = "classic" 23 // DevModePolicy is a special mode for snap creators and developers. 24 // A devmode snap runs as a strictly confined snap with full access to 25 // system resources, and produces debug output to identify unspecified 26 // interfaces. 27 DevModePolicy ConfinementPolicy = "devmode" 28 // JailModePolicy enforces the confinement model for a snap to ensure that 29 // the confinement is enforced. 30 JailModePolicy ConfinementPolicy = "jailmode" 31 ) 32 33 // Validate validates a given confinement policy to ensure it matches the ones we 34 // expect. 35 func (p ConfinementPolicy) Validate() error { 36 switch p { 37 case StrictPolicy, ClassicPolicy, DevModePolicy, JailModePolicy: 38 return nil 39 } 40 return errors.NotValidf("%s confinement", p) 41 } 42 43 // String representation of the confinement policy. 44 func (p ConfinementPolicy) String() string { 45 return string(p) 46 } 47 48 // App is a wrapper around a single snap 49 type App struct { 50 name string 51 confinementPolicy ConfinementPolicy 52 channel string 53 backgroundServices []BackgroundService 54 prerequisites []Installable 55 } 56 57 // NewNamedApp creates a new application from a given name. 58 func NewNamedApp(name string) *App { 59 return &App{ 60 name: name, 61 } 62 } 63 64 // NewApp creates a application along with it's dependencies. 65 func NewApp(name string, channel string, policy ConfinementPolicy, services []BackgroundService, prerequisites []Installable) *App { 66 return &App{ 67 name: name, 68 channel: channel, 69 confinementPolicy: policy, 70 backgroundServices: services, 71 prerequisites: prerequisites, 72 } 73 } 74 75 // Validate will validate a given application for any potential issues. 76 func (a *App) Validate() error { 77 if !snapNameRe.MatchString(a.name) { 78 return errors.NotValidf("application %v", a.name) 79 } 80 81 if a.confinementPolicy != "" { 82 if err := a.confinementPolicy.Validate(); err != nil { 83 return errors.Trace(err) 84 } 85 } 86 87 for _, backgroundService := range a.backgroundServices { 88 err := backgroundService.Validate() 89 if err != nil { 90 return errors.Trace(err) 91 } 92 } 93 94 for _, prerequisite := range a.prerequisites { 95 err := prerequisite.Validate() 96 if err != nil { 97 return errors.Trace(err) 98 } 99 } 100 101 return nil 102 } 103 104 // StartCommands returns a list if shell commands that should be executed (in order) 105 // to start App and its background services. executeable is a path to the snap 106 // executable. If the app has prerequisite applications defined, then take care to call 107 // StartCommands on those apps also. 108 func (a *App) StartCommands(executable string) []string { 109 if len(a.backgroundServices) == 0 { 110 return []string{fmt.Sprintf("%s start %s", executable, a.name)} 111 } 112 113 commands := make([]string, 0, len(a.backgroundServices)) 114 for _, backgroundService := range a.backgroundServices { 115 enableFlag := "" 116 if backgroundService.EnableAtStartup { 117 enableFlag = " --enable " 118 } 119 120 command := fmt.Sprintf("%s start %s %s.%s", executable, enableFlag, a.name, backgroundService.Name) 121 commands = append(commands, command) 122 } 123 return commands 124 } 125 126 // Install returns a way to install one application with all it's settings. 127 func (a *App) Install() []string { 128 args := []string{ 129 "install", 130 } 131 if a.channel != "" { 132 args = append(args, fmt.Sprintf("--channel=%s", a.channel)) 133 } 134 if a.confinementPolicy != "" { 135 args = append(args, fmt.Sprintf("--%s", a.confinementPolicy)) 136 } 137 return append(args, a.name) 138 } 139 140 // Prerequisites defines a list of all the Prerequisites required before the 141 // application also needs to be installed. 142 func (a *App) Prerequisites() []Installable { 143 return a.prerequisites 144 } 145 146 // BackgroundServices returns a list of background services that are 147 // required to be installed for the main application to run. 148 func (a *App) BackgroundServices() []BackgroundService { 149 return a.backgroundServices 150 } 151 152 // Name returns the name of the application 153 func (a *App) Name() string { 154 return a.name 155 }