File: spec.go

package info (click to toggle)
snapd 2.71-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 79,536 kB
  • sloc: ansic: 16,114; sh: 16,105; python: 9,941; makefile: 1,890; exp: 190; awk: 40; xml: 22
file content (136 lines) | stat: -rw-r--r-- 4,889 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
// -*- Mode: Go; indent-tabs-mode: t -*-

/*
 * Copyright (C) 2016-2021 Canonical Ltd
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 3 as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

package systemd

import (
	"fmt"

	"github.com/snapcore/snapd/interfaces"
	"github.com/snapcore/snapd/snap"
)

type addedService struct {
	iface string
	svc   *Service
}

// Specification assists in collecting custom systemd services associated with an interface.
//
// Unlike the Backend itself (which is stateless and non-persistent) this type
// holds internal state that is used by the systemd backend during the interface
// setup process.
type Specification struct {
	curIface string
	services map[string]*addedService
}

// AddService adds a new systemd service unit.
// distinctServiceSuffix is used to name the service and needs to be unique.
// Different interfaces should use different suffixes and different
// plugs/slots should also use distinct ones.
// Uniqueness across snaps is taken care of implicitly elsewhere.
func (spec *Specification) AddService(distinctServiceSuffix string, s *Service) error {
	if old, ok := spec.services[distinctServiceSuffix]; ok && old != nil && s != nil && *old.svc != *s {
		if old.iface == spec.curIface {
			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)
		} else {
			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)
		}
	}
	if spec.services == nil {
		spec.services = make(map[string]*addedService)
	}
	spec.services[distinctServiceSuffix] = &addedService{
		svc:   s,
		iface: spec.curIface,
	}
	return nil
}

// Services returns a deep copy of all the added services keyed by their service suffix.
func (spec *Specification) Services() map[string]*Service {
	if spec.services == nil {
		return nil
	}
	result := make(map[string]*Service, len(spec.services))
	for k, v := range spec.services {
		svc := *v.svc
		result[k] = &svc
	}
	return result
}

// Implementation of methods required by interfaces.Specification

// AddConnectedPlug records systemd-specific side-effects of having a connected plug.
func (spec *Specification) AddConnectedPlug(iface interfaces.Interface, plug *interfaces.ConnectedPlug, slot *interfaces.ConnectedSlot) error {
	type definer interface {
		interfaces.Interface
		SystemdConnectedPlug(spec *Specification, plug *interfaces.ConnectedPlug, slot *interfaces.ConnectedSlot) error
	}
	if iface, ok := iface.(definer); ok {
		spec.curIface = iface.Name()
		defer func() { spec.curIface = "" }()
		return iface.SystemdConnectedPlug(spec, plug, slot)
	}
	return nil
}

// AddConnectedSlot records systemd-specific side-effects of having a connected slot.
func (spec *Specification) AddConnectedSlot(iface interfaces.Interface, plug *interfaces.ConnectedPlug, slot *interfaces.ConnectedSlot) error {
	type definer interface {
		interfaces.Interface
		SystemdConnectedSlot(spec *Specification, plug *interfaces.ConnectedPlug, slot *interfaces.ConnectedSlot) error
	}
	if iface, ok := iface.(definer); ok {
		spec.curIface = iface.Name()
		defer func() { spec.curIface = "" }()
		return iface.SystemdConnectedSlot(spec, plug, slot)
	}
	return nil
}

// AddPermanentPlug records systemd-specific side-effects of having a plug.
func (spec *Specification) AddPermanentPlug(iface interfaces.Interface, plug *snap.PlugInfo) error {
	type definer interface {
		interfaces.Interface
		SystemdPermanentPlug(spec *Specification, plug *snap.PlugInfo) error
	}
	if iface, ok := iface.(definer); ok {
		spec.curIface = iface.Name()
		defer func() { spec.curIface = "" }()
		return iface.SystemdPermanentPlug(spec, plug)
	}
	return nil
}

// AddPermanentSlot records systemd-specific side-effects of having a slot.
func (spec *Specification) AddPermanentSlot(iface interfaces.Interface, slot *snap.SlotInfo) error {
	type definer interface {
		interfaces.Interface
		SystemdPermanentSlot(spec *Specification, slot *snap.SlotInfo) error
	}
	if iface, ok := iface.(definer); ok {
		spec.curIface = iface.Name()
		defer func() { spec.curIface = "" }()
		return iface.SystemdPermanentSlot(spec, slot)
	}
	return nil
}