Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[processor/resourcedetectionprocessor] support openshift #16079

Merged
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
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://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"
frzifus marked this conversation as resolved.
Show resolved Hide resolved

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 {
dashpole marked this conversation as resolved.
Show resolved Hide resolved
// 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