mirror of
https://github.com/openziti/zrok.git
synced 2026-08-24 02:34:20 -05:00
187 lines
6.2 KiB
Go
187 lines
6.2 KiB
Go
package controller
|
|
|
|
import (
|
|
"github.com/go-openapi/runtime/middleware"
|
|
"github.com/jmoiron/sqlx"
|
|
"github.com/michaelquigley/df/dl"
|
|
"github.com/openziti/zrok/v2/controller/automation"
|
|
"github.com/openziti/zrok/v2/controller/store"
|
|
"github.com/openziti/zrok/v2/rest_model_zrok"
|
|
"github.com/openziti/zrok/v2/rest_server_zrok/operations/share"
|
|
"github.com/openziti/zrok/v2/util"
|
|
"github.com/pkg/errors"
|
|
)
|
|
|
|
type unshareHandler struct{}
|
|
|
|
func newUnshareHandler() *unshareHandler {
|
|
return &unshareHandler{}
|
|
}
|
|
|
|
func (h *unshareHandler) Handle(params share.UnshareParams, principal *rest_model_zrok.Principal) middleware.Responder {
|
|
trx, err := str.Begin()
|
|
if err != nil {
|
|
dl.Errorf("error starting transaction for '%v': %v", principal.Email, err)
|
|
return share.NewUnshareInternalServerError()
|
|
}
|
|
defer func() { _ = trx.Rollback() }()
|
|
|
|
shrToken := params.Body.ShareToken
|
|
envZId := params.Body.EnvZID
|
|
|
|
// validate environment
|
|
env, err := h.validateEnvironment(envZId, principal, trx)
|
|
if err != nil {
|
|
dl.Errorf("environment validation failed for '%v': %v", principal.Email, err)
|
|
return share.NewUnshareNotFound()
|
|
}
|
|
|
|
// find and validate share
|
|
shr, err := h.findAndValidateShare(shrToken, env, trx)
|
|
if err != nil {
|
|
dl.Errorf("share validation failed for '%v': %v", principal.Email, err)
|
|
return share.NewUnshareNotFound()
|
|
}
|
|
|
|
// deallocate ziti resources using automation framework
|
|
if err := h.deallocateResources(shrToken); err != nil {
|
|
dl.Warnf("error deallocating ziti resources for share '%v': %v", shrToken, err)
|
|
}
|
|
|
|
// send unbind mapping updates before cleaning up share name mappings
|
|
if err := h.processDynamicMappings(shr.Id, trx); err != nil {
|
|
dl.Errorf("error sending unbind mapping updates for '%v': %v", shrToken, err)
|
|
}
|
|
|
|
// clean up share name mappings
|
|
if err := h.cleanupShareNameMappings(shr.Id, trx); err != nil {
|
|
dl.Errorf("error cleaning up share name mappings for '%v': %v", shrToken, err)
|
|
return share.NewUnshareInternalServerError()
|
|
}
|
|
|
|
// clean up access grants
|
|
if err := str.DeleteAccessGrantsForShare(shr.Id, trx); err != nil {
|
|
dl.Errorf("error deleting access grants for share '%v': %v", shrToken, err)
|
|
return share.NewUnshareInternalServerError()
|
|
}
|
|
|
|
// delete the share record
|
|
if err := str.DeleteShare(shr.Id, trx); err != nil {
|
|
dl.Errorf("error deleting share '%v': %v", shrToken, err)
|
|
return share.NewUnshareInternalServerError()
|
|
}
|
|
|
|
// commit transaction
|
|
if err := trx.Commit(); err != nil {
|
|
dl.Errorf("error committing transaction for '%v': %v", shrToken, err)
|
|
return share.NewUnshareInternalServerError()
|
|
}
|
|
|
|
dl.Infof("successfully unshared '%v' for '%v'", shrToken, principal.Email)
|
|
return share.NewUnshareOK()
|
|
}
|
|
|
|
func (h *unshareHandler) validateEnvironment(envZId string, principal *rest_model_zrok.Principal, trx *sqlx.Tx) (*store.Environment, error) {
|
|
env, err := str.FindEnvironmentForAccount(envZId, int(principal.ID), trx)
|
|
if err != nil {
|
|
return nil, errors.Wrapf(err, "error finding environment '%v' for account '%v'", envZId, principal.Email)
|
|
}
|
|
return env, nil
|
|
}
|
|
|
|
func (h *unshareHandler) findAndValidateShare(shrToken string, env *store.Environment, trx *sqlx.Tx) (*store.Share, error) {
|
|
shares, err := str.FindSharesForEnvironment(env.Id, trx)
|
|
if err != nil {
|
|
return nil, errors.Wrapf(err, "error finding shares for environment '%v'", env.ZId)
|
|
}
|
|
|
|
for _, share := range shares {
|
|
if share.Token == shrToken {
|
|
return share, nil
|
|
}
|
|
}
|
|
|
|
return nil, errors.Errorf("share '%v' not found in environment '%v'", shrToken, env.ZId)
|
|
}
|
|
|
|
func (h *unshareHandler) deallocateResources(shrToken string) error {
|
|
// get shared automation client
|
|
za, err := automation.NewZitiAutomation(cfg.Ziti)
|
|
if err != nil {
|
|
return errors.Wrap(err, "error getting ziti automation client")
|
|
}
|
|
|
|
// use fluent workflow API for tag-based cleanup
|
|
err = za.CleanupByTag("zrokShareToken", shrToken)
|
|
if err != nil {
|
|
return errors.Wrapf(err, "error cleaning up ziti resources for share '%v'", shrToken)
|
|
}
|
|
|
|
dl.Infof("deallocated ziti resources for share '%v'", shrToken)
|
|
return nil
|
|
}
|
|
|
|
func (h *unshareHandler) cleanupShareNameMappings(shareId int, trx *sqlx.Tx) error {
|
|
details, err := str.FindShareNameCleanupDetailsByShareId(shareId, trx)
|
|
if err != nil {
|
|
return errors.Wrapf(err, "error finding share name cleanup details for share '%v'", shareId)
|
|
}
|
|
|
|
for _, detail := range details {
|
|
// only delete names that are not reserved and are not already deleted
|
|
if !detail.Reserved && !detail.NameDeleted {
|
|
if err := str.DeleteName(detail.NameId, trx); err != nil {
|
|
return errors.Wrapf(err, "error deleting dynamically allocated name '%v'", detail.Name)
|
|
}
|
|
dl.Debugf("deleted dynamically allocated name '%v'", detail.Name)
|
|
}
|
|
|
|
// delete the share name mapping
|
|
if err := str.DeleteShareNameMapping(detail.MappingId, trx); err != nil {
|
|
return errors.Wrapf(err, "error deleting share name mapping '%v'", detail.MappingId)
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (h *unshareHandler) processDynamicMappings(shareId int, trx *sqlx.Tx) error {
|
|
// only send updates if dynamic proxy controller is enabled
|
|
if dPCtrl == nil {
|
|
return nil
|
|
}
|
|
|
|
details, err := str.FindShareNameCleanupDetailsByShareId(shareId, trx)
|
|
if err != nil {
|
|
return errors.Wrapf(err, "error finding share name cleanup details for share '%v'", shareId)
|
|
}
|
|
|
|
for _, detail := range details {
|
|
if detail.NamespaceDeleted {
|
|
dl.Warnf("namespace '%v' is deleted while unbinding share name mapping '%v'", detail.NamespaceName, detail.MappingId)
|
|
continue
|
|
}
|
|
|
|
// find dynamic frontends for this namespace
|
|
frontends, err := str.FindDynamicFrontendsForNamespace(detail.NamespaceID, trx)
|
|
if err != nil {
|
|
dl.Warnf("error finding dynamic frontends for namespace '%v': %v", detail.NamespaceName, err)
|
|
continue
|
|
}
|
|
|
|
// send unbind mapping updates to each dynamic frontend
|
|
for _, frontend := range frontends {
|
|
frontendName := util.NameInNamespace(detail.Name, detail.NamespaceName)
|
|
|
|
if err := dPCtrl.UnbindFrontendMapping(frontend.Token, frontendName, trx); err != nil {
|
|
dl.Errorf("error unbinding frontend mapping from frontend '%v': %v", frontend.Token, err)
|
|
// continue with other frontends rather than failing completely
|
|
} else {
|
|
dl.Debugf("unbound frontend mapping '%v' from dynamic frontend '%v'", frontendName, frontend.Token)
|
|
}
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|