Skip to content

Commit

Permalink
adding AI provider selection in API to APK Conf implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
CrowleyRajapakse committed Sep 24, 2024
1 parent 5cf017e commit 72a1121
Show file tree
Hide file tree
Showing 7 changed files with 114 additions and 38 deletions.
8 changes: 4 additions & 4 deletions apim-apk-agent/internal/k8sClient/k8s_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -228,8 +228,8 @@ func DeployBackendJWTCR(backendJWT *dpv1alpha1.BackendJWT, k8sClient client.Clie
}

// DeployAPIPolicyCR applies the given APIPolicies struct to the Kubernetes cluster.
func DeployAPIPolicyCR(apiPolicies *dpv1alpha2.APIPolicy, k8sClient client.Client) {
crAPIPolicies := &dpv1alpha2.APIPolicy{}
func DeployAPIPolicyCR(apiPolicies *dpv1alpha3.APIPolicy, k8sClient client.Client) {
crAPIPolicies := &dpv1alpha3.APIPolicy{}
if err := k8sClient.Get(context.Background(), client.ObjectKey{Namespace: apiPolicies.ObjectMeta.Namespace, Name: apiPolicies.Name}, crAPIPolicies); err != nil {
if !k8error.IsNotFound(err) {
loggers.LoggerK8sClient.Error("Unable to get APIPolicies CR: " + err.Error())
Expand Down Expand Up @@ -398,8 +398,8 @@ func UpdateRateLimitPolicyCR(policy eventhubTypes.RateLimitPolicy, k8sClient cli
}

// DeployBackendCR applies the given Backends struct to the Kubernetes cluster.
func DeployBackendCR(backends *dpv1alpha1.Backend, k8sClient client.Client) {
crBackends := &dpv1alpha1.Backend{}
func DeployBackendCR(backends *dpv1alpha2.Backend, k8sClient client.Client) {
crBackends := &dpv1alpha2.Backend{}
if err := k8sClient.Get(context.Background(), client.ObjectKey{Namespace: backends.ObjectMeta.Namespace, Name: backends.Name}, crBackends); err != nil {
if !k8error.IsNotFound(err) {
loggers.LoggerK8sClient.Error("Unable to get Backends CR: " + err.Error())
Expand Down
3 changes: 2 additions & 1 deletion apim-apk-agent/pkg/eventhub/types/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,8 @@ type AIProvider struct {

// Config for struct Metadata
type Config struct {
Metadata []Fields `json:"metadata"`
Metadata []Fields `json:"metadata"`
AuthHeader string `json:"authHeader"`
}

// Fields for struct Fields
Expand Down
9 changes: 9 additions & 0 deletions apim-apk-agent/pkg/transformer/api_model.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ type CustomParams struct {
type SecurityObj struct {
Enabled bool `json:"enabled"`
Type string `json:"type"`
APIKeyValue string `json:"apiKeyValue"`
APIKeyIdentifier string `json:"apiKeyIdentifier"`
Username string `json:"username"`
Password string `json:"password"`
GrantType string `json:"grantType"`
Expand Down Expand Up @@ -176,6 +178,13 @@ type APIMApi struct {
RevisionedAPIID string `yaml:"revisionedApiId"`
APIThrottlingPolicy string `yaml:"apiThrottlingPolicy"`
APIPolicies APIMOperationPolicies `yaml:"apiPolicies"`
AIConfiguration APIMAIConfiguration `yaml:"aiConfiguration"`
}

// APIMAIConfiguration holds the configuration details for AI providers
type APIMAIConfiguration struct {
LLMProviderName string `yaml:"llmProviderName"`
LLMProviderAPIVersion string `yaml:"llmProviderApiVersion"`
}

// APIYaml is a wrapper struct for YAML representation of an API.
Expand Down
16 changes: 13 additions & 3 deletions apim-apk-agent/pkg/transformer/apk_model.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,12 @@ package transformer

// SecretInfo holds the info related to the created secret upon enabling the endpoint security options like basic auth
type SecretInfo struct {
SecretName string `yaml:"secretName,omitempty"`
UsernameKey string `yaml:"userNameKey,omitempty"`
PasswordKey string `yaml:"passwordKey,omitempty"`
SecretName string `yaml:"secretName,omitempty"`
UsernameKey string `yaml:"userNameKey,omitempty"`
PasswordKey string `yaml:"passwordKey,omitempty"`
In string `yaml:"in,omitempty"`
APIKeyNameKey string `yaml:"apiKeyNameKey,omitempty"`
APIKeyValueKey string `yaml:"apiKeyValueKey,omitempty"`
}

// EndpointSecurity comtains the information related to endpoint security configurations enabled by a user for a given API
Expand Down Expand Up @@ -108,6 +111,12 @@ type VHost struct {
Sandbox []string `yaml:"sandbox,omitempty"`
}

// AIProvider represents the AI provider configuration.
type AIProvider struct {
Name string `yaml:"name,omitempty"`
APIVersion string `yaml:"apiVersion,omitempty"`
}

// API represents an main API type definition
type API struct {
Name string `yaml:"name,omitempty"`
Expand All @@ -125,4 +134,5 @@ type API struct {
SubscriptionValidation bool `yaml:"subscriptionValidation,omitempty"`
RateLimit *RateLimit `yaml:"rateLimit,omitempty"`
APIPolicies *OperationPolicies `yaml:"apiPolicies,omitempty"`
AIProvider *AIProvider `yaml:"aiProvider,omitempty"`
}
5 changes: 3 additions & 2 deletions apim-apk-agent/pkg/transformer/k8s_artifacts.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package transformer
import (
"github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1"
dpv1alpha2 "github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2"
dpv1alpha3 "github.com/wso2/apk/common-go-libs/apis/dp/v1alpha3"
corev1 "k8s.io/api/core/v1"
gwapiv1 "sigs.k8s.io/gateway-api/apis/v1"
)
Expand All @@ -12,10 +13,10 @@ type K8sArtifacts struct {
API dpv1alpha2.API
HTTPRoutes map[string]*gwapiv1.HTTPRoute
GQLRoutes map[string]*dpv1alpha2.GQLRoute
Backends map[string]*v1alpha1.Backend
Backends map[string]*dpv1alpha2.Backend
Scopes map[string]*v1alpha1.Scope
Authentication map[string]*dpv1alpha2.Authentication
APIPolicies map[string]*dpv1alpha2.APIPolicy
APIPolicies map[string]*dpv1alpha3.APIPolicy
InterceptorServices map[string]*v1alpha1.InterceptorService
ConfigMaps map[string]*corev1.ConfigMap
Secrets map[string]*corev1.Secret
Expand Down
103 changes: 75 additions & 28 deletions apim-apk-agent/pkg/transformer/transformer.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import (

dpv1alpha1 "github.com/wso2/apk/common-go-libs/apis/dp/v1alpha1"
dpv1alpha2 "github.com/wso2/apk/common-go-libs/apis/dp/v1alpha2"
dpv1alpha3 "github.com/wso2/apk/common-go-libs/apis/dp/v1alpha3"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
gwapiv1 "sigs.k8s.io/gateway-api/apis/v1"
Expand Down Expand Up @@ -83,6 +84,14 @@ func GenerateAPKConf(APIJson string, certArtifact CertificateArtifact, organizat
apk.DefinitionPath = "/definition"
apk.SubscriptionValidation = true

if apiYamlData.AIConfiguration.LLMProviderName != "" && apiYamlData.AIConfiguration.LLMProviderAPIVersion != "" {
sha1ValueforCRName := GetSha1Value(apiYamlData.AIConfiguration.LLMProviderName + "-" + apiYamlData.AIConfiguration.LLMProviderAPIVersion + "-" + organizationID)
apk.AIProvider = &AIProvider{
Name: sha1ValueforCRName,
APIVersion: apiYamlData.AIConfiguration.LLMProviderAPIVersion,
}
}

if apiYamlData.APIThrottlingPolicy != "" {
rateLimitPolicy := managementserver.GetRateLimitPolicy(apiYamlData.APIThrottlingPolicy, organizationID)
logger.LoggerTransformer.Debugf("Rate Limit Policy: %v", rateLimitPolicy)
Expand Down Expand Up @@ -584,19 +593,37 @@ func getEndpointConfigs(sandboxURL string, prodURL string, endCertAvailable bool

if endpointSecurityData.Sandbox.Enabled {
sandboxEndpointConf.EndSecurity.Enabled = true
sandboxEndpointConf.EndSecurity.SecurityType = SecretInfo{
SecretName: strings.Join([]string{apiUniqueID, "sandbox", "secret"}, "-"),
UsernameKey: "username",
PasswordKey: "password",
if endpointSecurityData.Sandbox.Type == "apikey" {
sandboxEndpointConf.EndSecurity.SecurityType = SecretInfo{
SecretName: strings.Join([]string{apiUniqueID, "sandbox", "secret"}, "-"),
In: "Header",
APIKeyNameKey: endpointSecurityData.Sandbox.APIKeyIdentifier,
APIKeyValueKey: "apiKey",
}
} else {
sandboxEndpointConf.EndSecurity.SecurityType = SecretInfo{
SecretName: strings.Join([]string{apiUniqueID, "sandbox", "secret"}, "-"),
UsernameKey: "username",
PasswordKey: "password",
}
}
}

if endpointSecurityData.Production.Enabled {
prodEndpointConf.EndSecurity.Enabled = true
prodEndpointConf.EndSecurity.SecurityType = SecretInfo{
SecretName: strings.Join([]string{apiUniqueID, "production", "secret"}, "-"),
UsernameKey: "username",
PasswordKey: "password",
if endpointSecurityData.Production.Type == "apikey" {
prodEndpointConf.EndSecurity.SecurityType = SecretInfo{
SecretName: strings.Join([]string{apiUniqueID, "production", "secret"}, "-"),
In: "Header",
APIKeyNameKey: endpointSecurityData.Production.APIKeyIdentifier,
APIKeyValueKey: "apiKey",
}
} else {
prodEndpointConf.EndSecurity.SecurityType = SecretInfo{
SecretName: strings.Join([]string{apiUniqueID, "production", "secret"}, "-"),
UsernameKey: "username",
PasswordKey: "password",
}
}
}

Expand All @@ -621,7 +648,7 @@ func getEndpointConfigs(sandboxURL string, prodURL string, endCertAvailable bool
// GenerateCRs takes the .apk-conf, api definition, vHost and the organization for a particular API and then generate and returns
// the relavant CRD set as a zip
func GenerateCRs(apkConf string, apiDefinition string, certContainer CertContainer, k8ResourceGenEndpoint string, organizationID string) (*K8sArtifacts, error) {
k8sArtifact := K8sArtifacts{HTTPRoutes: make(map[string]*gwapiv1.HTTPRoute), GQLRoutes: make(map[string]*dpv1alpha2.GQLRoute), Backends: make(map[string]*dpv1alpha1.Backend), Scopes: make(map[string]*dpv1alpha1.Scope), Authentication: make(map[string]*dpv1alpha2.Authentication), APIPolicies: make(map[string]*dpv1alpha2.APIPolicy), InterceptorServices: make(map[string]*dpv1alpha1.InterceptorService), ConfigMaps: make(map[string]*corev1.ConfigMap), Secrets: make(map[string]*corev1.Secret), RateLimitPolicies: make(map[string]*dpv1alpha1.RateLimitPolicy)}
k8sArtifact := K8sArtifacts{HTTPRoutes: make(map[string]*gwapiv1.HTTPRoute), GQLRoutes: make(map[string]*dpv1alpha2.GQLRoute), Backends: make(map[string]*dpv1alpha2.Backend), Scopes: make(map[string]*dpv1alpha1.Scope), Authentication: make(map[string]*dpv1alpha2.Authentication), APIPolicies: make(map[string]*dpv1alpha3.APIPolicy), InterceptorServices: make(map[string]*dpv1alpha1.InterceptorService), ConfigMaps: make(map[string]*corev1.ConfigMap), Secrets: make(map[string]*corev1.Secret), RateLimitPolicies: make(map[string]*dpv1alpha1.RateLimitPolicy)}
if apkConf == "" {
logger.LoggerTransformer.Error("Empty apk-conf parameter provided. Unable to generate CRDs.")
return nil, errors.New("Error: APK-Conf can't be empty")
Expand Down Expand Up @@ -724,7 +751,7 @@ func GenerateCRs(apkConf string, apiDefinition string, certContainer CertContain

switch kind {
case "APIPolicy":
var apiPolicy dpv1alpha2.APIPolicy
var apiPolicy dpv1alpha3.APIPolicy
err = k8Yaml.Unmarshal(yamlData, &apiPolicy)
if err != nil {
logger.LoggerSync.Errorf("Error unmarshaling APIPolicy YAML: %v", err)
Expand All @@ -741,7 +768,7 @@ func GenerateCRs(apkConf string, apiDefinition string, certContainer CertContain
k8sArtifact.HTTPRoutes[httpRoute.ObjectMeta.Name] = &httpRoute

case "Backend":
var backend dpv1alpha1.Backend
var backend dpv1alpha2.Backend
err = k8Yaml.Unmarshal(yamlData, &backend)
if err != nil {
logger.LoggerSync.Errorf("Error unmarshaling Backend YAML: %v", err)
Expand Down Expand Up @@ -1034,31 +1061,51 @@ func createConfigMaps(certFiles map[string]string, k8sArtifact *K8sArtifacts) {

// createEndpointSecrets creates and links the secret CRs need to be created for handling the endpoint security
func createEndpointSecrets(secretData EndpointSecurityConfig, k8sArtifact *K8sArtifacts) {
createSecret := func(environment string, username, password string) {
secret := corev1.Secret{
TypeMeta: metav1.TypeMeta{
Kind: "Secret",
APIVersion: "v1",
},
ObjectMeta: metav1.ObjectMeta{
Name: strings.Join([]string{k8sArtifact.API.Name, environment, "secret"}, "-"),
Namespace: k8sArtifact.API.Namespace,
Labels: make(map[string]string),
},
Data: map[string][]byte{
"username": []byte(username),
"password": []byte(password),
},
createSecret := func(environment string, username, password string, apiKeyValue string, securityType string) {
var secret corev1.Secret
if securityType == "apikey" {
secret = corev1.Secret{
TypeMeta: metav1.TypeMeta{
Kind: "Secret",
APIVersion: "v1",
},
ObjectMeta: metav1.ObjectMeta{
Name: strings.Join([]string{k8sArtifact.API.Name, environment, "secret"}, "-"),
Namespace: k8sArtifact.API.Namespace,
Labels: make(map[string]string),
},
Data: map[string][]byte{
"apiKey": []byte(apiKeyValue),
},
}
} else {
secret = corev1.Secret{
TypeMeta: metav1.TypeMeta{
Kind: "Secret",
APIVersion: "v1",
},
ObjectMeta: metav1.ObjectMeta{
Name: strings.Join([]string{k8sArtifact.API.Name, environment, "secret"}, "-"),
Namespace: k8sArtifact.API.Namespace,
Labels: make(map[string]string),
},
Data: map[string][]byte{
"username": []byte(username),
"password": []byte(password),
},
}
}
logger.LoggerTransformer.Debugf("New Secret Data for %s: %v", environment, secret)
k8sArtifact.Secrets[secret.ObjectMeta.Name] = &secret
}

if secretData.Production.Enabled {
createSecret("production", secretData.Production.Username, secretData.Production.Password)
if secretData.Production.Username == "" || secretData.Production.Password == "" {
createSecret("production", secretData.Production.Username, secretData.Production.Password, secretData.Production.APIKeyValue, secretData.Production.Type)
}
}

if secretData.Sandbox.Enabled {
createSecret("sandbox", secretData.Sandbox.Username, secretData.Sandbox.Password)
createSecret("sandbox", secretData.Sandbox.Username, secretData.Sandbox.Password, secretData.Sandbox.APIKeyValue, secretData.Sandbox.Type)
}
}
8 changes: 8 additions & 0 deletions apim-apk-agent/pkg/transformer/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -177,3 +177,11 @@ func GetUniqueIDForAPI(name, version, organization string) string {
hashedValue := hash.Sum(nil)
return hex.EncodeToString(hashedValue)
}

// GetSha1Value returns the SHA1 value of the input string
func GetSha1Value(input string) string {
hasher := sha1.New()
hasher.Write([]byte(input))
hashBytes := hasher.Sum(nil)
return hex.EncodeToString(hashBytes)
}

0 comments on commit 72a1121

Please sign in to comment.