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

Add SSH provider #69

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
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: 20 additions & 0 deletions cmd/flag.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,3 +117,23 @@ var (
Usage: "An optional Google Cloud Zone (default: random)",
}
)

// SSH flags
var (
SshFlag = cli.BoolFlag{
Name: provider.NameSsh,
Usage: "The darknode will be installed on an existing server with SSH",
}
SshUserFlag = cli.StringFlag{
Name: "ssh-user",
Usage: "SSH User",
}
SshHostnameFlag = cli.StringFlag{
Name: "ssh-hostname",
Usage: "SSH Hostname",
}
SshPrivateKeyFlag = cli.StringFlag{
Name: "ssh-private-key",
Usage: "SSH Private key",
}
)
2 changes: 2 additions & 0 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ func main() {
DoFlag, DoRegionFlag, DoSizeFlag, DoTokenFlag,
// Google Cloud Platform
GcpFlag, GcpZoneFlag, GcpCredFlag, GcpMachineFlag,
// SSH
SshFlag, SshUserFlag, SshHostnameFlag, SshPrivateKeyFlag,
},
Action: func(c *cli.Context) error {
p, err := provider.ParseProvider(c)
Expand Down
5 changes: 5 additions & 0 deletions cmd/provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ var (
NameAws = "aws"
NameDo = "do"
NameGcp = "gcp"
NameSsh = "ssh"
)

var darknodeService = `[Unit]
Expand Down Expand Up @@ -68,6 +69,10 @@ func ParseProvider(ctx *cli.Context) (Provider, error) {
return NewGcp(ctx)
}

if ctx.Bool(NameSsh) {
return NewSsh(ctx)
}

return nil, ErrUnknownProvider
}

Expand Down
57 changes: 57 additions & 0 deletions cmd/provider/ssh.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package provider

import (
"github.com/renproject/darknode-cli/darknode"
"github.com/renproject/darknode-cli/util"
"github.com/urfave/cli"
)

type providerSsh struct {
user string
hostname string
priKeyPath string
}

func NewSsh(ctx *cli.Context) (Provider, error) {
user := ctx.String("ssh-user")
hostname := ctx.String("ssh-hostname")
priKeyPath := ctx.String("ssh-private-key")

return providerSsh{
user: user,
hostname: hostname,
priKeyPath: priKeyPath,
}, nil
}

func (p providerSsh) Name() string {
return NameSsh
}

func (p providerSsh) Deploy(ctx *cli.Context) error {
name := ctx.String("name")
tags := ctx.String("tags")

latestVersion, err := util.LatestStableRelease()
if err != nil {
return err
}

// Initialization
network, err := darknode.NewNetwork(ctx.String("network"))
if err != nil {
return err
}
if err := initNode(name, tags, network); err != nil {
return err
}

// Generate terraform config and start deploying
if err := p.tfConfig(name, latestVersion); err != nil {
return err
}
if err := runTerraform(name); err != nil {
return err
}
return outputURL(name)
}
130 changes: 130 additions & 0 deletions cmd/provider/ssh_template.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
package provider

import (
"fmt"
"os"
"path/filepath"
"text/template"

"github.com/renproject/darknode-cli/util"
)

type sshTerraform struct {
Name string
User string
Hostname string
PubKeyPath string
RootPriKeyPath string
ConfigPath string
ServiceFile string
LatestVersion string
}

func (p providerSsh) tfConfig(name, latestVersion string) error {
tf := sshTerraform{
Name: name,
User: p.user,
Hostname: p.hostname,
ConfigPath: fmt.Sprintf("~/.darknode/darknodes/%v/config.json", name),
PubKeyPath: fmt.Sprintf("~/.darknode/darknodes/%v/ssh_keypair.pub", name),
RootPriKeyPath: fmt.Sprintf(p.priKeyPath),
ServiceFile: darknodeService,
LatestVersion: latestVersion,
}

t, err := template.New("ssh").Parse(sshTemplate)
if err != nil {
return err
}
tfFile, err := os.Create(filepath.Join(util.NodePath(name), "main.tf"))
if err != nil {
return err
}
return t.Execute(tfFile, tf)
}

var sshTemplate = `
resource "null_resource" "darknode" {
provisioner "remote-exec" {
inline = [
"set -x",
"until sudo apt update; do sleep 4; done",
"sudo adduser darknode --gecos \",,,\" --disabled-password",
"sudo rsync --archive --chown=darknode:darknode ~/.ssh /home/darknode",
"until sudo apt-get -y update; do sleep 4; done",
"until sudo apt-get -y upgrade; do sleep 4; done",
"until sudo apt-get -y autoremove; do sleep 4; done",
"until sudo apt-get install ufw; do sleep 4; done",
"sudo ufw limit 22/tcp",
"sudo ufw allow 18514/tcp",
"sudo ufw allow 18515/tcp",
"sudo ufw --force enable",
"until sudo apt-get -y install jq; do sleep 4; done",
]

connection {
host = "{{.Hostname}}"
type = "ssh"
user = "{{.User}}"
private_key = file("{{.RootPriKeyPath}}")
}
}

provisioner "file" {
source = "{{.ConfigPath}}"
destination = "$HOME/config.json"

connection {
host = "{{.Hostname}}"
type = "ssh"
user = "darknode"
private_key = file("{{.RootPriKeyPath}}")
}
}

provisioner "remote-exec" {
inline = [
"set -x",
"mkdir -p $HOME/.darknode/bin",
"mkdir -p $HOME/.config/systemd/user",
"mv $HOME/config.json $HOME/.darknode/config.json",
"curl -sL https://www.github.com/renproject/darknode-release/releases/latest/download/darknode > ~/.darknode/bin/darknode",
"chmod +x ~/.darknode/bin/darknode",
"echo {{.LatestVersion}} > ~/.darknode/version",
<<EOT
echo "{{.ServiceFile}}" > ~/.config/systemd/user/darknode.service
EOT
,
"loginctl enable-linger darknode",
"systemctl --user enable darknode.service",
"systemctl --user start darknode.service",
]

connection {
host = "{{.Hostname}}"
type = "ssh"
user = "darknode"
private_key = file("{{.RootPriKeyPath}}")
}
}

provisioner "file" {
source = "{{.PubKeyPath}}"
destination = "$HOME/.ssh/authorized_keys"

connection {
host = "{{.Hostname}}"
type = "ssh"
user = "darknode"
private_key = file("{{.RootPriKeyPath}}")
}
}
}

output "provider" {
value = "ssh"
}

output "ip" {
value = "{{.Hostname}}"
}`