11package main
22
33import (
4+ "bufio"
5+ "bytes"
6+ "context"
7+ "encoding/json"
48 "fmt"
59 "io/ioutil"
610 "net/http"
11+ "os"
12+ "strings"
13+ "time"
714
815 "github.com/fatih/color"
16+ "github.com/hashicorp/go-version"
917 "github.com/renproject/darknode-cli/util"
1018 "github.com/renproject/phi"
1119 "github.com/urfave/cli"
@@ -15,23 +23,62 @@ import (
1523// to update the config file of the darknode.
1624func updateNode (ctx * cli.Context ) error {
1725 name := ctx .Args ().First ()
18- if err := util .ValidateNodeName (name ); err != nil {
19- return err
20- }
2126 tags := ctx .String ("tags" )
2227 version := ctx .String ("version" )
2328
2429 nodes , err := util .ParseNodesFromNameAndTags (name , tags )
2530 if err != nil {
2631 return err
2732 }
33+ if ! compareVersion (nodes , version ){
34+ return nil
35+ }
36+
2837 errs := make ([]error , len (nodes ))
2938 phi .ParForAll (nodes , func (i int ) {
3039 errs [i ] = updateSingleNode (nodes [i ], version )
3140 })
3241 return util .HandleErrs (errs )
3342}
3443
44+ // Compare the current version and target version. Show warning to user if the
45+ // current version is greater than the target version and confirm with user
46+ // before updating. Returned boolean indicates whether we want to continue.
47+ func compareVersion (nodes []string , new string ) bool {
48+ curVersions := make ([]string , len (nodes ))
49+ phi .ParForAll (nodes , func (i int ) {
50+ // Ignore the error. Leave the version as empty string if we cannot get its current version.
51+ curVersions [i ], _ = getCurrentVersion (nodes [i ])
52+ })
53+
54+ newVersion , err := version .NewVersion (new )
55+ if err != nil {
56+ return true
57+ }
58+ lower := false
59+ for i , ver := range curVersions {
60+ if ver == "" {
61+ continue
62+ }
63+ curVersion , err := version .NewVersion (ver )
64+ if err != nil {
65+ continue
66+ }
67+ if curVersion .GreaterThan (newVersion ){
68+ color .Red ("Darknode [%v] currently running with version %v, and you are trying to downgrade to %v" , nodes [i ], curVersion .String (), newVersion .String ())
69+ lower = true
70+ }
71+ }
72+ if lower {
73+ color .Red ("Do you want to continue?(y/N)" )
74+ reader := bufio .NewReader (os .Stdin )
75+ text , _ := reader .ReadString ('\n' )
76+ input := strings .ToLower (strings .TrimSpace (text ))
77+ return input == "yes" || input == "y"
78+ }
79+ return true
80+ }
81+
3582func updateSingleNode (name , ver string ) error {
3683 url := "https://www.github.com/renproject/darknode-release/releases/latest/download/darknode"
3784 if ver != "" {
@@ -41,7 +88,7 @@ func updateSingleNode(name, ver string) error {
4188 url = fmt .Sprintf ("https://github.com/renproject/darknode-release/releases/download/%v/darknode" , ver )
4289 }
4390
44- script := fmt .Sprintf (`rm ~/.darknode/bin/darknode && curl -sL %v > ~/.darknode/bin/darknode && chmod +x ~/.darknode/bin/darknode && systemctl --user restart darknode` , url )
91+ script := fmt .Sprintf (`mv ~/.darknode/bin/darknode ~/.darknode/bin/darknode-backup && curl -sL %v > ~/.darknode/bin/darknode && chmod +x ~/.darknode/bin/darknode && systemctl --user restart darknode` , url )
4592 if err := util .RemoteRun (name , script ); err != nil {
4693 return err
4794 }
@@ -53,6 +100,46 @@ func updateSingleNode(name, ver string) error {
53100 return nil
54101}
55102
103+ func getCurrentVersion (name string ) (string , error ) {
104+ request := `{
105+ "jsonrpc": "2.0",
106+ "id": 1,
107+ "method": "ren_queryStat",
108+ "params": {}
109+ }`
110+ buf := bytes .NewBuffer ([]byte (request ))
111+ ip , err := util .IP (name )
112+ if err != nil {
113+ return "" , err
114+ }
115+ url := fmt .Sprintf ("http://%v:18515" , ip )
116+ ctx , cancel := context .WithTimeout (context .Background (), 2 * time .Second )
117+ defer cancel ()
118+ req , err := http .NewRequestWithContext (ctx , "POST" , url , buf )
119+ if err != nil {
120+ return "" , err
121+ }
122+ client := new (http.Client )
123+ resp , err := client .Do (req )
124+ if err != nil {
125+ return "" , err
126+ }
127+ response := struct {
128+ Result struct {
129+ Version string `json:"version"`
130+ } `json:"result"`
131+ } {}
132+
133+ if err := json .NewDecoder (resp .Body ).Decode (& response ); err != nil {
134+ return "" , err
135+ }
136+ versionString := strings .Split (response .Result .Version , "-" )
137+ if len (versionString ) < 1 {
138+ return "" , fmt .Errorf ("invalid version = %v" , response .Result .Version )
139+ }
140+ return versionString [0 ], nil
141+ }
142+
56143func validateVersion (version string ) error {
57144 url := fmt .Sprintf ("https://api.github.com/repos/renproject/darknode-release/releases/tags/%v" , version )
58145 response , err := http .Get (url )
0 commit comments