feat: [CDE-332]: Install tools (#2907)

* 

feat: [CDE-332]: Install tools
* 

feat: [CDE-332]: Install tools
* 

feat: [CDE-332]: Install tools
* 

feat: [CDE-332]: Install tools
* 

feat: [CDE-332]: Install tools
* 

feat: [CDE-332]: lint issues
* 





feat: [CDE-332]: Install tools
This commit is contained in:
Vikyath Harekal 2024-10-30 11:16:57 +00:00 committed by Harness
parent 75f695dc51
commit 9e9790a67d
13 changed files with 376 additions and 51 deletions

View File

@ -1,4 +1,4 @@
# Detect OS type
os() {
uname="$(uname)"
case $uname in
@ -9,7 +9,6 @@ os() {
esac
}
# Detect Linux distro type
distro() {
local os_name
os_name=$(os)
@ -38,7 +37,6 @@ distro() {
fi
}
# Print a human-readable name for the OS/distro
distro_name() {
if [ "$(uname)" = "Darwin" ]; then
echo "macOS v$(sw_vers -productVersion)"

View File

@ -0,0 +1,114 @@
// Copyright 2023 Harness, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package common
import (
"context"
"fmt"
"github.com/harness/gitness/app/gitspace/orchestrator/devcontainer"
"github.com/harness/gitness/app/gitspace/orchestrator/template"
"github.com/harness/gitness/types/enum"
)
const templateSupportedOSDistribution = "supported_os_distribution.sh"
const templateVsCodeWebToolsInstallation = "install_tools_vs_code_web.sh"
const templateVsCodeToolsInstallation = "install_tools_vs_code.sh"
func ValidateSupportedOS(ctx context.Context, exec *devcontainer.Exec) ([]byte, error) {
// TODO: Currently not supporting arch, freebsd and alpine.
// For alpine wee need to install multiple things from
// https://github.com/microsoft/vscode/wiki/How-to-Contribute#prerequisites
script, err := template.GenerateScriptFromTemplate(
templateSupportedOSDistribution, &template.SupportedOSDistributionPayload{
OSInfoScript: osDetectScript,
})
if err != nil {
return nil, fmt.Errorf("failed to generate scipt to validate supported os distribution from template %s: %w",
templateSupportedOSDistribution, err)
}
output, err := exec.ExecuteCommandInHomeDirectory(ctx, script, true, false)
if err != nil {
return nil, fmt.Errorf("error while detecting os distribution: %w", err)
}
return output, nil
}
func InstallTools(ctx context.Context, exec *devcontainer.Exec, ideType enum.IDEType) ([]byte, error) {
switch ideType {
case enum.IDETypeVSCodeWeb:
{
output, err := InstallToolsForVsCodeWeb(ctx, exec)
if err != nil {
return []byte(output), err
}
return []byte(output), nil
}
case enum.IDETypeVSCode:
{
output, err := InstallToolsForVsCode(ctx, exec)
if err != nil {
return []byte(output), err
}
return []byte(output), nil
}
}
return nil, nil
}
func InstallToolsForVsCodeWeb(ctx context.Context, exec *devcontainer.Exec) (string, error) {
script, err := template.GenerateScriptFromTemplate(
templateVsCodeWebToolsInstallation, &template.InstallToolsPayload{
OSInfoScript: osDetectScript,
})
if err != nil {
return "", fmt.Errorf(
"failed to generate scipt to install tools for vs code web from template %s: %w",
templateVsCodeWebToolsInstallation, err)
}
output := "Installing tools for vs code web inside container\n"
_, err = exec.ExecuteCommandInHomeDirectory(ctx, script, true, false)
if err != nil {
return "", fmt.Errorf("failed to install tools for vs code web: %w", err)
}
output += "Successfully installed tools for vs code web\n"
return output, nil
}
func InstallToolsForVsCode(ctx context.Context, exec *devcontainer.Exec) (string, error) {
script, err := template.GenerateScriptFromTemplate(
templateVsCodeToolsInstallation, &template.InstallToolsPayload{
OSInfoScript: osDetectScript,
})
if err != nil {
return "", fmt.Errorf(
"failed to generate scipt to install tools for vs code from template %s: %w",
templateVsCodeToolsInstallation, err)
}
output := "Installing tools for vs code inside container\n"
_, err = exec.ExecuteCommandInHomeDirectory(ctx, script, true, false)
if err != nil {
return "", fmt.Errorf("failed to install tools for vs code: %w", err)
}
output += "Successfully installed tools for vs code\n"
return output, nil
}

View File

@ -24,6 +24,7 @@ import (
"strings"
"github.com/harness/gitness/app/gitspace/logutil"
"github.com/harness/gitness/app/gitspace/orchestrator/common"
"github.com/harness/gitness/app/gitspace/orchestrator/devcontainer"
"github.com/harness/gitness/app/gitspace/orchestrator/git"
"github.com/harness/gitness/app/gitspace/orchestrator/ide"
@ -31,6 +32,7 @@ import (
"github.com/harness/gitness/app/gitspace/scm"
"github.com/harness/gitness/infraprovider"
"github.com/harness/gitness/types"
"github.com/harness/gitness/types/enum"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/filters"
@ -274,11 +276,21 @@ func (e *EmbeddedDockerOrchestrator) startGitspace(
AccessType: gitspaceConfig.GitspaceInstance.AccessType,
}
err = e.validateSupportedOS(ctx, exec, logStreamInstance)
if err != nil {
return err
}
err = e.manageUser(ctx, exec, logStreamInstance)
if err != nil {
return err
}
err = e.installTools(ctx, exec, logStreamInstance, gitspaceConfig.IDE)
if err != nil {
return err
}
err = e.setupIDE(ctx, exec, ideService, logStreamInstance)
if err != nil {
return err
@ -544,9 +556,9 @@ func (e *EmbeddedDockerOrchestrator) executePostCreateCommand(
return fmt.Errorf("logging error: %w", loggingErr)
}
output, err := exec.ExecuteCommand(ctx, devcontainerConfig.PostCreateCommand, false, false, codeRepoDir)
output, err := exec.ExecuteCommand(ctx, devcontainerConfig.PostCreateCommand, true, false, codeRepoDir)
if err != nil {
loggingErr = logStreamInstance.Write("Error while executing postCreate command")
loggingErr = logStreamInstance.Write("Error while executing postCreate command" + err.Error())
err = fmt.Errorf("failed to execute postCreate command %q: %w", devcontainerConfig.PostCreateCommand, err)
@ -951,6 +963,59 @@ func (e *EmbeddedDockerOrchestrator) removeContainer(
return nil
}
func (e *EmbeddedDockerOrchestrator) validateSupportedOS(
ctx context.Context,
exec *devcontainer.Exec,
logStreamInstance *logutil.LogStreamInstance,
) error {
output, err := common.ValidateSupportedOS(ctx, exec)
if err != nil {
loggingErr := logStreamInstance.Write("Error while detecting os inside container: " + err.Error())
err = fmt.Errorf("failed to detect os in %s: %w", exec.ContainerName, err)
if loggingErr != nil {
err = fmt.Errorf("original error: %w; logging error: %w", err, loggingErr)
}
return err
}
loggingErr := logStreamInstance.Write("Validate supported OSes...\n" + string(output))
if loggingErr != nil {
return fmt.Errorf("logging error: %w", loggingErr)
}
return nil
}
func (e *EmbeddedDockerOrchestrator) installTools(
ctx context.Context,
exec *devcontainer.Exec,
logStreamInstance *logutil.LogStreamInstance,
ideType enum.IDEType,
) error {
output, err := common.InstallTools(ctx, exec, ideType)
if err != nil {
loggingErr := logStreamInstance.Write("Error while installing tools inside container: " + err.Error())
err = fmt.Errorf("failed to install tools in %s: %w", exec.ContainerName, err)
if loggingErr != nil {
err = fmt.Errorf("original error: %w; logging error: %w", err, loggingErr)
}
return err
}
loggingErr := logStreamInstance.Write("Tools installation output...\n" + string(output))
if loggingErr != nil {
return fmt.Errorf("logging error: %w", loggingErr)
}
return nil
}
func (e *EmbeddedDockerOrchestrator) StreamLogs(
_ context.Context,
_ types.GitspaceConfig,

View File

@ -48,7 +48,7 @@ func (g *ServiceImpl) Install(ctx context.Context, exec *devcontainer.Exec) ([]b
"failed to generate scipt to setup git install from template %s: %w", templateGitInstallScript, err)
}
output := "Setting up git inside container\n"
_, err = exec.ExecuteCommandInHomeDirectory(ctx, script, false, false)
_, err = exec.ExecuteCommandInHomeDirectory(ctx, script, true, false)
if err != nil {
return nil, fmt.Errorf("failed to setup git: %w", err)
}

View File

@ -87,7 +87,7 @@ func (v *VSCode) Run(ctx context.Context, exec *devcontainer.Exec) ([]byte, erro
execOutput, err := exec.ExecuteCommandInHomeDirectory(ctx, runSSHScript, true, false)
if err != nil {
return nil, fmt.Errorf("failed to run SSH serverr: %w", err)
return nil, fmt.Errorf("failed to run SSH server: %w", err)
}
output += "SSH server run output...\n" + string(execOutput) + "\nSuccessfully run ssh-server\n"

View File

@ -74,6 +74,14 @@ type RunSSHServerPayload struct {
Port string
}
type InstallToolsPayload struct {
OSInfoScript string
}
type SupportedOSDistributionPayload struct {
OSInfoScript string
}
func init() {
err := LoadTemplates()
if err != nil {

View File

@ -9,34 +9,30 @@ install_git() {
# Check if Git is installed
if ! command -v git >/dev/null 2>&1; then
echo "Git is not installed. Installing Git..."
case "$(distro)" in
debian | ubuntu)
apt-get update && apt-get install -y git
;;
fedora | centos | rhel)
dnf install -y git
;;
opensuse)
zypper install -y git
;;
alpine)
apk add git
;;
arch | manjaro)
pacman -Sy --noconfirm git
;;
freebsd)
pkg install -y git
;;
macos)
brew install git
;;
*)
echo "Unsupported OS for automatic Git installation."
return 1
;;
esac
debian)
apt-get update && apt-get install -y git
;;
fedora)
dnf install -y git
;;
opensuse)
zypper install -y git
;;
alpine)
apk add git
;;
arch)
pacman -Sy --noconfirm git
;;
freebsd)
pkg install -y git
;;
*)
echo "Unsupported OS for automatic Git installation."
return 1
;;
esac
fi
# Verify installation

View File

@ -0,0 +1,21 @@
#!/bin/sh
osInfoScript={{ .OSInfoScript }}
eval "$osInfoScript"
echo "Checking if tar is installed..."
if ! command -v tar >/dev/null 2>&1; then
echo "Installing tar for $(distro)"
case "$(distro)" in
opensuse)
zypper install -y tar
zypper install -y gzip
;;
*)
echo "Distribution: $distro. tar installation not required"
exit 1
;;
esac
echo "tar installation completed."
fi

View File

@ -0,0 +1,57 @@
#!/bin/sh
osInfoScript={{ .OSInfoScript }}
eval "$osInfoScript"
# Check if curl is installed
echo "Checking if curl is installed..."
if ! command -v curl >/dev/null 2>&1; then
echo "Installing curl for $(distro)"
case "$(distro)" in
debian)
apt update && apt install -y curl
;;
fedora)
dnf install -y curl
;;
opensuse)
zypper install -y curl
;;
alpine)
apk add --no-cache curl
;;
arch)
pacman -Syu --noconfirm curl
;;
freebsd)
pkg install -y curl
;;
*)
echo "Unsupported distribution: $distro."
exit 1
;;
esac
echo "Curl installation completed."
fi
if ! command -v npm >/dev/null 2>&1; then
echo "Installing npm..."
case "$(distro)" in
alpine)
echo "Detected Alpine Linux. Installing npm..."
apk update
apk add nodejs npm
;;
freebsd)
echo "Detected FreeBSD. Installing npm..."
pkg update
pkg install -y node
;;
*)
echo "Distribution: $distro. npm installation not required"
;;
esac
echo "npm installation completed."
fi

View File

@ -10,18 +10,39 @@ eval "$osInfoScript"
# Check if the user already exists
if id "$username" >/dev/null 2>&1; then
echo "User $username already exists."
echo "User $username already exists."
else
# Create a new user
case "$(distro)" in
debian | ubuntu)
# Create a new user
case "$(distro)" in
debian)
apt-get update && apt-get install -y adduser
adduser --disabled-password --home "$homeDir" --gecos "" "$username"
usermod -aG sudo "$username"
;;
fedora | centos | rhel)
fedora)
useradd -m -d "$homeDir" "$username"
usermod -aG wheel "$username"
;;
opensuse)
useradd -m -d "$homeDir" "$username"
passwd -l "$username" # Locks the password to prevent login
zypper in -y sudo
groupadd sudo
usermod -aG sudo "$username"
echo "%sudo ALL=(ALL:ALL) NOPASSWD: ALL" >> /etc/sudoers
chown -R "$username":sudo "$homeDir"
;;
alpine)
adduser -h "$homeDir" -s /bin/ash -D "$username" # Default shell is ash for Alpine
;;
arch)
useradd -m -d "$homeDir" -s /bin/bash "$username"
;;
freebsd)
pw useradd -n "$username" -d "$homeDir" -m
;;
*)
echo "Unsupported distribution for user creation. Exiting..."
echo "Unsupported distribution: $distro."
exit 1
;;
esac

View File

@ -4,6 +4,28 @@ SSH_PORT={{ .Port }}
config_file='/etc/ssh/sshd_config'
HOST_KEYS="/etc/ssh/ssh_host_rsa_key /etc/ssh/ssh_host_ecdsa_key /etc/ssh/ssh_host_ed25519_key"
for KEY in $HOST_KEYS; do
if [ ! -f "$KEY" ]; then
echo "Generating host key: $KEY"
case "$KEY" in
"/etc/ssh/ssh_host_rsa_key")
ssh-keygen -t rsa -b 4096 -f "$KEY" -N ""
;;
"/etc/ssh/ssh_host_ecdsa_key")
ssh-keygen -t ecdsa -b 521 -f "$KEY" -N ""
;;
"/etc/ssh/ssh_host_ed25519_key")
ssh-keygen -t ed25519 -f "$KEY" -N ""
;;
esac
chmod 600 "$KEY"
chmod 644 "${KEY}.pub"
else
echo "Host key already exists: $KEY"
fi
done
# Change the default SSH port
sed -i "s/^#Port 22/Port $SSH_PORT/" $config_file
if ! grep -q "^Port $SSH_PORT" $config_file; then

View File

@ -9,24 +9,32 @@ if ! command -v sshd >/dev/null 2>&1; then
echo "OpenSSH server is not installed. Installing..."
case "$(distro)" in
debian | ubuntu)
debian)
apt-get update
apt-get install -y openssh-server
;;
fedora | centos | rhel)
;;
fedora)
dnf install -y openssh-server
;;
;;
opensuse)
zypper install -y openssh
;;
;;
alpine)
apk add openssh
;;
apk add openssh
;;
arch)
pacman -Syu --noconfirm openssh
;;
freebsd)
pkg install -y openssh-portable
;;
*)
echo "Unsupported distribution for SSH installation. Exiting..."
exit 1
;;
esac
echo "Unsupported distribution: $distro."
exit 1
;;
esac
else
echo "OpenSSH server is already installed."
fi

View File

@ -0,0 +1,15 @@
#!/bin/sh
osInfoScript={{ .OSInfoScript }}
eval "$osInfoScript"
case "$(distro)" in
debian|fedora|opensuse)
echo "Detected $(distro) distribution"
;;
*)
echo "Unsupported distribution: $distro." >&2
exit 1
;;
esac