-
Notifications
You must be signed in to change notification settings - Fork 501
/
builtin.go
155 lines (135 loc) · 4.82 KB
/
builtin.go
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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
// Copyright 2019 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.
package provider
import (
"bytes"
"context"
"fmt"
"os"
"path/filepath"
"runtime"
"strings"
jujuclock "github.com/juju/clock"
"github.com/juju/errors"
"github.com/juju/utils/v4"
"github.com/juju/utils/v4/exec"
k8s "github.com/juju/juju/caas/kubernetes"
"github.com/juju/juju/caas/kubernetes/clientconfig"
k8scloud "github.com/juju/juju/caas/kubernetes/cloud"
jujucloud "github.com/juju/juju/cloud"
"github.com/juju/juju/core/version"
envtools "github.com/juju/juju/environs/tools"
)
func attemptMicroK8sCloud(cmdRunner CommandRunner, getKubeConfigDir func() (string, error)) (jujucloud.Cloud, error) {
microk8sConfig, err := getLocalMicroK8sConfig(cmdRunner, getKubeConfigDir)
if err != nil {
return jujucloud.Cloud{}, err
}
k8sCloud, err := k8scloud.CloudFromKubeConfigClusterReader(
k8s.MicroK8sClusterName,
bytes.NewReader(microk8sConfig),
k8scloud.CloudParamaters{
Description: jujucloud.DefaultCloudDescription(jujucloud.CloudTypeKubernetes),
Name: k8s.K8sCloudMicrok8s,
Regions: []jujucloud.Region{{
Name: k8s.Microk8sRegion,
}},
},
)
return k8sCloud, err
}
func attemptMicroK8sCredential(ctx context.Context, cmdRunner CommandRunner, getKubeConfigDir func() (string, error)) (jujucloud.Credential, error) {
microk8sConfig, err := getLocalMicroK8sConfig(cmdRunner, getKubeConfigDir)
if err != nil {
return jujucloud.Credential{}, err
}
k8sConfig, err := k8scloud.ConfigFromReader(bytes.NewReader(microk8sConfig))
if err != nil {
return jujucloud.Credential{}, errors.Annotate(err, "processing microk8s config to make juju credentials")
}
contextName, err := k8scloud.PickContextByClusterName(k8sConfig, k8s.MicroK8sClusterName)
if err != nil {
return jujucloud.Credential{}, errors.Trace(err)
}
context := k8sConfig.Contexts[contextName]
resolver := clientconfig.GetJujuAdminServiceAccountResolver(ctx, jujuclock.WallClock)
conf, err := resolver(k8s.K8sCloudMicrok8s, k8sConfig, contextName)
if err != nil {
return jujucloud.Credential{}, errors.Annotate(err, "resolving microk8s credentials")
}
return k8scloud.CredentialFromKubeConfig(context.AuthInfo, conf)
}
// For testing.
var CheckJujuOfficial = envtools.JujudVersion
func decideKubeConfigDir() (string, error) {
jujuDir, err := envtools.ExistingJujuLocation()
if err != nil {
return "", errors.Annotate(err, "cannot find juju binary")
}
_, isOffical, err := CheckJujuOfficial(jujuDir)
if err != nil && !errors.Is(err, errors.NotFound) {
return "", errors.Trace(err)
}
if isOffical {
return filepath.Join(os.Getenv("SNAP_DATA"), "microk8s", "credentials", "client.config"), nil
}
return filepath.Join("/var/snap/microk8s/current/", "credentials", "client.config"), nil
}
var microk8sGroupError = `
Insufficient permissions to access MicroK8s.
You can either try again with sudo or add the user %s to the 'snap_microk8s' group:
sudo usermod -a -G snap_microk8s %s
After this, reload the user groups either via a reboot or by running 'newgrp snap_microk8s'.
`[1:]
func getLocalMicroK8sConfig(cmdRunner CommandRunner, getKubeConfigDir func() (string, error)) ([]byte, error) {
if runtime.GOOS != "linux" {
return getLocalMicroK8sConfigNonLinux(cmdRunner)
}
notSupportErr := errors.NewNotSupported(nil, fmt.Sprintf("juju %q can only work with strictly confined microk8s", version.Current))
clientConfigPath, err := getKubeConfigDir()
if err != nil {
return nil, errors.Trace(err)
}
logger.Tracef("reading kubeconfig %q", clientConfigPath)
content, err := os.ReadFile(clientConfigPath)
if os.IsNotExist(err) {
return nil, errors.Annotatef(notSupportErr, "%q does not exist", clientConfigPath)
}
if os.IsPermission(err) {
user, err := utils.LocalUsername()
if err != nil {
user = "<user>"
}
return nil, errors.Errorf(microk8sGroupError, user, user)
}
if err != nil {
return nil, errors.Annotatef(err, "cannot read %q", clientConfigPath)
}
return content, nil
}
func getLocalMicroK8sConfigNonLinux(cmdRunner CommandRunner) ([]byte, error) {
_, err := cmdRunner.LookPath("microk8s")
if err != nil {
return []byte{}, errors.NotFoundf("microk8s")
}
execParams := exec.RunParams{
Commands: "microk8s config",
}
result, err := cmdRunner.RunCommands(execParams)
if err != nil {
return []byte{}, err
}
if result.Code != 0 {
// TODO - confined snaps can't execute other commands.
errMessage := strings.ReplaceAll(string(result.Stderr), "\n", "")
if strings.HasSuffix(strings.ToLower(errMessage), "permission denied") {
return []byte{}, errors.NotFoundf("microk8s")
}
return []byte{}, errors.New(string(result.Stderr))
} else {
if strings.HasPrefix(strings.ToLower(string(result.Stdout)), "microk8s is not running") {
return []byte{}, errors.NotFoundf("microk8s is not running")
}
}
return result.Stdout, nil
}