Skip to content

Commit

Permalink
use few labels on tsuru pod (#2689)
Browse files Browse the repository at this point in the history
* remove unused pod labels: provisioner, is-build and build-image

* Add way to define a allow list of pod labels

* Remove unused code

* Fix tests

* Remove unused permission

* Fix monitor to use is-tsuru instead of is-service label

* Drop unused SetUnitStatus method
  • Loading branch information
wpjunior committed Apr 24, 2024
1 parent 543d386 commit 86100e0
Show file tree
Hide file tree
Showing 32 changed files with 187 additions and 1,014 deletions.
112 changes: 0 additions & 112 deletions api/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,7 @@ import (
stdContext "context"
"encoding/json"
"fmt"
"io"
"net/http"
"net/url"
"regexp"
"strconv"
"strings"
Expand Down Expand Up @@ -802,51 +800,6 @@ func removeUnits(w http.ResponseWriter, r *http.Request, t auth.Token) (err erro
return a.RemoveUnits(ctx, n, processName, version, evt)
}

// title: set unit status
// path: /apps/{app}/units/{unit}
// method: POST
// consume: application/x-www-form-urlencoded
// responses:
//
// 200: Ok
// 400: Invalid data
// 401: Unauthorized
// 404: App or unit not found
func setUnitStatus(w http.ResponseWriter, r *http.Request, t auth.Token) error {
ctx := r.Context()
unitName := r.URL.Query().Get(":unit")
if unitName == "" {
return &errors.HTTP{
Code: http.StatusBadRequest,
Message: "missing unit",
}
}
postStatus := InputValue(r, "status")
status, err := provision.ParseStatus(postStatus)
if err != nil {
return &errors.HTTP{
Code: http.StatusBadRequest,
Message: err.Error(),
}
}
appName := r.URL.Query().Get(":app")
a, err := app.GetByName(ctx, appName)
if err != nil {
return &errors.HTTP{Code: http.StatusNotFound, Message: err.Error()}
}
allowed := permission.Check(t, permission.PermAppUpdateUnitStatus,
contextsForApp(a)...,
)
if !allowed {
return permission.ErrUnauthorized
}
err = a.SetUnitStatus(unitName, status)
if _, ok := err.(*provision.UnitNotFoundError); ok {
return &errors.HTTP{Code: http.StatusNotFound, Message: err.Error()}
}
return err
}

// title: kill a running unit
// path: /apps/{app}/units/{unit}
// method: DELETE
Expand Down Expand Up @@ -1977,71 +1930,6 @@ func forceDeleteLock(w http.ResponseWriter, r *http.Request, t auth.Token) (err
return &errors.HTTP{Code: http.StatusGone, Message: "app unlock is deprecated, this call does nothing"}
}

func isDeployAgentUA(r *http.Request) bool {
ua := strings.ToLower(r.UserAgent())
return strings.HasPrefix(ua, "go-http-client") ||
strings.HasPrefix(ua, "tsuru-deploy-agent")
}

// title: register unit
// path: /apps/{app}/units/register
// method: POST
// consume: application/x-www-form-urlencoded
// produce: application/json
// responses:
//
// 200: Ok
// 401: Unauthorized
// 404: App not found
func registerUnit(w http.ResponseWriter, r *http.Request, t auth.Token) error {
ctx := r.Context()
appName := r.URL.Query().Get(":app")
a, err := app.GetByName(ctx, appName)
if err != nil {
return err
}
allowed := permission.Check(t, permission.PermAppUpdateUnitRegister,
contextsForApp(a)...,
)
if !allowed {
return permission.ErrUnauthorized
}
if isDeployAgentUA(r) && r.Header.Get("X-Agent-Version") == "" {
// Filtering the user-agent is not pretty, but it's safer than doing
// the header check for every request, otherwise calling directly the
// API would always fail without this header that only makes sense to
// the agent.
msgError := fmt.Sprintf("Please contact admin. %s platform is using outdated deploy-agent version, minimum required version is 0.2.4", a.GetPlatform())
return &errors.HTTP{Code: http.StatusBadRequest, Message: msgError}
}
defer r.Body.Close()
data, err := io.ReadAll(r.Body)
if err != nil {
return err
}
val, err := url.ParseQuery(string(data))
if err != nil {
return err
}
hostname := val.Get("hostname")
var customData map[string]interface{}
rawCustomData := val.Get("customdata")
if rawCustomData != "" {
err = json.Unmarshal([]byte(rawCustomData), &customData)
if err != nil {
return err
}
}
err = a.RegisterUnit(ctx, hostname, customData)
if err != nil {
if err, ok := err.(*provision.UnitNotFoundError); ok {
return &errors.HTTP{Code: http.StatusNotFound, Message: err.Error()}
}
return err
}
return writeEnvVars(w, a)
}

// compatRebuildRoutesResult is a backward compatible rebuild routes struct
// used in the handler so that old clients won't break.
type compatRebuildRoutesResult struct {
Expand Down
231 changes: 0 additions & 231 deletions api/app_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2766,72 +2766,6 @@ func (s *S) TestRemoveUnitsReturns400IfNumberIsInvalid(c *check.C) {
}
}

func (s *S) TestSetUnitStatus(c *check.C) {
a := app.App{Name: "telegram", Platform: "zend", TeamOwner: s.team.Name}
err := app.CreateApp(context.TODO(), &a, s.user)
c.Assert(err, check.IsNil)
s.provisioner.AddUnits(context.TODO(), &a, 3, "web", nil, nil)
body := strings.NewReader("status=error")
units, err := a.Units()
c.Assert(err, check.IsNil)
unit := units[0]
request, err := http.NewRequest("POST", "/apps/telegram/units/"+unit.ID, body)
c.Assert(err, check.IsNil)
request.Header.Set("Content-Type", "application/x-www-form-urlencoded")
request.Header.Set("Authorization", "bearer "+s.token.GetValue())
recorder := httptest.NewRecorder()
s.testServer.ServeHTTP(recorder, request)
c.Assert(recorder.Code, check.Equals, http.StatusOK)
units, err = a.Units()
c.Assert(err, check.IsNil)
unit = units[0]
c.Assert(unit.Status, check.Equals, provision.StatusError)
}

func (s *S) TestSetUnitStatusNoUnit(c *check.C) {
body := strings.NewReader("status=error")
request, err := http.NewRequest("POST", "/apps/velha/units/af32db?:app=velha", body)
c.Assert(err, check.IsNil)
request.Header.Set("Content-Type", "application/x-www-form-urlencoded")
recorder := httptest.NewRecorder()
err = setUnitStatus(recorder, request, s.token)
c.Assert(err, check.NotNil)
e, ok := err.(*errors.HTTP)
c.Assert(ok, check.Equals, true)
c.Assert(e.Code, check.Equals, http.StatusBadRequest)
c.Assert(e.Message, check.Equals, "missing unit")
}

func (s *S) TestSetUnitStatusInvalidStatus(c *check.C) {
bodies := []io.Reader{strings.NewReader("status=something"), strings.NewReader("")}
for _, body := range bodies {
request, err := http.NewRequest("POST", "/apps/velha/units/af32db?:app=velha&:unit=af32db", body)
c.Assert(err, check.IsNil)
request.Header.Set("Content-Type", "application/x-www-form-urlencoded")
recorder := httptest.NewRecorder()
err = setUnitStatus(recorder, request, s.token)
c.Assert(err, check.NotNil)
e, ok := err.(*errors.HTTP)
c.Assert(ok, check.Equals, true)
c.Check(e.Code, check.Equals, http.StatusBadRequest)
c.Check(e.Message, check.Equals, provision.ErrInvalidStatus.Error())
}
}

func (s *S) TestSetUnitStatusAppNotFound(c *check.C) {
body := strings.NewReader("status=error")
request, err := http.NewRequest("POST", "/apps/velha/units/af32db?:app=velha&:unit=af32db", body)
c.Assert(err, check.IsNil)
request.Header.Set("Content-Type", "application/x-www-form-urlencoded")
recorder := httptest.NewRecorder()
err = setUnitStatus(recorder, request, s.token)
c.Assert(err, check.NotNil)
e, ok := err.(*errors.HTTP)
c.Assert(ok, check.Equals, true)
c.Check(e.Code, check.Equals, http.StatusNotFound)
c.Check(e.Message, check.Equals, "App not found")
}

func (s *S) TestAddTeamToTheApp(c *check.C) {
t := authTypes.Team{Name: "itshardteam"}
s.mockService.Team.OnList = func() ([]authTypes.Team, error) {
Expand Down Expand Up @@ -6325,171 +6259,6 @@ func (s *S) TestForceDeleteLock(c *check.C) {
c.Assert(recorder.Body.String(), check.Equals, "app unlock is deprecated, this call does nothing\n")
}

func (s *S) TestRegisterUnit(c *check.C) {
a := app.App{
Name: "myappx",
Platform: "python",
Env: map[string]bindTypes.EnvVar{
"MY_VAR_1": {Name: "MY_VAR_1", Value: "value1", Public: true},
},
TeamOwner: s.team.Name,
}
err := app.CreateApp(context.TODO(), &a, s.user)
c.Assert(err, check.IsNil)
err = s.provisioner.AddUnits(context.TODO(), &a, 1, "web", nil, nil)
c.Assert(err, check.IsNil)
units, err := a.Units()
c.Assert(err, check.IsNil)
oldIP := units[0].IP
body := strings.NewReader("hostname=" + units[0].ID)
request, err := http.NewRequest("POST", "/apps/myappx/units/register", body)
c.Assert(err, check.IsNil)
request.Header.Set("Authorization", "bearer "+s.token.GetValue())
request.Header.Set("X-Agent-Version", "0.2.4")
recorder := httptest.NewRecorder()
s.testServer.ServeHTTP(recorder, request)
c.Assert(recorder.Code, check.Equals, http.StatusOK)
c.Assert(recorder.Header().Get("Content-Type"), check.Equals, "application/json")
result := []map[string]interface{}{}
err = json.Unmarshal(recorder.Body.Bytes(), &result)
c.Assert(err, check.IsNil)
envMap := map[interface{}]interface{}{}
for _, envVar := range result {
envMap[envVar["name"]] = envVar["value"]
}
c.Assert(envMap["MY_VAR_1"], check.Equals, "value1")
units, err = a.Units()
c.Assert(err, check.IsNil)
c.Assert(units[0].IP, check.Equals, oldIP+"-updated")
}

func (s *S) TestRegisterUnitInvalidUnit(c *check.C) {
a := app.App{
Name: "myappx",
Platform: "python",
Teams: []string{s.team.Name},
Env: map[string]bindTypes.EnvVar{
"MY_VAR_1": {Name: "MY_VAR_1", Value: "value1", Public: true},
},
}
err := s.conn.Apps().Insert(a)
c.Assert(err, check.IsNil)
err = s.provisioner.Provision(context.TODO(), &a)
c.Assert(err, check.IsNil)
body := strings.NewReader("hostname=invalid-unit-host")
request, err := http.NewRequest("POST", "/apps/myappx/units/register", body)
c.Assert(err, check.IsNil)
request.Header.Set("Authorization", "bearer "+s.token.GetValue())
request.Header.Set("X-Agent-Version", "0.2.4")
recorder := httptest.NewRecorder()
s.testServer.ServeHTTP(recorder, request)
c.Assert(recorder.Code, check.Equals, http.StatusNotFound)
c.Assert(recorder.Body.String(), check.Equals, "unit \"invalid-unit-host\" not found\n")
}

func (s *S) TestRegisterUnitOutdatedDeployAgent(c *check.C) {
a := app.App{
Name: "myappx",
Platform: "python",
Teams: []string{s.team.Name},
Env: map[string]bindTypes.EnvVar{
"MY_VAR_1": {Name: "MY_VAR_1", Value: "value1", Public: true},
},
}
err := s.conn.Apps().Insert(a)
c.Assert(err, check.IsNil)
err = s.provisioner.Provision(context.TODO(), &a)
c.Assert(err, check.IsNil)
body := strings.NewReader("hostname=invalid-unit-host")
request, err := http.NewRequest("POST", "/apps/myappx/units/register", body)
c.Assert(err, check.IsNil)
request.Header.Set("User-Agent", "Go-http-client/1.1")
request.Header.Set("Authorization", "bearer "+s.token.GetValue())
recorder := httptest.NewRecorder()
s.testServer.ServeHTTP(recorder, request)
c.Assert(recorder.Code, check.Equals, http.StatusBadRequest)
c.Assert(recorder.Body.String(), check.Equals, "Please contact admin. python platform is using outdated deploy-agent version, minimum required version is 0.2.4\n")

body = strings.NewReader("hostname=invalid-unit-host")
request, err = http.NewRequest("POST", "/apps/myappx/units/register", body)
c.Assert(err, check.IsNil)
request.Header.Set("User-Agent", "tsuru-deploy-agent/1.1")
request.Header.Set("Authorization", "bearer "+s.token.GetValue())
recorder = httptest.NewRecorder()
s.testServer.ServeHTTP(recorder, request)
c.Assert(recorder.Code, check.Equals, http.StatusBadRequest)
c.Assert(recorder.Body.String(), check.Equals, "Please contact admin. python platform is using outdated deploy-agent version, minimum required version is 0.2.4\n")
}

func (s *S) TestRegisterUnitOtherUA(c *check.C) {
a := app.App{
Name: "myappx",
Platform: "python",
Env: map[string]bindTypes.EnvVar{
"MY_VAR_1": {Name: "MY_VAR_1", Value: "value1", Public: true},
},
TeamOwner: s.team.Name,
}
err := app.CreateApp(context.TODO(), &a, s.user)
c.Assert(err, check.IsNil)
err = s.provisioner.AddUnits(context.TODO(), &a, 1, "web", nil, nil)
c.Assert(err, check.IsNil)
units, err := a.Units()
c.Assert(err, check.IsNil)
body := strings.NewReader("hostname=" + units[0].ID)
request, err := http.NewRequest("POST", "/apps/myappx/units/register", body)
c.Assert(err, check.IsNil)
request.Header.Set("Authorization", "bearer "+s.token.GetValue())
request.Header.Set("User-Agent", "curl/1.1")
recorder := httptest.NewRecorder()
s.testServer.ServeHTTP(recorder, request)
c.Assert(recorder.Code, check.Equals, http.StatusOK)
}

func (s *S) TestRegisterUnitWithCustomData(c *check.C) {
a := app.App{
Name: "myappx",
Platform: "python",
Env: map[string]bindTypes.EnvVar{
"MY_VAR_1": {Name: "MY_VAR_1", Value: "value1", Public: true},
},
TeamOwner: s.team.Name,
}
err := app.CreateApp(context.TODO(), &a, s.user)
c.Assert(err, check.IsNil)
err = s.provisioner.AddUnits(context.TODO(), &a, 1, "web", nil, nil)
c.Assert(err, check.IsNil)
units, err := a.Units()
c.Assert(err, check.IsNil)
oldIP := units[0].IP
v := url.Values{}
v.Set("hostname", units[0].ID)
v.Set("customdata", `{"mydata": "something"}`)
body := strings.NewReader(v.Encode())
request, err := http.NewRequest("POST", "/apps/myappx/units/register", body)
c.Assert(err, check.IsNil)
request.Header.Set("Authorization", "bearer "+s.token.GetValue())
request.Header.Set("X-Agent-Version", "0.2.4")
recorder := httptest.NewRecorder()
s.testServer.ServeHTTP(recorder, request)
c.Assert(recorder.Code, check.Equals, http.StatusOK)
c.Assert(recorder.Header().Get("Content-Type"), check.Equals, "application/json")
result := []map[string]interface{}{}
err = json.Unmarshal(recorder.Body.Bytes(), &result)
c.Assert(err, check.IsNil)
envMap := map[interface{}]interface{}{}
for _, envVar := range result {
envMap[envVar["name"]] = envVar["value"]
}
c.Assert(envMap["MY_VAR_1"], check.Equals, "value1")
units, err = a.Units()
c.Assert(err, check.IsNil)
c.Assert(units[0].IP, check.Equals, oldIP+"-updated")
c.Assert(s.provisioner.CustomData(&a), check.DeepEquals, map[string]interface{}{
"mydata": "something",
})
}

func (s *S) TestRebuildRoutes(c *check.C) {
a := app.App{Name: "myappx", Platform: "zend", TeamOwner: s.team.Name, Router: "fake"}
err := app.CreateApp(context.TODO(), &a, s.user)
Expand Down
2 changes: 0 additions & 2 deletions api/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -285,8 +285,6 @@ func RunServer(dry bool) http.Handler {
m.Add("1.9", http.MethodGet, "/apps/{app}/units/autoscale", AuthorizationRequiredHandler(autoScaleUnitsInfo))
m.Add("1.9", http.MethodPost, "/apps/{app}/units/autoscale", AuthorizationRequiredHandler(addAutoScaleUnits))
m.Add("1.9", http.MethodDelete, "/apps/{app}/units/autoscale", AuthorizationRequiredHandler(removeAutoScaleUnits))
m.Add("1.0", http.MethodPost, "/apps/{app}/units/register", AuthorizationRequiredHandler(registerUnit))
m.Add("1.0", http.MethodPost, "/apps/{app}/units/{unit}", AuthorizationRequiredHandler(setUnitStatus))
m.Add("1.12", http.MethodDelete, "/apps/{app}/units/{unit}", AuthorizationRequiredHandler(killUnit))
m.Add("1.0", http.MethodPut, "/apps/{app}/teams/{team}", AuthorizationRequiredHandler(grantAppAccess))
m.Add("1.0", http.MethodDelete, "/apps/{app}/teams/{team}", AuthorizationRequiredHandler(revokeAppAccess))
Expand Down

0 comments on commit 86100e0

Please sign in to comment.