2 Copyright 2019 The Kubeedge Authors.
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
8 http://www.apache.org/licenses/LICENSE-2.0
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.
25 //types "github.com/kubeedge/kubeedge/keadm/app/cmd/common"
26 types "elcli/cmd/common"
29 const downloadRetryTimes int = 3
33 UbuntuXenial = "xenial"
34 UbuntuBionic = "bionic"
37 //UbuntuOS struct objects shall have information of the tools version to be installed
38 //on Hosts having Ubuntu OS.
39 //It implements OSTypeInstaller interface
40 type UbuntuOS struct {
42 KubernetesVersion string
43 KubeEdgeVersion string
44 IsEdgeNode bool //True - Edgenode False - EliotCloudnode
45 K8SImageRepository string
46 K8SPodNetworkCidr string
49 //SetDockerVersion sets the Docker version for the objects instance
50 func (u *UbuntuOS) SetDockerVersion(version string) {
51 u.DockerVersion = version
54 //SetK8SVersionAndIsNodeFlag sets the K8S version for the objects instance
55 //It also sets if this host shall act as edge node or not
56 func (u *UbuntuOS) SetK8SVersionAndIsNodeFlag(version string, flag bool) {
57 u.KubernetesVersion = version
61 //SetK8SImageRepoAndPodNetworkCidr sets the K8S image Repository and pod network
63 func (u *UbuntuOS) SetK8SImageRepoAndPodNetworkCidr(repo, cidr string) {
64 u.K8SImageRepository = repo
65 u.K8SPodNetworkCidr = cidr
68 //SetKubeEdgeVersion sets the KubeEdge version for the objects instance
69 func (u *UbuntuOS) SetKubeEdgeVersion(version string) {
70 u.KubeEdgeVersion = version
73 //IsToolVerInRepo checks if the tool mentioned in available in OS repo or not
74 func (u *UbuntuOS) IsToolVerInRepo(toolName, version string) (bool, error) {
75 //Check if requested Docker or K8S components said version is available in OS repo or not
77 chkToolVer := fmt.Sprintf("apt-cache madison '%s' | grep -w %s | head -1 | awk '{$1=$1};1' | cut -d' ' -f 3", toolName, version)
78 cmd := &Command{Cmd: exec.Command("sh", "-c", chkToolVer)}
80 stdout := cmd.GetStdOutput()
81 errout := cmd.GetStdErr()
84 return false, fmt.Errorf("%s", errout)
88 fmt.Println(toolName, stdout, "is available in OS repo")
92 fmt.Println(toolName, "version", version, "not found in OS repo")
96 func (u *UbuntuOS) addDockerRepositoryAndUpdate() error {
98 cmd := &Command{Cmd: exec.Command("sh", "-c", "lsb_release -cs")}
100 distVersion := cmd.GetStdOutput()
101 if distVersion == "" {
102 return fmt.Errorf("ubuntu dist version not available")
104 fmt.Println("Ubuntu distribution version is", distVersion)
107 stdout, err := runCommandWithShell("apt-get update")
113 //"curl -fsSL \"$DOWNLOAD_URL/linux/$lsb_dist/gpg\" | apt-key add"
115 curl := fmt.Sprintf("curl -fsSL \"%s/linux/%s/gpg\" | apt-key add", DefaultDownloadURL, UbuntuOSType)
116 cmd = &Command{Cmd: exec.Command("sh", "-c", curl)}
118 curlOutput := cmd.GetStdOutput()
119 if curlOutput == "" {
120 return fmt.Errorf("not able add the apt key")
122 fmt.Println(curlOutput)
124 //Add the repo in OS source.list
125 aptRepo := fmt.Sprintf("deb [arch=$(dpkg --print-architecture)] %s/linux/%s %s stable", DefaultDownloadURL, UbuntuOSType, distVersion)
126 updtRepo := fmt.Sprintf("echo \"%s\" > /etc/apt/sources.list.d/docker.list", aptRepo)
127 cmd = &Command{Cmd: exec.Command("sh", "-c", updtRepo)}
129 updtRepoErr := cmd.GetStdErr()
130 if updtRepoErr != "" {
131 return fmt.Errorf("not able add update repo due to error : %s", updtRepoErr)
134 //Do an apt-get update
135 stdout, err = runCommandWithShell("apt-get update")
144 //IsDockerInstalled checks if docker is installed in the host or not
145 func (u *UbuntuOS) IsDockerInstalled(defVersion string) (types.InstallState, error) {
146 cmd := &Command{Cmd: exec.Command("sh", "-c", "docker -v | cut -d ' ' -f3 | cut -d ',' -f1")}
148 str := cmd.GetStdOutput()
150 if strings.Contains(str, u.DockerVersion) {
151 return types.AlreadySameVersionExist, nil
154 if err := u.addDockerRepositoryAndUpdate(); err != nil {
155 return types.VersionNAInRepo, err
159 return types.NewInstallRequired, nil
162 isReqVerAvail, err := u.IsToolVerInRepo("docker-ce", u.DockerVersion)
164 return types.VersionNAInRepo, err
167 var isDefVerAvail bool
168 if u.DockerVersion != defVersion {
169 isDefVerAvail, err = u.IsToolVerInRepo("docker-ce", defVersion)
171 return types.VersionNAInRepo, err
176 return types.NewInstallRequired, nil
180 return types.DefVerInstallRequired, nil
183 return types.VersionNAInRepo, nil
186 //InstallDocker will install the specified docker in the host
187 func (u *UbuntuOS) InstallDocker() error {
188 fmt.Println("Installing ", u.DockerVersion, "version of docker")
190 //Do an apt-get install
191 instPreReq := fmt.Sprintf("apt-get install -y %s", DockerPreqReqList)
192 stdout, err := runCommandWithShell(instPreReq)
198 //Get the exact version string from OS repo, so that it can search and install.
199 chkDockerVer := fmt.Sprintf("apt-cache madison 'docker-ce' | grep %s | head -1 | awk '{$1=$1};1' | cut -d' ' -f 3", u.DockerVersion)
200 cmd := &Command{Cmd: exec.Command("sh", "-c", chkDockerVer)}
202 stdout = cmd.GetStdOutput()
203 errout := cmd.GetStdErr()
205 return fmt.Errorf("%s", errout)
208 fmt.Println("Expected docker version to install is", stdout)
211 dockerInst := fmt.Sprintf("apt-get install -y --allow-change-held-packages --allow-downgrades docker-ce=%s", stdout)
212 stdout, err = runCommandWithShell(dockerInst)
218 fmt.Println("Docker", u.DockerVersion, "version is installed in this Host")
223 //IsK8SComponentInstalled checks if said K8S version is already installed in the host
224 func (u *UbuntuOS) IsK8SComponentInstalled(component, defVersion string) (types.InstallState, error) {
226 find := fmt.Sprintf("dpkg -l | grep %s | awk '{print $3}'", component)
227 cmd := &Command{Cmd: exec.Command("sh", "-c", find)}
229 str := cmd.GetStdOutput()
231 if strings.Contains(str, u.KubernetesVersion) {
232 return types.AlreadySameVersionExist, nil
235 if err := u.addK8SRepositoryAndUpdate(); err != nil {
236 return types.VersionNAInRepo, err
240 return types.NewInstallRequired, nil
243 isReqVerAvail, err := u.IsToolVerInRepo(component, u.KubernetesVersion)
245 return types.VersionNAInRepo, err
248 var isDefVerAvail bool
249 if u.KubernetesVersion != defVersion {
250 isDefVerAvail, _ = u.IsToolVerInRepo(component, defVersion)
252 return types.VersionNAInRepo, err
257 return types.NewInstallRequired, nil
261 return types.DefVerInstallRequired, nil
264 return types.VersionNAInRepo, nil
267 func (u *UbuntuOS) addK8SRepositoryAndUpdate() error {
268 //Get the distribution version
269 cmd := &Command{Cmd: exec.Command("sh", "-c", "lsb_release -cs")}
271 distVersion := cmd.GetStdOutput()
272 if distVersion == "" {
273 return fmt.Errorf("ubuntu dist version not available")
275 fmt.Println("Ubuntu distribution version is", distVersion)
276 distVersionForSuite := distVersion
277 if distVersion == UbuntuBionic {
278 // No bionic-specific version is available on apt.kubernetes.io.
279 // Use xenial version instead.
280 distVersionForSuite = UbuntuXenial
282 suite := fmt.Sprintf("kubernetes-%s", distVersionForSuite)
283 fmt.Println("Deb suite to use:", suite)
285 //Do an apt-get update
286 stdout, err := runCommandWithShell("apt-get update")
292 //curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add -
294 curl := fmt.Sprintf("curl -s %s | apt-key add -", KubernetesGPGURL)
295 cmd = &Command{Cmd: exec.Command("sh", "-c", curl)}
297 curlOutput := cmd.GetStdOutput()
298 curlErr := cmd.GetStdErr()
299 if curlOutput == "" || curlErr != "" {
300 return fmt.Errorf("not able add the apt key due to error : %s", curlErr)
302 fmt.Println(curlOutput)
304 //Add K8S repo to local apt-get source.list
305 aptRepo := fmt.Sprintf("deb %s %s main", KubernetesDownloadURL, suite)
306 updtRepo := fmt.Sprintf("echo \"%s\" > /etc/apt/sources.list.d/kubernetes.list", aptRepo)
307 cmd = &Command{Cmd: exec.Command("sh", "-c", updtRepo)}
309 updtRepoErr := cmd.GetStdErr()
310 if updtRepoErr != "" {
311 return fmt.Errorf("not able add update repo due to error : %s", updtRepoErr)
314 //Do an apt-get update
315 stdout, err = runCommandWithShell("apt-get update")
323 //InstallK8S will install kubeadm, kudectl and kubelet for the cloud node
324 func (u *UbuntuOS) InstallK8S() error {
325 k8sComponent := "kubeadm"
326 fmt.Println("Installing", k8sComponent, u.KubernetesVersion, "version")
328 //Get the exact version string from OS repo, so that it can search and install.
329 chkKubeadmVer := fmt.Sprintf("apt-cache madison '%s' | grep %s | head -1 | awk '{$1=$1};1' | cut -d' ' -f 3", k8sComponent, u.KubernetesVersion)
330 cmd := &Command{Cmd: exec.Command("sh", "-c", chkKubeadmVer)}
332 stdout := cmd.GetStdOutput()
333 errout := cmd.GetStdErr()
335 return fmt.Errorf("%s", errout)
338 fmt.Println("Expected K8S('", k8sComponent, "') version to install is", stdout)
340 //Install respective K8S components based on where it is being installed
341 k8sInst := fmt.Sprintf("apt-get install -y --allow-change-held-packages --allow-downgrades kubeadm=%s kubelet=%s kubectl=%s", stdout, stdout, stdout)
342 stdout, err := runCommandWithShell(k8sInst)
348 fmt.Println(k8sComponent, "version", u.KubernetesVersion, "is installed in this Host")
353 //StartK8Scluster will do "kubeadm init" and cluster will be started
354 func (u *UbuntuOS) StartK8Scluster() error {
356 cmd := &Command{Cmd: exec.Command("sh", "-c", "kubeadm version")}
358 str := cmd.GetStdOutput()
365 k8sInit := fmt.Sprintf("swapoff -a && kubeadm init --image-repository \"%s\" --pod-network-cidr=%s", u.K8SImageRepository, u.K8SPodNetworkCidr)
366 stdout, err := runCommandWithShell(k8sInit)
372 stdout, err = runCommandWithShell("mkdir -p $HOME/.kube && cp -r /etc/kubernetes/admin.conf $HOME/.kube/config && sudo chown $(id -u):$(id -g) $HOME/.kube/config")
378 return fmt.Errorf("kubeadm not installed in this host")
380 fmt.Println("Kubeadm init successfully executed")
383 // // runCommandWithShell executes the given command with "sh -c".
384 // // It returns an error if the command outputs anything on the stderr.
385 // func runCommandWithShell(command string) (string, error) {
386 // cmd := &Command{Cmd: exec.Command("sh", "-c", command)}
387 // err := cmd.ExecuteCmdShowOutput()
391 // errout := cmd.GetStdErr()
393 // return "", fmt.Errorf("%s", errout)
395 // return cmd.GetStdOutput(), nil