feat(client): Add EdgeConnect client for app management
Some checks failed
Go Tests / go-tests (push) Failing after 1m15s

Introduce a new EdgeConnect client to interact with the platform's API.

Includes methods to:
- Retrieve authentication tokens.
- Create new app instances.
- Create new apps.

Defines necessary data structures for API payloads, such as app and instance keys, flavors, and configurations.

Also adds an example implementation in a separate main package for demonstration purposes.

Refs: IPCEICIS-5755
This commit is contained in:
Daniel Sy 2025-09-02 15:23:19 +02:00
parent 0b411dc9cf
commit b1928ad9e7
Signed by: Daniel.Sy
GPG key ID: 1F39A8BBCD2EE3D3
2 changed files with 271 additions and 0 deletions

229
internal/client/client.go Normal file
View file

@ -0,0 +1,229 @@
package client
import (
"bytes"
"context"
"encoding/json"
"fmt"
"io"
"net/http"
"os"
)
type EdgeConnect struct {
BaseURL string
HttpClient *http.Client
}
// curl -X POST https://mc.orca.platform.mg3.mdb.osc.live/api/v1/auth/ctrl/CreateAppInst -H 'Content-Type: application/json' -H "Authorization: Bearer $EDGEXR_TOKEN" -S --data "$CREATEAPPINSTANCE_JSON" --fail-with-body
func (e *EdgeConnect) NewAppInstance(ctx context.Context, input NewAppInstanceInput) error {
json_data, err := json.Marshal(input)
if err != nil {
return err
}
request, err := http.NewRequestWithContext(ctx, "POST", e.BaseURL+"/api/v1/auth/ctrl/CreateAppInst", bytes.NewBuffer(json_data))
if err != nil {
return err
}
request.Header.Set("Content-Type", "application/json")
request.Header.Set("Authorization", "Bearer "+os.Getenv("EDGEXR_TOKEN"))
resp, err := e.HttpClient.Do(request)
if err != nil {
return err
}
defer resp.Body.Close()
fmt.Printf("Header: %v\n", request.Header)
bodyBytes, err := io.ReadAll(resp.Body)
if err != nil {
return err
}
fmt.Printf("Response: %v\n", string(bodyBytes))
return nil
}
// curl -X POST https://mc.orca.platform.mg3.mdb.osc.live/api/v1/auth/ctrl/CreateApp -H 'Content-Type: application/json' -H "Authorization: Bearer $EDGEXR_TOKEN" -S --data "$CREATEAPP_JSON" --fail-with-body
func (e *EdgeConnect) NewApp(ctx context.Context, input NewAppInput) error {
json_data, err := json.Marshal(input)
if err != nil {
return err
}
request, err := http.NewRequestWithContext(ctx, "POST", e.BaseURL+"/api/v1/auth/ctrl/CreateApp", bytes.NewBuffer(json_data))
if err != nil {
return err
}
request.Header.Set("Content-Type", "application/json")
request.Header.Set("Authorization", "Bearer "+os.Getenv("EDGEXR_TOKEN"))
resp, err := e.HttpClient.Do(request)
if err != nil {
return err
}
defer resp.Body.Close()
fmt.Printf("Header: %v\n", request.Header)
bodyBytes, err := io.ReadAll(resp.Body)
if err != nil {
return err
}
fmt.Printf("Response: %v\n", string(bodyBytes))
return nil
}
type NewAppInstanceInput struct {
Region string `json:"region"`
AppInst AppInstance `json:"appinst"`
}
type AppInstance struct {
Key AppInstanceKey `json:"key"`
AppKey AppKey `json:"app_key"`
Flavor Flavor `json:"flavor"`
}
type AppInstanceKey struct {
Organization string `json:"organization"`
Name string `json:"name"`
CloudletKey CloudletKey `json:"cloudlet_key"`
}
type CloudletKey struct {
Organization string `json:"organization"`
Name string `json:"name"`
}
type AppKey struct {
Organization string `json:"organization"`
Name string `json:"name"`
Version string `json:"version"`
}
type Flavor struct {
Name string `json:"name"`
}
type NewAppInput struct {
Region string `json:"region"`
App App `json:"app"`
}
type App struct {
Key AppKey `json:"key"`
Deployment string `json:"deployment"`
ImageType string `json:"image_type"`
ImagePath string `json:"image_path"`
AllowServerless bool `json:"allow_serverless"`
DefaultFlavor Flavor `json:"defaultFlavor"`
ServerlessConfig any `json:"serverless_config"`
DeploymentGenerator string `json:"deployment_generator"`
DeploymentManifest string `json:"deployment_manifest"`
}
func (e *EdgeConnect) RetrieveToken(ctx context.Context, username, password string) (string, error) {
json_data, err := json.Marshal(map[string]string{
"username": username,
"password": password,
})
if err != nil {
return "", err
}
request, err := http.NewRequestWithContext(ctx, "POST", e.BaseURL+"/api/v1/login", bytes.NewBuffer(json_data))
if err != nil {
return "", err
}
request.Header.Set("Content-Type", "application/json")
resp, err := e.HttpClient.Do(request)
if err != nil {
return "", err
}
defer resp.Body.Close()
fmt.Printf("Header: %v\n", request.Header)
bodyBytes, err := io.ReadAll(resp.Body)
if err != nil {
return "", err
}
fmt.Printf("Response: %v\n", string(bodyBytes))
var respData struct {
Token string `json:"token"`
}
err = json.Unmarshal(bodyBytes, &respData)
if err != nil {
return "", err
}
return respData.Token, nil
}
// EDGEXR_TOKEN="$(curl -X POST https://mc.orca.platform.mg3.mdb.osc.live/api/v1/login -H 'Content-Type: application/json' --data '{"password": "'${EDGEXR_PLATFORM_PASSWORD}'","username": "'${EDGEXR_PLATFORM_USERNAME}'"}' -sSf | jq -r .token)"
// CREATEAPP_JSON=$(cat <<EOF
// {
// "region": "${APP_REGION}",
// "app": {
// "key": {
// "organization": "dev-framework",
// "name": "$(echo ${{ steps.repository.outputs.repository }} | sed -e 's|^.*/||')",
// "version": "${{ steps.docker.outputs.version }}"
// },
// "deployment": "kubernetes",
// "image_type": "Docker",
// "image_path": "${{ steps.repository.outputs.registry }}/${{ steps.repository.outputs.repository }}:${{ steps.docker.outputs.version }}",
// "allow_serverless": true,
// "defaultFlavor": {
// "name": "${APP_FLAVOR}"
// },
// "serverless_config": {},
// "deployment_generator": "kubernetes-basic",
// "deployment_manifest": "apiVersion: v1\nkind: Service\nmetadata:\n name: $(echo ${{ steps.repository.outputs.repository }} | sed -e 's|^.*/||')-tcp\n labels:\n run: $(echo ${{ steps.repository.outputs.repository }} | sed -e 's|^.*/||')\nspec:\n type: LoadBalancer\n ports:\n - name: tcp80\n protocol: TCP\n port: 80\n targetPort: 80\n selector:\n run: $(echo ${{ steps.repository.outputs.repository }} | sed -e 's|^.*/||')\n---\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: $(echo ${{ steps.repository.outputs.repository }} | sed -e 's|^.*/||')-deployment\nspec:\n replicas: 1\n selector:\n matchLabels:\n run: $(echo ${{ steps.repository.outputs.repository }} | sed -e 's|^.*/||')\n template:\n metadata:\n labels:\n run: $(echo ${{ steps.repository.outputs.repository }} | sed -e 's|^.*/||')\n mexDeployGen: kubernetes-basic\n spec:\n volumes:\n containers:\n - name: $(echo ${{ steps.repository.outputs.repository }} | sed -e 's|^.*/||')\n image: ${{ steps.repository.outputs.registry }}/${{ steps.repository.outputs.repository }}:${{ steps.docker.outputs.version }}\n imagePullPolicy: Always\n ports:\n - containerPort: 80\n protocol: TCP\n\n"
// }
// }
// EOF
// )
// echo $CREATEAPP_JSON
// echo create app
// curl -X POST https://mc.orca.platform.mg3.mdb.osc.live/api/v1/auth/ctrl/CreateApp -H 'Content-Type: application/json' -H "Authorization: Bearer $EDGEXR_TOKEN" -S --data "$CREATEAPP_JSON" --fail-with-body
// CREATEAPPINSTANCE_JSON=$(cat <<EOF
// {
// "region": "${APP_REGION}",
// "appinst": {
// "key": {
// "organization": "dev-framework",
// "name": "$(echo ${{ steps.repository.outputs.repository }} | sed -e 's|^.*/||')-instance",
// "cloudlet_key": {
// "organization": "TelekomOP",
// "name": "${CLOUDLET}"
// }
// },
// "app_key": {
// "organization": "dev-framework",
// "name": "$(echo ${{ steps.repository.outputs.repository }} | sed -e 's|^.*/||')",
// "version": "${{ steps.docker.outputs.version }}"
// },
// "flavor": {
// "name": "${APP_FLAVOR}"
// }
// }
// }
// EOF
// )
// echo $CREATEAPPINSTANCE_JSON
// echo create app instance
// curl -X POST https://mc.orca.platform.mg3.mdb.osc.live/api/v1/auth/ctrl/CreateAppInst -H 'Content-Type: application/json' -H "Authorization: Bearer $EDGEXR_TOKEN" -S --data "$CREATEAPPINSTANCE_JSON" --fail-with-body