Port envd from e2b with internalized shared packages and Connect RPC
- Copy envd source from e2b-dev/infra, internalize shared dependencies
into envd/internal/shared/ (keys, filesystem, id, smap, utils)
- Switch from gRPC to Connect RPC for all envd services
- Update module paths to git.omukk.dev/wrenn/{sandbox,sandbox/envd}
- Add proto specs (process, filesystem) with buf-based code generation
- Implement full envd: process exec, filesystem ops, port forwarding,
cgroup management, MMDS integration, and HTTP API
- Update main module dependencies (firecracker SDK, pgx, goose, etc.)
- Remove placeholder .gitkeep files replaced by real implementations
This commit is contained in:
568
envd/internal/api/api.gen.go
Normal file
568
envd/internal/api/api.gen.go
Normal file
@ -0,0 +1,568 @@
|
||||
// Package api provides primitives to interact with the openapi HTTP API.
|
||||
//
|
||||
// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.5.1 DO NOT EDIT.
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/oapi-codegen/runtime"
|
||||
openapi_types "github.com/oapi-codegen/runtime/types"
|
||||
)
|
||||
|
||||
const (
|
||||
AccessTokenAuthScopes = "AccessTokenAuth.Scopes"
|
||||
)
|
||||
|
||||
// Defines values for EntryInfoType.
|
||||
const (
|
||||
File EntryInfoType = "file"
|
||||
)
|
||||
|
||||
// EntryInfo defines model for EntryInfo.
|
||||
type EntryInfo struct {
|
||||
// Name Name of the file
|
||||
Name string `json:"name"`
|
||||
|
||||
// Path Path to the file
|
||||
Path string `json:"path"`
|
||||
|
||||
// Type Type of the file
|
||||
Type EntryInfoType `json:"type"`
|
||||
}
|
||||
|
||||
// EntryInfoType Type of the file
|
||||
type EntryInfoType string
|
||||
|
||||
// EnvVars Environment variables to set
|
||||
type EnvVars map[string]string
|
||||
|
||||
// Error defines model for Error.
|
||||
type Error struct {
|
||||
// Code Error code
|
||||
Code int `json:"code"`
|
||||
|
||||
// Message Error message
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
// Metrics Resource usage metrics
|
||||
type Metrics struct {
|
||||
// CpuCount Number of CPU cores
|
||||
CpuCount *int `json:"cpu_count,omitempty"`
|
||||
|
||||
// CpuUsedPct CPU usage percentage
|
||||
CpuUsedPct *float32 `json:"cpu_used_pct,omitempty"`
|
||||
|
||||
// DiskTotal Total disk space in bytes
|
||||
DiskTotal *int `json:"disk_total,omitempty"`
|
||||
|
||||
// DiskUsed Used disk space in bytes
|
||||
DiskUsed *int `json:"disk_used,omitempty"`
|
||||
|
||||
// MemTotal Total virtual memory in bytes
|
||||
MemTotal *int `json:"mem_total,omitempty"`
|
||||
|
||||
// MemUsed Used virtual memory in bytes
|
||||
MemUsed *int `json:"mem_used,omitempty"`
|
||||
|
||||
// Ts Unix timestamp in UTC for current sandbox time
|
||||
Ts *int64 `json:"ts,omitempty"`
|
||||
}
|
||||
|
||||
// VolumeMount Volume
|
||||
type VolumeMount struct {
|
||||
NfsTarget string `json:"nfs_target"`
|
||||
Path string `json:"path"`
|
||||
}
|
||||
|
||||
// FilePath defines model for FilePath.
|
||||
type FilePath = string
|
||||
|
||||
// Signature defines model for Signature.
|
||||
type Signature = string
|
||||
|
||||
// SignatureExpiration defines model for SignatureExpiration.
|
||||
type SignatureExpiration = int
|
||||
|
||||
// User defines model for User.
|
||||
type User = string
|
||||
|
||||
// FileNotFound defines model for FileNotFound.
|
||||
type FileNotFound = Error
|
||||
|
||||
// InternalServerError defines model for InternalServerError.
|
||||
type InternalServerError = Error
|
||||
|
||||
// InvalidPath defines model for InvalidPath.
|
||||
type InvalidPath = Error
|
||||
|
||||
// InvalidUser defines model for InvalidUser.
|
||||
type InvalidUser = Error
|
||||
|
||||
// NotEnoughDiskSpace defines model for NotEnoughDiskSpace.
|
||||
type NotEnoughDiskSpace = Error
|
||||
|
||||
// UploadSuccess defines model for UploadSuccess.
|
||||
type UploadSuccess = []EntryInfo
|
||||
|
||||
// GetFilesParams defines parameters for GetFiles.
|
||||
type GetFilesParams struct {
|
||||
// Path Path to the file, URL encoded. Can be relative to user's home directory.
|
||||
Path *FilePath `form:"path,omitempty" json:"path,omitempty"`
|
||||
|
||||
// Username User used for setting the owner, or resolving relative paths.
|
||||
Username *User `form:"username,omitempty" json:"username,omitempty"`
|
||||
|
||||
// Signature Signature used for file access permission verification.
|
||||
Signature *Signature `form:"signature,omitempty" json:"signature,omitempty"`
|
||||
|
||||
// SignatureExpiration Signature expiration used for defining the expiration time of the signature.
|
||||
SignatureExpiration *SignatureExpiration `form:"signature_expiration,omitempty" json:"signature_expiration,omitempty"`
|
||||
}
|
||||
|
||||
// PostFilesMultipartBody defines parameters for PostFiles.
|
||||
type PostFilesMultipartBody struct {
|
||||
File *openapi_types.File `json:"file,omitempty"`
|
||||
}
|
||||
|
||||
// PostFilesParams defines parameters for PostFiles.
|
||||
type PostFilesParams struct {
|
||||
// Path Path to the file, URL encoded. Can be relative to user's home directory.
|
||||
Path *FilePath `form:"path,omitempty" json:"path,omitempty"`
|
||||
|
||||
// Username User used for setting the owner, or resolving relative paths.
|
||||
Username *User `form:"username,omitempty" json:"username,omitempty"`
|
||||
|
||||
// Signature Signature used for file access permission verification.
|
||||
Signature *Signature `form:"signature,omitempty" json:"signature,omitempty"`
|
||||
|
||||
// SignatureExpiration Signature expiration used for defining the expiration time of the signature.
|
||||
SignatureExpiration *SignatureExpiration `form:"signature_expiration,omitempty" json:"signature_expiration,omitempty"`
|
||||
}
|
||||
|
||||
// PostInitJSONBody defines parameters for PostInit.
|
||||
type PostInitJSONBody struct {
|
||||
// AccessToken Access token for secure access to envd service
|
||||
AccessToken *SecureToken `json:"accessToken,omitempty"`
|
||||
|
||||
// DefaultUser The default user to use for operations
|
||||
DefaultUser *string `json:"defaultUser,omitempty"`
|
||||
|
||||
// DefaultWorkdir The default working directory to use for operations
|
||||
DefaultWorkdir *string `json:"defaultWorkdir,omitempty"`
|
||||
|
||||
// EnvVars Environment variables to set
|
||||
EnvVars *EnvVars `json:"envVars,omitempty"`
|
||||
|
||||
// HyperloopIP IP address of the hyperloop server to connect to
|
||||
HyperloopIP *string `json:"hyperloopIP,omitempty"`
|
||||
|
||||
// Timestamp The current timestamp in RFC3339 format
|
||||
Timestamp *time.Time `json:"timestamp,omitempty"`
|
||||
VolumeMounts *[]VolumeMount `json:"volumeMounts,omitempty"`
|
||||
}
|
||||
|
||||
// PostFilesMultipartRequestBody defines body for PostFiles for multipart/form-data ContentType.
|
||||
type PostFilesMultipartRequestBody PostFilesMultipartBody
|
||||
|
||||
// PostInitJSONRequestBody defines body for PostInit for application/json ContentType.
|
||||
type PostInitJSONRequestBody PostInitJSONBody
|
||||
|
||||
// ServerInterface represents all server handlers.
|
||||
type ServerInterface interface {
|
||||
// Get the environment variables
|
||||
// (GET /envs)
|
||||
GetEnvs(w http.ResponseWriter, r *http.Request)
|
||||
// Download a file
|
||||
// (GET /files)
|
||||
GetFiles(w http.ResponseWriter, r *http.Request, params GetFilesParams)
|
||||
// Upload a file and ensure the parent directories exist. If the file exists, it will be overwritten.
|
||||
// (POST /files)
|
||||
PostFiles(w http.ResponseWriter, r *http.Request, params PostFilesParams)
|
||||
// Check the health of the service
|
||||
// (GET /health)
|
||||
GetHealth(w http.ResponseWriter, r *http.Request)
|
||||
// Set initial vars, ensure the time and metadata is synced with the host
|
||||
// (POST /init)
|
||||
PostInit(w http.ResponseWriter, r *http.Request)
|
||||
// Get the stats of the service
|
||||
// (GET /metrics)
|
||||
GetMetrics(w http.ResponseWriter, r *http.Request)
|
||||
}
|
||||
|
||||
// Unimplemented server implementation that returns http.StatusNotImplemented for each endpoint.
|
||||
|
||||
type Unimplemented struct{}
|
||||
|
||||
// Get the environment variables
|
||||
// (GET /envs)
|
||||
func (_ Unimplemented) GetEnvs(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusNotImplemented)
|
||||
}
|
||||
|
||||
// Download a file
|
||||
// (GET /files)
|
||||
func (_ Unimplemented) GetFiles(w http.ResponseWriter, r *http.Request, params GetFilesParams) {
|
||||
w.WriteHeader(http.StatusNotImplemented)
|
||||
}
|
||||
|
||||
// Upload a file and ensure the parent directories exist. If the file exists, it will be overwritten.
|
||||
// (POST /files)
|
||||
func (_ Unimplemented) PostFiles(w http.ResponseWriter, r *http.Request, params PostFilesParams) {
|
||||
w.WriteHeader(http.StatusNotImplemented)
|
||||
}
|
||||
|
||||
// Check the health of the service
|
||||
// (GET /health)
|
||||
func (_ Unimplemented) GetHealth(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusNotImplemented)
|
||||
}
|
||||
|
||||
// Set initial vars, ensure the time and metadata is synced with the host
|
||||
// (POST /init)
|
||||
func (_ Unimplemented) PostInit(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusNotImplemented)
|
||||
}
|
||||
|
||||
// Get the stats of the service
|
||||
// (GET /metrics)
|
||||
func (_ Unimplemented) GetMetrics(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusNotImplemented)
|
||||
}
|
||||
|
||||
// ServerInterfaceWrapper converts contexts to parameters.
|
||||
type ServerInterfaceWrapper struct {
|
||||
Handler ServerInterface
|
||||
HandlerMiddlewares []MiddlewareFunc
|
||||
ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
|
||||
}
|
||||
|
||||
type MiddlewareFunc func(http.Handler) http.Handler
|
||||
|
||||
// GetEnvs operation middleware
|
||||
func (siw *ServerInterfaceWrapper) GetEnvs(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
ctx := r.Context()
|
||||
|
||||
ctx = context.WithValue(ctx, AccessTokenAuthScopes, []string{})
|
||||
|
||||
r = r.WithContext(ctx)
|
||||
|
||||
handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
siw.Handler.GetEnvs(w, r)
|
||||
}))
|
||||
|
||||
for _, middleware := range siw.HandlerMiddlewares {
|
||||
handler = middleware(handler)
|
||||
}
|
||||
|
||||
handler.ServeHTTP(w, r)
|
||||
}
|
||||
|
||||
// GetFiles operation middleware
|
||||
func (siw *ServerInterfaceWrapper) GetFiles(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
var err error
|
||||
|
||||
ctx := r.Context()
|
||||
|
||||
ctx = context.WithValue(ctx, AccessTokenAuthScopes, []string{})
|
||||
|
||||
r = r.WithContext(ctx)
|
||||
|
||||
// Parameter object where we will unmarshal all parameters from the context
|
||||
var params GetFilesParams
|
||||
|
||||
// ------------- Optional query parameter "path" -------------
|
||||
|
||||
err = runtime.BindQueryParameter("form", true, false, "path", r.URL.Query(), ¶ms.Path)
|
||||
if err != nil {
|
||||
siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "path", Err: err})
|
||||
return
|
||||
}
|
||||
|
||||
// ------------- Optional query parameter "username" -------------
|
||||
|
||||
err = runtime.BindQueryParameter("form", true, false, "username", r.URL.Query(), ¶ms.Username)
|
||||
if err != nil {
|
||||
siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "username", Err: err})
|
||||
return
|
||||
}
|
||||
|
||||
// ------------- Optional query parameter "signature" -------------
|
||||
|
||||
err = runtime.BindQueryParameter("form", true, false, "signature", r.URL.Query(), ¶ms.Signature)
|
||||
if err != nil {
|
||||
siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "signature", Err: err})
|
||||
return
|
||||
}
|
||||
|
||||
// ------------- Optional query parameter "signature_expiration" -------------
|
||||
|
||||
err = runtime.BindQueryParameter("form", true, false, "signature_expiration", r.URL.Query(), ¶ms.SignatureExpiration)
|
||||
if err != nil {
|
||||
siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "signature_expiration", Err: err})
|
||||
return
|
||||
}
|
||||
|
||||
handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
siw.Handler.GetFiles(w, r, params)
|
||||
}))
|
||||
|
||||
for _, middleware := range siw.HandlerMiddlewares {
|
||||
handler = middleware(handler)
|
||||
}
|
||||
|
||||
handler.ServeHTTP(w, r)
|
||||
}
|
||||
|
||||
// PostFiles operation middleware
|
||||
func (siw *ServerInterfaceWrapper) PostFiles(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
var err error
|
||||
|
||||
ctx := r.Context()
|
||||
|
||||
ctx = context.WithValue(ctx, AccessTokenAuthScopes, []string{})
|
||||
|
||||
r = r.WithContext(ctx)
|
||||
|
||||
// Parameter object where we will unmarshal all parameters from the context
|
||||
var params PostFilesParams
|
||||
|
||||
// ------------- Optional query parameter "path" -------------
|
||||
|
||||
err = runtime.BindQueryParameter("form", true, false, "path", r.URL.Query(), ¶ms.Path)
|
||||
if err != nil {
|
||||
siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "path", Err: err})
|
||||
return
|
||||
}
|
||||
|
||||
// ------------- Optional query parameter "username" -------------
|
||||
|
||||
err = runtime.BindQueryParameter("form", true, false, "username", r.URL.Query(), ¶ms.Username)
|
||||
if err != nil {
|
||||
siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "username", Err: err})
|
||||
return
|
||||
}
|
||||
|
||||
// ------------- Optional query parameter "signature" -------------
|
||||
|
||||
err = runtime.BindQueryParameter("form", true, false, "signature", r.URL.Query(), ¶ms.Signature)
|
||||
if err != nil {
|
||||
siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "signature", Err: err})
|
||||
return
|
||||
}
|
||||
|
||||
// ------------- Optional query parameter "signature_expiration" -------------
|
||||
|
||||
err = runtime.BindQueryParameter("form", true, false, "signature_expiration", r.URL.Query(), ¶ms.SignatureExpiration)
|
||||
if err != nil {
|
||||
siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "signature_expiration", Err: err})
|
||||
return
|
||||
}
|
||||
|
||||
handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
siw.Handler.PostFiles(w, r, params)
|
||||
}))
|
||||
|
||||
for _, middleware := range siw.HandlerMiddlewares {
|
||||
handler = middleware(handler)
|
||||
}
|
||||
|
||||
handler.ServeHTTP(w, r)
|
||||
}
|
||||
|
||||
// GetHealth operation middleware
|
||||
func (siw *ServerInterfaceWrapper) GetHealth(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
siw.Handler.GetHealth(w, r)
|
||||
}))
|
||||
|
||||
for _, middleware := range siw.HandlerMiddlewares {
|
||||
handler = middleware(handler)
|
||||
}
|
||||
|
||||
handler.ServeHTTP(w, r)
|
||||
}
|
||||
|
||||
// PostInit operation middleware
|
||||
func (siw *ServerInterfaceWrapper) PostInit(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
ctx := r.Context()
|
||||
|
||||
ctx = context.WithValue(ctx, AccessTokenAuthScopes, []string{})
|
||||
|
||||
r = r.WithContext(ctx)
|
||||
|
||||
handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
siw.Handler.PostInit(w, r)
|
||||
}))
|
||||
|
||||
for _, middleware := range siw.HandlerMiddlewares {
|
||||
handler = middleware(handler)
|
||||
}
|
||||
|
||||
handler.ServeHTTP(w, r)
|
||||
}
|
||||
|
||||
// GetMetrics operation middleware
|
||||
func (siw *ServerInterfaceWrapper) GetMetrics(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
ctx := r.Context()
|
||||
|
||||
ctx = context.WithValue(ctx, AccessTokenAuthScopes, []string{})
|
||||
|
||||
r = r.WithContext(ctx)
|
||||
|
||||
handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
siw.Handler.GetMetrics(w, r)
|
||||
}))
|
||||
|
||||
for _, middleware := range siw.HandlerMiddlewares {
|
||||
handler = middleware(handler)
|
||||
}
|
||||
|
||||
handler.ServeHTTP(w, r)
|
||||
}
|
||||
|
||||
type UnescapedCookieParamError struct {
|
||||
ParamName string
|
||||
Err error
|
||||
}
|
||||
|
||||
func (e *UnescapedCookieParamError) Error() string {
|
||||
return fmt.Sprintf("error unescaping cookie parameter '%s'", e.ParamName)
|
||||
}
|
||||
|
||||
func (e *UnescapedCookieParamError) Unwrap() error {
|
||||
return e.Err
|
||||
}
|
||||
|
||||
type UnmarshalingParamError struct {
|
||||
ParamName string
|
||||
Err error
|
||||
}
|
||||
|
||||
func (e *UnmarshalingParamError) Error() string {
|
||||
return fmt.Sprintf("Error unmarshaling parameter %s as JSON: %s", e.ParamName, e.Err.Error())
|
||||
}
|
||||
|
||||
func (e *UnmarshalingParamError) Unwrap() error {
|
||||
return e.Err
|
||||
}
|
||||
|
||||
type RequiredParamError struct {
|
||||
ParamName string
|
||||
}
|
||||
|
||||
func (e *RequiredParamError) Error() string {
|
||||
return fmt.Sprintf("Query argument %s is required, but not found", e.ParamName)
|
||||
}
|
||||
|
||||
type RequiredHeaderError struct {
|
||||
ParamName string
|
||||
Err error
|
||||
}
|
||||
|
||||
func (e *RequiredHeaderError) Error() string {
|
||||
return fmt.Sprintf("Header parameter %s is required, but not found", e.ParamName)
|
||||
}
|
||||
|
||||
func (e *RequiredHeaderError) Unwrap() error {
|
||||
return e.Err
|
||||
}
|
||||
|
||||
type InvalidParamFormatError struct {
|
||||
ParamName string
|
||||
Err error
|
||||
}
|
||||
|
||||
func (e *InvalidParamFormatError) Error() string {
|
||||
return fmt.Sprintf("Invalid format for parameter %s: %s", e.ParamName, e.Err.Error())
|
||||
}
|
||||
|
||||
func (e *InvalidParamFormatError) Unwrap() error {
|
||||
return e.Err
|
||||
}
|
||||
|
||||
type TooManyValuesForParamError struct {
|
||||
ParamName string
|
||||
Count int
|
||||
}
|
||||
|
||||
func (e *TooManyValuesForParamError) Error() string {
|
||||
return fmt.Sprintf("Expected one value for %s, got %d", e.ParamName, e.Count)
|
||||
}
|
||||
|
||||
// Handler creates http.Handler with routing matching OpenAPI spec.
|
||||
func Handler(si ServerInterface) http.Handler {
|
||||
return HandlerWithOptions(si, ChiServerOptions{})
|
||||
}
|
||||
|
||||
type ChiServerOptions struct {
|
||||
BaseURL string
|
||||
BaseRouter chi.Router
|
||||
Middlewares []MiddlewareFunc
|
||||
ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
|
||||
}
|
||||
|
||||
// HandlerFromMux creates http.Handler with routing matching OpenAPI spec based on the provided mux.
|
||||
func HandlerFromMux(si ServerInterface, r chi.Router) http.Handler {
|
||||
return HandlerWithOptions(si, ChiServerOptions{
|
||||
BaseRouter: r,
|
||||
})
|
||||
}
|
||||
|
||||
func HandlerFromMuxWithBaseURL(si ServerInterface, r chi.Router, baseURL string) http.Handler {
|
||||
return HandlerWithOptions(si, ChiServerOptions{
|
||||
BaseURL: baseURL,
|
||||
BaseRouter: r,
|
||||
})
|
||||
}
|
||||
|
||||
// HandlerWithOptions creates http.Handler with additional options
|
||||
func HandlerWithOptions(si ServerInterface, options ChiServerOptions) http.Handler {
|
||||
r := options.BaseRouter
|
||||
|
||||
if r == nil {
|
||||
r = chi.NewRouter()
|
||||
}
|
||||
if options.ErrorHandlerFunc == nil {
|
||||
options.ErrorHandlerFunc = func(w http.ResponseWriter, r *http.Request, err error) {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
}
|
||||
}
|
||||
wrapper := ServerInterfaceWrapper{
|
||||
Handler: si,
|
||||
HandlerMiddlewares: options.Middlewares,
|
||||
ErrorHandlerFunc: options.ErrorHandlerFunc,
|
||||
}
|
||||
|
||||
r.Group(func(r chi.Router) {
|
||||
r.Get(options.BaseURL+"/envs", wrapper.GetEnvs)
|
||||
})
|
||||
r.Group(func(r chi.Router) {
|
||||
r.Get(options.BaseURL+"/files", wrapper.GetFiles)
|
||||
})
|
||||
r.Group(func(r chi.Router) {
|
||||
r.Post(options.BaseURL+"/files", wrapper.PostFiles)
|
||||
})
|
||||
r.Group(func(r chi.Router) {
|
||||
r.Get(options.BaseURL+"/health", wrapper.GetHealth)
|
||||
})
|
||||
r.Group(func(r chi.Router) {
|
||||
r.Post(options.BaseURL+"/init", wrapper.PostInit)
|
||||
})
|
||||
r.Group(func(r chi.Router) {
|
||||
r.Get(options.BaseURL+"/metrics", wrapper.GetMetrics)
|
||||
})
|
||||
|
||||
return r
|
||||
}
|
||||
Reference in New Issue
Block a user