fixes #129, errors w/ tx enrollment

- addresses issues w/ tests not covering the error
- adds tests that run transit routers post enrollment
- adds test that list mixed transit routers (enrolled, not, fabric)
This commit is contained in:
Andrew Martinez
2020-04-07 14:36:14 -04:00
parent f331230b54
commit fb189994a0
8 changed files with 173 additions and 11 deletions
@@ -119,7 +119,7 @@ func MapTransitRouterToApiEntity(appEnv *env.AppEnv, context *response.RequestCo
enrollment := enrollments[0]
ret.EnrollmentExpiresAt = enrollment.ExpiresAt
ret.EnrollmentCreatedAt = &enrollment.CreatedAt
ret.EnrollmentCreatedAt = enrollment.IssuedAt
ret.EnrollmentJwt = &enrollment.Jwt
ret.EnrollmentToken = &enrollment.Token
}
@@ -71,13 +71,13 @@ func (ir *TransitRouterRouter) Delete(ae *env.AppEnv, rc *response.RequestContex
func (ir *TransitRouterRouter) Update(ae *env.AppEnv, rc *response.RequestContext) {
transitRouterUpdate := &TransitRouterApi{}
Update(rc, ae.Schemes.TransitRouter.Put, ir.IdType, transitRouterUpdate, func(id string) error {
return ae.Handlers.TransitRouter.Update(transitRouterUpdate.ToModel(id))
return ae.Handlers.TransitRouter.Update(transitRouterUpdate.ToModel(id), false)
})
}
func (ir *TransitRouterRouter) Patch(ae *env.AppEnv, rc *response.RequestContext) {
transitRouterUpdate := &TransitRouterApi{}
Patch(rc, ae.Schemes.TransitRouter.Patch, ir.IdType, transitRouterUpdate, func(id string, fields JsonFields) error {
return ae.Handlers.TransitRouter.Patch(transitRouterUpdate.ToModel(id), fields.ConcatNestedNames().FilterMaps("tags"))
return ae.Handlers.TransitRouter.Patch(transitRouterUpdate.ToModel(id), fields.ConcatNestedNames().FilterMaps("tags"), false)
})
}
+3 -2
View File
@@ -23,6 +23,7 @@ import (
"github.com/netfoundry/ziti-edge/controller/validation"
"github.com/netfoundry/ziti-edge/internal/cert"
"github.com/xeipuuv/gojsonschema"
"strings"
"time"
)
@@ -152,9 +153,9 @@ func (module *EnrollModuleRouterOtt) Process(context EnrollmentContext) (*Enroll
cltFp := module.fingerprintGenerator.FromPem(cltPem)
txRouter.IsVerified = true
txRouter.Fingerprint = cltFp
txRouter.Fingerprint = strings.ToLower(strings.Replace(cltFp, ":", "", -1))
if err := module.env.GetHandlers().TransitRouter.Update(txRouter); err != nil {
if err := module.env.GetHandlers().TransitRouter.Update(txRouter, true); err != nil {
return nil, fmt.Errorf("could not update edge router: %s", err)
}
+18 -4
View File
@@ -28,6 +28,10 @@ import (
func NewTransitRouterHandler(env Env) *TransitRouterHandler {
handler := &TransitRouterHandler{
baseHandler: newBaseHandler(env, env.GetStores().TransitRouter),
allowedFields: boltz.MapFieldChecker{
persistence.FieldName: struct{}{},
boltz.FieldTags: struct{}{},
},
}
handler.impl = handler
return handler
@@ -35,6 +39,7 @@ func NewTransitRouterHandler(env Env) *TransitRouterHandler {
type TransitRouterHandler struct {
baseHandler
allowedFields boltz.FieldChecker
}
func (handler *TransitRouterHandler) Delete(id string) error {
@@ -97,12 +102,21 @@ func (handler *TransitRouterHandler) CreateWithEnrollment(txRouter *TransitRoute
return txRouter.Id, enrollmentId, nil
}
func (handler *TransitRouterHandler) Update(entity *TransitRouter) error {
return handler.updateEntity(entity, nil)
func (handler *TransitRouterHandler) Update(entity *TransitRouter, allowAllFields bool) error {
if allowAllFields {
return handler.updateEntity(entity, nil)
}
return handler.updateEntity(entity, handler.allowedFields)
}
func (handler *TransitRouterHandler) Patch(entity *TransitRouter, checker boltz.FieldChecker) error {
return handler.patchEntity(entity, checker)
func (handler *TransitRouterHandler) Patch(entity *TransitRouter, checker boltz.FieldChecker, allowAllFields bool) error {
if allowAllFields {
return handler.patchEntity(entity, checker)
}
combinedChecker := &AndFieldChecker{first: handler.allowedFields, second: checker}
return handler.patchEntity(entity, combinedChecker)
}
func (handler *TransitRouterHandler) ReadOneByQuery(query string) (*TransitRouter, error) {
+3 -1
View File
@@ -51,8 +51,10 @@ func (entity *TransitRouter) toBoltEntityForUpdate(tx *bbolt.Tx, handler Handler
ret := &persistence.TransitRouter{
Router: db.Router{
BaseExtEntity: *boltz.NewExtEntity(entity.Id, entity.Tags),
Fingerprint: entity.Fingerprint,
},
Name: entity.Name,
Name: entity.Name,
IsVerified: entity.IsVerified,
}
return ret, nil
@@ -78,7 +78,11 @@ func (entity *TransitRouter) LoadValues(store boltz.CrudStore, bucket *boltz.Typ
func (entity *TransitRouter) SetValues(ctx *boltz.PersistContext) {
entity.Router.SetValues(ctx.GetParentContext())
entity.SetBaseValues(ctx)
ctx.SetString(FieldName, entity.Name)
if ctx.Bucket != nil {
ctx.SetString(FieldName, entity.Name)
ctx.SetBool(FieldTransitRouterIsVerified, entity.IsVerified)
ctx.SetStringList(FieldTransitRouterEnrollments, entity.Enrollments)
}
}
func (entity *TransitRouter) GetEntityType() string {
+68
View File
@@ -267,6 +267,19 @@ func (ctx *TestContext) createAndEnrollTransitRouter() *transitRouter {
return ctx.transitRouterEntity
}
func (ctx *TestContext) createEnrollAndStartTransitRouter() {
ctx.createAndEnrollTransitRouter()
ctx.startTransitRouter()
}
func (ctx *TestContext) startTransitRouter() {
config, err := router.LoadConfig(TransitRouterConfFile)
ctx.req.NoError(err)
ctx.router = router.Create(config)
ctx.req.NoError(ctx.router.Start())
}
func (ctx *TestContext) createEnrollAndStartEdgeRouter(roleAttributes ...string) {
ctx.createAndEnrollEdgeRouter(roleAttributes...)
@@ -518,3 +531,58 @@ func (ctx *TestContext) idsJson(ids ...string) *gabs.Container {
ctx.setJsonValue(entityData, ids, "ids")
return entityData
}
func (ctx *TestContext) requireEntityNotEnrolled(name string, entity *gabs.Container) {
fingerprint, ok := entity.Path("fingerprint").Data().(string)
ctx.req.True(ok, "expected "+name+" with isVerified=false to not have a fingerprint, could not cast")
ctx.req.Empty(fingerprint, "expected "+name+" with isVerified=false to have an empty fingerprint")
token, ok := entity.Path("enrollmentToken").Data().(string)
ctx.req.True(ok, "expected "+name+" with isVerified=false to have an enrollment token, could not cast")
ctx.req.NotEmpty(token, "expected "+name+" with isVerified=false to have an enrollment token, was empty")
jwt, ok := entity.Path("enrollmentJwt").Data().(string)
ctx.req.True(ok, "expected "+name+" with isVerified=false to have an enrollment jwt, could not cast")
ctx.req.NotEmpty(jwt, "expected "+name+" with isVerified=false to have an enrollment jwt, was empty")
createdAtStr, ok := entity.Path("enrollmentCreatedAt").Data().(string)
ctx.req.True(ok, "expected "+name+" with isVerified=false to have an enrollment created at date, could not cast")
ctx.req.NotEmpty(createdAtStr, "expected "+name+" with isVerified=false to have an enrollment created at date string, was empty")
createdAt, err := time.Parse(time.RFC3339, createdAtStr)
ctx.req.NoError(err, "expected "+name+" with isVerified=false to have a parsable created at date time string")
ctx.req.NotEmpty(createdAt, "expected "+name+" with isVerified=false to have an enrollment created at date, was empty")
expiresAtStr, ok := entity.Path("enrollmentExpiresAt").Data().(string)
ctx.req.True(ok, "expected "+name+" with isVerified=false to have an enrollment expires at date, could not cast")
ctx.req.NotEmpty(expiresAtStr, "expected "+name+" with isVerified=false to have an enrollment expires at date string, was empty")
expiresAt, err := time.Parse(time.RFC3339, expiresAtStr)
ctx.req.NoError(err, "expected "+name+" with isVerified=false to have a parsable expires at date time string")
ctx.req.True(ok, "expected "+name+" with isVerified=false to have an enrollment expires at date, could not cast")
ctx.req.NotEmpty(expiresAt, "expected "+name+" with isVerified=false to have an enrollment expires at date, was empty")
ctx.req.True(expiresAt.After(createdAt), "expected "+name+" with isVerified=false to have an enrollment expires at date after the created at date")
}
func (ctx *TestContext) requireEntityEnrolled(name string, entity *gabs.Container) {
fingerprint, ok := entity.Path("fingerprint").Data().(string)
ctx.req.True(ok, "expected "+name+" with isVerified=true to have a fingerprint, could not cast")
ctx.req.NotEmpty(fingerprint, "expected "+name+" with isVerified=true to have a fingerprint, was empty")
ctx.req.False(strings.Contains(fingerprint, ":"), "fingerprint should not contain colons")
ctx.req.False(strings.ToLower(fingerprint) != fingerprint, "fingerprint should not contain uppercase characters")
token := entity.Path("enrollmentToken").Data()
ctx.req.Nil(token, "expected "+name+" with isVerified=true to have an nil enrollment token")
jwt := entity.Path("enrollmentJwt").Data()
ctx.req.Nil(jwt, "expected "+name+" with isVerified=true to have an nil enrollment jwt")
createdAt := entity.Path("enrollmentCreatedAt").Data()
ctx.req.Nil(createdAt, "expected "+name+" with isVerified=true to have an nil enrollment created at date")
expiresAt := entity.Path("enrollmentExpiresAt").Data()
ctx.req.Nil(expiresAt, "expected "+name+" with isVerified=true to have an nil enrollment expires at date")
}
+73
View File
@@ -19,7 +19,10 @@
package tests
import (
"github.com/netfoundry/ziti-fabric/controller/models"
"github.com/netfoundry/ziti-fabric/controller/network"
"testing"
"time"
)
func Test_TransitRouters(t *testing.T) {
@@ -33,6 +36,56 @@ func Test_TransitRouters(t *testing.T) {
ctx.createAndEnrollTransitRouter()
})
t.Run("transit routers can be created, enrolled, and started", func(t *testing.T) {
ctx.testContextChanged(t)
ctx.createEnrollAndStartTransitRouter()
})
t.Run("transit routers can be created, enrolled, and listed", func(t *testing.T) {
ctx.testContextChanged(t)
ctx.AdminSession.requireQuery("transit-routers")
})
t.Run("transit routers can be listed with enrolled and un-enrolled states", func(t *testing.T) {
ctx.testContextChanged(t)
ctx.createAndEnrollTransitRouter()
_ = ctx.AdminSession.requireNewTransitRouter()
body := ctx.AdminSession.requireQuery("transit-routers")
ctx.logJson(body.Bytes())
t.Run("enrolled router is verified and has a fingerprint, un-enrolled router does not", func(t *testing.T) {
ctx.testContextChanged(t)
routers := body.Path("data")
children, err := routers.Children()
ctx.req.NoError(err)
ctx.req.Len(children, 2, "two routers should have been returned")
router0IsVerified, ok := children[0].Path("isVerified").Data().(bool)
ctx.req.True(ok, "issue getting transit router 0 isVerified state")
router1IsVerified, ok := children[1].Path("isVerified").Data().(bool)
ctx.req.True(ok, "issue getting transit router 1 isVerified state")
ctx.req.True(router0IsVerified != router1IsVerified, "expected 1 enrolled transit router and 1 un-enrolled transit router")
if router0IsVerified {
ctx.requireEntityEnrolled("transit router 0", children[0])
} else {
ctx.requireEntityNotEnrolled("transit router 0", children[0])
}
if router1IsVerified {
ctx.requireEntityEnrolled("transit router 1", children[1])
} else {
ctx.requireEntityNotEnrolled("transit router 1", children[1])
}
})
})
t.Run("create transit router, then delete", func(t *testing.T) {
ctx.testContextChanged(t)
router := ctx.AdminSession.requireNewTransitRouter()
@@ -44,4 +97,24 @@ func Test_TransitRouters(t *testing.T) {
router := ctx.createAndEnrollTransitRouter()
ctx.AdminSession.requireDeleteEntity(router)
})
t.Run("can list transit routers created in fabric", func(t *testing.T) {
ctx.testContextChanged(t)
fabTxRouter := &network.Router{
BaseEntity: models.BaseEntity{
Id: "uMvqq",
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
Tags: nil,
},
Fingerprint: "f6fc1c03175f674f1f0b505a9ff930e5",
AdvertisedListener: "tls:127.0.0.1",
}
err := ctx.fabricController.GetNetwork().Routers.Create(fabTxRouter)
ctx.req.NoError(err, "could not create router at fabric level")
body := ctx.AdminSession.requireQuery("transit-routers")
ctx.logJson(body.Bytes())
})
}