Skip to content

Commit 6dbeb25

Browse files
committed
Cleanup annotations: move to separate pkg
Signed-off-by: apostasie <spam_blackhole@farcloser.world>
1 parent 71ebb98 commit 6dbeb25

File tree

11 files changed

+578
-427
lines changed

11 files changed

+578
-427
lines changed

pkg/annotations/annotations.go

Lines changed: 330 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,340 @@
1-
/*
2-
Copyright The containerd Authors.
1+
package annotations
32

4-
Licensed under the Apache License, Version 2.0 (the "License");
5-
you may not use this file except in compliance with the License.
6-
You may obtain a copy of the License at
3+
import (
4+
"context"
5+
"encoding/json"
6+
"fmt"
7+
"strconv"
8+
"strings"
79

8-
http://www.apache.org/licenses/LICENSE-2.0
10+
"github.com/opencontainers/runtime-spec/specs-go"
911

10-
Unless required by applicable law or agreed to in writing, software
11-
distributed under the License is distributed on an "AS IS" BASIS,
12-
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13-
See the License for the specific language governing permissions and
14-
limitations under the License.
15-
*/
12+
containerd "github.com/containerd/containerd/v2/client"
13+
"github.com/containerd/go-cni"
1614

17-
// Package annotations defines OCI annotations
18-
package annotations
15+
"github.com/containerd/nerdctl/v2/pkg/inspecttypes/dockercompat"
16+
"github.com/containerd/nerdctl/v2/pkg/mountutil"
17+
"github.com/containerd/nerdctl/v2/pkg/platformutil"
18+
)
1919

20-
const (
21-
// Prefix is the common prefix of nerdctl annotations
22-
Prefix = "nerdctl/"
20+
func New(ctx context.Context, con containerd.Container) (*Annotations, error) {
21+
an := &Annotations{}
22+
err := an.Unmarshall(ctx, con)
23+
return an, err
24+
}
2325

24-
// Bypass4netns is the flag for acceleration with bypass4netns
25-
// Boolean value which can be parsed with strconv.ParseBool() is required.
26-
// (like "nerdctl/bypass4netns=true" or "nerdctl/bypass4netns=false")
27-
Bypass4netns = Prefix + "bypass4netns"
26+
func NewFromState(state *specs.State) (*Annotations, error) {
27+
an := &Annotations{}
28+
if state == nil || state.Annotations == nil {
29+
return nil, fmt.Errorf("invalid state")
30+
}
31+
err := an.UnmarshallFromMap(state.Annotations)
32+
return an, err
33+
}
2834

29-
// Bypass4netnsIgnoreSubnets is a JSON of []string that is appended to
30-
// the `bypass4netns --ignore` list.
31-
Bypass4netnsIgnoreSubnets = Bypass4netns + "-ignore-subnets"
35+
type Log struct {
36+
Driver string
37+
Opts map[string]string
38+
Address string
39+
}
3240

33-
// Bypass4netnsIgnoreBind disables acceleration for bind.
34-
// Boolean value which can be parsed with strconv.ParseBool() is required.
35-
Bypass4netnsIgnoreBind = Bypass4netns + "-ignore-bind"
36-
)
41+
type Annotations struct {
42+
AnonVolumes []string
43+
Bypass4netns bool
44+
Bypass4netnsIgnoreBind bool
45+
Bypass4netnsIgnoreSubnets []string
46+
CidFile string
47+
DeviceMapping []dockercompat.DeviceMapping
48+
DNSResolvConfOptions []string
49+
DNSSearchDomains []string
50+
DNSServers []string
51+
DomainName string
52+
ExtraHosts map[string]string
53+
// GroupAdd []string
54+
HostName string
55+
IPC string
56+
LogConfig *Log
57+
LogURI string
58+
MountPoints []*mountutil.Processed
59+
Name string
60+
Namespace string
61+
NetworkNamespace string
62+
Networks []string
63+
Platform string
64+
StateDir string
65+
PidContainer string
66+
PidFile string
67+
Ports []cni.PortMapping
68+
Rm bool
69+
User string
70+
71+
// FIXME: these should be replaced by a richer Network label allowing per network ip and mac
72+
IP6Address string
73+
IPAddress string
74+
MACAddress string
75+
}
76+
77+
func (an *Annotations) UnmarshallFromMap(source map[string]string) error {
78+
hostConfig := &dockercompat.HostConfig{}
79+
dnsConfig := &dockercompat.DNSSettings{}
80+
for k, v := range source {
81+
switch k {
82+
case AnonymousVolumes:
83+
_ = json.Unmarshal([]byte(v), &an.AnonVolumes)
84+
case Bypass4netns:
85+
an.Bypass4netns, _ = strconv.ParseBool(v)
86+
case Bypass4netnsIgnoreBind:
87+
an.Bypass4netnsIgnoreBind, _ = strconv.ParseBool(v)
88+
case Bypass4netnsIgnoreSubnets:
89+
_ = json.Unmarshal([]byte(v), &an.Bypass4netnsIgnoreSubnets)
90+
case DNSSetting:
91+
_ = json.Unmarshal([]byte(v), dnsConfig)
92+
an.DNSServers = dnsConfig.DNSServers
93+
an.DNSSearchDomains = dnsConfig.DNSSearchDomains
94+
an.DNSResolvConfOptions = dnsConfig.DNSResolvConfOptions
95+
case Domainname:
96+
an.DomainName = v
97+
case ExtraHosts:
98+
hosts := []string{}
99+
_ = json.Unmarshal([]byte(v), &hosts)
100+
if an.ExtraHosts == nil {
101+
an.ExtraHosts = map[string]string{}
102+
}
103+
for _, host := range hosts {
104+
if v := strings.SplitN(host, ":", 2); len(v) == 2 {
105+
an.ExtraHosts[v[0]] = v[1]
106+
}
107+
}
108+
109+
case HostConfig:
110+
_ = json.Unmarshal([]byte(v), hostConfig)
111+
an.CidFile = hostConfig.ContainerIDFile
112+
// = hostConfig.CgroupnsMode
113+
case Hostname:
114+
an.HostName = v
115+
case IP6Address:
116+
an.IP6Address = v
117+
case IPAddress:
118+
an.IPAddress = v
119+
case IPC:
120+
an.IPC = v
121+
case LogConfig:
122+
_ = json.Unmarshal([]byte(v), &an.LogConfig)
123+
case LogURI:
124+
an.LogURI = v
125+
case MACAddress:
126+
an.MACAddress = v
127+
case Mounts:
128+
_ = json.Unmarshal([]byte(v), &an.MountPoints)
129+
case Name:
130+
an.Name = v
131+
case Namespace:
132+
an.Namespace = v
133+
case NetworkNamespace:
134+
an.NetworkNamespace = v
135+
case Networks:
136+
_ = json.Unmarshal([]byte(v), &an.Networks)
137+
case PIDContainer:
138+
an.PidContainer = v
139+
case PIDFile:
140+
an.PidFile = v
141+
case Platform:
142+
an.Platform = v
143+
case Ports:
144+
_ = json.Unmarshal([]byte(v), &an.Ports)
145+
case ContainerAutoRemove:
146+
an.Rm, _ = strconv.ParseBool(v)
147+
case StateDir:
148+
an.StateDir = v
149+
// FIXME: add missing, including NetworkNamespace
150+
case User:
151+
an.User = v
152+
default:
153+
}
154+
}
155+
156+
return nil
157+
}
158+
159+
func (an *Annotations) Unmarshall(ctx context.Context, con containerd.Container) error {
160+
conSpecs, err := con.Spec(ctx)
161+
if err != nil || conSpecs.Annotations == nil {
162+
return err
163+
}
164+
165+
return an.UnmarshallFromMap(conSpecs.Annotations)
166+
}
167+
168+
func (an *Annotations) Marshall() (map[string]string, error) {
169+
annot := make(map[string]string)
170+
171+
var (
172+
err error
173+
hostConfig dockercompat.HostConfigLabel
174+
dnsSettings dockercompat.DNSSettings
175+
)
176+
177+
if len(an.AnonVolumes) > 0 {
178+
anonVolumeJSON, err := json.Marshal(an.AnonVolumes)
179+
if err != nil {
180+
return nil, err
181+
}
182+
annot[AnonymousVolumes] = string(anonVolumeJSON)
183+
}
184+
185+
if an.CidFile != "" {
186+
hostConfig.CidFile = an.CidFile
187+
}
188+
189+
if len(an.DeviceMapping) > 0 {
190+
hostConfig.Devices = append(hostConfig.Devices, an.DeviceMapping...)
191+
}
192+
193+
if len(an.DNSResolvConfOptions) > 0 {
194+
dnsSettings.DNSResolvConfOptions = an.DNSResolvConfOptions
195+
}
196+
197+
if len(an.DNSServers) > 0 {
198+
dnsSettings.DNSServers = an.DNSServers
199+
}
200+
201+
if len(an.DNSSearchDomains) > 0 {
202+
dnsSettings.DNSSearchDomains = an.DNSSearchDomains
203+
}
204+
205+
dnsSettingsJSON, err := json.Marshal(dnsSettings)
206+
if err != nil {
207+
return nil, err
208+
}
209+
annot[DNSSetting] = string(dnsSettingsJSON)
210+
211+
annot[Domainname] = an.DomainName
212+
213+
//if len(an.GroupAdd) > 0 {
214+
//}
215+
216+
hosts := []string{}
217+
for k, v := range an.ExtraHosts {
218+
hosts = append(hosts, fmt.Sprintf("%s:%s", k, v))
219+
}
220+
extraHostsJSON, err := json.Marshal(hosts)
221+
if err != nil {
222+
return nil, err
223+
}
224+
annot[ExtraHosts] = string(extraHostsJSON)
225+
226+
hostConfigJSON, err := json.Marshal(hostConfig)
227+
if err != nil {
228+
return nil, err
229+
}
230+
annot[HostConfig] = string(hostConfigJSON)
231+
232+
annot[Hostname] = an.HostName
233+
234+
if an.IP6Address != "" {
235+
annot[IP6Address] = an.IP6Address
236+
}
237+
238+
if an.IPAddress != "" {
239+
annot[IPAddress] = an.IPAddress
240+
}
241+
242+
if an.IPC != "" {
243+
annot[IPC] = an.IPC
244+
}
245+
246+
if an.LogURI != "" {
247+
annot[LogURI] = an.LogURI
248+
249+
if an.LogConfig != nil {
250+
logConfigJSON, err := json.Marshal(an.LogConfig)
251+
if err != nil {
252+
return nil, err
253+
}
254+
255+
annot[LogConfig] = string(logConfigJSON)
256+
}
257+
}
258+
259+
if an.MACAddress != "" {
260+
annot[MACAddress] = an.MACAddress
261+
}
262+
263+
if len(an.MountPoints) > 0 {
264+
mounts := dockercompatMounts(an.MountPoints)
265+
mountPointsJSON, err := json.Marshal(mounts)
266+
if err != nil {
267+
return nil, err
268+
}
269+
annot[Mounts] = string(mountPointsJSON)
270+
}
271+
272+
annot[Name] = an.Name
273+
annot[Namespace] = an.Namespace
274+
275+
networksJSON, err := json.Marshal(an.Networks)
276+
if err != nil {
277+
return nil, err
278+
}
279+
annot[Networks] = string(networksJSON)
280+
281+
annot[Platform], err = platformutil.NormalizeString(an.Platform)
282+
if err != nil {
283+
return nil, err
284+
}
285+
286+
if an.PidFile != "" {
287+
annot[PIDFile] = an.PidFile
288+
}
289+
290+
if len(an.Ports) > 0 {
291+
portsJSON, err := json.Marshal(an.Ports)
292+
if err != nil {
293+
return nil, err
294+
}
295+
296+
annot[Ports] = string(portsJSON)
297+
}
298+
299+
if an.PidContainer != "" {
300+
annot[PIDContainer] = an.PidContainer
301+
}
302+
303+
annot[ContainerAutoRemove] = fmt.Sprintf("%t", an.Rm)
304+
305+
annot[StateDir] = an.StateDir
306+
307+
if an.User != "" {
308+
annot[User] = an.User
309+
}
310+
311+
return annot, nil
312+
}
313+
314+
func dockercompatMounts(mountPoints []*mountutil.Processed) []dockercompat.MountPoint {
315+
result := make([]dockercompat.MountPoint, len(mountPoints))
316+
for i := range mountPoints {
317+
mp := mountPoints[i]
318+
result[i] = dockercompat.MountPoint{
319+
Type: mp.Type,
320+
Name: mp.Name,
321+
Source: mp.Mount.Source,
322+
Destination: mp.Mount.Destination,
323+
Driver: "",
324+
Mode: mp.Mode,
325+
}
326+
result[i].RW, result[i].Propagation = dockercompat.ParseMountProperties(strings.Split(mp.Mode, ","))
327+
328+
// it's an anonymous volume
329+
if mp.AnonymousVolume != "" {
330+
result[i].Name = mp.AnonymousVolume
331+
}
332+
333+
// volume only support local driver
334+
if mp.Type == "volume" {
335+
result[i].Driver = "local"
336+
}
337+
}
37338

38-
var ShellCompletions = []string{
39-
Bypass4netns + "=true",
40-
Bypass4netns + "=false",
41-
Bypass4netnsIgnoreSubnets + "=",
42-
Bypass4netnsIgnoreBind + "=true",
43-
Bypass4netnsIgnoreBind + "=false",
339+
return result
44340
}

0 commit comments

Comments
 (0)