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

write instance and preflight reports to a secret #4105

Merged
merged 6 commits into from
Oct 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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 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)
cbodonnell marked this conversation as resolved.
Show resolved Hide resolved
}

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
Loading