github.com/meulengracht/snapd@v0.0.0-20210719210640-8bde69bcc84e/interfaces/builtin/kubernetes_support_test.go (about)

     1  // -*- Mode: Go; indent-tabs-mode: t -*-
     2  
     3  /*
     4   * Copyright (C) 2017-2018 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 builtin_test
    21  
    22  import (
    23  	"fmt"
    24  
    25  	. "gopkg.in/check.v1"
    26  
    27  	"github.com/snapcore/snapd/dirs"
    28  	"github.com/snapcore/snapd/interfaces"
    29  	"github.com/snapcore/snapd/interfaces/apparmor"
    30  	"github.com/snapcore/snapd/interfaces/builtin"
    31  	"github.com/snapcore/snapd/interfaces/kmod"
    32  	"github.com/snapcore/snapd/interfaces/seccomp"
    33  	"github.com/snapcore/snapd/interfaces/udev"
    34  	"github.com/snapcore/snapd/snap"
    35  	"github.com/snapcore/snapd/snap/snaptest"
    36  	"github.com/snapcore/snapd/testutil"
    37  )
    38  
    39  type KubernetesSupportInterfaceSuite struct {
    40  	iface                interfaces.Interface
    41  	slotInfo             *snap.SlotInfo
    42  	slot                 *interfaces.ConnectedSlot
    43  	plugInfo             *snap.PlugInfo
    44  	plug                 *interfaces.ConnectedPlug
    45  	plugKubeletInfo      *snap.PlugInfo
    46  	plugKubelet          *interfaces.ConnectedPlug
    47  	plugKubeproxyInfo    *snap.PlugInfo
    48  	plugKubeproxy        *interfaces.ConnectedPlug
    49  	plugKubeAutobindInfo *snap.PlugInfo
    50  	plugKubeAutobind     *interfaces.ConnectedPlug
    51  	plugBadInfo          *snap.PlugInfo
    52  	plugBad              *interfaces.ConnectedPlug
    53  }
    54  
    55  const k8sMockPlugSnapInfoYaml = `name: kubernetes-support
    56  version: 0
    57  plugs:
    58    k8s-default:
    59      interface: kubernetes-support
    60    k8s-kubelet:
    61      interface: kubernetes-support
    62      flavor: kubelet
    63    k8s-kubeproxy:
    64      interface: kubernetes-support
    65      flavor: kubeproxy
    66    k8s-autobind-unix:
    67      interface: kubernetes-support
    68      flavor: autobind-unix
    69    k8s-bad:
    70      interface: kubernetes-support
    71      flavor: bad
    72  apps:
    73   default:
    74    plugs: [k8s-default]
    75   kubelet:
    76    plugs: [k8s-kubelet]
    77   kubeproxy:
    78    plugs: [k8s-kubeproxy]
    79   kube-autobind-unix:
    80    plugs: [k8s-autobind-unix]
    81  `
    82  
    83  var _ = Suite(&KubernetesSupportInterfaceSuite{
    84  	iface: builtin.MustInterface("kubernetes-support"),
    85  })
    86  
    87  func (s *KubernetesSupportInterfaceSuite) SetUpTest(c *C) {
    88  	s.slotInfo = &snap.SlotInfo{
    89  		Snap:      &snap.Info{SuggestedName: "core", SnapType: snap.TypeOS},
    90  		Name:      "kubernetes-support",
    91  		Interface: "kubernetes-support",
    92  	}
    93  	s.slot = interfaces.NewConnectedSlot(s.slotInfo, nil, nil)
    94  	plugSnap := snaptest.MockInfo(c, k8sMockPlugSnapInfoYaml, nil)
    95  
    96  	s.plugInfo = plugSnap.Plugs["k8s-default"]
    97  	s.plug = interfaces.NewConnectedPlug(s.plugInfo, nil, nil)
    98  
    99  	s.plugKubeletInfo = plugSnap.Plugs["k8s-kubelet"]
   100  	s.plugKubelet = interfaces.NewConnectedPlug(s.plugKubeletInfo, nil, nil)
   101  
   102  	s.plugKubeproxyInfo = plugSnap.Plugs["k8s-kubeproxy"]
   103  	s.plugKubeproxy = interfaces.NewConnectedPlug(s.plugKubeproxyInfo, nil, nil)
   104  
   105  	s.plugKubeAutobindInfo = plugSnap.Plugs["k8s-autobind-unix"]
   106  	s.plugKubeAutobind = interfaces.NewConnectedPlug(s.plugKubeAutobindInfo, nil, nil)
   107  
   108  	s.plugBadInfo = plugSnap.Plugs["k8s-bad"]
   109  	s.plugBad = interfaces.NewConnectedPlug(s.plugBadInfo, nil, nil)
   110  }
   111  
   112  func (s *KubernetesSupportInterfaceSuite) TestName(c *C) {
   113  	c.Assert(s.iface.Name(), Equals, "kubernetes-support")
   114  }
   115  
   116  func (s *KubernetesSupportInterfaceSuite) TestSanitizeSlot(c *C) {
   117  	c.Assert(interfaces.BeforePrepareSlot(s.iface, s.slotInfo), IsNil)
   118  }
   119  
   120  func (s *KubernetesSupportInterfaceSuite) TestSanitizePlug(c *C) {
   121  	c.Assert(interfaces.BeforePreparePlug(s.iface, s.plugInfo), IsNil)
   122  	c.Assert(interfaces.BeforePreparePlug(s.iface, s.plugKubeletInfo), IsNil)
   123  	c.Assert(interfaces.BeforePreparePlug(s.iface, s.plugKubeproxyInfo), IsNil)
   124  	c.Assert(interfaces.BeforePreparePlug(s.iface, s.plugBadInfo), ErrorMatches, `kubernetes-support plug requires "flavor" to be either "kubelet", "kubeproxy" or "autobind-unix"`)
   125  }
   126  
   127  func (s *KubernetesSupportInterfaceSuite) TestKModConnectedPlug(c *C) {
   128  	// default should have kubeproxy modules
   129  	spec := &kmod.Specification{}
   130  	err := spec.AddConnectedPlug(s.iface, s.plug, s.slot)
   131  	c.Assert(err, IsNil)
   132  	c.Assert(spec.Modules(), DeepEquals, map[string]bool{
   133  		"llc":       true,
   134  		"stp":       true,
   135  		"ip_vs_rr":  true,
   136  		"ip_vs_sh":  true,
   137  		"ip_vs_wrr": true,
   138  		"libcrc32c": true,
   139  	})
   140  
   141  	// kubeproxy should have its modules
   142  	spec = &kmod.Specification{}
   143  	err = spec.AddConnectedPlug(s.iface, s.plugKubeproxy, s.slot)
   144  	c.Assert(err, IsNil)
   145  	c.Assert(spec.Modules(), DeepEquals, map[string]bool{
   146  		"llc":       true,
   147  		"stp":       true,
   148  		"ip_vs_rr":  true,
   149  		"ip_vs_sh":  true,
   150  		"ip_vs_wrr": true,
   151  		"libcrc32c": true,
   152  	})
   153  
   154  	// kubelet shouldn't have anything
   155  	spec = &kmod.Specification{}
   156  	err = spec.AddConnectedPlug(s.iface, s.plugKubelet, s.slot)
   157  	c.Assert(err, IsNil)
   158  	c.Assert(spec.Modules(), DeepEquals, map[string]bool{})
   159  }
   160  
   161  func (s *KubernetesSupportInterfaceSuite) TestAppArmorConnectedPlug(c *C) {
   162  	// default should have kubeproxy, kubelet and autobind rules
   163  	spec := &apparmor.Specification{}
   164  	err := spec.AddConnectedPlug(s.iface, s.plug, s.slot)
   165  	c.Assert(err, IsNil)
   166  	c.Assert(spec.SecurityTags(), DeepEquals, []string{"snap.kubernetes-support.default"})
   167  	c.Check(spec.SnippetForTag("snap.kubernetes-support.default"), testutil.Contains, "# Common rules for running as a kubernetes node\n")
   168  	c.Check(spec.SnippetForTag("snap.kubernetes-support.default"), testutil.Contains, "# Allow running as the kubelet service\n")
   169  	c.Check(spec.SnippetForTag("snap.kubernetes-support.default"), testutil.Contains, "# Allow running as the kubeproxy service\n")
   170  	c.Check(spec.SnippetForTag("snap.kubernetes-support.default"), testutil.Contains, "# Common rules for kubernetes use of systemd_run\n")
   171  	c.Check(spec.SnippetForTag("snap.kubernetes-support.default"), testutil.Contains, "# kubelet mount rules\n")
   172  	c.Check(spec.SnippetForTag("snap.kubernetes-support.default"), testutil.Contains, "# Allow using the 'autobind' feature of bind() (eg, for journald via go-systemd)\n")
   173  	c.Check(spec.UsesPtraceTrace(), Equals, true)
   174  
   175  	// kubeproxy should have its rules and autobind rules
   176  	spec = &apparmor.Specification{}
   177  	err = spec.AddConnectedPlug(s.iface, s.plugKubeproxy, s.slot)
   178  	c.Assert(err, IsNil)
   179  	c.Assert(spec.SecurityTags(), DeepEquals, []string{"snap.kubernetes-support.kubeproxy"})
   180  	c.Check(spec.SnippetForTag("snap.kubernetes-support.kubeproxy"), testutil.Contains, "# Common rules for running as a kubernetes node\n")
   181  	c.Check(spec.SnippetForTag("snap.kubernetes-support.kubeproxy"), testutil.Contains, "# Allow running as the kubeproxy service\n")
   182  	c.Check(spec.SnippetForTag("snap.kubernetes-support.kubeproxy"), Not(testutil.Contains), "# Allow running as the kubelet service\n")
   183  	c.Check(spec.SnippetForTag("snap.kubernetes-support.kubeproxy"), testutil.Contains, "# Common rules for kubernetes use of systemd_run\n")
   184  	c.Check(spec.SnippetForTag("snap.kubernetes-support.kubeproxy"), Not(testutil.Contains), "# kubelet mount rules\n")
   185  	c.Check(spec.SnippetForTag("snap.kubernetes-support.kubeproxy"), testutil.Contains, "# Allow using the 'autobind' feature of bind() (eg, for journald via go-systemd)\n")
   186  	c.Check(spec.UsesPtraceTrace(), Equals, false)
   187  
   188  	// kubelet should have its rules and autobind rules
   189  	spec = &apparmor.Specification{}
   190  	err = spec.AddConnectedPlug(s.iface, s.plugKubelet, s.slot)
   191  	c.Assert(err, IsNil)
   192  	c.Assert(spec.SecurityTags(), DeepEquals, []string{"snap.kubernetes-support.kubelet"})
   193  	c.Check(spec.SnippetForTag("snap.kubernetes-support.kubelet"), testutil.Contains, "# Common rules for running as a kubernetes node\n")
   194  	c.Check(spec.SnippetForTag("snap.kubernetes-support.kubelet"), testutil.Contains, "# Allow running as the kubelet service\n")
   195  	c.Check(spec.SnippetForTag("snap.kubernetes-support.kubelet"), Not(testutil.Contains), "# Allow running as the kubeproxy service\n")
   196  	c.Check(spec.SnippetForTag("snap.kubernetes-support.kubelet"), testutil.Contains, "# Common rules for kubernetes use of systemd_run\n")
   197  	c.Check(spec.SnippetForTag("snap.kubernetes-support.kubelet"), testutil.Contains, "# kubelet mount rules\n")
   198  	c.Check(spec.SnippetForTag("snap.kubernetes-support.kubelet"), testutil.Contains, "# Allow using the 'autobind' feature of bind() (eg, for journald via go-systemd)\n")
   199  	c.Check(spec.UsesPtraceTrace(), Equals, true)
   200  
   201  	// kube-autobind-unix should have only its autobind rules
   202  	spec = &apparmor.Specification{}
   203  	err = spec.AddConnectedPlug(s.iface, s.plugKubeAutobind, s.slot)
   204  	c.Assert(err, IsNil)
   205  	c.Assert(spec.SecurityTags(), DeepEquals, []string{"snap.kubernetes-support.kube-autobind-unix"})
   206  	c.Check(spec.SnippetForTag("snap.kubernetes-support.kube-autobind-unix"), Not(testutil.Contains), "# Common rules for running as a kubernetes node\n")
   207  	c.Check(spec.SnippetForTag("snap.kubernetes-support.kube-autobind-unix"), Not(testutil.Contains), "# Allow running as the kubelet service\n")
   208  	c.Check(spec.SnippetForTag("snap.kubernetes-support.kube-autobind-unix"), Not(testutil.Contains), "# Allow running as the kubeproxy service\n")
   209  	c.Check(spec.SnippetForTag("snap.kubernetes-support.kube-autobind-unix"), Not(testutil.Contains), "# Common rules for kubernetes use of systemd_run\n")
   210  	c.Check(spec.SnippetForTag("snap.kubernetes-support.kube-autobind-unix"), Not(testutil.Contains), "# kubelet mount rules\n")
   211  	c.Check(spec.SnippetForTag("snap.kubernetes-support.kube-autobind-unix"), testutil.Contains, "# Allow using the 'autobind' feature of bind() (eg, for journald via go-systemd)\n")
   212  	c.Check(spec.UsesPtraceTrace(), Equals, false)
   213  }
   214  
   215  func (s *KubernetesSupportInterfaceSuite) TestSecCompConnectedPlug(c *C) {
   216  	// default should have kubelet rules
   217  	spec := &seccomp.Specification{}
   218  	err := spec.AddConnectedPlug(s.iface, s.plug, s.slot)
   219  	c.Assert(err, IsNil)
   220  	c.Assert(spec.SecurityTags(), DeepEquals, []string{"snap.kubernetes-support.default"})
   221  	c.Check(spec.SnippetForTag("snap.kubernetes-support.default"), testutil.Contains, "# Allow running as the kubelet service\n")
   222  	c.Check(spec.SnippetForTag("snap.kubernetes-support.default"), testutil.Contains, "# Allow using the 'autobind' feature of bind() (eg, for journald).\n")
   223  
   224  	// kubeproxy should have the autobind rules
   225  	spec = &seccomp.Specification{}
   226  	err = spec.AddConnectedPlug(s.iface, s.plugKubeproxy, s.slot)
   227  	c.Assert(err, IsNil)
   228  	c.Assert(spec.SecurityTags(), DeepEquals, []string{"snap.kubernetes-support.kubeproxy"})
   229  	c.Check(spec.SnippetForTag("snap.kubernetes-support.kubeproxy"), Not(testutil.Contains), "# Allow running as the kubelet service\n")
   230  	c.Check(spec.SnippetForTag("snap.kubernetes-support.kubeproxy"), testutil.Contains, "# Allow using the 'autobind' feature of bind() (eg, for journald).\n")
   231  
   232  	// kubelet should have its rules and the autobind rules
   233  	spec = &seccomp.Specification{}
   234  	err = spec.AddConnectedPlug(s.iface, s.plugKubelet, s.slot)
   235  	c.Assert(err, IsNil)
   236  	c.Assert(spec.SecurityTags(), DeepEquals, []string{"snap.kubernetes-support.kubelet"})
   237  	c.Check(spec.SnippetForTag("snap.kubernetes-support.kubelet"), testutil.Contains, "# Allow running as the kubelet service\n")
   238  	c.Check(spec.SnippetForTag("snap.kubernetes-support.kubelet"), testutil.Contains, "# Allow using the 'autobind' feature of bind() (eg, for journald).\n")
   239  
   240  	// kube-autobind-unix should have the autobind rules
   241  	spec = &seccomp.Specification{}
   242  	err = spec.AddConnectedPlug(s.iface, s.plugKubeAutobind, s.slot)
   243  	c.Assert(err, IsNil)
   244  	c.Assert(spec.SecurityTags(), DeepEquals, []string{"snap.kubernetes-support.kube-autobind-unix"})
   245  	c.Check(spec.SnippetForTag("snap.kubernetes-support.kube-autobind-unix"), Not(testutil.Contains), "# Allow running as the kubelet service\n")
   246  	c.Check(spec.SnippetForTag("snap.kubernetes-support.kube-autobind-unix"), testutil.Contains, "# Allow using the 'autobind' feature of bind() (eg, for journald).\n")
   247  }
   248  
   249  func (s *KubernetesSupportInterfaceSuite) TestUDevConnectedPlug(c *C) {
   250  	// default should have kubelet rules
   251  	spec := &udev.Specification{}
   252  	err := spec.AddConnectedPlug(s.iface, s.plug, s.slot)
   253  	c.Assert(err, IsNil)
   254  	c.Assert(spec.Snippets(), HasLen, 2)
   255  	c.Assert(spec.Snippets(), testutil.Contains, `# kubernetes-support
   256  KERNEL=="kmsg", TAG+="snap_kubernetes-support_default"`)
   257  	c.Assert(spec.Snippets(), testutil.Contains, fmt.Sprintf(`TAG=="snap_kubernetes-support_default", RUN+="%v/snap-device-helper $env{ACTION} snap_kubernetes-support_default $devpath $major:$minor"`, dirs.DistroLibExecDir))
   258  
   259  	// kubeproxy should not have any rules
   260  	spec = &udev.Specification{}
   261  	err = spec.AddConnectedPlug(s.iface, s.plugKubeproxy, s.slot)
   262  	c.Assert(err, IsNil)
   263  	c.Assert(spec.Snippets(), HasLen, 0)
   264  
   265  	// kubelet should have only its rules
   266  	spec = &udev.Specification{}
   267  	err = spec.AddConnectedPlug(s.iface, s.plugKubelet, s.slot)
   268  	c.Assert(err, IsNil)
   269  	c.Assert(spec.Snippets(), HasLen, 2)
   270  	c.Assert(spec.Snippets(), testutil.Contains, `# kubernetes-support
   271  KERNEL=="kmsg", TAG+="snap_kubernetes-support_kubelet"`)
   272  	c.Assert(spec.Snippets(), testutil.Contains, fmt.Sprintf(`TAG=="snap_kubernetes-support_kubelet", RUN+="%v/snap-device-helper $env{ACTION} snap_kubernetes-support_kubelet $devpath $major:$minor"`, dirs.DistroLibExecDir))
   273  }
   274  
   275  func (s *KubernetesSupportInterfaceSuite) TestInterfaces(c *C) {
   276  	c.Check(builtin.Interfaces(), testutil.DeepContains, s.iface)
   277  }
   278  
   279  func (s *KubernetesSupportInterfaceSuite) TestPermanentPlugServiceSnippets(c *C) {
   280  	for _, t := range []struct {
   281  		plug *snap.PlugInfo
   282  		exp  []string
   283  	}{
   284  		{s.plugInfo, []string{"Delegate=true"}},
   285  		{s.plugKubeletInfo, []string{"Delegate=true"}},
   286  		{s.plugKubeproxyInfo, []string{"Delegate=true"}},
   287  		// only autobind-unix flavor does not get Delegate=true
   288  		{s.plugKubeAutobindInfo, nil},
   289  	} {
   290  		snips, err := interfaces.PermanentPlugServiceSnippets(s.iface, t.plug)
   291  		c.Assert(err, IsNil)
   292  		c.Check(snips, DeepEquals, t.exp)
   293  	}
   294  }