Skip to content

Commit

Permalink
[processor/resourcedetectionprocessor] support openshift (open-teleme…
Browse files Browse the repository at this point in the history
…try#16079)

This pr adds openshift support to the resourcedetectionprocessor.
Closes open-telemetry#15694
  • Loading branch information
frzifus committed Jan 17, 2023
1 parent 6928546 commit b93ee90
Show file tree
Hide file tree
Showing 17 changed files with 966 additions and 2 deletions.
16 changes: 16 additions & 0 deletions .chloggen/resourcedetectionprocessor_support_openshift.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix'
change_type: enhancement

# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver)
component: resourcedetectionprocessor

# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
note: add openshift support

# One or more tracking issues related to the change
issues: [15694]

# (Optional) One or more lines of additional information to render under the primary note.
# These lines will be padded with 2 spaces and then inserted directly into the document.
# Use pipe (|) for multiline entries.
subtext:
1 change: 1 addition & 0 deletions .github/CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ processor/resourcedetectionprocessor/ @open-telemetry/collect
processor/resourceprocessor/ @open-telemetry/collector-contrib-approvers @dmitryax
processor/resourcedetectionprocessor/internal/azure/ @open-telemetry/collector-contrib-approvers @mx-psi
processor/resourcedetectionprocessor/internal/heroku/ @open-telemetry/collector-contrib-approvers @atoulme
processor/resourcedetectionprocessor/internal/openshift/ @open-telemetry/collector-contrib-approvers @frzifus
processor/routingprocessor/ @open-telemetry/collector-contrib-approvers @jpkrohling @kovrus
processor/schemaprocessor/ @open-telemetry/collector-contrib-approvers @MovieStoreGuy
processor/servicegraphprocessor/ @open-telemetry/collector-contrib-approvers @jpkrohling @mapno
Expand Down
1 change: 1 addition & 0 deletions .github/ISSUE_TEMPLATE/bug_report.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ body:
- processor/resourcedetection
- processor/resourcedetection/internal/azure
- processor/resourcedetection/internal/heroku
- processor/resourcedetection/internal/openshift
- processor/routing
- processor/schema
- processor/servicegraph
Expand Down
1 change: 1 addition & 0 deletions .github/ISSUE_TEMPLATE/feature_request.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ body:
- processor/resourcedetection
- processor/resourcedetection/internal/azure
- processor/resourcedetection/internal/heroku
- processor/resourcedetection/internal/openshift
- processor/routing
- processor/schema
- processor/servicegraph
Expand Down
1 change: 1 addition & 0 deletions .github/ISSUE_TEMPLATE/other.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ body:
- processor/resourcedetection
- processor/resourcedetection/internal/azure
- processor/resourcedetection/internal/heroku
- processor/resourcedetection/internal/openshift
- processor/routing
- processor/schema
- processor/servicegraph
Expand Down
208 changes: 208 additions & 0 deletions internal/metadataproviders/openshift/metadata.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
// Copyright The OpenTelemetry Authors
//
// 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:https://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 openshift // import "github.com/open-telemetry/opentelemetry-collector-contrib/internal/metadataproviders/openshift"

import (
"context"
"encoding/json"
"fmt"
"net/http"
"strings"
)

// Provider gets cluster metadata from Openshift.
type Provider interface {
K8SClusterVersion(context.Context) (string, error)
OpenShiftClusterVersion(context.Context) (string, error)
Infrastructure(context.Context) (*InfrastructureAPIResponse, error)
}

// NewProvider creates a new metadata provider.
func NewProvider(address, token string) Provider {
return &openshiftProvider{
address: address,
token: token,
client: &http.Client{},
}
}

type openshiftProvider struct {
client *http.Client
address string
token string
}

func (o *openshiftProvider) makeOCPRequest(ctx context.Context, endpoint, target string) (*http.Request, error) {
addr := fmt.Sprintf("%s/apis/config.openshift.io/v1/%s/%s/status", o.address, endpoint, target)
req, err := http.NewRequestWithContext(ctx, http.MethodGet, addr, nil)
if err != nil {
return nil, err
}
req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", o.token))
return req, nil
}

// OpenShiftClusterVersion requests the ClusterVersion from the openshift api.
func (o *openshiftProvider) OpenShiftClusterVersion(ctx context.Context) (string, error) {
req, err := o.makeOCPRequest(ctx, "clusterversions", "version")
if err != nil {
return "", err
}
resp, err := o.client.Do(req)
if err != nil {
return "", err
}
res := ocpClusterVersionAPIResponse{}
if err := json.NewDecoder(resp.Body).Decode(&res); err != nil {
return "", err
}
return res.Status.Desired.Version, nil
}

// ClusterVersion requests Infrastructure details from the openshift api.
func (o *openshiftProvider) Infrastructure(ctx context.Context) (*InfrastructureAPIResponse, error) {
req, err := o.makeOCPRequest(ctx, "infrastructures", "cluster")
if err != nil {
return nil, err
}
resp, err := o.client.Do(req)
if err != nil {
return nil, err
}
res := &InfrastructureAPIResponse{}
if err := json.NewDecoder(resp.Body).Decode(res); err != nil {
return nil, err
}

return res, nil
}

// K8SClusterVersion requests the ClusterVersion from the kubernetes api.
func (o *openshiftProvider) K8SClusterVersion(ctx context.Context) (string, error) {
addr := fmt.Sprintf("%s/version", o.address)
req, err := http.NewRequestWithContext(ctx, http.MethodGet, addr, nil)
if err != nil {
return "", err
}
req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", o.token))

resp, err := o.client.Do(req)
if err != nil {
return "", err
}
res := k8sClusterVersionAPIResponse{}
if err := json.NewDecoder(resp.Body).Decode(&res); err != nil {
return "", err
}
version := res.GitVersion
if strings.Contains(version, "+") {
version = strings.Split(version, "+")[0]
}
return version, nil
}

type ocpClusterVersionAPIResponse struct {
Status struct {
Desired struct {
Version string `json:"version"`
} `json:"desired"`
} `json:"status"`
}

// InfrastructureAPIResponse from OpenShift API.
type InfrastructureAPIResponse struct {
Status InfrastructureStatus `json:"status"`
}

// InfrastructureStatus holds cluster-wide information about Infrastructure.
// https://docs.openshift.com/container-platform/4.11/rest_api/config_apis/infrastructure-config-openshift-io-v1.html#apisconfig-openshift-iov1infrastructuresnamestatus
type InfrastructureStatus struct {
// ControlPlaneTopology expresses the expectations for operands that normally
// run on control nodes. The default is 'HighlyAvailable', which represents
// the behavior operators have in a "normal" cluster. The 'SingleReplica' mode
// will be used in single-node deployments and the operators should not
// configure the operand for highly-available operation The 'External' mode
// indicates that the control plane is hosted externally to the cluster and
// that its components are not visible within the cluster.
ControlPlaneTopology string `json:"controlPlaneTopology"`
// InfrastructureName uniquely identifies a cluster with a human friendly
// name. Once set it should not be changed. Must be of max length 27 and must
// have only alphanumeric or hyphen characters.
InfrastructureName string `json:"infrastructureName"`
// InfrastructureTopology expresses the expectations for infrastructure
// services that do not run on control plane nodes, usually indicated by a
// node selector for a role value other than master. The default is
// 'HighlyAvailable', which represents the behavior operators have in a
// "normal" cluster. The 'SingleReplica' mode will be used in single-node
// deployments and the operators should not configure the operand for
// highly-available operation.
InfrastructureTopology string `json:"infrastructureTopology"`
// PlatformStatus holds status information specific to the underlying
// infrastructure provider.
PlatformStatus InfrastructurePlatformStatus `json:"platformStatus"`
}

// InfrastructurePlatformStatus reported by the OpenShift API.
type InfrastructurePlatformStatus struct {
Aws InfrastructureStatusAWS `json:"aws"`
Azure InfrastructureStatusAzure `json:"azure"`
Baremetal struct{} `json:"baremetal"`
GCP InfrastructureStatusGCP `json:"gcp"`
IBMCloud InfrastructureStatusIBMCloud `json:"ibmcloud"`
OpenStack InfrastructureStatusOpenStack `json:"openstack"`
OVirt struct{} `json:"ovirt"`
VSphere struct{} `json:"vsphere"`
Type string `json:"type"`
}

// InfrastructureStatusAWS reported by the OpenShift API.
type InfrastructureStatusAWS struct {
// Region holds the default AWS region for new AWS resources created by the
// cluster.
Region string `json:"region"`
}

// InfrastructureStatusAzure reported by the OpenShift API.
type InfrastructureStatusAzure struct {
// CloudName is the name of the Azure cloud environment which can be used to
// configure the Azure SDK with the appropriate Azure API endpoints. If empty,
// the value is equal to AzurePublicCloud.
CloudName string `json:"cloudName"`
}

// InfrastructureStatusGCP reported by the OpenShift API.
type InfrastructureStatusGCP struct {
// Region holds the region for new GCP resources created for the cluster.
Region string `json:"region"`
}

// InfrastructureStatusIBMCloud reported by the OpenShift API.
type InfrastructureStatusIBMCloud struct {
// Location is where the cluster has been deployed.
Location string `json:"location"`
}

// InfrastructureStatusOpenStack reported by the OpenShift API.
type InfrastructureStatusOpenStack struct {
// CloudName is the name of the desired OpenStack cloud in the client
// configuration file (clouds.yaml).
CloudName string `json:"cloudName"`
}

// k8sClusterVersionAPIResponse of OpenShift.
// https://docs.openshift.com/container-platform/4.11/rest_api/config_apis/clusterversion-config-openshift-io-v1.html#apisconfig-openshift-iov1clusterversionsnamestatus
type k8sClusterVersionAPIResponse struct {
GitVersion string `json:"gitVersion"`
}
Loading

0 comments on commit b93ee90

Please sign in to comment.