Skip to content

Commit

Permalink
Merge branch '2.8' into 2.8-into-2.9
Browse files Browse the repository at this point in the history
  • Loading branch information
SimonRichardson committed Mar 23, 2021
2 parents 0bbed64 + 9a75495 commit 1ff248b
Show file tree
Hide file tree
Showing 86 changed files with 3,009 additions and 2,554 deletions.
8 changes: 4 additions & 4 deletions acceptancetests/jujupy/k8s_provider/aks.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@

import logging
import os
from pprint import pformat
from datetime import datetime, timezone
from pprint import pformat

import yaml
from azure.identity import ClientSecretCredential
Expand All @@ -46,8 +46,8 @@ class AKS(Base):
driver = None
parameters = None

def __init__(self, bs_manager, cluster_name=None, timeout=1800):
super().__init__(bs_manager, cluster_name, timeout)
def __init__(self, bs_manager, cluster_name=None, enable_rbac=False, timeout=1800):
super().__init__(bs_manager, cluster_name, enable_rbac, timeout)

self.default_storage_class_name = ''
self.__init_client(bs_manager.client.env)
Expand Down Expand Up @@ -137,7 +137,7 @@ def _get_parameters(
service_principal_profile=service_principal_profile,
agent_pool_profiles=[agentpool_default],
linux_profile=linux_profile,
enable_rbac=True,
enable_rbac=self.enable_rbac,
tags={'createdAt': datetime.now(tz=timezone.utc).isoformat()},
)

Expand Down
20 changes: 19 additions & 1 deletion acceptancetests/jujupy/k8s_provider/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
from jujupy.client import temp_bootstrap_env
from jujupy.utility import ensure_dir, until_timeout


logger = logging.getLogger(__name__)


Expand Down Expand Up @@ -157,6 +158,7 @@ def substrate_context(self):
self._ensure_kube_dir()
self.check_cluster_healthy(300)
self._ensure_cluster_config()
self.assert_rbac_config()

yield self
finally:
Expand Down Expand Up @@ -202,6 +204,21 @@ def check_cluster_healthy(self, timeout=60):
logger.error(err)
return False

def assert_rbac_config(self):
rbac_enabled_in_cluster = self.check_rbac_enable()
if self.enable_rbac and not rbac_enabled_in_cluster:
raise Exception("RBAC is required but it's NOT enabled in the cluster")
if not self.enable_rbac and rbac_enabled_in_cluster:
raise Exception("RBAC is unexpectedly enabled in the cluster")

def check_rbac_enable(self):
timeout = 180
cmd = ['/bin/sh', '-c', f'{" ".join(self._kubectl_bin)} run --timeout={timeout}s tmp-shell --restart=Never --rm -i --tty --image bitnami/kubectl:latest -- auth can-i create pods; exit 0']
o = self.sh(*cmd, timeout=timeout)
logger.info('checking RBAC by run "%s" -> %s', ' '.join(cmd), o)
# The default SA in the default namespace does NOT have permission to create pods when RBAC is enabled.
return 'no' in o.split()

def kubectl(self, *args):
return self.sh(*(self._kubectl_bin + args))

Expand All @@ -217,14 +234,15 @@ def patch_configmap(self, namespace, cm_name, key, value):
cm['data'] = data
self.kubectl_apply(json.dumps(cm))

def sh(self, *args, shell=False, ignore_quote=False):
def sh(self, *args, shell=False, ignore_quote=False, timeout=None):
args = [quote(str(arg)) if shell and not ignore_quote else str(arg) for arg in args]
logger.debug('sh -> %s', ' '.join(args))
return subprocess.check_output(
# cmd should be a list of str.
args,
stderr=subprocess.STDOUT,
shell=shell,
timeout=timeout,
).decode('UTF-8').strip()

def _ensure_kubectl_bin(self):
Expand Down
4 changes: 2 additions & 2 deletions acceptancetests/jujupy/k8s_provider/eks.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ class EKS(Base):
location = None
parameters = None

def __init__(self, bs_manager, cluster_name=None, timeout=1800):
super().__init__(bs_manager, cluster_name, timeout)
def __init__(self, bs_manager, cluster_name=None, enable_rbac=False, timeout=1800):
super().__init__(bs_manager, cluster_name, enable_rbac, timeout)

self._eksctl_bin = os.path.join(self.juju_home, 'eksctl')
self._ensure_eksctl_bin()
Expand Down
4 changes: 2 additions & 2 deletions acceptancetests/jujupy/k8s_provider/gke.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@ class GKE(Base):
driver = None
default_params = None

def __init__(self, bs_manager, cluster_name=None, timeout=1800):
super().__init__(bs_manager, cluster_name, timeout)
def __init__(self, bs_manager, cluster_name=None, enable_rbac=False, timeout=1800):
super().__init__(bs_manager, cluster_name, enable_rbac, timeout)

self.default_storage_class_name = ''
self.__init_driver(bs_manager.client.env)
Expand Down
12 changes: 4 additions & 8 deletions acceptancetests/jujupy/k8s_provider/kubernetes_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,12 @@
from __future__ import print_function

import logging
import tempfile
import subprocess
import tempfile

from .base import (
Base,
K8sProviderType,
)
from .base import Base, K8sProviderType
from .factory import register_provider


logger = logging.getLogger(__name__)


Expand Down Expand Up @@ -182,8 +178,8 @@ class KubernetesCore(Base):

name = K8sProviderType.K8S_CORE

def __init__(self, bs_manager, cluster_name=None, timeout=1800):
super().__init__(bs_manager, cluster_name, timeout)
def __init__(self, bs_manager, cluster_name=None, enable_rbac=False, timeout=1800):
super().__init__(bs_manager, cluster_name, enable_rbac, timeout)
self.default_storage_class_name = "juju-storageclass"

def _ensure_kube_dir(self):
Expand Down
4 changes: 2 additions & 2 deletions acceptancetests/jujupy/k8s_provider/microk8s.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ class MicroK8s(Base):
name = K8sProviderType.MICROK8S
cloud_name = 'microk8s' # built-in cloud name

def __init__(self, bs_manager, cluster_name=None, timeout=1800):
super().__init__(bs_manager, cluster_name, timeout)
def __init__(self, bs_manager, cluster_name=None, enable_rbac=False, timeout=1800):
super().__init__(bs_manager, cluster_name, enable_rbac, timeout)
self.default_storage_class_name = 'microk8s-hostpath'

def _ensure_cluster_stack(self):
Expand Down
5 changes: 5 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -493,10 +493,13 @@ github.com/juju/os/v2 v2.1.2 h1:RZ1mRJ/fx6O6KpLBLaNwMbb+EMI+iEfBPTdb3CWpi7w=
github.com/juju/os/v2 v2.1.2/go.mod h1:S/AadPYIeAZtep7zu519c+eWGWV7dVR+Hb8RTGBR1+I=
github.com/juju/packaging v0.0.0-20200421095529-970596d2622a h1:dMBYD9gIFbskcksH9ib+OvmOwwkJTS5ldwvZq3axlbY=
github.com/juju/packaging v0.0.0-20200421095529-970596d2622a/go.mod h1:Brg98KsCnaxL6UxQ4pbVFlT4MoQO7x0kSzwnuvRbUy8=
github.com/juju/packaging v0.0.0-20210322161715-32d1b6c12454 h1:Wcxl0szmXbgdAvMia0y9U9hnR3UXM2bAEDC8iYnhluc=
github.com/juju/packaging v0.0.0-20210322161715-32d1b6c12454/go.mod h1:tC/T9cCGw0tgm2xgx+7ZVmFbfV1ZPZSmO/E+HlRdPjc=
github.com/juju/persistent-cookiejar v0.0.0-20170428161559-d67418f14c93 h1:nlmpG1/Pv5elsi69wXhLkBhefGPE19bOCJ/xVwovl7A=
github.com/juju/persistent-cookiejar v0.0.0-20170428161559-d67418f14c93/go.mod h1:zrbmo4nBKaiP/Ez3F67ewkMbzGYfXyMvRtbOfuAwG0w=
github.com/juju/postgrestest v1.0.1/go.mod h1:/n17Y2T6iFozzXwSCO0JYJ5gSiz2caEtSwAjh/uLXDM=
github.com/juju/postgrestest v1.1.0/go.mod h1:/n17Y2T6iFozzXwSCO0JYJ5gSiz2caEtSwAjh/uLXDM=
github.com/juju/proxy v0.0.0-20180516023828-df38202e4713/go.mod h1:8eZt3fxDIlRXkEkf4N4PCNSZzryF6NxULBg07OjDofA=
github.com/juju/proxy v0.0.0-20180523025733-5f8741c297b4 h1:y2eoq0Uof/dWLAXRyKKGOJuF0TEkauPscQI7Q1XQqvM=
github.com/juju/proxy v0.0.0-20180523025733-5f8741c297b4/go.mod h1:8eZt3fxDIlRXkEkf4N4PCNSZzryF6NxULBg07OjDofA=
github.com/juju/pubsub v0.0.0-20190419131051-c1f7536b9cc6 h1:2aARJxmMC2IF9GqVtt5PYcIy4jyuAcR44byqwXKTK0o=
Expand Down Expand Up @@ -829,6 +832,7 @@ go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
golang.org/x/crypto v0.0.0-20150830180642-aedad9a179ec/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20160922170629-8e06e8ddd962/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20170421043120-96846453c37f/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20180214000028-650f4a345ab4/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20180723164146-c126467f60eb/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
Expand Down Expand Up @@ -1204,6 +1208,7 @@ gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22/go.mod h1:yeKp02qBN3iKW1OzL3M
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce h1:+JknDZhAj8YMt7GC73Ei8pv4MzjDUNPHgQWJdtMAaDU=
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c=
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
gopkg.in/retry.v1 v1.0.0-20170531091238-01631078ef2f/go.mod h1:vVowKz5q49oxHG8AyXjsr6MGDyX2pQRrhjrsAou+stU=
gopkg.in/retry.v1 v1.0.2/go.mod h1:tLRIBNXxoKtalyAWBSIbHdWkIBN2x9jVEm5l0Z+BjXs=
gopkg.in/retry.v1 v1.0.3 h1:a9CArYczAVv6Qs6VGoLMio99GEs7kY9UzSF9+LD+iGs=
gopkg.in/retry.v1 v1.0.3/go.mod h1:FJkXmWiMaAo7xB+xhvDF59zhfjDWyzmyAxiT4dB688g=
Expand Down
3 changes: 1 addition & 2 deletions mongo/mongo.go
Original file line number Diff line number Diff line change
Expand Up @@ -705,7 +705,6 @@ func installMongod(mongoDep packaging.Dependency, usingMongoFromSnap bool, hostS
}
}

prerequisites := []snap.App{snap.NewApp("core")}
backgroundServices := []snap.BackgroundService{
{
Name: "daemon",
Expand All @@ -715,7 +714,7 @@ func installMongod(mongoDep packaging.Dependency, usingMongoFromSnap bool, hostS
conf := newConf(&ConfigArgs{})
conf.Desc = ServiceName + " snap"
snapChannel := fmt.Sprintf("%s/%s", SnapTrack, SnapRisk)
snapSvc, err := snap.NewService(snapName, ServiceName, conf, snap.Command, snapChannel, "", backgroundServices, prerequisites)
snapSvc, err := snap.NewService(snapName, ServiceName, conf, snap.Command, snapChannel, "", backgroundServices, []snap.Installable{})
if err != nil {
return errors.Trace(err)
}
Expand Down
4 changes: 0 additions & 4 deletions packaging/dependency/mongo.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,6 @@ func (dep mongoDependency) PackageList(series string) ([]packaging.Package, erro

snapList = append(
snapList,
packaging.Package{
Name: "core",
PackageManager: packaging.SnapPackageManager,
},
packaging.Package{
Name: "juju-db",
InstallOptions: fmt.Sprintf("--channel %s", dep.snapChannel),
Expand Down
154 changes: 154 additions & 0 deletions service/snap/app.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
// Copyright 2021 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.
package snap

import (
"fmt"

"github.com/juju/errors"
)

// ConfinementPolicy describes the confinement policy for installing a given
// snap application.
type ConfinementPolicy string

const (
// StrictPolicy confined snaps run in complete isolation, up to a minimal
// access level that’s deemed always safe.
StrictPolicy ConfinementPolicy = "strict"
// ClassicPolicy allows access to your system’s resources in much the same
// way traditional packages do
ClassicPolicy ConfinementPolicy = "classic"
// DevModePolicy is a special mode for snap creators and developers.
// A devmode snap runs as a strictly confined snap with full access to
// system resources, and produces debug output to identify unspecified
// interfaces.
DevModePolicy ConfinementPolicy = "devmode"
// JailModePolicy enforces the confinement model for a snap to ensure that
// the confinement is enforced.
JailModePolicy ConfinementPolicy = "jailmode"
)

// Valid validates a given confinement policy to ensure it matches the ones we
// expect.
func (p ConfinementPolicy) Validate() error {
switch p {
case StrictPolicy, ClassicPolicy, DevModePolicy, JailModePolicy:
return nil
}
return errors.NotValidf("%s confinement", p)
}

// String representation of the confinement policy.
func (p ConfinementPolicy) String() string {
return string(p)
}

// App is a wrapper around a single snap
type App struct {
name string
confinementPolicy ConfinementPolicy
channel string
backgroundServices []BackgroundService
prerequisites []Installable
}

// NewNamedApp creates a new application from a given name.
func NewNamedApp(name string) *App {
return &App{
name: name,
}
}

// NewApp creates a application along with it's dependencies.
func NewApp(name string, channel string, policy ConfinementPolicy, services []BackgroundService, prerequisites []Installable) *App {
return &App{
name: name,
channel: channel,
confinementPolicy: policy,
backgroundServices: services,
prerequisites: prerequisites,
}
}

// Validate will validate a given application for any potential issues.
func (a *App) Validate() error {
if !snapNameRe.MatchString(a.name) {
return errors.NotValidf("application %v", a.name)
}

if a.confinementPolicy != "" {
if err := a.confinementPolicy.Validate(); err != nil {
return errors.Trace(err)
}
}

for _, backgroundService := range a.backgroundServices {
err := backgroundService.Validate()
if err != nil {
return errors.Trace(err)
}
}

for _, prerequisite := range a.prerequisites {
err := prerequisite.Validate()
if err != nil {
return errors.Trace(err)
}
}

return nil
}

// StartCommands returns a list if shell commands that should be executed (in order)
// to start App and its background services. executeable is a path to the snap
// executable. If the app has prerequisite applications defined, then take care to call
// StartCommands on those apps also.
func (a *App) StartCommands(executable string) []string {
if len(a.backgroundServices) == 0 {
return []string{fmt.Sprintf("%s start %s", executable, a.name)}
}

commands := make([]string, 0, len(a.backgroundServices))
for _, backgroundService := range a.backgroundServices {
enableFlag := ""
if backgroundService.EnableAtStartup {
enableFlag = " --enable "
}

command := fmt.Sprintf("%s start %s %s.%s", executable, enableFlag, a.name, backgroundService.Name)
commands = append(commands, command)
}
return commands
}

// Install returns a way to install one application with all it's settings.
func (a *App) Install() []string {
args := []string{
"install",
}
if a.channel != "" {
args = append(args, fmt.Sprintf("--channel=%s", a.channel))
}
if a.confinementPolicy != "" {
args = append(args, fmt.Sprintf("--%s", a.confinementPolicy))
}
return append(args, a.name)
}

// Prerequisites defines a list of all the Prerequisites required before the
// application also needs to be installed.
func (a *App) Prerequisites() []Installable {
return a.prerequisites
}

// BackgroundServices returns a list of background services that are
// required to be installed for the main application to run.
func (a *App) BackgroundServices() []BackgroundService {
return a.backgroundServices
}

// Name returns the name of the application
func (a *App) Name() string {
return a.name
}
Loading

0 comments on commit 1ff248b

Please sign in to comment.