1package cni
2
3import (
4	"errors"
5
6	"github.com/Microsoft/go-winio/pkg/guid"
7	"github.com/Microsoft/hcsshim/internal/regstate"
8)
9
10const (
11	cniRoot = "cni"
12	cniKey  = "cfg"
13)
14
15// PersistedNamespaceConfig is the registry version of the `NamespaceID` to UVM
16// map.
17type PersistedNamespaceConfig struct {
18	namespaceID string
19	stored      bool
20
21	ContainerID  string
22	HostUniqueID guid.GUID
23}
24
25// NewPersistedNamespaceConfig creates an in-memory namespace config that can be
26// persisted to the registry.
27func NewPersistedNamespaceConfig(namespaceID, containerID string, containerHostUniqueID guid.GUID) *PersistedNamespaceConfig {
28	return &PersistedNamespaceConfig{
29		namespaceID:  namespaceID,
30		ContainerID:  containerID,
31		HostUniqueID: containerHostUniqueID,
32	}
33}
34
35// LoadPersistedNamespaceConfig loads a persisted config from the registry that matches
36// `namespaceID`. If not found returns `regstate.NotFoundError`
37func LoadPersistedNamespaceConfig(namespaceID string) (*PersistedNamespaceConfig, error) {
38	sk, err := regstate.Open(cniRoot, false)
39	if err != nil {
40		return nil, err
41	}
42	defer sk.Close()
43
44	pnc := PersistedNamespaceConfig{
45		namespaceID: namespaceID,
46		stored:      true,
47	}
48	if err := sk.Get(namespaceID, cniKey, &pnc); err != nil {
49		return nil, err
50	}
51	return &pnc, nil
52}
53
54// Store stores or updates the in-memory config to its registry state. If the
55// store failes returns the store error.
56func (pnc *PersistedNamespaceConfig) Store() error {
57	if pnc.namespaceID == "" {
58		return errors.New("invalid namespaceID ''")
59	}
60	if pnc.ContainerID == "" {
61		return errors.New("invalid containerID ''")
62	}
63	empty := guid.GUID{}
64	if pnc.HostUniqueID == empty {
65		return errors.New("invalid containerHostUniqueID 'empy'")
66	}
67	sk, err := regstate.Open(cniRoot, false)
68	if err != nil {
69		return err
70	}
71	defer sk.Close()
72
73	if pnc.stored {
74		if err := sk.Set(pnc.namespaceID, cniKey, pnc); err != nil {
75			return err
76		}
77	} else {
78		if err := sk.Create(pnc.namespaceID, cniKey, pnc); err != nil {
79			return err
80		}
81	}
82	pnc.stored = true
83	return nil
84}
85
86// Remove removes any persisted state associated with this config. If the config
87// is not found in the registery `Remove` returns no error.
88func (pnc *PersistedNamespaceConfig) Remove() error {
89	if pnc.stored {
90		sk, err := regstate.Open(cniRoot, false)
91		if err != nil {
92			if regstate.IsNotFoundError(err) {
93				pnc.stored = false
94				return nil
95			}
96			return err
97		}
98		defer sk.Close()
99
100		if err := sk.Remove(pnc.namespaceID); err != nil {
101			if regstate.IsNotFoundError(err) {
102				pnc.stored = false
103				return nil
104			}
105			return err
106		}
107	}
108	pnc.stored = false
109	return nil
110}
111