Skip to content

Commit

Permalink
write instance and preflight reports to a secret (#4105)
Browse files Browse the repository at this point in the history
  • Loading branch information
Craig O'Donnell authored Oct 27, 2023
1 parent e9c55bc commit aa429aa
Show file tree
Hide file tree
Showing 16 changed files with 840 additions and 479 deletions.
2 changes: 1 addition & 1 deletion pkg/api/reporting/types/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ type ReportingInfo struct {
KurlNodeCountReady int `json:"kurl_node_count_ready"`
K8sVersion string `json:"k8s_version"`
K8sDistribution string `json:"k8s_distribution"`
KOTSVersion string `json:"kots_version"`
UserAgent string `json:"user_agent"`
KOTSInstallID string `json:"kots_install_id"`
KURLInstallID string `json:"kurl_install_id"`
IsGitOpsEnabled bool `json:"is_gitops_enabled"`
Expand Down
2 changes: 1 addition & 1 deletion pkg/handlers/preflight.go
Original file line number Diff line number Diff line change
Expand Up @@ -366,7 +366,7 @@ func (h *Handler) PreflightsReports(w http.ResponseWriter, r *http.Request) {

go func() {
if err := reporting.GetReporter().SubmitPreflightData(license, foundApp.ID, clusterID, 0, true, "", false, "", ""); err != nil {
logger.Debugf("failed to send preflights data to replicated app: %v", err)
logger.Debugf("failed to submit preflight data: %v", err)
return
}
}()
Expand Down
11 changes: 9 additions & 2 deletions pkg/reporting/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,14 @@ func Init() error {
}

if kotsadm.IsAirgap() {
reporter = &AirgapReporter{}
clientset, err := k8sutil.GetClientset()
if err != nil {
return errors.Wrap(err, "failed to get clientset")
}
reporter = &AirgapReporter{
clientset: clientset,
store: store.GetStore(),
}
} else {
reporter = &OnlineReporter{}
}
Expand Down Expand Up @@ -175,7 +182,7 @@ func GetReportingInfo(appID string) *types.ReportingInfo {
InstanceID: appID,
KOTSInstallID: os.Getenv("KOTS_INSTALL_ID"),
KURLInstallID: os.Getenv("KURL_INSTALL_ID"),
KOTSVersion: buildversion.Version(),
UserAgent: buildversion.GetUserAgent(),
}

clientset, err := k8sutil.GetClientset()
Expand Down
62 changes: 54 additions & 8 deletions pkg/reporting/app_airgap.go
Original file line number Diff line number Diff line change
@@ -1,29 +1,75 @@
package reporting

import (
"strconv"
"time"

"github.com/pkg/errors"
"github.com/replicatedhq/kots/pkg/store"
"github.com/replicatedhq/kots/pkg/api/reporting/types"
"github.com/replicatedhq/kots/pkg/logger"
"github.com/replicatedhq/kots/pkg/util"
)

func (r *AirgapReporter) SubmitAppInfo(appID string) error {
a, err := store.GetStore().GetApp(appID)
a, err := r.store.GetApp(appID)
if err != nil {
if store.GetStore().IsNotFound(err) {
if r.store.IsNotFound(err) {
return nil
}
return errors.Wrap(err, "failed to get airgaped app")
return errors.Wrap(err, "failed to get airgapped app")
}

license, err := store.GetStore().GetLatestLicenseForApp(a.ID)
license, err := r.store.GetLatestLicenseForApp(a.ID)
if err != nil {
return errors.Wrap(err, "failed to get license for airgapped app")
}
reportingInfo := GetReportingInfo(appID)

err = store.GetStore().SaveReportingInfo(license.Spec.LicenseID, reportingInfo)
if err != nil {
return errors.Wrap(err, "failed to save reporting info")
report := BuildInstanceReport(license.Spec.LicenseID, reportingInfo)

if err := AppendReport(r.clientset, util.PodNamespace, a.Slug, report); err != nil {
return errors.Wrap(err, "failed to append instance report")
}

return nil
}

func BuildInstanceReport(licenseID string, reportingInfo *types.ReportingInfo) *InstanceReport {
// not using the "cursor" packages because it doesn't provide access to the underlying int64
downstreamSequence, err := strconv.ParseUint(reportingInfo.Downstream.Cursor, 10, 64)
if err != nil {
logger.Debugf("failed to parse downstream cursor %q: %v", reportingInfo.Downstream.Cursor, err)
}

return &InstanceReport{
Events: []InstanceReportEvent{
{
ReportedAt: time.Now().UTC().UnixMilli(),
LicenseID: licenseID,
InstanceID: reportingInfo.InstanceID,
ClusterID: reportingInfo.ClusterID,
AppStatus: reportingInfo.AppStatus,
IsKurl: reportingInfo.IsKurl,
KurlNodeCountTotal: reportingInfo.KurlNodeCountTotal,
KurlNodeCountReady: reportingInfo.KurlNodeCountReady,
K8sVersion: reportingInfo.K8sVersion,
K8sDistribution: reportingInfo.K8sDistribution,
UserAgent: reportingInfo.UserAgent,
KotsInstallID: reportingInfo.KOTSInstallID,
KurlInstallID: reportingInfo.KURLInstallID,
IsGitOpsEnabled: reportingInfo.IsGitOpsEnabled,
GitOpsProvider: reportingInfo.GitOpsProvider,
DownstreamChannelID: reportingInfo.Downstream.ChannelID,
DownstreamChannelSequence: downstreamSequence,
DownstreamChannelName: reportingInfo.Downstream.ChannelName,
DownstreamSequence: reportingInfo.Downstream.Sequence,
DownstreamSource: reportingInfo.Downstream.Source,
InstallStatus: reportingInfo.Downstream.Status,
PreflightState: reportingInfo.Downstream.PreflightState,
SkipPreflights: reportingInfo.Downstream.SkipPreflights,
ReplHelmInstalls: reportingInfo.Downstream.ReplHelmInstalls,
NativeHelmInstalls: reportingInfo.Downstream.NativeHelmInstalls,
},
},
}
}
76 changes: 76 additions & 0 deletions pkg/reporting/instance_report.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package reporting

import (
"fmt"
"sync"

"github.com/pkg/errors"
)

var instanceReportMtx = sync.Mutex{}

type InstanceReport struct {
Events []InstanceReportEvent `json:"events"`
}

type InstanceReportEvent struct {
ReportedAt int64 `json:"reported_at"`
LicenseID string `json:"license_id"`
InstanceID string `json:"instance_id"`
ClusterID string `json:"cluster_id"`
AppStatus string `json:"app_status"`
IsKurl bool `json:"is_kurl"`
KurlNodeCountTotal int `json:"kurl_node_count_total"`
KurlNodeCountReady int `json:"kurl_node_count_ready"`
K8sVersion string `json:"k8s_version"`
K8sDistribution string `json:"k8s_distribution,omitempty"`
UserAgent string `json:"user_agent"`
KotsInstallID string `json:"kots_install_id,omitempty"`
KurlInstallID string `json:"kurl_install_id,omitempty"`
IsGitOpsEnabled bool `json:"is_gitops_enabled"`
GitOpsProvider string `json:"gitops_provider"`
DownstreamChannelID string `json:"downstream_channel_id,omitempty"`
DownstreamChannelSequence uint64 `json:"downstream_channel_sequence,omitempty"`
DownstreamChannelName string `json:"downstream_channel_name,omitempty"`
DownstreamSequence *int64 `json:"downstream_sequence,omitempty"`
DownstreamSource string `json:"downstream_source,omitempty"`
InstallStatus string `json:"install_status,omitempty"`
PreflightState string `json:"preflight_state,omitempty"`
SkipPreflights bool `json:"skip_preflights"`
ReplHelmInstalls int `json:"repl_helm_installs"`
NativeHelmInstalls int `json:"native_helm_installs"`
}

func (r *InstanceReport) GetType() ReportType {
return ReportTypeInstance
}

func (r *InstanceReport) GetSecretName(appSlug string) string {
return fmt.Sprintf(ReportSecretNameFormat, fmt.Sprintf("%s-%s", appSlug, r.GetType()))
}

func (r *InstanceReport) GetSecretKey() string {
return ReportSecretKey
}

func (r *InstanceReport) AppendEvents(report Report) error {
reportToAppend, ok := report.(*InstanceReport)
if !ok {
return errors.Errorf("report is not an instance report")
}

r.Events = append(r.Events, reportToAppend.Events...)
if len(r.Events) > r.GetEventLimit() {
r.Events = r.Events[len(r.Events)-r.GetEventLimit():]
}

return nil
}

func (r *InstanceReport) GetEventLimit() int {
return ReportEventLimit
}

func (r *InstanceReport) GetMtx() *sync.Mutex {
return &instanceReportMtx
}
2 changes: 1 addition & 1 deletion pkg/reporting/preflight.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ func WaitAndReportPreflightChecks(appID string, sequence int64, isSkipPreflights
}

if err := GetReporter().SubmitPreflightData(license, appID, clusterID, sequence, isSkipPreflights, currentVersionStatus, isCLI, preflightState, string(appStatus)); err != nil {
logger.Debugf("failed to send preflights data to replicated app: %v", err)
logger.Debugf("failed to submit preflight data: %v", err)
return
}
}()
Expand Down
45 changes: 30 additions & 15 deletions pkg/reporting/preflight_airgap.go
Original file line number Diff line number Diff line change
@@ -1,29 +1,44 @@
package reporting

import (
"time"

"github.com/pkg/errors"
reportingtypes "github.com/replicatedhq/kots/pkg/api/reporting/types"
"github.com/replicatedhq/kots/pkg/buildversion"
"github.com/replicatedhq/kots/pkg/store"
storetypes "github.com/replicatedhq/kots/pkg/store/types"
"github.com/replicatedhq/kots/pkg/util"
kotsv1beta1 "github.com/replicatedhq/kotskinds/apis/kots/v1beta1"
)

func (r *AirgapReporter) SubmitPreflightData(license *kotsv1beta1.License, appID string, clusterID string, sequence int64, skipPreflights bool, installStatus storetypes.DownstreamVersionStatus, isCLI bool, preflightStatus string, appStatus string) error {
status := &reportingtypes.PreflightStatus{
InstanceID: appID,
ClusterID: clusterID,
Sequence: sequence,
SkipPreflights: skipPreflights,
InstallStatus: string(installStatus),
IsCLI: isCLI,
PreflightStatus: preflightStatus,
AppStatus: preflightStatus,
KOTSVersion: buildversion.Version(),
}
err := store.GetStore().SavePreflightReport(license.Spec.LicenseID, status)
app, err := r.store.GetApp(appID)
if err != nil {
return errors.Wrap(err, "failed to save preflight report")
if r.store.IsNotFound(err) {
return nil
}
return errors.Wrap(err, "failed to get airgapped app")
}

report := &PreflightReport{
Events: []PreflightReportEvent{
{
ReportedAt: time.Now().UTC().UnixMilli(),
LicenseID: license.Spec.LicenseID,
InstanceID: appID,
ClusterID: clusterID,
Sequence: sequence,
SkipPreflights: skipPreflights,
InstallStatus: string(installStatus),
IsCLI: isCLI,
PreflightStatus: preflightStatus,
AppStatus: appStatus,
UserAgent: buildversion.GetUserAgent(),
},
},
}

if err := AppendReport(r.clientset, util.PodNamespace, app.Slug, report); err != nil {
return errors.Wrap(err, "failed to append preflight report")
}

return nil
Expand Down
62 changes: 62 additions & 0 deletions pkg/reporting/preflight_report.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package reporting

import (
"fmt"
"sync"

"github.com/pkg/errors"
)

var preflightReportMtx = sync.Mutex{}

type PreflightReport struct {
Events []PreflightReportEvent `json:"events"`
}

type PreflightReportEvent struct {
ReportedAt int64 `json:"reported_at"`
LicenseID string `json:"license_id"`
InstanceID string `json:"instance_id"`
ClusterID string `json:"cluster_id"`
Sequence int64 `json:"sequence"`
SkipPreflights bool `json:"skip_preflights"`
InstallStatus string `json:"install_status"`
IsCLI bool `json:"is_cli"`
PreflightStatus string `json:"preflight_status"`
AppStatus string `json:"app_status"`
UserAgent string `json:"user_agent"`
}

func (r *PreflightReport) GetType() ReportType {
return ReportTypePreflight
}

func (r *PreflightReport) GetSecretName(appSlug string) string {
return fmt.Sprintf(ReportSecretNameFormat, fmt.Sprintf("%s-%s", appSlug, r.GetType()))
}

func (r *PreflightReport) GetSecretKey() string {
return ReportSecretKey
}

func (r *PreflightReport) AppendEvents(report Report) error {
reportToAppend, ok := report.(*PreflightReport)
if !ok {
return errors.Errorf("report is not a preflight report")
}

r.Events = append(r.Events, reportToAppend.Events...)
if len(r.Events) > r.GetEventLimit() {
r.Events = r.Events[len(r.Events)-r.GetEventLimit():]
}

return nil
}

func (r *PreflightReport) GetEventLimit() int {
return ReportEventLimit
}

func (r *PreflightReport) GetMtx() *sync.Mutex {
return &preflightReportMtx
}
Loading

0 comments on commit aa429aa

Please sign in to comment.