Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DEVOPS-3141 Fix tsh not found issue after installation #119

Merged
merged 7 commits into from
Nov 9, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 8 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,28 +57,24 @@ For a full list of functionalities, run `ridectl --help`
### Manual Installation
You can find pre-compiled macOS and Linux binaries for `ridectl` [on the GitHub releases page](https://github.com/Ridecell/ridectl/releases/latest).

Download the one appropriate to your platform, unzip it, and copy it to `/usr/local/bin/ridectl` or similar. Run `ridectl -h` to confirm it is installed correctly.
Download the one appropriate to your platform, unzip it, and copy it to `/usr/local/bin/ridectl` or similar. Run `ridectl status` for further configutation.

# Mac-os
```
curl -L "https://github.com/Ridecell/ridectl/releases/latest/download/ridectl_macos.zip" -o ./ridectl_macos.zip
unzip ridectl_macos.zip
chmod 0755 ridectl
cp ridectl /usr/local/bin/ridectl
ridectl -h
sudo cp ridectl /usr/local/bin/ridectl
# Follow instructions for further configuration
ridectl status
```
When running ridectl for first time, mac os will not allow the binary to execute. So solve this issue, navigate to System Prefrences > Security & Privacy and in General section, allow ridectl to open.
**Note:** When running `ridectl` for first time, Mac OS will not allow the binary to execute. So, to solve this issue, navigate to `System Prefrences` > `Security & Privacy` and in `General` section, allow `ridectl` to open.
# Linux
```
curl -L "https://github.com/Ridecell/ridectl/releases/latest/download/ridectl_linux.zip" -o ./ridectl_linux.zip
unzip ridectl_linux.zip
chmod 0755 ridectl
cp ridectl /usr/local/bin/ridectl
ridectl -h
sudo cp ridectl /usr/local/bin/ridectl
# Follow instructions for further configuration
ridectl status
```

# Add kubernetes contexts
You can follow the quip doc [here](https://ridecell.quip.com/O8W1AaqtWWAH/Ridectl)

Note:
Old ridectl code is still present [here](https://github.com/Ridecell/ridectl/tree/ridectl-v0.0.0). Ref:- ridectl-v0.0.0
16 changes: 16 additions & 0 deletions pkg/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import (
"github.com/pterm/pterm"
"github.com/spf13/cobra"
"k8s.io/client-go/kubernetes/scheme"
"github.com/Ridecell/ridectl/pkg/utils"

dbv1beta2 "github.com/Ridecell/ridecell-controllers/apis/db/v1beta2"
secretsv1beta2 "github.com/Ridecell/ridecell-controllers/apis/secrets/v1beta2"
Expand Down Expand Up @@ -76,6 +77,10 @@ func init() {
rootCmd.PersistentFlags().StringVar(&kubeconfigFlag, "kubeconfig", filepath.Join(home, ".kube", "config"), "(optional) absolute path to the kubeconfig file")
rootCmd.Flags().BoolVar(&versionFlag, "version", false, "--version")
rootCmd.PersistentFlags().BoolVar(&inCluster, "incluster", false, "(optional) use in cluster kube config")

// Display announcement banner if present
displayAnnouncementBanner()

// check version and update if not latest
if !isLatestVersion() {
updatePrompt := promptui.Prompt{
Expand All @@ -85,6 +90,8 @@ func init() {
shouldUpdate, _ := updatePrompt.Run()
if shouldUpdate == "y" {
selfUpdate()
pterm.Info.Println("Ridectl update is completed. Please re-run the command.")
os.Exit(0)
}
}
// Register all types from summon-operator and ridecell-controllers secrets
Expand Down Expand Up @@ -197,3 +204,12 @@ func getBinary(src []byte) (io.Reader, error) {
}
return nil, fmt.Errorf("failed to find binary in zip file")
}

func displayAnnouncementBanner() {
announcementMessage := utils.GetAnnouncementMessage()
if announcementMessage == "" {
return
}

pterm.Info.Printf(announcementMessage+"\n")
}
66 changes: 56 additions & 10 deletions pkg/exec/exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,33 +15,79 @@ package exec

import (
"bytes"
"crypto/md5"
_ "embed"
"encoding/hex"
"fmt"
"io"
"os"
"os/exec"
"path/filepath"

"github.com/pkg/errors"
"github.com/pterm/pterm"
)

var (
//go:embed bin/tsh
tsh []byte
tshMD5 string
tshInstallDir = "/usr/local/bin/"
)

func InstallTsh() error {
executablePath, _ := os.Executable()
dir, err := filepath.Abs(filepath.Dir(executablePath))
if err != nil {
func InstallOrUpgradeTsh() error {
binPath, installed := CheckBinary("tsh")
if !installed {
pterm.Info.Println("Tsh binary not found, installing using sudo...")
// First write tsh binary to tmp
err := os.WriteFile("/tmp/tsh", tsh, 0755)
if err != nil {
return err
}
// Copy tsh binary to Bin Path
cp := []string{"cp", "/tmp/tsh", tshInstallDir}
err = ExecuteCommand("sudo", cp, false)
if err == nil {
pterm.Info.Println("Tsh installation completed.")
return nil
}
return err
}
// First write tsh binary to tmp
err = os.WriteFile("/tmp/tsh", tsh, 0755)
if err != nil {

//Generate MD5 hash of installed tsh binary
f, err := os.Open(binPath)
if err != nil {
return errors.Wrapf(err, "Error opening tsh")
}
defer f.Close()

hash := md5.New()
_, err = io.Copy(hash, f)
if err != nil {
return errors.Wrapf(err, "Error generating hash for tsh")
}
// Check if tsh binary's md5 is same; if not, install tsh
if hex.EncodeToString(hash.Sum(nil)) != GetTshMd5Hash() {
pterm.Info.Println("Tsh version not matched, re-installing using sudo...")
// First write tsh binary to tmp
err = os.WriteFile("/tmp/tsh", tsh, 0755)
if err != nil {
return err
}
dir, err := filepath.Abs(filepath.Dir(binPath))
if err != nil {
return err
}
// Copy tsh binary to Bin Path
cp := []string{"cp", "/tmp/tsh", dir}
err = ExecuteCommand("sudo", cp, false)
if err == nil {
pterm.Info.Println("Tsh upgrade completed.")
return nil
}
return err
}
// Copy tsh binary to Bin Path
cp := []string{"cp", "/tmp/tsh", dir}
return ExecuteCommand("sudo", cp, false)
return nil
}

func GetTshMd5Hash() string {
Expand Down
49 changes: 15 additions & 34 deletions pkg/utils/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,9 @@ limitations under the License.
package utils

import (
"crypto/md5"
"encoding/hex"
"flag"
"io"
"net/http"
"io"
"os"
"path/filepath"
"strings"
Expand Down Expand Up @@ -69,41 +67,12 @@ func CheckVPN() {
}
}

func installTsh() {
err := exec.InstallTsh()
if err != nil {
pterm.Error.Printf("Error installing tsh : %s\n", err)
os.Exit(1)
}
pterm.Info.Println("Tsh installation completed.")
}

func CheckTshLogin() {
binPath, installed := exec.CheckBinary("tsh")
if !installed {
pterm.Info.Println("Tsh cli not found, installing using sudo...")
installTsh()
}

//Generate MD5 hash of installed tsh binary
f, err := os.Open(binPath)
err := exec.InstallOrUpgradeTsh()
if err != nil {
pterm.Error.Printf("Error opening tsh : %s\n", err)
pterm.Error.Printf("Error while installing or upgrading tsh : %s\n", err)
os.Exit(1)
}
defer f.Close()

hash := md5.New()
_, err = io.Copy(hash, f)
if err != nil {
pterm.Error.Printf("Error generating hash for tsh : %s\n", err)
os.Exit(1)
}
// Check if tsh binary's md5 is same; if not, install tsh
if hex.EncodeToString(hash.Sum(nil)) != exec.GetTshMd5Hash() {
pterm.Info.Println("Tsh version not matched, re-installing using sudo...")
installTsh()
}

// Check if tsh login profile is active or not
statusArgs := []string{"status"}
Expand All @@ -118,3 +87,15 @@ func CheckTshLogin() {
pterm.Error.Println("No teleport profile found. Refer teleport login command from FAQs:\nhttps://ridecell.quip.com/CILaAnAUnkla/Ridectl-FAQs#temp:C:ZZZabcdcead11c941ccbb5ad29b3 ")
os.Exit(1)
}

func GetAnnouncementMessage() string {
resp, err := http.Get("https://ridectl.s3.us-west-2.amazonaws.com/ridectl-announcement-banner.txt")
if err == nil && resp.StatusCode == 200 {
content, err := io.ReadAll(resp.Body)
if err == nil {
return string(content)
}
}
defer resp.Body.Close()
return ""
}