Skip to content

Commit

Permalink
Alarm subscription server support 1st part: (#71)
Browse files Browse the repository at this point in the history
1. Start alarm subscription server, initialize the path, related registrations
2. Alarm subscription server basic resp api support for get, list, add, and delete
  • Loading branch information
Jennifer-chen-rh authored Mar 8, 2024
1 parent 60c2282 commit 3a24a17
Show file tree
Hide file tree
Showing 11 changed files with 935 additions and 3 deletions.
18 changes: 16 additions & 2 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,21 @@
"--log-level=debug",
"--cloud-id=6575154c-72fc-4ed8-9a87-a81885ab38bb",
"--backend-url=${env:BACKEND_URL}",
"--backend-token=${env:BACKEND_TOKEN}",
"--backend-token=${env:BACKEND_TOKEN}"
]
},
{
"name": "start alarm-subscription-server",
"type": "go",
"request": "launch",
"mode": "auto",
"program": "${workspaceFolder}",
"args": [
"start",
"alarm-subscription-server",
"--log-level=debug",
"--log-field=server=alarm-subscription",
"--cloud-id=6575154c-72fc-4ed8-9a87-a81885ab38bb"
]
},
{
Expand All @@ -79,4 +93,4 @@
"program": "${fileDirname}"
}
]
}
}
1 change: 1 addition & 0 deletions api/v1alpha1/orano2ims_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ type ORANO2IMSSpec struct {
DeploymentManagerServer bool `json:"deploymentManagerServer"`
//+kubebuilder:default=false
ResourceServer bool `json:"resourceServer"`
AlarmSubscriptionServer bool `json:"alarmSubscriptionServer"`
//+optional
IngressHost string `json:"ingressHost,omitempty"`
//+optional
Expand Down
4 changes: 4 additions & 0 deletions config/crd/bases/oran.openshift.io_orano2imses.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ spec:
items:
type: string
type: array
alarmSubscriptionServer:
default: false
type: boolean
ingressHost:
type: string
metadataServer:
Expand All @@ -67,6 +70,7 @@ spec:
required:
- cloudId
- deploymentManagerServer
- AlarmSubscriptionServer
- metadataServer
- resourceServer
type: object
Expand Down
210 changes: 210 additions & 0 deletions internal/cmd/server/start_alarm_subscription_server.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,210 @@
/*
Copyright 2023 Red Hat Inc.
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied. See the License for the specific language governing permissions and limitations under the
License.
*/

package server

import (
"log/slog"
"net/http"

"github.com/gorilla/mux"
"github.com/spf13/cobra"

"github.com/openshift-kni/oran-o2ims/internal"
"github.com/openshift-kni/oran-o2ims/internal/exit"
"github.com/openshift-kni/oran-o2ims/internal/logging"
"github.com/openshift-kni/oran-o2ims/internal/network"
"github.com/openshift-kni/oran-o2ims/internal/service"
)

// Server creates and returns the `start alarm-subscription-server` command.
func AlarmSubscriptionServer() *cobra.Command {
c := NewAlarmSubscriptionServer()
result := &cobra.Command{
Use: "alarm-subscription-server",
Short: "Starts the alarm Subscription Server",
Args: cobra.NoArgs,
RunE: c.run,
}
flags := result.Flags()

// no need for now
//authentication.AddFlags(flags)
//authorization.AddFlags(flags)

network.AddListenerFlags(flags, network.APIListener, network.APIAddress)
_ = flags.String(
cloudIDFlagName,
"",
"O-Cloud identifier.",
)
_ = flags.StringArray(
extensionsFlagName,
[]string{},
"Extension to add to alarm subscriptions.",
)
return result
}

// alarmSubscriptionServerCommand contains the data and logic needed to run the `start
// alarm-subscription-server` command.
type AlarmSubscriptionServerCommand struct {
}

// NewAlarmSubscriptionServer creates a new runner that knows how to execute the `start
// alarm-subscription-server` command.
func NewAlarmSubscriptionServer() *AlarmSubscriptionServerCommand {
return &AlarmSubscriptionServerCommand{}
}

// run executes the `start alarm-subscription-server` command.
func (c *AlarmSubscriptionServerCommand) run(cmd *cobra.Command, argv []string) error {
// Get the context:
ctx := cmd.Context()

// Get the dependencies from the context:
logger := internal.LoggerFromContext(ctx)

// Get the flags:
flags := cmd.Flags()

// Get the cloud identifier:
cloudID, err := flags.GetString(cloudIDFlagName)
if err != nil {
logger.Error(
"Failed to get cloud identifier flag",
"flag", cloudIDFlagName,
"error", err.Error(),
)
return exit.Error(1)
}
if cloudID == "" {
logger.Error(
"Cloud identifier is empty",
"flag", cloudIDFlagName,
)
return exit.Error(1)
}
logger.Info(
"Cloud identifier",
"value", cloudID,
)

// Get the backend details:
extensions, err := flags.GetStringArray(extensionsFlagName)
if err != nil {
logger.Error(
"Failed to extension flag",
"flag", extensionsFlagName,
"error", err.Error(),
)
return exit.Error(1)
}
logger.Info(
"alarm subscription extensions details",
slog.Any("extensions", extensions),
)

// Create the logging wrapper:
loggingWrapper, err := logging.NewTransportWrapper().
SetLogger(logger).
SetFlags(flags).
Build()
if err != nil {
logger.Error(
"Failed to create transport wrapper",
"error", err.Error(),
)
return exit.Error(1)
}

// Create the router:
router := mux.NewRouter()
router.NotFoundHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
service.SendError(w, http.StatusNotFound, "Not found")
})
router.MethodNotAllowedHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
service.SendError(w, http.StatusMethodNotAllowed, "Method not allowed")
})
//router.Use(authenticationWrapper, authorizationWrapper)

// Create the handler:
handler, err := service.NewAlarmSubscriptionHandler().
SetLogger(logger).
SetLoggingWrapper(loggingWrapper).
SetCloudID(cloudID).
SetExtensions(extensions...).
Build()
if err != nil {
logger.Error(
"Failed to create handler",
"error", err,
)
return exit.Error(1)
}

// Create the routes:
adapter, err := service.NewAdapter().
SetLogger(logger).
SetPathVariables("alarmSubscriptionID").
SetHandler(handler).
Build()
if err != nil {
logger.Error(
"Failed to create adapter",
"error", err,
)
return exit.Error(1)
}
router.Handle(
"/o2ims-infrastructureMonitoring/{version}/alarmSubscriptions",
adapter,
).Methods(http.MethodGet, http.MethodPost)

router.Handle(
"/o2ims-infrastructureMonitoring/{version}/alarmSubscriptions/{alarmSubscriptionID}",
adapter,
).Methods(http.MethodGet, http.MethodDelete)

// Start the API server:
apiListener, err := network.NewListener().
SetLogger(logger).
SetFlags(flags, network.APIListener).
Build()
if err != nil {
logger.Error(
"Failed to to create API listener",
slog.String("error", err.Error()),
)
return exit.Error(1)
}
logger.Info(
"API listening",
slog.String("address", apiListener.Addr().String()),
)
apiServer := http.Server{
Addr: apiListener.Addr().String(),
Handler: router,
}
err = apiServer.Serve(apiListener)
if err != nil {
logger.Error(
"API server finished with error",
slog.String("error", err.Error()),
)
return exit.Error(1)
}

return nil
}
1 change: 1 addition & 0 deletions internal/cmd/start_cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,5 +31,6 @@ func Start() *cobra.Command {
result.AddCommand(server.MetadataServer())
result.AddCommand(server.ResourceServer())
result.AddCommand(server.AlarmServer())
result.AddCommand(server.AlarmSubscriptionServer())
return result
}
54 changes: 53 additions & 1 deletion internal/controllers/orano2ims_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ func (r *ORANO2IMSReconciler) Reconcile(ctx context.Context, req ctrl.Request) (
nextReconcile = ctrl.Result{RequeueAfter: 5 * time.Minute}

// Create the needed Ingress if at least one server is required by the Spec.
if orano2ims.Spec.MetadataServer || orano2ims.Spec.DeploymentManagerServer || orano2ims.Spec.ResourceServer {
if orano2ims.Spec.MetadataServer || orano2ims.Spec.DeploymentManagerServer || orano2ims.Spec.ResourceServer || orano2ims.Spec.AlarmSubscriptionServer {
err = r.createIngress(ctx, orano2ims)
if err != nil {
r.Log.Error(err, "Failed to deploy Ingress.")
Expand Down Expand Up @@ -178,6 +178,43 @@ func (r *ORANO2IMSReconciler) Reconcile(ctx context.Context, req ctrl.Request) (
return
}
}
// Start the alert subscription server if required by the Spec.
if orano2ims.Spec.AlarmSubscriptionServer {
// Create the client ServiceAccount.
err = r.createServiceAccount(ctx, orano2ims, utils.ORANO2IMSClientSAName)
if err != nil {
r.Log.Error(err, fmt.Sprintf("Failed to deploy ServiceAccount %s for alert subscription server.", utils.ORANO2IMSClientSAName))
return
}

// Create authz ConfigMap.
err = r.createConfigMap(ctx, orano2ims, utils.ORANO2IMSConfigMapName)
if err != nil {
r.Log.Error(err, "Failed to deploy ConfigMap for alert subscription server.")
return
}

// Create the needed ServiceAccount.
err = r.createServiceAccount(ctx, orano2ims, utils.ORANO2IMSAlarmSubscriptionServerName)
if err != nil {
r.Log.Error(err, "Failed to deploy ServiceAccount for Alarm Subscription server.")
return
}

// Create the Service needed for the alert subscription server.
err = r.createService(ctx, orano2ims, utils.ORANO2IMSAlarmSubscriptionServerName)
if err != nil {
r.Log.Error(err, "Failed to deploy Service for Alarm Subscription server.")
return
}

// Create the alert subscription-server deployment.
err = r.deployServer(ctx, orano2ims, utils.ORANO2IMSAlarmSubscriptionServerName)
if err != nil {
r.Log.Error(err, "Failed to deploy the alert subscription server.")
return
}
}

err = r.updateORANO2ISMStatus(ctx, orano2ims)
if err != nil {
Expand Down Expand Up @@ -412,6 +449,21 @@ func (r *ORANO2IMSReconciler) createIngress(ctx context.Context, orano2ims *oran
},
},
},
{
Path: "/o2ims-infrastructureMonitoring/v1/alertSubscriptions",
PathType: func() *networkingv1.PathType {
pathType := networkingv1.PathTypePrefix
return &pathType
}(),
Backend: networkingv1.IngressBackend{
Service: &networkingv1.IngressServiceBackend{
Name: "alert-subscription-server",
Port: networkingv1.ServiceBackendPort{
Name: utils.ORANO2IMSIngressName,
},
},
},
},
},
},
},
Expand Down
2 changes: 2 additions & 0 deletions internal/controllers/utils/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,15 @@ const (
ORANO2IMSMetadata = "metadata"
ORANO2IMSDeploymentManager = "deployment-manager"
ORANO2IMSResource = "resource"
ORANO2IMSAlarmSubscription = "alarm-subscription"
)

// Deployment names
const (
ORANO2IMSMetadataServerName = ORANO2IMSMetadata + "-server"
ORANO2IMSDeploymentManagerServerName = ORANO2IMSDeploymentManager + "-server"
ORANO2IMSResourceServerName = ORANO2IMSResource + "-server"
ORANO2IMSAlarmSubscriptionServerName = ORANO2IMSAlarmSubscription + "-server"
)

// CR default names
Expand Down
Loading

0 comments on commit 3a24a17

Please sign in to comment.