Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
bb49900
OSD-26415: Allow pull-secret to be updated w/o transferring ownership.
nephomaniac Mar 26, 2025
2314441
OSD-26415: Update with generate-docs content
nephomaniac Apr 23, 2025
086e0ba
OSD-26415: New update-pullsecret wrapper cmd separate from transfer-o…
nephomaniac May 21, 2025
970f001
OSD-26415: Lint updates
nephomaniac May 21, 2025
bc3f528
OSD-26415: Update Docs
nephomaniac May 21, 2025
0062370
Forcing an empty commit.
nephomaniac May 21, 2025
be702b3
OSD-26415: Update messaging, format when prompting user.
nephomaniac May 22, 2025
365972a
Merge branch 'master' into OSD-26415-merge2
nephomaniac Jun 9, 2025
abf4aac
OSD-26415: Allow setting service log dryrun flag externally
nephomaniac Jun 9, 2025
9b45c08
OSD-26415: Update docs
nephomaniac Jun 9, 2025
ce1fcd7
OSD-26415: Update comments
nephomaniac Jun 9, 2025
0714868
OSD-26415: Use existing pull-secret naming for cmd
nephomaniac Jun 17, 2025
c5c557e
Add Handover Announcements to Cluster Context Command
devppratik Jun 2, 2025
572d9ac
Update DTP Labels to v3
devppratik Jun 13, 2025
cad7060
Add Test Cases for the utils/jira
devppratik Jun 13, 2025
b2abef1
Add initial command for creating handover announcements
devppratik Jun 13, 2025
94ad358
add more supported instance types for down scale
feichashao Jun 27, 2025
0bf5148
SREP-1010: Added "osdctl dt" check for vault cli (#772)
drakshakhan Jul 10, 2025
ff59bcf
Add SRE-P Orange to owners
typeid Jul 10, 2025
5d742da
Added unit test case for infra_node and controlplane_node
amitupadh Apr 30, 2025
2a5b8c9
fixed lint issues
amitupadh May 6, 2025
284d84b
removed unwanted test case
amitupadh Jul 2, 2025
d10240b
removed unwanted test case
amitupadh Jul 2, 2025
7e98c37
removed unwanted test case
amitupadh Jul 2, 2025
ae52a9a
fixed go fmt
amitupadh Jul 3, 2025
d4ecdae
Update HCP Must-Gather help
faldanarh Jul 7, 2025
e695169
Replace unmainted pkg golang-gomock with uber-gomock
RaphaelBut Jul 10, 2025
7ee1fb4
Fix dt logs console URL
MateSaary Jul 10, 2025
03f03d2
Bump github.com/openshift/backplane-cli from 0.1.46 to 0.1.47
dependabot[bot] Jun 4, 2025
27ab999
OSD-30374: update long description based on SOP
devppratik Jun 17, 2025
ee4eab7
SREP-1062 Adding network info section to cluster context
Makdaam Jul 22, 2025
8fd43fd
SREP-962: Add absolute timestamps to fetching DT logs
MateSaary Jul 29, 2025
35a46ae
Standardize --cluster-id flag to support -C shorthand across all comm…
joshbranham Jul 31, 2025
d2f38ab
Fix last month time period calculation to handle year boundaries
joshbranham Jul 31, 2025
7da4b9c
Use boilerplate v8 in CI
joshbranham Aug 6, 2025
9b70b71
SREP-862: Add support for `osdctl network verify-egress --pod-mode` (…
joshbranham Aug 7, 2025
c54fce5
SREP-1442: add dead link checking to osdctl servicelog post (#787)
eth1030 Aug 11, 2025
2b588db
Hosted cluster dump and a dynatrace logs export
rbhilare Aug 6, 2025
873110e
SREP-861 - support service accounts and no service log flag (#788)
dakotalongRH Aug 18, 2025
188312a
SREP-217: Improving filtering on osdctl-cloudtrail command (#760)
evlin-rh Aug 19, 2025
63ba5a1
OSD-26415: Skip pull-secret auths validations during dry-run.
nephomaniac Aug 29, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .ci-operator.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
build_root_image:
name: boilerplate
namespace: openshift
tag: image-v7.2.0
tag: image-v8.0.0
18 changes: 18 additions & 0 deletions OWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,15 @@ reviewers:
- devppratik
- Tafhim
- joshbranham
- bergmannf
- Makdaam
- Nikokolas3270
- RaphaelBut
- MateSaary
- rolandmkunkel
- petrkotas
- zmird-r
- hectorakemp
approvers:
- clcollins
- dustman9000
Expand All @@ -18,6 +27,15 @@ approvers:
- devppratik
- Tafhim
- joshbranham
- bergmannf
- Makdaam
- Nikokolas3270
- RaphaelBut
- MateSaary
- rolandmkunkel
- petrkotas
- zmird-r
- hectorakemp
maintainers:
- clcollins
- fahlmant
2 changes: 1 addition & 1 deletion cmd/alerts/list_alerts.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ func NewCmdListAlerts() *cobra.Command {
ListAlerts(alertCmd)
},
}
newCmd.Flags().StringVar(&alertCmd.clusterID, "cluster-id", "", "Provide the internal ID of the cluster")
newCmd.Flags().StringVarP(&alertCmd.clusterID, "cluster-id", "C", "", "Provide the internal ID of the cluster")
_ = newCmd.MarkFlagRequired("cluster-id")

newCmd.Flags().StringVarP(&alertCmd.alertLevel, "level", "l", "all", "Alert level [warning, critical, firing, pending, all]")
Expand Down
2 changes: 1 addition & 1 deletion cmd/alerts/silence/add_silence.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ func NewCmdAddSilence() *cobra.Command {
},
}

cmd.Flags().StringVar(&addSilenceCmd.clusterID, "cluster-id", "", "Provide the internal ID of the cluster")
cmd.Flags().StringVarP(&addSilenceCmd.clusterID, "cluster-id", "C", "", "Provide the internal ID of the cluster")
cmd.Flags().StringSliceVar(&addSilenceCmd.alertID, "alertname", []string{}, "alertname (comma-separated)")
cmd.Flags().StringVarP(&addSilenceCmd.comment, "comment", "c", "Adding silence using the osdctl alert command", "add comment about silence")
cmd.Flags().StringVarP(&addSilenceCmd.duration, "duration", "d", "15d", "Adding duration for silence as 15 days") //default duration set to 15 days
Expand Down
2 changes: 1 addition & 1 deletion cmd/alerts/silence/clear_silence.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ func NewCmdClearSilence() *cobra.Command {
},
}

cmd.Flags().StringVar(&silenceCmd.clusterID, "cluster-id", "", "Provide the internal ID of the cluster")
cmd.Flags().StringVarP(&silenceCmd.clusterID, "cluster-id", "C", "", "Provide the internal ID of the cluster")
cmd.Flags().StringSliceVar(&silenceCmd.silenceIDs, "silence-id", []string{}, "silence id (comma-separated)")
cmd.Flags().BoolVarP(&silenceCmd.all, "all", "a", false, "clear all silences")
cmd.Flags().StringVar(&silenceCmd.reason, "reason", "", "The reason for this command, which requires elevation, to be run (usualy an OHSS or PD ticket)")
Expand Down
2 changes: 1 addition & 1 deletion cmd/alerts/silence/list_silence.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ func NewCmdListSilence() *cobra.Command {
ListSilence(listSilenceCmd)
},
}
cmd.Flags().StringVar(&listSilenceCmd.clusterID, "cluster-id", "", "Provide the internal ID of the cluster")
cmd.Flags().StringVarP(&listSilenceCmd.clusterID, "cluster-id", "C", "", "Provide the internal ID of the cluster")
cmd.Flags().StringVar(&listSilenceCmd.reason, "reason", "", "The reason for this command, which requires elevation, to be run (usualy an OHSS or PD ticket)")
_ = cmd.MarkFlagRequired("cluster-id")
_ = cmd.MarkFlagRequired("reason")
Expand Down
49 changes: 6 additions & 43 deletions cmd/cloudtrail/pkg/aws/aws.go → cmd/cloudtrail/aws.go
Original file line number Diff line number Diff line change
@@ -1,19 +1,16 @@
package pkg
package cloudtrail

import (
"context"
"encoding/json"
"fmt"
"time"

"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/aws/arn"
"github.com/aws/aws-sdk-go-v2/service/cloudtrail"
"github.com/aws/aws-sdk-go-v2/service/cloudtrail/types"
"github.com/aws/aws-sdk-go-v2/service/sts"
)

// RawEventDetails struct represents the structure of an AWS raw event
// RawEventDetails represents the structure of relevant fields extracted from a CloudTrail event JSON.
type RawEventDetails struct {
EventVersion string `json:"eventVersion"`
UserIdentity struct {
Expand All @@ -31,11 +28,12 @@ type RawEventDetails struct {
ErrorCode string `json:"errorCode"`
}

// QueryOptions defines the start time for querying CloudTrail events.
type QueryOptions struct {
StartTime time.Time
}

// Extracts Raw cloudtrailEvent Details
// ExtractUserDetails parses a CloudTrail event JSON string and extracts user identity details.
func ExtractUserDetails(cloudTrailEvent *string) (*RawEventDetails, error) {
if cloudTrailEvent == nil || *cloudTrailEvent == "" {
return &RawEventDetails{}, fmt.Errorf("cannot parse a nil input")
Expand All @@ -59,7 +57,8 @@ func ExtractUserDetails(cloudTrailEvent *string) (*RawEventDetails, error) {
return &res, nil
}

// whoami retrieves caller identity information
// Whoami retrieves the AWS account ARN and account ID for the current caller
// using the provided STS client.
func Whoami(stsClient sts.Client) (accountArn string, accountId string, err error) {
ctx := context.TODO()
callerIdentityOutput, err := stsClient.GetCallerIdentity(ctx, &sts.GetCallerIdentityInput{})
Expand All @@ -74,39 +73,3 @@ func Whoami(stsClient sts.Client) (accountArn string, accountId string, err erro

return userArn.String(), userArn.AccountID, nil
}

// getWriteEvents retrieves cloudtrail events since the specified time
// using the provided cloudtrail client and starttime from since flag.
func GetEvents(cloudtailClient *cloudtrail.Client, startTime time.Time, writeOnly bool) ([]types.Event, error) {

alllookupEvents := []types.Event{}
input := cloudtrail.LookupEventsInput{
StartTime: &startTime,
EndTime: aws.Time(time.Now()),
}

if writeOnly {
input.LookupAttributes = []types.LookupAttribute{
{AttributeKey: "ReadOnly",
AttributeValue: aws.String("false")},
}
}

paginator := cloudtrail.NewLookupEventsPaginator(cloudtailClient, &input, func(c *cloudtrail.LookupEventsPaginatorOptions) {})
for paginator.HasMorePages() {

lookupOutput, err := paginator.NextPage(context.TODO())
if err != nil {
return nil, fmt.Errorf("[WARNING] paginator error: \n%w", err)
}
alllookupEvents = append(alllookupEvents, lookupOutput.Events...)

input.NextToken = lookupOutput.NextToken
if lookupOutput.NextToken == nil {
break
}

}

return alllookupEvents, nil
}
4 changes: 2 additions & 2 deletions cmd/cloudtrail/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ func NewCloudtrailCmd() *cobra.Command {
cloudtrailCmd := &cobra.Command{
Use: "cloudtrail",
Short: "AWS CloudTrail related utilities",
RunE: func(cmd *cobra.Command, args []string) error {
return cmd.Help()
Run: func(cmd *cobra.Command, args []string) {
cmd.Help()
},
}

Expand Down
188 changes: 188 additions & 0 deletions cmd/cloudtrail/event.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
package cloudtrail

import (
"context"
"fmt"
"strings"
"time"

"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/service/cloudtrail"
"github.com/aws/aws-sdk-go-v2/service/cloudtrail/types"
)

// GetEvents etrieve CloudTrail events using the provided client and time range.
// It paginates through all available events, and returns all.
func GetEvents(cloudtailClient *cloudtrail.Client, startTime time.Time, endTime time.Time, writeOnly bool) ([]types.Event, error) {

alllookupEvents := []types.Event{}
input := cloudtrail.LookupEventsInput{
StartTime: &startTime,
EndTime: &endTime,
}

if writeOnly {
input.LookupAttributes = []types.LookupAttribute{
{AttributeKey: "ReadOnly",
AttributeValue: aws.String("false")},
}
}

paginator := cloudtrail.NewLookupEventsPaginator(cloudtailClient, &input, func(c *cloudtrail.LookupEventsPaginatorOptions) {})
for paginator.HasMorePages() {
lookupOutput, err := paginator.NextPage(context.TODO())
if err != nil {
return nil, fmt.Errorf("[WARNING] paginator error: \n%w", err)
}
alllookupEvents = append(alllookupEvents, lookupOutput.Events...)

input.NextToken = lookupOutput.NextToken
if lookupOutput.NextToken == nil {
break
}

}

return alllookupEvents, nil
}

// PrintEvents prints the filtered CloudTrail events in a human-readable format.
// Allows to print cloudtrail event url link or its raw JSON format.
// Allows to print cloutrail event resource name & type.
func PrintEvents(filterEvents []types.Event, printUrl bool, printRaw bool) {
var eventStringBuilder = strings.Builder{}

for i := len(filterEvents) - 1; i >= 0; i-- {
if printRaw {
if filterEvents[i].CloudTrailEvent != nil {
fmt.Printf("%v \n", *filterEvents[i].CloudTrailEvent)
return
}
}
rawEventDetails, err := ExtractUserDetails(filterEvents[i].CloudTrailEvent)
if err != nil {
fmt.Printf("[Error] Error extracting event details: %v", err)
}
sessionIssuer := rawEventDetails.UserIdentity.SessionContext.SessionIssuer.UserName
if filterEvents[i].EventName != nil {
eventStringBuilder.WriteString(fmt.Sprintf("\n%v", *filterEvents[i].EventName))
}
if filterEvents[i].EventTime != nil {
eventStringBuilder.WriteString(fmt.Sprintf(" | %v", filterEvents[i].EventTime.String()))
}
if filterEvents[i].Username != nil {
eventStringBuilder.WriteString(fmt.Sprintf(" | Username: %v", *filterEvents[i].Username))
}
if sessionIssuer != "" {
eventStringBuilder.WriteString(fmt.Sprintf(" | ARN: %v", sessionIssuer))
}

for _, resource := range filterEvents[i].Resources {
if resource.ResourceName != nil {
eventStringBuilder.WriteString(fmt.Sprintf("| Resource Name: %v", *resource.ResourceName))
}
if resource.ResourceType != nil {
eventStringBuilder.WriteString(fmt.Sprintf(" | Resource Type: %v", *resource.ResourceType))
}
}

if printUrl && filterEvents[i].CloudTrailEvent != nil {
if err == nil {
eventStringBuilder.WriteString(fmt.Sprintf("\n%v |", generateLink(*rawEventDetails)))
} else {
fmt.Println("EventLink: <not available>")
}
}

}
fmt.Println(eventStringBuilder.String())
}

// PrintFormat allows the user to specify which fields to print.
// Allows to print cloudtrail event url link
func PrintFormat(filterEvents []types.Event, printUrl bool, printRaw bool, table []string) {
var eventStringBuilder = strings.Builder{}
tableFilter := map[string]struct{}{}

for _, field := range table {
tableFilter[field] = struct{}{}
}

for i := len(filterEvents) - 1; i >= 0; i-- {

rawEventDetails, err := ExtractUserDetails(filterEvents[i].CloudTrailEvent)
if err != nil {
fmt.Printf("[Error] Error extracting event details: %v", err)
}
sessionIssuer := rawEventDetails.UserIdentity.SessionContext.SessionIssuer.UserName
eventStringBuilder.WriteString("\n")
if _, ok := tableFilter["event"]; ok && filterEvents[i].EventName != nil {
eventStringBuilder.WriteString(fmt.Sprintf("%v | ", *filterEvents[i].EventName))
}
if _, ok := tableFilter["time"]; ok && filterEvents[i].EventTime != nil {
eventStringBuilder.WriteString(fmt.Sprintf("%v | ", filterEvents[i].EventTime.String()))
}
if _, ok := tableFilter["username"]; ok && filterEvents[i].Username != nil {
eventStringBuilder.WriteString(fmt.Sprintf("Username: %v | ", *filterEvents[i].Username))
}
if _, ok := tableFilter["arn"]; ok && sessionIssuer != "" {
eventStringBuilder.WriteString(fmt.Sprintf("ARN: %v | ", sessionIssuer))
}

for _, resource := range filterEvents[i].Resources {
if _, ok := tableFilter["resource-name"]; ok && resource.ResourceName != nil {
eventStringBuilder.WriteString(fmt.Sprintf("Resource Name: %v | ", *resource.ResourceName))
}
if _, ok := tableFilter["resource-type"]; ok && resource.ResourceType != nil {
eventStringBuilder.WriteString(fmt.Sprintf("Resource Type: %v | ", *resource.ResourceType))
}
}

if printUrl && filterEvents[i].CloudTrailEvent != nil {
if err == nil {
eventStringBuilder.WriteString(fmt.Sprintf("%v", generateLink(*rawEventDetails)))
} else {
fmt.Println("EventLink: <not available>")
}
}

}
fmt.Println(eventStringBuilder.String())
}

// generateLink generates a hyperlink to aws cloudTrail event
// based on the provided RawEventDetails.
func generateLink(raw RawEventDetails) (url_link string) {
str1 := "https://"
str2 := ".console.aws.amazon.com/cloudtrailv2/home?region="
str3 := "#/events/"

eventRegion := raw.EventRegion
eventId := raw.EventId

var url = str1 + eventRegion + str2 + eventRegion + str3 + eventId
url_link = url

return url_link
}

// ValidateTable checks for the string list given and returns error
// if it does not match.
func ValidateFormat(table []string) error {
allowedKeys := map[string]struct{}{
"username": {},
"event": {},
"resource-name": {},
"resource-type": {},
"arn": {},
"time": {},
}

for _, column := range table {
if _, ok := allowedKeys[strings.ToLower(column)]; !ok {
return fmt.Errorf("invalid table column: %s (allowed: username, event, resource-name, resource-type, arn, time, url, region)", column)
}
}

return nil
}
Loading