Compare commits

...

13 Commits

Author SHA1 Message Date
Karan Balani
8e59a6a40f chore: fix method call in handler 2026-02-18 20:07:39 +05:30
Karan Balani
57b426cad8 feat: add get deployments api also 2026-02-18 19:41:48 +05:30
Karan Balani
3cd32c84ee chore: use new instead of var 2026-02-18 18:21:05 +05:30
Karan Balani
1686d151ec chore: using binding package 2026-02-18 18:00:36 +05:30
Karan Balani
d05e2ae0c7 feat: pass the error message from zeus to caller 2026-02-18 17:32:11 +05:30
Karan Balani
9955931aea fix: model 2026-02-18 17:22:15 +05:30
Karan Balani
477ec1e9ad fix: model 2026-02-18 17:21:58 +05:30
Karan Balani
ce651cd693 fix: openapi specs and endpoints 2026-02-18 17:03:09 +05:30
Karan Balani
91d6aeea0a fix: openapi spec 2026-02-18 12:57:01 +05:30
Karan Balani
78f75ac8cc chore: handle 409 conflict also 2026-02-18 12:20:43 +05:30
Karan Balani
002bdab078 fix: host update endpoint 2026-02-18 11:41:48 +05:30
Karan Balani
7d3b21463f chore: update open api specs 2026-02-18 10:59:42 +05:30
Karan Balani
bcfb986127 feat: add zeus handler with profile and host apis 2026-02-18 01:26:29 +05:30
16 changed files with 1162 additions and 44 deletions

View File

@@ -3526,6 +3526,175 @@ paths:
summary: Rotate session
tags:
- sessions
/api/v2/zeus/deployments:
get:
deprecated: false
description: This endpoint gets the deployment info from zeus.
operationId: GetDeploymentsFromZeus
responses:
"200":
content:
application/json:
schema:
properties:
data:
$ref: '#/components/schemas/ZeustypesGettableDeployment'
status:
type: string
type: object
description: OK
"400":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Bad Request
"401":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Unauthorized
"403":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Forbidden
"404":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Not Found
"500":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Internal Server Error
security:
- api_key:
- ADMIN
- tokenizer:
- ADMIN
summary: Get deployments from Zeus.
tags:
- zeus
/api/v2/zeus/hosts:
put:
deprecated: false
description: This endpoint saves the host of a deployment to zeus.
operationId: PutHostInZeus
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/ZeustypesPostableHost'
responses:
"204":
description: No Content
"400":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Bad Request
"401":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Unauthorized
"403":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Forbidden
"404":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Not Found
"409":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Conflict
"500":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Internal Server Error
security:
- api_key:
- ADMIN
- tokenizer:
- ADMIN
summary: Put host in Zeus for a deployment.
tags:
- zeus
/api/v2/zeus/profiles:
put:
deprecated: false
description: This endpoint saves the profile of a deployment to zeus.
operationId: PutProfileInZeus
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/ZeustypesPostableProfile'
responses:
"204":
description: No Content
"400":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Bad Request
"401":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Unauthorized
"403":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Forbidden
"404":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Not Found
"409":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Conflict
"500":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Internal Server Error
security:
- api_key:
- ADMIN
- tokenizer:
- ADMIN
summary: Put profile in Zeus for a deployment.
tags:
- zeus
components:
schemas:
AuthtypesAttributeMapping:
@@ -4688,6 +4857,146 @@ components:
format: date-time
type: string
type: object
ZeustypesClusterResponseModel:
properties:
address:
type: string
buffer:
format: int64
type: integer
ca:
type: string
cloud_account_id:
type: string
cloud_provider:
type: string
cloud_region:
type: string
created_at:
format: date-time
type: string
id:
type: string
name:
type: string
region:
$ref: '#/components/schemas/ZeustypesRegionModel'
region_id:
type: string
updated_at:
format: date-time
type: string
type: object
ZeustypesDeploymentHistoryModel:
properties:
created_at:
format: date-time
type: string
deployment_id:
type: string
event:
type: string
id:
type: string
state_after:
type: string
state_before:
type: string
type: object
ZeustypesGettableDeployment:
properties:
cluster:
$ref: '#/components/schemas/ZeustypesClusterResponseModel'
cluster_id:
type: string
created_at:
format: date-time
type: string
histories:
items:
$ref: '#/components/schemas/ZeustypesDeploymentHistoryModel'
nullable: true
type: array
hosts:
items:
$ref: '#/components/schemas/ZeustypesHostModel'
type: array
id:
type: string
license_id:
type: string
name:
type: string
password:
type: string
state:
type: string
tier:
type: string
updated_at:
format: date-time
type: string
user:
type: string
type: object
ZeustypesHostModel:
properties:
is_default:
type: boolean
name:
type: string
type: object
ZeustypesPostableHost:
properties:
name:
type: string
required:
- name
type: object
ZeustypesPostableProfile:
properties:
existing_observability_tool:
type: string
has_existing_observability_tool:
type: boolean
logs_scale_per_day_in_gb:
format: int64
type: integer
number_of_hosts:
format: int64
type: integer
number_of_services:
format: int64
type: integer
reasons_for_interest_in_signoz:
items:
type: string
nullable: true
type: array
timeline_for_migrating_to_signoz:
type: string
uses_otel:
type: boolean
where_did_you_discover_signoz:
type: string
type: object
ZeustypesRegionModel:
properties:
category:
type: string
created_at:
format: date-time
type: string
dns:
type: string
id:
type: string
name:
type: string
updated_at:
format: date-time
type: string
type: object
securitySchemes:
api_key:
description: API Keys

View File

@@ -188,34 +188,15 @@ func (ah *APIHandler) getOrCreateCloudIntegrationUser(
func (ah *APIHandler) getIngestionUrlAndSigNozAPIUrl(ctx context.Context, licenseKey string) (
string, *basemodel.ApiError,
) {
// TODO: remove this struct from here
type deploymentResponse struct {
Name string `json:"name"`
ClusterInfo struct {
Region struct {
DNS string `json:"dns"`
} `json:"region"`
} `json:"cluster"`
}
respBytes, err := ah.Signoz.Zeus.GetDeployment(ctx, licenseKey)
deployment, err := ah.Signoz.Zeus.GetDeployment(ctx, licenseKey)
if err != nil {
return "", basemodel.InternalError(fmt.Errorf(
"couldn't query for deployment info: error: %w", err,
))
}
resp := new(deploymentResponse)
err = json.Unmarshal(respBytes, resp)
if err != nil {
return "", basemodel.InternalError(fmt.Errorf(
"couldn't unmarshal deployment info response: error: %w", err,
))
}
regionDns := resp.ClusterInfo.Region.DNS
deploymentName := resp.Name
regionDns := deployment.Cluster.Region.DNS
deploymentName := deployment.Name
if len(regionDns) < 1 || len(deploymentName) < 1 {
// Fail early if actual response structure and expectation here ever diverge

View File

@@ -3,6 +3,7 @@ package httpzeus
import (
"bytes"
"context"
"encoding/json"
"io"
"net/http"
"net/url"
@@ -10,6 +11,7 @@ import (
"github.com/SigNoz/signoz/pkg/errors"
"github.com/SigNoz/signoz/pkg/factory"
"github.com/SigNoz/signoz/pkg/http/client"
"github.com/SigNoz/signoz/pkg/types/zeustypes"
"github.com/SigNoz/signoz/pkg/zeus"
"github.com/tidwall/gjson"
)
@@ -92,7 +94,7 @@ func (provider *Provider) GetPortalURL(ctx context.Context, key string, body []b
return []byte(gjson.GetBytes(response, "data").String()), nil
}
func (provider *Provider) GetDeployment(ctx context.Context, key string) ([]byte, error) {
func (provider *Provider) GetDeployment(ctx context.Context, key string) (*zeustypes.GettableDeployment, error) {
response, err := provider.do(
ctx,
provider.config.URL.JoinPath("/v2/deployments/me"),
@@ -104,7 +106,12 @@ func (provider *Provider) GetDeployment(ctx context.Context, key string) ([]byte
return nil, err
}
return []byte(gjson.GetBytes(response, "data").String()), nil
gettableDeployment := new(zeustypes.GettableDeployment)
if err := json.Unmarshal([]byte(gjson.GetBytes(response, "data").String()), &gettableDeployment); err != nil {
return nil, err
}
return gettableDeployment, nil
}
func (provider *Provider) PutMeters(ctx context.Context, key string, data []byte) error {
@@ -119,8 +126,13 @@ func (provider *Provider) PutMeters(ctx context.Context, key string, data []byte
return err
}
func (provider *Provider) PutProfile(ctx context.Context, key string, body []byte) error {
_, err := provider.do(
func (provider *Provider) PutProfile(ctx context.Context, key string, profile *zeustypes.PostableProfile) error {
body, err := json.Marshal(profile)
if err != nil {
return err
}
_, err = provider.do(
ctx,
provider.config.URL.JoinPath("/v2/profiles/me"),
http.MethodPut,
@@ -131,10 +143,15 @@ func (provider *Provider) PutProfile(ctx context.Context, key string, body []byt
return err
}
func (provider *Provider) PutHost(ctx context.Context, key string, body []byte) error {
_, err := provider.do(
func (provider *Provider) PutHost(ctx context.Context, key string, host *zeustypes.PostableHost) error {
body, err := json.Marshal(host)
if err != nil {
return err
}
_, err = provider.do(
ctx,
provider.config.URL.JoinPath("/v2/deployments/me/hosts"),
provider.config.URL.JoinPath("/v2/deployments/me/host"),
http.MethodPut,
key,
body,
@@ -169,21 +186,28 @@ func (provider *Provider) do(ctx context.Context, url *url.URL, method string, k
return body, nil
}
return nil, provider.errFromStatusCode(response.StatusCode)
errorMessage := gjson.GetBytes(body, "error").String()
if errorMessage == "" {
errorMessage = "an unknown error occurred"
}
return nil, provider.errFromStatusCode(response.StatusCode, errorMessage)
}
// This can be taken down to the client package
func (provider *Provider) errFromStatusCode(statusCode int) error {
func (provider *Provider) errFromStatusCode(statusCode int, errorMessage string) error {
switch statusCode {
case http.StatusBadRequest:
return errors.Newf(errors.TypeInvalidInput, errors.CodeInvalidInput, "bad request")
return errors.New(errors.TypeInvalidInput, errors.CodeInvalidInput, errorMessage)
case http.StatusUnauthorized:
return errors.Newf(errors.TypeUnauthenticated, errors.CodeUnauthenticated, "unauthenticated")
return errors.New(errors.TypeUnauthenticated, errors.CodeUnauthenticated, errorMessage)
case http.StatusForbidden:
return errors.Newf(errors.TypeForbidden, errors.CodeForbidden, "forbidden")
return errors.New(errors.TypeForbidden, errors.CodeForbidden, errorMessage)
case http.StatusNotFound:
return errors.Newf(errors.TypeNotFound, errors.CodeNotFound, "not found")
return errors.New(errors.TypeNotFound, errors.CodeNotFound, errorMessage)
case http.StatusConflict:
return errors.New(errors.TypeAlreadyExists, errors.CodeAlreadyExists, errorMessage)
}
return errors.Newf(errors.TypeInternal, errors.CodeInternal, "internal")
return errors.New(errors.TypeInternal, errors.CodeInternal, errorMessage)
}

View File

@@ -1561,6 +1561,230 @@ export interface TypesUserDTO {
updatedAt?: Date;
}
export interface ZeustypesClusterResponseModelDTO {
/**
* @type string
*/
address?: string;
/**
* @type integer
* @format int64
*/
buffer?: number;
/**
* @type string
*/
ca?: string;
/**
* @type string
*/
cloud_account_id?: string;
/**
* @type string
*/
cloud_provider?: string;
/**
* @type string
*/
cloud_region?: string;
/**
* @type string
* @format date-time
*/
created_at?: Date;
/**
* @type string
*/
id?: string;
/**
* @type string
*/
name?: string;
region?: ZeustypesRegionModelDTO;
/**
* @type string
*/
region_id?: string;
/**
* @type string
* @format date-time
*/
updated_at?: Date;
}
export interface ZeustypesDeploymentHistoryModelDTO {
/**
* @type string
* @format date-time
*/
created_at?: Date;
/**
* @type string
*/
deployment_id?: string;
/**
* @type string
*/
event?: string;
/**
* @type string
*/
id?: string;
/**
* @type string
*/
state_after?: string;
/**
* @type string
*/
state_before?: string;
}
export interface ZeustypesGettableDeploymentDTO {
cluster?: ZeustypesClusterResponseModelDTO;
/**
* @type string
*/
cluster_id?: string;
/**
* @type string
* @format date-time
*/
created_at?: Date;
/**
* @type array
* @nullable true
*/
histories?: ZeustypesDeploymentHistoryModelDTO[] | null;
/**
* @type array
*/
hosts?: ZeustypesHostModelDTO[];
/**
* @type string
*/
id?: string;
/**
* @type string
*/
license_id?: string;
/**
* @type string
*/
name?: string;
/**
* @type string
*/
password?: string;
/**
* @type string
*/
state?: string;
/**
* @type string
*/
tier?: string;
/**
* @type string
* @format date-time
*/
updated_at?: Date;
/**
* @type string
*/
user?: string;
}
export interface ZeustypesHostModelDTO {
/**
* @type boolean
*/
is_default?: boolean;
/**
* @type string
*/
name?: string;
}
export interface ZeustypesPostableHostDTO {
/**
* @type string
*/
name: string;
}
export interface ZeustypesPostableProfileDTO {
/**
* @type string
*/
existing_observability_tool?: string;
/**
* @type boolean
*/
has_existing_observability_tool?: boolean;
/**
* @type integer
* @format int64
*/
logs_scale_per_day_in_gb?: number;
/**
* @type integer
* @format int64
*/
number_of_hosts?: number;
/**
* @type integer
* @format int64
*/
number_of_services?: number;
/**
* @type array
* @nullable true
*/
reasons_for_interest_in_signoz?: string[] | null;
/**
* @type string
*/
timeline_for_migrating_to_signoz?: string;
/**
* @type boolean
*/
uses_otel?: boolean;
/**
* @type string
*/
where_did_you_discover_signoz?: string;
}
export interface ZeustypesRegionModelDTO {
/**
* @type string
*/
category?: string;
/**
* @type string
* @format date-time
*/
created_at?: Date;
/**
* @type string
*/
dns?: string;
/**
* @type string
*/
id?: string;
/**
* @type string
*/
name?: string;
/**
* @type string
* @format date-time
*/
updated_at?: Date;
}
export type ChangePasswordPathParameters = {
id: string;
};
@@ -2252,3 +2476,11 @@ export type RotateSession200 = {
*/
status?: string;
};
export type GetDeploymentsFromZeus200 = {
data?: ZeustypesGettableDeploymentDTO;
/**
* @type string
*/
status?: string;
};

View File

@@ -0,0 +1,279 @@
/**
* ! Do not edit manually
* * The file has been auto-generated using Orval for SigNoz
* * regenerate with 'yarn generate:api'
* SigNoz
*/
import type {
InvalidateOptions,
MutationFunction,
QueryClient,
QueryFunction,
QueryKey,
UseMutationOptions,
UseMutationResult,
UseQueryOptions,
UseQueryResult,
} from 'react-query';
import { useMutation, useQuery } from 'react-query';
import { GeneratedAPIInstance } from '../../../index';
import type {
GetDeploymentsFromZeus200,
RenderErrorResponseDTO,
ZeustypesPostableHostDTO,
ZeustypesPostableProfileDTO,
} from '../sigNoz.schemas';
type AwaitedInput<T> = PromiseLike<T> | T;
type Awaited<O> = O extends AwaitedInput<infer T> ? T : never;
/**
* This endpoint gets the deployment info from zeus.
* @summary Get deployments from Zeus.
*/
export const getDeploymentsFromZeus = (signal?: AbortSignal) => {
return GeneratedAPIInstance<GetDeploymentsFromZeus200>({
url: `/api/v2/zeus/deployments`,
method: 'GET',
signal,
});
};
export const getGetDeploymentsFromZeusQueryKey = () => {
return ['getDeploymentsFromZeus'] as const;
};
export const getGetDeploymentsFromZeusQueryOptions = <
TData = Awaited<ReturnType<typeof getDeploymentsFromZeus>>,
TError = RenderErrorResponseDTO
>(options?: {
query?: UseQueryOptions<
Awaited<ReturnType<typeof getDeploymentsFromZeus>>,
TError,
TData
>;
}) => {
const { query: queryOptions } = options ?? {};
const queryKey = queryOptions?.queryKey ?? getGetDeploymentsFromZeusQueryKey();
const queryFn: QueryFunction<
Awaited<ReturnType<typeof getDeploymentsFromZeus>>
> = ({ signal }) => getDeploymentsFromZeus(signal);
return { queryKey, queryFn, ...queryOptions } as UseQueryOptions<
Awaited<ReturnType<typeof getDeploymentsFromZeus>>,
TError,
TData
> & { queryKey: QueryKey };
};
export type GetDeploymentsFromZeusQueryResult = NonNullable<
Awaited<ReturnType<typeof getDeploymentsFromZeus>>
>;
export type GetDeploymentsFromZeusQueryError = RenderErrorResponseDTO;
/**
* @summary Get deployments from Zeus.
*/
export function useGetDeploymentsFromZeus<
TData = Awaited<ReturnType<typeof getDeploymentsFromZeus>>,
TError = RenderErrorResponseDTO
>(options?: {
query?: UseQueryOptions<
Awaited<ReturnType<typeof getDeploymentsFromZeus>>,
TError,
TData
>;
}): UseQueryResult<TData, TError> & { queryKey: QueryKey } {
const queryOptions = getGetDeploymentsFromZeusQueryOptions(options);
const query = useQuery(queryOptions) as UseQueryResult<TData, TError> & {
queryKey: QueryKey;
};
query.queryKey = queryOptions.queryKey;
return query;
}
/**
* @summary Get deployments from Zeus.
*/
export const invalidateGetDeploymentsFromZeus = async (
queryClient: QueryClient,
options?: InvalidateOptions,
): Promise<QueryClient> => {
await queryClient.invalidateQueries(
{ queryKey: getGetDeploymentsFromZeusQueryKey() },
options,
);
return queryClient;
};
/**
* This endpoint saves the host of a deployment to zeus.
* @summary Put host in Zeus for a deployment.
*/
export const putHostInZeus = (
zeustypesPostableHostDTO: ZeustypesPostableHostDTO,
) => {
return GeneratedAPIInstance<void>({
url: `/api/v2/zeus/hosts`,
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
data: zeustypesPostableHostDTO,
});
};
export const getPutHostInZeusMutationOptions = <
TError = RenderErrorResponseDTO,
TContext = unknown
>(options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof putHostInZeus>>,
TError,
{ data: ZeustypesPostableHostDTO },
TContext
>;
}): UseMutationOptions<
Awaited<ReturnType<typeof putHostInZeus>>,
TError,
{ data: ZeustypesPostableHostDTO },
TContext
> => {
const mutationKey = ['putHostInZeus'];
const { mutation: mutationOptions } = options
? options.mutation &&
'mutationKey' in options.mutation &&
options.mutation.mutationKey
? options
: { ...options, mutation: { ...options.mutation, mutationKey } }
: { mutation: { mutationKey } };
const mutationFn: MutationFunction<
Awaited<ReturnType<typeof putHostInZeus>>,
{ data: ZeustypesPostableHostDTO }
> = (props) => {
const { data } = props ?? {};
return putHostInZeus(data);
};
return { mutationFn, ...mutationOptions };
};
export type PutHostInZeusMutationResult = NonNullable<
Awaited<ReturnType<typeof putHostInZeus>>
>;
export type PutHostInZeusMutationBody = ZeustypesPostableHostDTO;
export type PutHostInZeusMutationError = RenderErrorResponseDTO;
/**
* @summary Put host in Zeus for a deployment.
*/
export const usePutHostInZeus = <
TError = RenderErrorResponseDTO,
TContext = unknown
>(options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof putHostInZeus>>,
TError,
{ data: ZeustypesPostableHostDTO },
TContext
>;
}): UseMutationResult<
Awaited<ReturnType<typeof putHostInZeus>>,
TError,
{ data: ZeustypesPostableHostDTO },
TContext
> => {
const mutationOptions = getPutHostInZeusMutationOptions(options);
return useMutation(mutationOptions);
};
/**
* This endpoint saves the profile of a deployment to zeus.
* @summary Put profile in Zeus for a deployment.
*/
export const putProfileInZeus = (
zeustypesPostableProfileDTO: ZeustypesPostableProfileDTO,
) => {
return GeneratedAPIInstance<void>({
url: `/api/v2/zeus/profiles`,
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
data: zeustypesPostableProfileDTO,
});
};
export const getPutProfileInZeusMutationOptions = <
TError = RenderErrorResponseDTO,
TContext = unknown
>(options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof putProfileInZeus>>,
TError,
{ data: ZeustypesPostableProfileDTO },
TContext
>;
}): UseMutationOptions<
Awaited<ReturnType<typeof putProfileInZeus>>,
TError,
{ data: ZeustypesPostableProfileDTO },
TContext
> => {
const mutationKey = ['putProfileInZeus'];
const { mutation: mutationOptions } = options
? options.mutation &&
'mutationKey' in options.mutation &&
options.mutation.mutationKey
? options
: { ...options, mutation: { ...options.mutation, mutationKey } }
: { mutation: { mutationKey } };
const mutationFn: MutationFunction<
Awaited<ReturnType<typeof putProfileInZeus>>,
{ data: ZeustypesPostableProfileDTO }
> = (props) => {
const { data } = props ?? {};
return putProfileInZeus(data);
};
return { mutationFn, ...mutationOptions };
};
export type PutProfileInZeusMutationResult = NonNullable<
Awaited<ReturnType<typeof putProfileInZeus>>
>;
export type PutProfileInZeusMutationBody = ZeustypesPostableProfileDTO;
export type PutProfileInZeusMutationError = RenderErrorResponseDTO;
/**
* @summary Put profile in Zeus for a deployment.
*/
export const usePutProfileInZeus = <
TError = RenderErrorResponseDTO,
TContext = unknown
>(options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof putProfileInZeus>>,
TError,
{ data: ZeustypesPostableProfileDTO },
TContext
>;
}): UseMutationResult<
Awaited<ReturnType<typeof putProfileInZeus>>,
TError,
{ data: ZeustypesPostableProfileDTO },
TContext
> => {
const mutationOptions = getPutProfileInZeusMutationOptions(options);
return useMutation(mutationOptions);
};

View File

@@ -22,6 +22,7 @@ import (
"github.com/SigNoz/signoz/pkg/modules/user"
"github.com/SigNoz/signoz/pkg/types"
"github.com/SigNoz/signoz/pkg/types/ctxtypes"
"github.com/SigNoz/signoz/pkg/zeus"
"github.com/gorilla/mux"
)
@@ -44,6 +45,7 @@ type provider struct {
gatewayHandler gateway.Handler
fieldsHandler fields.Handler
authzHandler authz.Handler
zeusHandler zeus.Handler
}
func NewFactory(
@@ -63,6 +65,7 @@ func NewFactory(
gatewayHandler gateway.Handler,
fieldsHandler fields.Handler,
authzHandler authz.Handler,
zeusHandler zeus.Handler,
) factory.ProviderFactory[apiserver.APIServer, apiserver.Config] {
return factory.NewProviderFactory(factory.MustNewName("signoz"), func(ctx context.Context, providerSettings factory.ProviderSettings, config apiserver.Config) (apiserver.APIServer, error) {
return newProvider(
@@ -85,6 +88,7 @@ func NewFactory(
gatewayHandler,
fieldsHandler,
authzHandler,
zeusHandler,
)
})
}
@@ -109,6 +113,7 @@ func newProvider(
gatewayHandler gateway.Handler,
fieldsHandler fields.Handler,
authzHandler authz.Handler,
zeusHandler zeus.Handler,
) (apiserver.APIServer, error) {
settings := factory.NewScopedProviderSettings(providerSettings, "github.com/SigNoz/signoz/pkg/apiserver/signozapiserver")
router := mux.NewRouter().UseEncodedPath()
@@ -131,6 +136,7 @@ func newProvider(
gatewayHandler: gatewayHandler,
fieldsHandler: fieldsHandler,
authzHandler: authzHandler,
zeusHandler: zeusHandler,
}
provider.authZ = middleware.NewAuthZ(settings.Logger(), orgGetter, authz)
@@ -199,6 +205,10 @@ func (provider *provider) AddToRouter(router *mux.Router) error {
return err
}
if err := provider.addZeusRoutes(router); err != nil {
return err
}
return nil
}

View File

@@ -0,0 +1,65 @@
package signozapiserver
import (
"net/http"
"github.com/SigNoz/signoz/pkg/http/handler"
"github.com/SigNoz/signoz/pkg/types"
"github.com/SigNoz/signoz/pkg/types/zeustypes"
"github.com/gorilla/mux"
)
func (provider *provider) addZeusRoutes(router *mux.Router) error {
if err := router.Handle("/api/v2/zeus/profiles", handler.New(provider.authZ.AdminAccess(provider.zeusHandler.PutProfile), handler.OpenAPIDef{
ID: "PutProfileInZeus",
Tags: []string{"zeus"},
Summary: "Put profile in Zeus for a deployment.",
Description: "This endpoint saves the profile of a deployment to zeus.",
Request: new(zeustypes.PostableProfile),
RequestContentType: "application/json",
Response: nil,
ResponseContentType: "",
SuccessStatusCode: http.StatusNoContent,
ErrorStatusCodes: []int{http.StatusBadRequest, http.StatusUnauthorized, http.StatusForbidden, http.StatusNotFound, http.StatusConflict},
Deprecated: false,
SecuritySchemes: newSecuritySchemes(types.RoleAdmin),
})).Methods(http.MethodPut).GetError(); err != nil {
return err
}
if err := router.Handle("/api/v2/zeus/deployments", handler.New(provider.authZ.AdminAccess(provider.zeusHandler.GetDeployment), handler.OpenAPIDef{
ID: "GetDeploymentsFromZeus",
Tags: []string{"zeus"},
Summary: "Get deployments from Zeus.",
Description: "This endpoint gets the deployment info from zeus.",
Request: nil,
RequestContentType: "",
Response: new(zeustypes.GettableDeployment),
ResponseContentType: "application/json",
SuccessStatusCode: http.StatusOK,
ErrorStatusCodes: []int{http.StatusBadRequest, http.StatusUnauthorized, http.StatusForbidden, http.StatusNotFound},
Deprecated: false,
SecuritySchemes: newSecuritySchemes(types.RoleAdmin),
})).Methods(http.MethodGet).GetError(); err != nil {
return err
}
if err := router.Handle("/api/v2/zeus/hosts", handler.New(provider.authZ.AdminAccess(provider.zeusHandler.PutHost), handler.OpenAPIDef{
ID: "PutHostInZeus",
Tags: []string{"zeus"},
Summary: "Put host in Zeus for a deployment.",
Description: "This endpoint saves the host of a deployment to zeus.",
Request: new(zeustypes.PostableHost),
RequestContentType: "application/json",
Response: nil,
ResponseContentType: "",
SuccessStatusCode: http.StatusNoContent,
ErrorStatusCodes: []int{http.StatusBadRequest, http.StatusUnauthorized, http.StatusForbidden, http.StatusNotFound, http.StatusConflict},
Deprecated: false,
SecuritySchemes: newSecuritySchemes(types.RoleAdmin),
})).Methods(http.MethodPut).GetError(); err != nil {
return err
}
return nil
}

View File

@@ -31,6 +31,7 @@ import (
"github.com/SigNoz/signoz/pkg/modules/tracefunnel/impltracefunnel"
"github.com/SigNoz/signoz/pkg/querier"
"github.com/SigNoz/signoz/pkg/types/telemetrytypes"
"github.com/SigNoz/signoz/pkg/zeus"
)
type Handlers struct {
@@ -48,6 +49,7 @@ type Handlers struct {
GatewayHandler gateway.Handler
Fields fields.Handler
AuthzHandler authz.Handler
ZeusHandler zeus.Handler
}
func NewHandlers(
@@ -60,6 +62,7 @@ func NewHandlers(
gatewayService gateway.Gateway,
telemetryMetadataStore telemetrytypes.MetadataStore,
authz authz.AuthZ,
zeusService zeus.Zeus,
) Handlers {
return Handlers{
SavedView: implsavedview.NewHandler(modules.SavedView),
@@ -76,5 +79,6 @@ func NewHandlers(
GatewayHandler: gateway.NewHandler(gatewayService),
Fields: implfields.NewHandler(providerSettings, telemetryMetadataStore),
AuthzHandler: signozauthzapi.NewHandler(authz),
ZeusHandler: zeus.NewHandler(zeusService, licensing),
}
}

View File

@@ -42,7 +42,7 @@ func TestNewHandlers(t *testing.T) {
dashboardModule := impldashboard.NewModule(impldashboard.NewStore(sqlstore), providerSettings, nil, orgGetter, queryParser)
modules := NewModules(sqlstore, tokenizer, emailing, providerSettings, orgGetter, alertmanager, nil, nil, nil, nil, nil, nil, nil, queryParser, Config{}, dashboardModule)
handlers := NewHandlers(modules, providerSettings, nil, nil, nil, nil, nil, nil, nil)
handlers := NewHandlers(modules, providerSettings, nil, nil, nil, nil, nil, nil, nil, nil)
reflectVal := reflect.ValueOf(handlers)
for i := 0; i < reflectVal.NumField(); i++ {
f := reflectVal.Field(i)

View File

@@ -23,6 +23,7 @@ import (
"github.com/SigNoz/signoz/pkg/modules/session"
"github.com/SigNoz/signoz/pkg/modules/user"
"github.com/SigNoz/signoz/pkg/types/ctxtypes"
"github.com/SigNoz/signoz/pkg/zeus"
"github.com/swaggest/jsonschema-go"
"github.com/swaggest/openapi-go"
"github.com/swaggest/openapi-go/openapi3"
@@ -52,6 +53,7 @@ func NewOpenAPI(ctx context.Context, instrumentation instrumentation.Instrumenta
struct{ gateway.Handler }{},
struct{ fields.Handler }{},
struct{ authz.Handler }{},
struct{ zeus.Handler }{},
).New(ctx, instrumentation.ToProviderSettings(), apiserver.Config{})
if err != nil {
return nil, err

View File

@@ -252,6 +252,7 @@ func NewAPIServerProviderFactories(orgGetter organization.Getter, authz authz.Au
handlers.GatewayHandler,
handlers.Fields,
handlers.AuthzHandler,
handlers.ZeusHandler,
),
)
}

View File

@@ -392,7 +392,7 @@ func New(
userService := impluser.NewService(providerSettings, impluser.NewStore(sqlstore, providerSettings), modules.User, orgGetter, authz, config.User.Root)
// Initialize all handlers for the modules
handlers := NewHandlers(modules, providerSettings, querier, licensing, global, flagger, gateway, telemetryMetadataStore, authz)
handlers := NewHandlers(modules, providerSettings, querier, licensing, global, flagger, gateway, telemetryMetadataStore, authz, zeus)
// Initialize the API server
apiserver, err := factory.NewProviderFromNamedMap(

View File

@@ -0,0 +1,85 @@
package zeustypes
import (
"time"
"github.com/SigNoz/signoz/pkg/valuer"
)
type PostableHost struct {
Name string `json:"name" required:"true"`
}
type PostableProfile struct {
UsesOtel bool `json:"uses_otel"`
HasExistingObservabilityTool bool `json:"has_existing_observability_tool"`
ExistingObservabilityTool string `json:"existing_observability_tool"`
ReasonsForInterestInSigNoz []string `json:"reasons_for_interest_in_signoz"`
LogsScalePerDayInGB int64 `json:"logs_scale_per_day_in_gb"`
NumberOfServices int64 `json:"number_of_services"`
NumberOfHosts int64 `json:"number_of_hosts"`
WhereDidYouDiscoverSigNoz string `json:"where_did_you_discover_signoz"`
TimelineForMigratingToSigNoz string `json:"timeline_for_migrating_to_signoz"`
}
type GettableDeployment struct {
DeploymentModel
Cluster ClusterResponseModel `json:"cluster"`
Histories []DeploymentHistoryModel `json:"histories"`
}
type DeploymentModel struct {
ID valuer.UUID `json:"id"`
Name string `json:"name"`
State string `json:"state"`
Tier string `json:"tier"`
User string `json:"user"`
LicenseID string `json:"license_id,omitempty"`
Password string `json:"password,omitempty"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
ClusterID valuer.UUID `json:"cluster_id"`
Hosts []HostModel `json:"hosts,omitempty"`
}
type ClusterResponseModel struct {
ClusterModel
Region RegionModel `json:"region"`
}
type DeploymentHistoryModel struct {
ID valuer.UUID `json:"id"`
StateBefore string `json:"state_before"`
StateAfter string `json:"state_after"`
Event string `json:"event"`
CreatedAt time.Time `json:"created_at"`
DeploymentID valuer.UUID `json:"deployment_id"`
}
type HostModel struct {
Name string `json:"name"`
IsDefault bool `json:"is_default"`
}
type ClusterModel struct {
ID valuer.UUID `json:"id"`
Name string `json:"name"`
CloudProvider string `json:"cloud_provider"`
CloudAccountID string `json:"cloud_account_id"`
CloudRegion string `json:"cloud_region"`
Address string `json:"address"`
Ca string `json:"ca"`
Buffer int64 `json:"buffer"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
RegionID valuer.UUID `json:"region_id"`
}
type RegionModel struct {
ID valuer.UUID `json:"id"`
Name string `json:"name"`
Category string `json:"category"`
DNS string `json:"dns"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}

112
pkg/zeus/handler.go Normal file
View File

@@ -0,0 +1,112 @@
package zeus
import (
"net/http"
"github.com/SigNoz/signoz/pkg/errors"
"github.com/SigNoz/signoz/pkg/http/binding"
"github.com/SigNoz/signoz/pkg/http/render"
"github.com/SigNoz/signoz/pkg/licensing"
"github.com/SigNoz/signoz/pkg/types/authtypes"
"github.com/SigNoz/signoz/pkg/types/zeustypes"
"github.com/SigNoz/signoz/pkg/valuer"
)
type handler struct {
zeus Zeus
licensing licensing.Licensing
}
func NewHandler(zeus Zeus, licensing licensing.Licensing) Handler {
return &handler{
zeus: zeus,
licensing: licensing,
}
}
func (h *handler) PutProfile(rw http.ResponseWriter, r *http.Request) {
ctx := r.Context()
claims, err := authtypes.ClaimsFromContext(ctx)
if err != nil {
render.Error(rw, err)
return
}
license, err := h.licensing.GetActive(ctx, valuer.MustNewUUID(claims.OrgID))
if err != nil {
render.Error(rw, err)
return
}
req := new(zeustypes.PostableProfile)
if err := binding.JSON.BindBody(r.Body, req); err != nil {
render.Error(rw, errors.New(errors.TypeInvalidInput, errors.CodeInvalidInput, "invalid request body"))
return
}
if err := h.zeus.PutProfile(ctx, license.Key, req); err != nil {
render.Error(rw, err)
return
}
render.Success(rw, http.StatusNoContent, nil)
}
func (h *handler) GetDeployment(rw http.ResponseWriter, r *http.Request) {
ctx := r.Context()
claims, err := authtypes.ClaimsFromContext(ctx)
if err != nil {
render.Error(rw, err)
return
}
license, err := h.licensing.GetActive(ctx, valuer.MustNewUUID(claims.OrgID))
if err != nil {
render.Error(rw, err)
return
}
response, err := h.zeus.GetDeployment(ctx, license.Key)
if err != nil {
render.Error(rw, err)
return
}
render.Success(rw, http.StatusOK, response)
}
func (h *handler) PutHost(rw http.ResponseWriter, r *http.Request) {
ctx := r.Context()
claims, err := authtypes.ClaimsFromContext(ctx)
if err != nil {
render.Error(rw, err)
return
}
license, err := h.licensing.GetActive(ctx, valuer.MustNewUUID(claims.OrgID))
if err != nil {
render.Error(rw, err)
return
}
req := new(zeustypes.PostableHost)
if err := binding.JSON.BindBody(r.Body, req); err != nil {
render.Error(rw, errors.New(errors.TypeInvalidInput, errors.CodeInvalidInput, "invalid request body"))
return
}
if req.Name == "" {
render.Error(rw, errors.New(errors.TypeInvalidInput, errors.CodeInvalidInput, "name is required"))
return
}
if err := h.zeus.PutHost(ctx, license.Key, req); err != nil {
render.Error(rw, err)
return
}
render.Success(rw, http.StatusNoContent, nil)
}

View File

@@ -5,6 +5,7 @@ import (
"github.com/SigNoz/signoz/pkg/errors"
"github.com/SigNoz/signoz/pkg/factory"
"github.com/SigNoz/signoz/pkg/types/zeustypes"
"github.com/SigNoz/signoz/pkg/zeus"
)
@@ -32,7 +33,7 @@ func (provider *provider) GetPortalURL(_ context.Context, _ string, _ []byte) ([
return nil, errors.New(errors.TypeUnsupported, zeus.ErrCodeUnsupported, "getting the portal url is not supported")
}
func (provider *provider) GetDeployment(_ context.Context, _ string) ([]byte, error) {
func (provider *provider) GetDeployment(_ context.Context, _ string) (*zeustypes.GettableDeployment, error) {
return nil, errors.New(errors.TypeUnsupported, zeus.ErrCodeUnsupported, "getting the deployment is not supported")
}
@@ -40,10 +41,10 @@ func (provider *provider) PutMeters(_ context.Context, _ string, _ []byte) error
return errors.New(errors.TypeUnsupported, zeus.ErrCodeUnsupported, "putting meters is not supported")
}
func (provider *provider) PutProfile(_ context.Context, _ string, _ []byte) error {
func (provider *provider) PutProfile(_ context.Context, _ string, _ *zeustypes.PostableProfile) error {
return errors.New(errors.TypeUnsupported, zeus.ErrCodeUnsupported, "putting profile is not supported")
}
func (provider *provider) PutHost(_ context.Context, _ string, _ []byte) error {
func (provider *provider) PutHost(_ context.Context, _ string, _ *zeustypes.PostableHost) error {
return errors.New(errors.TypeUnsupported, zeus.ErrCodeUnsupported, "putting host is not supported")
}

View File

@@ -2,8 +2,10 @@ package zeus
import (
"context"
"net/http"
"github.com/SigNoz/signoz/pkg/errors"
"github.com/SigNoz/signoz/pkg/types/zeustypes"
)
var (
@@ -22,14 +24,25 @@ type Zeus interface {
GetPortalURL(context.Context, string, []byte) ([]byte, error)
// Returns the deployment for the given license key.
GetDeployment(context.Context, string) ([]byte, error)
GetDeployment(context.Context, string) (*zeustypes.GettableDeployment, error)
// Puts the meters for the given license key.
PutMeters(context.Context, string, []byte) error
// Put profile for the given license key.
PutProfile(context.Context, string, []byte) error
PutProfile(context.Context, string, *zeustypes.PostableProfile) error
// Put host for the given license key.
PutHost(context.Context, string, []byte) error
PutHost(context.Context, string, *zeustypes.PostableHost) error
}
type Handler interface {
// API level handler for PutProfile
PutProfile(http.ResponseWriter, *http.Request)
// API level handler for GetDeployment
GetDeployment(http.ResponseWriter, *http.Request)
// API level handler for PutHost
PutHost(http.ResponseWriter, *http.Request)
}