diff --git a/README.md b/README.md index b115c46f..a6da7c4b 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,7 @@ The SDK can be configured using environment variables: - `CORALOGIX_TEAM_API_KEY`: The API key that is used for all team-level interactions. Note that it has to have appropriate permissions. Read the [docs](https://coralogix.com/docs/api-keys/) for more information. - `CORALOGIX_USER_API_KEY`: The API key that is used for all user-level interactions. Note that it has to have appropriate permissions. Read the [docs](https://coralogix.com/docs/api-keys/) for more information. +- `CORALOGIX_ORG_API_KEY`: The API key that is used for all organization-level interactions. - `CORALGOIX_REGION`: The region/cluster to connect to as a shorthand (EU2, AP1, etc. read more [here](https://coralogix.com/docs/coralogix-domain/)). Furthermore, if you want to run the examples locally, you're going to to have set the following environment variables: diff --git a/go/callPropertiesCreator.go b/go/callPropertiesCreator.go index 059fdbee..bb52a943 100644 --- a/go/callPropertiesCreator.go +++ b/go/callPropertiesCreator.go @@ -33,6 +33,7 @@ type CallPropertiesCreator struct { coraglogixRegion string teamsLevelAPIKey string userLevelAPIKey string + orgLevelAPIKey string correlationID string sdkVersion string //allowRetry bool @@ -75,6 +76,21 @@ func (c CallPropertiesCreator) GetUserLevelCallProperties(ctx context.Context) ( return &CallProperties{Ctx: ctx, Connection: conn, CallOptions: callOptions}, nil } +// GetOrgLevelCallProperties returns a new CallProperties object built from an organization-level API key. It essentially prepares the context, connection, and call options for a gRPC call. +func (c CallPropertiesCreator) GetOrgLevelCallProperties(ctx context.Context) (*CallProperties, error) { + ctx = createContext(ctx, c.orgLevelAPIKey, c.correlationID, c.sdkVersion) + + endpoint := CoralogixGrpcEndpointFromRegion(c.coraglogixRegion) + conn, err := createSecureConnection(endpoint) + if err != nil { + return nil, err + } + + callOptions := createCallOptions() + + return &CallProperties{Ctx: ctx, Connection: conn, CallOptions: callOptions}, nil +} + func createCallOptions() []grpc.CallOption { var callOptions []grpc.CallOption callOptions = append(callOptions, grpc_retry.WithMax(5)) @@ -99,6 +115,7 @@ func NewCallPropertiesCreator(region string, authContext AuthContext) *CallPrope coraglogixRegion: region, teamsLevelAPIKey: authContext.teamLevelAPIKey, userLevelAPIKey: authContext.userLevelAPIKey, + orgLevelAPIKey: authContext.orgLevelAPIKey, correlationID: uuid.New().String(), sdkVersion: vanillaSdkVersion, } @@ -109,6 +126,7 @@ func NewCallPropertiesCreatorTerraformOperator(region string, authContext AuthCo return &CallPropertiesCreator{ coraglogixRegion: region, teamsLevelAPIKey: authContext.teamLevelAPIKey, + orgLevelAPIKey: authContext.orgLevelAPIKey, userLevelAPIKey: authContext.userLevelAPIKey, correlationID: uuid.New().String(), sdkVersion: terraformOperatorVersion, diff --git a/go/cxsdk.go b/go/cxsdk.go index 33f1cacf..5c193355 100644 --- a/go/cxsdk.go +++ b/go/cxsdk.go @@ -157,8 +157,8 @@ func (c *ClientSet) DataUsage() *DataUsageClient { } // NewClientSet Creates a new ClientSet. -func NewClientSet(targetURL, teamsLevelAPIKey string, userLevelAPIKey string) *ClientSet { - authContext := NewAuthContext(teamsLevelAPIKey, userLevelAPIKey) +func NewClientSet(targetURL, teamsLevelAPIKey, userLevelAPIKey, orgLevelAPIKey string) *ClientSet { + authContext := NewAuthContext(teamsLevelAPIKey, userLevelAPIKey, orgLevelAPIKey) apikeyCPC := NewCallPropertiesCreator(targetURL, authContext) return &ClientSet{ @@ -196,6 +196,9 @@ const EnvCoralogixTeamLevelAPIKey = "CORALOGIX_TEAM_API_KEY" // EnvCoralogixUserLevelAPIKey is the name of the environment variable that contains the Coralogix User API key. const EnvCoralogixUserLevelAPIKey = "CORALOGIX_USER_API_KEY" +// EnvCoralogixOrgLevelAPIKey is the name of the environment variable that contains the Coralogix Organization API key. +const EnvCoralogixOrgLevelAPIKey = "CORALOGIX_ORG_API_KEY" + // CoralogixRegionFromEnv reads the Coralogix region from environment variables. func CoralogixRegionFromEnv() (string, error) { regionIdentifier := strings.ToLower(os.Getenv(EnvCoralogxRegion)) @@ -271,31 +274,34 @@ const ( type AuthContext struct { teamLevelAPIKey string userLevelAPIKey string + orgLevelAPIKey string } // NewAuthContext creates a new AuthContext. -func NewAuthContext(teamLevelAPIKey, userLevelAPIKey string) AuthContext { +func NewAuthContext(teamLevelAPIKey, userLevelAPIKey, orgLevelAPIKey string) AuthContext { if teamLevelAPIKey == "" { log.Println("Warning: teamLevelAPIKey was not provided. Some functionality will not be available.") } if userLevelAPIKey == "" { log.Println("Warning: userLevelAPIKey was not provided. Some functionality will not be available.") } + if orgLevelAPIKey == "" { + log.Println("Warning: orgLevelAPIKey was not provided. Some functionality will not be available.") + } return AuthContext{ teamLevelAPIKey: teamLevelAPIKey, userLevelAPIKey: userLevelAPIKey, + orgLevelAPIKey: orgLevelAPIKey, } } // AuthContextFromEnv reads the Coralogix API keys from environment variables. func AuthContextFromEnv() (AuthContext, error) { - teamLevelAPIKey, err := CoralogixTeamsLevelAPIKeyFromEnv() - if err != nil { - return AuthContext{}, err - } - userLevelAPIKey, err := CoralogixUserLevelAPIKeyFromEnv() - if err != nil { - return AuthContext{}, err + teamLevelAPIKey := os.Getenv(EnvCoralogixTeamLevelAPIKey) + userLevelAPIKey := os.Getenv(EnvCoralogixUserLevelAPIKey) + orgLevelAPIKey := os.Getenv(EnvCoralogixOrgLevelAPIKey) + if teamLevelAPIKey == "" && userLevelAPIKey == "" && orgLevelAPIKey == "" { + return AuthContext{}, fmt.Errorf("at least one of %s, %s, or %s must be set", EnvCoralogixTeamLevelAPIKey, EnvCoralogixUserLevelAPIKey, EnvCoralogixOrgLevelAPIKey) } if teamLevelAPIKey == "" { log.Println("Warning: teamLevelAPIKey is empty. Some functionality will not be available.") @@ -303,24 +309,9 @@ func AuthContextFromEnv() (AuthContext, error) { if userLevelAPIKey == "" { log.Println("Warning: userLevelAPIKey is empty. Some functionality will not be available.") } - - return AuthContext{teamLevelAPIKey: teamLevelAPIKey, userLevelAPIKey: userLevelAPIKey}, nil -} - -// CoralogixTeamsLevelAPIKeyFromEnv reads the Coralogix Team API key from environment variables. -func CoralogixTeamsLevelAPIKeyFromEnv() (string, error) { - apiKey := os.Getenv(EnvCoralogixTeamLevelAPIKey) - if apiKey == "" { - return "", fmt.Errorf("the %s environment variable is not set", EnvCoralogixTeamLevelAPIKey) + if orgLevelAPIKey == "" { + log.Println("Warning: orgLevelAPIKey is empty. Some functionality will not be available.") } - return apiKey, nil -} -// CoralogixUserLevelAPIKeyFromEnv reads the Coralogix User API key from environment variables. -func CoralogixUserLevelAPIKeyFromEnv() (string, error) { - apiKey := os.Getenv(EnvCoralogixUserLevelAPIKey) - if apiKey == "" { - return "", fmt.Errorf("the %s environment variable is not set", EnvCoralogixUserLevelAPIKey) - } - return apiKey, nil + return AuthContext{teamLevelAPIKey: teamLevelAPIKey, userLevelAPIKey: userLevelAPIKey, orgLevelAPIKey: orgLevelAPIKey}, nil } diff --git a/go/teams-client.go b/go/teams-client.go index 632e646c..491d0f3e 100644 --- a/go/teams-client.go +++ b/go/teams-client.go @@ -63,7 +63,7 @@ type TeamsClient struct { // Create creates a new team. func (c TeamsClient) Create(ctx context.Context, req *CreateTeamInOrgRequest) (*teams.CreateTeamInOrgResponse, error) { - callProperties, err := c.callPropertiesCreator.GetTeamsLevelCallProperties(ctx) + callProperties, err := c.callPropertiesCreator.GetOrgLevelCallProperties(ctx) if err != nil { return nil, err } @@ -77,7 +77,7 @@ func (c TeamsClient) Create(ctx context.Context, req *CreateTeamInOrgRequest) (* // Update updates a team. func (c TeamsClient) Update(ctx context.Context, req *UpdateTeamRequest) (*teams.UpdateTeamResponse, error) { - callProperties, err := c.callPropertiesCreator.GetTeamsLevelCallProperties(ctx) + callProperties, err := c.callPropertiesCreator.GetOrgLevelCallProperties(ctx) if err != nil { return nil, err } @@ -91,7 +91,7 @@ func (c TeamsClient) Update(ctx context.Context, req *UpdateTeamRequest) (*teams // Get gets a team. func (c TeamsClient) Get(ctx context.Context, req *GetTeamRequest) (*teams.GetTeamResponse, error) { - callProperties, err := c.callPropertiesCreator.GetTeamsLevelCallProperties(ctx) + callProperties, err := c.callPropertiesCreator.GetOrgLevelCallProperties(ctx) if err != nil { return nil, err } @@ -105,7 +105,7 @@ func (c TeamsClient) Get(ctx context.Context, req *GetTeamRequest) (*teams.GetTe // Delete deletes a team. func (c TeamsClient) Delete(ctx context.Context, req *DeleteTeamRequest) (*teams.DeleteTeamResponse, error) { - callProperties, err := c.callPropertiesCreator.GetTeamsLevelCallProperties(ctx) + callProperties, err := c.callPropertiesCreator.GetOrgLevelCallProperties(ctx) if err != nil { return nil, err } @@ -119,7 +119,7 @@ func (c TeamsClient) Delete(ctx context.Context, req *DeleteTeamRequest) (*teams // SetDailyQuota sets the daily quota for a team. func (c TeamsClient) SetDailyQuota(ctx context.Context, req *SetDailyQuotaRequest) (*teams.SetDailyQuotaResponse, error) { - callProperties, err := c.callPropertiesCreator.GetTeamsLevelCallProperties(ctx) + callProperties, err := c.callPropertiesCreator.GetOrgLevelCallProperties(ctx) if err != nil { return nil, err } @@ -133,7 +133,7 @@ func (c TeamsClient) SetDailyQuota(ctx context.Context, req *SetDailyQuotaReques // GetQuota gets the quota for a team. func (c TeamsClient) GetQuota(ctx context.Context, req *GetTeamQuotaRequest) (*teams.GetTeamQuotaResponse, error) { - callProperties, err := c.callPropertiesCreator.GetTeamsLevelCallProperties(ctx) + callProperties, err := c.callPropertiesCreator.GetOrgLevelCallProperties(ctx) if err != nil { return nil, err } @@ -147,7 +147,7 @@ func (c TeamsClient) GetQuota(ctx context.Context, req *GetTeamQuotaRequest) (*t // MoveQuota moves the quota from one team to another. func (c TeamsClient) MoveQuota(ctx context.Context, req *MoveQuotaRequest) (*teams.MoveQuotaResponse, error) { - callProperties, err := c.callPropertiesCreator.GetTeamsLevelCallProperties(ctx) + callProperties, err := c.callPropertiesCreator.GetOrgLevelCallProperties(ctx) if err != nil { return nil, err } diff --git a/rust/cx-sdk/src/auth.rs b/rust/cx-sdk/src/auth.rs index c3a9081d..1f61292c 100644 --- a/rust/cx-sdk/src/auth.rs +++ b/rust/cx-sdk/src/auth.rs @@ -13,13 +13,11 @@ // limitations under the License. use crate::error::Result; -use std::fmt::{ - Debug, - Formatter, -}; +use std::fmt::{Debug, Formatter}; const ENV_TEAM_API_KEY: &str = "CORALOGIX_TEAM_API_KEY"; const ENV_USER_API_KEY: &str = "CORALOGIX_USER_API_KEY"; +const ENV_ORG_API_KEY: &str = "CORALOGIX_ORG_API_KEY"; #[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Default)] /// The authentication context. @@ -28,6 +26,8 @@ pub struct AuthContext { pub(crate) team_level_api_key: ApiKey, /// The user level API key. pub(crate) user_level_api_key: ApiKey, + /// The organization level API key. + pub(crate) org_level_api_key: ApiKey, } impl AuthContext { @@ -36,16 +36,27 @@ impl AuthContext { /// # Arguments /// * `team_level_api_key` - The team level API key. /// * `user_level_api_key` - The user level API key. - pub fn new(team_level_api_key: Option, user_level_api_key: Option) -> Self { + /// * `org_level_api_key` - The organization level API key. + pub fn new( + team_level_api_key: Option, + user_level_api_key: Option, + org_level_api_key: Option, + ) -> Self { if team_level_api_key.is_none() { log::warn!("Team level API key is not set. some functionality may not be available."); } if user_level_api_key.is_none() { log::warn!("User level API key is not set. some functionality may not be available."); } + if org_level_api_key.is_none() { + log::warn!( + "Organization level API key is not set. some functionality may not be available." + ); + } AuthContext { team_level_api_key: team_level_api_key.unwrap_or_default(), user_level_api_key: user_level_api_key.unwrap_or_default(), + org_level_api_key: org_level_api_key.unwrap_or_default(), } } @@ -54,6 +65,7 @@ impl AuthContext { AuthContext::new( ApiKey::teams_level_from_env().ok(), ApiKey::user_level_from_env().ok(), + ApiKey::org_level_from_env().ok(), ) } } @@ -81,6 +93,13 @@ impl ApiKey { .map(ApiKey) .map_err(From::from) } + + /// Creates a new organization-level API key from the ENV_API_KEY environment variable. + pub fn org_level_from_env() -> Result { + std::env::var(ENV_ORG_API_KEY) + .map(ApiKey) + .map_err(From::from) + } } impl From<&str> for ApiKey { diff --git a/rust/cx-sdk/src/client/teams.rs b/rust/cx-sdk/src/client/teams.rs index c4d703ab..188e726d 100644 --- a/rust/cx-sdk/src/client/teams.rs +++ b/rust/cx-sdk/src/client/teams.rs @@ -16,43 +16,22 @@ use std::str::FromStr; use crate::{ auth::AuthContext, - error::{ - Result, - SdkApiError, - SdkError, - }, + error::{Result, SdkApiError, SdkError}, metadata::CallProperties, util::make_request_with_metadata, }; use cx_api::proto::com::coralogixapis::aaa::organisations::v2::{ - CreateTeamInOrgRequest, - CreateTeamInOrgResponse, - DeleteTeamRequest, - DeleteTeamResponse, - GetTeamQuotaRequest, - GetTeamQuotaResponse, - GetTeamRequest, - GetTeamResponse, - ListTeamsRequest, - ListTeamsResponse, - MoveQuotaRequest, - MoveQuotaResponse, - SetDailyQuotaRequest, - SetDailyQuotaResponse, - TeamId, - UpdateTeamRequest, + team_service_client::TeamServiceClient, CreateTeamInOrgRequest, CreateTeamInOrgResponse, + DeleteTeamRequest, DeleteTeamResponse, GetTeamQuotaRequest, GetTeamQuotaResponse, + GetTeamRequest, GetTeamResponse, ListTeamsRequest, ListTeamsResponse, MoveQuotaRequest, + MoveQuotaResponse, SetDailyQuotaRequest, SetDailyQuotaResponse, TeamId, UpdateTeamRequest, UpdateTeamResponse, - team_service_client::TeamServiceClient, }; use tokio::sync::Mutex; use tonic::{ metadata::MetadataMap, - transport::{ - Channel, - ClientTlsConfig, - Endpoint, - }, + transport::{Channel, ClientTlsConfig, Endpoint}, }; use crate::CoralogixRegion; @@ -74,7 +53,7 @@ impl TeamsClient { let channel: Channel = Endpoint::from_str(region.grpc_endpoint().as_str())? .tls_config(ClientTlsConfig::new().with_native_roots())? .connect_lazy(); - let request_metadata: CallProperties = (&auth_context.team_level_api_key).into(); + let request_metadata: CallProperties = (&auth_context.org_level_api_key).into(); Ok(Self { metadata_map: request_metadata.to_metadata_map(), service_client: Mutex::new(TeamServiceClient::new(channel)),