Skip to content

Commit 5ccfc73

Browse files
authored
Merge pull request #286 from golangaccount/master
fix:fix server address error when running in k8s
2 parents b4f0c87 + e04d051 commit 5ccfc73

File tree

5 files changed

+146
-21
lines changed

5 files changed

+146
-21
lines changed

cmd/server.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,10 @@
1717
package cmd
1818

1919
import (
20+
"log"
21+
2022
"github.com/qiniu/goc/pkg/cover"
2123
"github.com/spf13/cobra"
22-
"log"
2324
)
2425

2526
var serverCmd = &cobra.Command{
@@ -41,14 +42,17 @@ goc server --port=localhost:8080
4142
if err != nil {
4243
log.Fatalf("New file based server failed, err: %v", err)
4344
}
45+
server.IPRevise = iprevise
4446
server.Run(port)
4547
},
4648
}
4749

4850
var port, localPersistence string
51+
var iprevise bool
4952

5053
func init() {
5154
serverCmd.Flags().StringVarP(&port, "port", "", ":7777", "listen port to start a coverage host center")
5255
serverCmd.Flags().StringVarP(&localPersistence, "local-persistence", "", "_svrs_address.txt", "the file to save services address information")
56+
serverCmd.Flags().BoolVarP(&iprevise, "ip_revise", "", true, "setting the network type(default:regist server use proxy or under nat、same network ect,direct:use register request parm)")
5357
rootCmd.AddCommand(serverCmd)
5458
}

pkg/cover/server.go

Lines changed: 48 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import (
2626
"net/url"
2727
"os"
2828
"regexp"
29+
"strconv"
2930

3031
"github.com/gin-gonic/gin"
3132
log "github.com/sirupsen/logrus"
@@ -38,6 +39,7 @@ const LogFile = "goc.log"
3839

3940
type server struct {
4041
PersistenceFile string
42+
IPRevise bool // whether to do ip revise during registering
4143
Store Store
4244
}
4345

@@ -98,8 +100,9 @@ func (s *server) Route(w io.Writer) *gin.Engine {
98100

99101
// ServiceUnderTest is a entry under being tested
100102
type ServiceUnderTest struct {
101-
Name string `form:"name" json:"name" binding:"required"`
102-
Address string `form:"address" json:"address" binding:"required"`
103+
Name string `form:"name" json:"name" binding:"required"`
104+
Address string `form:"address" json:"address" binding:"required"`
105+
IPRevise string `form:"iprevise" json:"-"`
103106
}
104107

105108
// ProfileParam is param of profile API
@@ -123,24 +126,57 @@ func (s *server) registerService(c *gin.Context) {
123126
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
124127
return
125128
}
126-
129+
if service.IPRevise == "" {
130+
service.IPRevise = strconv.FormatBool(s.IPRevise)
131+
}
132+
isrevise, err := strconv.ParseBool(service.IPRevise)
133+
if err != nil {
134+
isrevise = s.IPRevise
135+
}
127136
u, err := url.Parse(service.Address)
128137
if err != nil {
129138
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
130139
return
131140
}
132-
host, port, err := net.SplitHostPort(u.Host)
133-
if err != nil {
134-
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
141+
if u.Scheme != "https" && u.Scheme != "http" {
142+
c.JSON(http.StatusBadRequest, gin.H{"error": "unsupport schema"})
143+
return
144+
} else if u.Path != "" {
145+
c.JSON(http.StatusBadRequest, gin.H{"error": "uri path must empty"})
135146
return
136147
}
148+
if !isrevise {
149+
if u.Host == "" {
150+
c.JSON(http.StatusBadRequest, gin.H{"error": "address is empty"})
151+
return
152+
}
153+
if u.Hostname() == "" {
154+
c.JSON(http.StatusBadRequest, gin.H{"error": "empty host name"})
155+
return
156+
}
157+
} else {
158+
host := u.Hostname()
159+
port := u.Port()
160+
if host == "" {
161+
host = c.ClientIP()
162+
}
163+
if port == "" {
164+
port = "80"
165+
}
166+
u.Host = fmt.Sprintf("%s:%s", host, port)
167+
host, port, err := net.SplitHostPort(u.Host)
168+
if err != nil {
169+
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
170+
return
171+
}
137172

138-
realIP := c.ClientIP()
139-
// only for IPV4
140-
// refer: https://github.com/qiniu/goc/issues/177
141-
if net.ParseIP(realIP).To4() != nil && host != realIP {
142-
log.Printf("the registered host %s of service %s is different with the real one %s, here we choose the real one", service.Name, host, realIP)
143-
service.Address = fmt.Sprintf("http://%s:%s", realIP, port)
173+
realIP := c.ClientIP()
174+
// only for IPV4
175+
// refer: https://github.com/qiniu/goc/issues/177
176+
if net.ParseIP(realIP).To4() != nil && host != realIP {
177+
log.Printf("the registered host %s of service %s is different with the real one %s, here we choose the real one", service.Name, host, realIP)
178+
service.Address = fmt.Sprintf("%s://%s:%s", u.Scheme, realIP, port)
179+
}
144180
}
145181

146182
address := s.Store.Get(service.Name)
@@ -152,7 +188,6 @@ func (s *server) registerService(c *gin.Context) {
152188
}
153189

154190
c.JSON(http.StatusOK, gin.H{"result": "success"})
155-
return
156191
}
157192

158193
// profile API examples:

pkg/cover/server_test.go

Lines changed: 90 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"net/url"
1010
"os"
1111
"reflect"
12+
"strconv"
1213
"strings"
1314
"testing"
1415

@@ -139,7 +140,7 @@ func TestRegisterService(t *testing.T) {
139140

140141
assert.Equal(t, http.StatusBadRequest, w.Code)
141142

142-
// register with invalid service.Address
143+
// register with invalid service.Address(bad uri)
143144
data := url.Values{}
144145
data.Set("name", "aaa")
145146
data.Set("address", "&%%")
@@ -151,22 +152,104 @@ func TestRegisterService(t *testing.T) {
151152
assert.Equal(t, http.StatusBadRequest, w.Code)
152153
assert.Contains(t, w.Body.String(), "invalid URL escape")
153154

154-
// register with host but no port
155+
// regist with invalid service.Address(schema)
155156
data = url.Values{}
156157
data.Set("name", "aaa")
157-
data.Set("address", "http://127.0.0.1")
158+
data.Set("address", "fpt://127.0.0.1:21")
158159
w = httptest.NewRecorder()
159160
req, _ = http.NewRequest("POST", "/v1/cover/register", strings.NewReader(data.Encode()))
160161
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
161162
router.ServeHTTP(w, req)
163+
assert.Equal(t, http.StatusBadRequest, w.Code)
164+
assert.Contains(t, w.Body.String(), "unsupport schema")
162165

166+
// regist with unempty path
167+
data = url.Values{}
168+
data.Set("name", "aaa")
169+
data.Set("address", "http://127.0.0.1:21/")
170+
w = httptest.NewRecorder()
171+
req, _ = http.NewRequest("POST", "/v1/cover/register", strings.NewReader(data.Encode()))
172+
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
173+
router.ServeHTTP(w, req)
163174
assert.Equal(t, http.StatusBadRequest, w.Code)
164-
assert.Contains(t, w.Body.String(), "missing port in address")
175+
assert.Contains(t, w.Body.String(), "uri path must empty")
176+
177+
// regist with empty host(in direct mode,empty must fail,default is success)
178+
// in default,use request realhost as host,use 80 as port
179+
server.IPRevise = false
180+
data = url.Values{}
181+
data.Set("name", "aaa")
182+
data.Set("address", "http://")
183+
w = httptest.NewRecorder()
184+
req, _ = http.NewRequest("POST", "/v1/cover/register", strings.NewReader(data.Encode()))
185+
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
186+
router.ServeHTTP(w, req)
187+
assert.Equal(t, http.StatusBadRequest, w.Code)
188+
assert.Contains(t, w.Body.String(), "address is empty")
189+
190+
data = url.Values{}
191+
data.Set("name", "aaa")
192+
data.Set("address", "http://:8080")
193+
w = httptest.NewRecorder()
194+
req, _ = http.NewRequest("POST", "/v1/cover/register", strings.NewReader(data.Encode()))
195+
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
196+
router.ServeHTTP(w, req)
197+
assert.Equal(t, http.StatusBadRequest, w.Code)
198+
assert.Contains(t, w.Body.String(), "empty host name")
199+
200+
data = url.Values{}
201+
data.Set("name", "aaa")
202+
data.Set("address", "http://127.0.0.1")
203+
w = httptest.NewRecorder()
204+
req, _ = http.NewRequest("POST", "/v1/cover/register", strings.NewReader(data.Encode()))
205+
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
206+
router.ServeHTTP(w, req)
207+
assert.Equal(t, http.StatusOK, w.Code)
208+
209+
//change network type
210+
data = url.Values{}
211+
data.Set("name", "aaa")
212+
data.Set("address", "http://")
213+
data.Set("iprevise", "true")
214+
w = httptest.NewRecorder()
215+
req, _ = http.NewRequest("POST", "/v1/cover/register", strings.NewReader(data.Encode()))
216+
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
217+
router.ServeHTTP(w, req)
218+
assert.Equal(t, http.StatusOK, w.Code)
219+
220+
server.IPRevise = true //use clientip and default port(80)
221+
data = url.Values{}
222+
data.Set("name", "aaa")
223+
data.Set("address", "http://")
224+
w = httptest.NewRecorder()
225+
req, _ = http.NewRequest("POST", "/v1/cover/register", strings.NewReader(data.Encode()))
226+
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
227+
router.ServeHTTP(w, req)
228+
assert.Equal(t, http.StatusOK, w.Code)
229+
230+
data = url.Values{}
231+
data.Set("name", "aaa")
232+
data.Set("address", "http://:8080")
233+
w = httptest.NewRecorder()
234+
req, _ = http.NewRequest("POST", "/v1/cover/register", strings.NewReader(data.Encode()))
235+
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
236+
router.ServeHTTP(w, req)
237+
assert.Equal(t, http.StatusOK, w.Code)
238+
239+
data = url.Values{}
240+
data.Set("name", "aaa")
241+
data.Set("address", "http://127.0.0.1")
242+
w = httptest.NewRecorder()
243+
req, _ = http.NewRequest("POST", "/v1/cover/register", strings.NewReader(data.Encode()))
244+
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
245+
router.ServeHTTP(w, req)
246+
assert.Equal(t, http.StatusOK, w.Code)
165247

166248
// register with store failure
167249
expectedS := ServiceUnderTest{
168-
Name: "foo",
169-
Address: "http://:64444", // the real IP is empty in unittest, so server will get a empty one
250+
Name: "foo",
251+
Address: "http://:64444", // the real IP is empty in unittest, so server will get a empty one
252+
IPRevise: strconv.FormatBool(server.IPRevise),
170253
}
171254
testObj := new(MockStore)
172255
testObj.On("Get", "foo").Return([]string{"http://127.0.0.1:66666"})
@@ -177,6 +260,7 @@ func TestRegisterService(t *testing.T) {
177260
w = httptest.NewRecorder()
178261
data.Set("name", expectedS.Name)
179262
data.Set("address", expectedS.Address)
263+
data.Set("network", "")
180264
req, _ = http.NewRequest("POST", "/v1/cover/register", strings.NewReader(data.Encode()))
181265
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
182266
router.ServeHTTP(w, req)

pkg/cover/store_test.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,14 @@ package cover
1818

1919
import (
2020
"fmt"
21+
"os"
2122
"testing"
2223

2324
"github.com/stretchr/testify/assert"
2425
)
2526

2627
func TestLocalStore(t *testing.T) {
28+
os.Remove("_svrs_address.txt") //remove _svrs_address.txt file,make sure no data effect this unit test
2729
localStore, err := NewFileStore("_svrs_address.txt")
2830
assert.NoError(t, err)
2931
var tc1 = ServiceUnderTest{

tests/register.bats

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ teardown_file() {
5959
run gocc register --center=http://127.0.0.1:60001 --name=xyz --address=http://137.0.0.1 --debug --debugcisyncfile ci-sync.bak;
6060
info register2 output: $output
6161
[ "$status" -eq 0 ]
62-
[[ "$output" == *"missing port"* ]]
62+
[[ "$output" != *"missing port"* ]]
6363

6464
wait $profile_pid
6565
}

0 commit comments

Comments
 (0)