github.com/meulengracht/snapd@v0.0.0-20210719210640-8bde69bcc84e/interfaces/systemd/spec.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 3 /* 4 * Copyright (C) 2016-2021 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 systemd 21 22 import ( 23 "fmt" 24 25 "github.com/snapcore/snapd/interfaces" 26 "github.com/snapcore/snapd/snap" 27 ) 28 29 type addedService struct { 30 iface string 31 svc *Service 32 } 33 34 // Specification assists in collecting custom systemd services associated with an interface. 35 // 36 // Unlike the Backend itself (which is stateless and non-persistent) this type 37 // holds internal state that is used by the systemd backend during the interface 38 // setup process. 39 type Specification struct { 40 curIface string 41 services map[string]*addedService 42 } 43 44 // AddService adds a new systemd service unit. 45 // distinctServiceSuffix is used to name the service and needs to be unique. 46 // Different interfaces should use different suffixes and different 47 // plugs/slots should also use distinct ones. 48 // Uniqueness across snaps is taken care of implicitly elsewhere. 49 func (spec *Specification) AddService(distinctServiceSuffix string, s *Service) error { 50 if old, ok := spec.services[distinctServiceSuffix]; ok && old != nil && s != nil && *old.svc != *s { 51 if old.iface == spec.curIface { 52 return fmt.Errorf("internal error: interface %q has inconsistent system needs: service for %q used to be defined as %#v, now re-defined as %#v", spec.curIface, distinctServiceSuffix, *old.svc, *s) 53 } else { 54 return fmt.Errorf("internal error: interface %q and %q have conflicting system needs: service for %q used to be defined as %#v by %q, now re-defined as %#v", spec.curIface, old.iface, distinctServiceSuffix, *old.svc, old.iface, *s) 55 } 56 } 57 if spec.services == nil { 58 spec.services = make(map[string]*addedService) 59 } 60 spec.services[distinctServiceSuffix] = &addedService{ 61 svc: s, 62 iface: spec.curIface, 63 } 64 return nil 65 } 66 67 // Services returns a deep copy of all the added services keyed by their service suffix. 68 func (spec *Specification) Services() map[string]*Service { 69 if spec.services == nil { 70 return nil 71 } 72 result := make(map[string]*Service, len(spec.services)) 73 for k, v := range spec.services { 74 svc := *v.svc 75 result[k] = &svc 76 } 77 return result 78 } 79 80 // Implementation of methods required by interfaces.Specification 81 82 // AddConnectedPlug records systemd-specific side-effects of having a connected plug. 83 func (spec *Specification) AddConnectedPlug(iface interfaces.Interface, plug *interfaces.ConnectedPlug, slot *interfaces.ConnectedSlot) error { 84 type definer interface { 85 interfaces.Interface 86 SystemdConnectedPlug(spec *Specification, plug *interfaces.ConnectedPlug, slot *interfaces.ConnectedSlot) error 87 } 88 if iface, ok := iface.(definer); ok { 89 spec.curIface = iface.Name() 90 defer func() { spec.curIface = "" }() 91 return iface.SystemdConnectedPlug(spec, plug, slot) 92 } 93 return nil 94 } 95 96 // AddConnectedSlot records systemd-specific side-effects of having a connected slot. 97 func (spec *Specification) AddConnectedSlot(iface interfaces.Interface, plug *interfaces.ConnectedPlug, slot *interfaces.ConnectedSlot) error { 98 type definer interface { 99 interfaces.Interface 100 SystemdConnectedSlot(spec *Specification, plug *interfaces.ConnectedPlug, slot *interfaces.ConnectedSlot) error 101 } 102 if iface, ok := iface.(definer); ok { 103 spec.curIface = iface.Name() 104 defer func() { spec.curIface = "" }() 105 return iface.SystemdConnectedSlot(spec, plug, slot) 106 } 107 return nil 108 } 109 110 // AddPermanentPlug records systemd-specific side-effects of having a plug. 111 func (spec *Specification) AddPermanentPlug(iface interfaces.Interface, plug *snap.PlugInfo) error { 112 type definer interface { 113 interfaces.Interface 114 SystemdPermanentPlug(spec *Specification, plug *snap.PlugInfo) error 115 } 116 if iface, ok := iface.(definer); ok { 117 spec.curIface = iface.Name() 118 defer func() { spec.curIface = "" }() 119 return iface.SystemdPermanentPlug(spec, plug) 120 } 121 return nil 122 } 123 124 // AddPermanentSlot records systemd-specific side-effects of having a slot. 125 func (spec *Specification) AddPermanentSlot(iface interfaces.Interface, slot *snap.SlotInfo) error { 126 type definer interface { 127 interfaces.Interface 128 SystemdPermanentSlot(spec *Specification, slot *snap.SlotInfo) error 129 } 130 if iface, ok := iface.(definer); ok { 131 spec.curIface = iface.Name() 132 defer func() { spec.curIface = "" }() 133 return iface.SystemdPermanentSlot(spec, slot) 134 } 135 return nil 136 }