github.com/hugh712/snapd@v0.0.0-20200910133618-1a99902bd583/overlord/servicestate/service_control.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 3 /* 4 * Copyright (C) 2020 Canonical Ltd 5 * 6 * This program is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 3 as 8 * published by the Free Software Foundation. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 * 18 */ 19 20 package servicestate 21 22 import ( 23 "fmt" 24 25 "github.com/snapcore/snapd/overlord/snapstate" 26 "github.com/snapcore/snapd/overlord/state" 27 "github.com/snapcore/snapd/snap" 28 "github.com/snapcore/snapd/wrappers" 29 30 tomb "gopkg.in/tomb.v2" 31 ) 32 33 // ServiceAction encapsulates a single service-related action (such as starting, 34 // stopping or restarting) run against services of a given snap. The action is 35 // run for services listed in services attribute, or for all services of the 36 // snap if services list is empty. 37 // The names of services are app names (as defined in snap yaml). 38 type ServiceAction struct { 39 SnapName string `json:"snap-name"` 40 Action string `json:"action"` 41 ActionModifier string `json:"action-modifier,omitempty"` 42 Services []string `json:"services,omitempty"` 43 } 44 45 func (m *ServiceManager) doServiceControl(t *state.Task, _ *tomb.Tomb) error { 46 st := t.State() 47 st.Lock() 48 defer st.Unlock() 49 50 perfTimings := state.TimingsForTask(t) 51 defer perfTimings.Save(st) 52 53 var sc ServiceAction 54 err := t.Get("service-action", &sc) 55 if err != nil { 56 return fmt.Errorf("internal error: cannot get service-action: %v", err) 57 } 58 59 var snapst snapstate.SnapState 60 if err := snapstate.Get(st, sc.SnapName, &snapst); err != nil { 61 return err 62 } 63 info, err := snapst.CurrentInfo() 64 if err != nil { 65 return err 66 } 67 68 svcs := info.Services() 69 if len(svcs) == 0 { 70 return nil 71 } 72 73 var services []*snap.AppInfo 74 if len(sc.Services) == 0 { 75 // no services specified, take all services of the snap 76 services = info.Services() 77 } else { 78 for _, svc := range sc.Services { 79 app := info.Apps[svc] 80 if app == nil { 81 return fmt.Errorf("no such service: %s", svc) 82 } 83 if !app.IsService() { 84 return fmt.Errorf("%s is not a service", svc) 85 } 86 services = append(services, app) 87 } 88 } 89 90 meter := snapstate.NewTaskProgressAdapterLocked(t) 91 92 switch sc.Action { 93 case "stop": 94 flags := &wrappers.StopServicesFlags{ 95 Disable: sc.ActionModifier == "disable", 96 } 97 if err := wrappers.StopServices(services, flags, snap.StopReasonOther, meter, perfTimings); err != nil { 98 return err 99 } 100 case "start": 101 startupOrdered, err := snap.SortServices(services) 102 if err != nil { 103 return err 104 } 105 flags := &wrappers.StartServicesFlags{ 106 Enable: sc.ActionModifier == "enable", 107 } 108 if err := wrappers.StartServices(startupOrdered, nil, flags, meter, perfTimings); err != nil { 109 return err 110 } 111 case "restart": 112 return wrappers.RestartServices(services, nil, meter, perfTimings) 113 case "reload-or-restart": 114 flags := &wrappers.RestartServicesFlags{Reload: true} 115 return wrappers.RestartServices(services, flags, meter, perfTimings) 116 default: 117 return fmt.Errorf("unhandled service action: %q", sc.Action) 118 } 119 return nil 120 }