2022-12-05 19:12:12 +01:00
package controller
import (
2022-12-05 21:40:42 +01:00
"bytes"
2022-12-05 19:12:12 +01:00
"context"
2022-12-05 21:40:42 +01:00
"encoding/json"
2022-12-05 19:12:12 +01:00
"fmt"
2023-05-25 17:50:38 +02:00
"github.com/openziti/edge-api/rest_management_api_client"
2023-07-14 15:42:06 +02:00
restMgmtEdgeConfig "github.com/openziti/edge-api/rest_management_api_client/config"
2023-05-25 17:50:38 +02:00
"github.com/openziti/edge-api/rest_management_api_client/edge_router_policy"
"github.com/openziti/edge-api/rest_management_api_client/identity"
2023-07-14 15:42:06 +02:00
restModelEdge "github.com/openziti/edge-api/rest_model"
2023-08-18 22:22:17 +02:00
"github.com/openziti/edge-api/rest_util"
2022-12-05 20:00:51 +01:00
"github.com/openziti/sdk-golang/ziti"
2023-07-14 15:42:06 +02:00
"github.com/openziti/zrok/controller/config"
2023-01-13 21:01:34 +01:00
"github.com/openziti/zrok/controller/store"
"github.com/openziti/zrok/controller/zrokEdgeSdk"
2023-07-13 20:26:35 +02:00
"github.com/openziti/zrok/environment"
2023-11-21 20:27:17 +01:00
"github.com/openziti/zrok/sdk/golang/sdk"
2022-12-05 19:12:12 +01:00
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
2023-05-25 20:59:39 +02:00
"time"
2022-12-05 19:12:12 +01:00
)
2023-07-14 15:42:06 +02:00
func Bootstrap ( skipFrontend bool , inCfg * config . Config ) error {
2022-12-05 19:12:12 +01:00
cfg = inCfg
2022-12-06 18:25:17 +01:00
if v , err := store . Open ( cfg . Store ) ; err == nil {
str = v
} else {
return errors . Wrap ( err , "error opening store" )
}
2022-12-07 18:01:56 +01:00
logrus . Info ( "connecting to the ziti edge management api" )
2023-03-07 20:31:39 +01:00
edge , err := zrokEdgeSdk . Client ( cfg . Ziti )
2022-12-05 20:25:49 +01:00
if err != nil {
2022-12-07 18:01:56 +01:00
return errors . Wrap ( err , "error connecting to the ziti edge management api" )
2022-12-05 20:25:49 +01:00
}
2023-07-14 16:14:32 +02:00
env , err := environment . LoadRoot ( )
if err != nil {
return err
}
2022-12-05 21:40:42 +01:00
var frontendZId string
2022-12-05 21:00:22 +01:00
if ! skipFrontend {
2023-07-17 19:51:51 +02:00
logrus . Info ( "creating identity for public frontend access" )
2022-12-07 18:01:56 +01:00
2023-07-17 19:51:51 +02:00
if frontendZId , err = getIdentityId ( env . PublicIdentityName ( ) ) ; err == nil {
2022-12-05 21:00:22 +01:00
logrus . Infof ( "frontend identity: %v" , frontendZId )
2022-12-05 21:40:42 +01:00
} else {
2023-07-17 19:51:51 +02:00
frontendZId , err = bootstrapIdentity ( env . PublicIdentityName ( ) , edge )
2022-12-05 21:40:42 +01:00
if err != nil {
2022-12-05 21:00:22 +01:00
panic ( err )
}
2022-12-05 21:40:42 +01:00
}
if err := assertIdentity ( frontendZId , edge ) ; err != nil {
panic ( err )
}
2023-07-17 19:51:51 +02:00
if err := assertErpForIdentity ( env . PublicIdentityName ( ) , frontendZId , edge ) ; err != nil {
2022-12-05 20:25:49 +01:00
panic ( err )
}
2022-12-06 18:25:17 +01:00
tx , err := str . Begin ( )
if err != nil {
panic ( err )
}
defer func ( ) { _ = tx . Rollback ( ) } ( )
publicFe , err := str . FindFrontendWithZId ( frontendZId , tx )
if err != nil {
2023-01-04 20:21:23 +01:00
logrus . Warnf ( "missing public frontend for ziti id '%v'; please use 'zrok admin create frontend %v public https://{token}.your.dns.name' to create a frontend instance" , frontendZId , frontendZId )
2022-12-06 18:25:17 +01:00
} else {
if publicFe . PublicName != nil && publicFe . UrlTemplate != nil {
logrus . Infof ( "found public frontend entry '%v' (%v) for ziti identity '%v'" , * publicFe . PublicName , publicFe . Token , frontendZId )
} else {
2022-12-06 20:53:59 +01:00
logrus . Warnf ( "found frontend entry for ziti identity '%v'; missing either public name or url template" , frontendZId )
2022-12-06 18:25:17 +01:00
}
}
2022-12-05 20:00:51 +01:00
}
2022-12-05 19:12:12 +01:00
if err := assertZrokProxyConfigType ( edge ) ; err != nil {
return err
}
return nil
}
func assertZrokProxyConfigType ( edge * rest_management_api_client . ZitiEdgeManagement ) error {
2023-07-17 22:45:20 +02:00
filter := fmt . Sprintf ( "name=\"%v\"" , sdk . ZrokProxyConfig )
2022-12-05 19:12:12 +01:00
limit := int64 ( 100 )
offset := int64 ( 0 )
2023-07-14 15:42:06 +02:00
listReq := & restMgmtEdgeConfig . ListConfigTypesParams {
2022-12-05 19:12:12 +01:00
Filter : & filter ,
Limit : & limit ,
Offset : & offset ,
Context : context . Background ( ) ,
}
listReq . SetTimeout ( 30 * time . Second )
listResp , err := edge . Config . ListConfigTypes ( listReq , nil )
if err != nil {
return err
}
if len ( listResp . Payload . Data ) < 1 {
2023-07-17 22:45:20 +02:00
name := sdk . ZrokProxyConfig
2023-07-14 15:42:06 +02:00
ct := & restModelEdge . ConfigTypeCreate { Name : & name }
createReq := & restMgmtEdgeConfig . CreateConfigTypeParams { ConfigType : ct }
2022-12-05 19:12:12 +01:00
createReq . SetTimeout ( 30 * time . Second )
createResp , err := edge . Config . CreateConfigType ( createReq , nil )
if err != nil {
return err
}
2023-07-17 22:45:20 +02:00
logrus . Infof ( "created '%v' config type with id '%v'" , sdk . ZrokProxyConfig , createResp . Payload . Data . ID )
2022-12-05 19:12:12 +01:00
} else if len ( listResp . Payload . Data ) > 1 {
2023-07-17 22:45:20 +02:00
return errors . Errorf ( "found %d '%v' config types; expected 0 or 1" , len ( listResp . Payload . Data ) , sdk . ZrokProxyConfig )
2022-12-05 19:12:12 +01:00
} else {
2023-07-17 22:45:20 +02:00
logrus . Infof ( "found '%v' config type with id '%v'" , sdk . ZrokProxyConfig , * ( listResp . Payload . Data [ 0 ] . ID ) )
2022-12-05 19:12:12 +01:00
}
return nil
}
2022-12-05 20:00:51 +01:00
func getIdentityId ( identityName string ) ( string , error ) {
2023-07-13 20:26:35 +02:00
env , err := environment . LoadRoot ( )
if err != nil {
return "" , errors . Wrap ( err , "error opening environment root" )
}
2023-07-14 16:14:32 +02:00
zif , err := env . ZitiIdentityNamed ( identityName )
2022-12-05 20:00:51 +01:00
if err != nil {
2023-07-10 22:41:16 +02:00
return "" , errors . Wrapf ( err , "error opening identity '%v' from environment" , identityName )
2022-12-05 20:00:51 +01:00
}
2023-05-25 20:59:39 +02:00
zcfg , err := ziti . NewConfigFromFile ( zif )
2022-12-05 20:00:51 +01:00
if err != nil {
2022-12-05 20:06:53 +01:00
return "" , errors . Wrapf ( err , "error loading ziti config from file '%v'" , zif )
2022-12-05 20:00:51 +01:00
}
2023-05-25 17:50:38 +02:00
zctx , err := ziti . NewContext ( zcfg )
if err != nil {
return "" , errors . Wrap ( err , "error loading ziti context" )
}
2022-12-05 20:00:51 +01:00
id , err := zctx . GetCurrentIdentity ( )
if err != nil {
2022-12-05 20:06:53 +01:00
return "" , errors . Wrapf ( err , "error getting current identity from '%v'" , zif )
2022-12-05 20:00:51 +01:00
}
2023-05-25 17:50:38 +02:00
if id . ID != nil {
return * id . ID , nil
}
return "" , nil
2022-12-05 20:00:51 +01:00
}
2022-12-05 20:25:49 +01:00
func assertIdentity ( zId string , edge * rest_management_api_client . ZitiEdgeManagement ) error {
filter := fmt . Sprintf ( "id=\"%v\"" , zId )
limit := int64 ( 0 )
offset := int64 ( 0 )
listReq := & identity . ListIdentitiesParams {
Filter : & filter ,
Limit : & limit ,
Offset : & offset ,
}
listReq . SetTimeout ( 30 * time . Second )
listResp , err := edge . Identity . ListIdentities ( listReq , nil )
if err != nil {
return errors . Wrapf ( err , "error listing identities for '%v'" , zId )
}
if len ( listResp . Payload . Data ) != 1 {
2022-12-05 21:03:55 +01:00
return errors . Wrapf ( err , "found %d identities for '%v'" , len ( listResp . Payload . Data ) , zId )
2022-12-05 20:25:49 +01:00
}
logrus . Infof ( "asserted identity '%v'" , zId )
return nil
}
2022-12-05 21:40:42 +01:00
func bootstrapIdentity ( name string , edge * rest_management_api_client . ZitiEdgeManagement ) ( string , error ) {
2023-07-13 20:26:35 +02:00
env , err := environment . LoadRoot ( )
if err != nil {
return "" , errors . Wrap ( err , "error loading environment root" )
}
2023-07-14 15:42:06 +02:00
idc , err := zrokEdgeSdk . CreateIdentity ( name , restModelEdge . IdentityTypeDevice , nil , edge )
2022-12-05 21:40:42 +01:00
if err != nil {
2023-08-18 22:22:17 +02:00
return "" , errors . Wrapf ( rest_util . WrapErr ( err ) , "error creating '%v' identity" , name )
2022-12-05 21:40:42 +01:00
}
zId := idc . Payload . Data . ID
2022-12-14 20:40:45 +01:00
cfg , err := zrokEdgeSdk . EnrollIdentity ( zId , edge )
2022-12-05 21:40:42 +01:00
if err != nil {
2023-08-18 22:22:17 +02:00
return "" , errors . Wrapf ( rest_util . WrapErr ( err ) , "error enrolling '%v' identity" , name )
2022-12-05 21:40:42 +01:00
}
var out bytes . Buffer
enc := json . NewEncoder ( & out )
enc . SetEscapeHTML ( false )
err = enc . Encode ( & cfg )
if err != nil {
return "" , errors . Wrapf ( err , "error encoding identity config '%v'" , name )
}
2023-07-14 16:14:32 +02:00
if err := env . SaveZitiIdentityNamed ( name , out . String ( ) ) ; err != nil {
2022-12-05 21:40:42 +01:00
return "" , errors . Wrapf ( err , "error saving identity config '%v'" , name )
}
return zId , nil
}
2022-12-05 20:25:49 +01:00
func assertErpForIdentity ( name , zId string , edge * rest_management_api_client . ZitiEdgeManagement ) error {
filter := fmt . Sprintf ( "name=\"%v\" and tags.zrok != null" , name )
limit := int64 ( 0 )
offset := int64 ( 0 )
listReq := & edge_router_policy . ListEdgeRouterPoliciesParams {
Filter : & filter ,
Limit : & limit ,
Offset : & offset ,
}
listReq . SetTimeout ( 30 * time . Second )
listResp , err := edge . EdgeRouterPolicy . ListEdgeRouterPolicies ( listReq , nil )
if err != nil {
return errors . Wrapf ( err , "error listing edge router policies for '%v' (%v)" , name , zId )
}
if len ( listResp . Payload . Data ) != 1 {
2022-12-05 21:00:22 +01:00
logrus . Infof ( "creating erp for '%v' (%v)" , name , zId )
2022-12-14 20:40:45 +01:00
if err := zrokEdgeSdk . CreateEdgeRouterPolicy ( name , zId , edge ) ; err != nil {
2022-12-05 21:00:22 +01:00
return errors . Wrapf ( err , "error creating erp for '%v' (%v)" , name , zId )
}
2022-12-05 20:25:49 +01:00
}
logrus . Infof ( "asserted erps for '%v' (%v)" , name , zId )
return nil
}