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

support managed SDK deployment #89

Merged
merged 8 commits into from
Oct 6, 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
7 changes: 7 additions & 0 deletions .github/workflows/main.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,13 @@ jobs:
exit 1
fi

output=$(helm template oci://ttl.sh/automated-${{ github.run_id }}/replicated --version 0.0.0 --set userAgent=test-user-agent)

if ! echo $output | grep -q 'value: "test-user-agent"'; then
printf "user-set userAgent should exist:\n\n%s\n\n" "$output"
exit 1
fi

cat << EOF >> test-values.yaml
extraEnv:
- name: TEST_EXTRA_ENV
Expand Down
4 changes: 4 additions & 0 deletions chart/templates/replicated-deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ spec:
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: DISABLE_OUTBOUND_CONNECTIONS
value: {{ .Values.isAirgap | default "false" | quote }}
- name: IS_HELM_MANAGED
value: "true"
- name: HELM_RELEASE_NAME
Expand All @@ -83,6 +85,8 @@ spec:
name: {{ include "replicated.secretName" . }}
key: integration-license-id
{{- end }}
- name: REPLICATED_USER_AGENT
value: {{ .Values.userAgent | default "" | quote }}
ports:
- containerPort: 3000
name: http
Expand Down
2 changes: 2 additions & 0 deletions chart/templates/replicated-secret.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ stringData:
statusInformers:
{{- .Values.statusInformers | toYaml | nindent 6 }}
{{- end }}
replicatedID: {{ .Values.replicatedID | default "" | quote }}
appID: {{ .Values.appID | default "" | quote }}
{{- if (.Values.integration).licenseID }}
integration-license-id: {{ .Values.integration.licenseID }}
{{- end }}
Expand Down
6 changes: 6 additions & 0 deletions chart/values.yaml.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,9 @@ integration:
licenseID: ""
# enabled: false
mockData: ""

isAirgap: false

userAgent: ""
replicatedID: ""
appID: ""
22 changes: 4 additions & 18 deletions cmd/replicated/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,8 @@ import (
"strings"

"github.com/pkg/errors"
kotsv1beta1 "github.com/replicatedhq/kotskinds/apis/kots/v1beta1"
"github.com/replicatedhq/replicated-sdk/pkg/apiserver"
"github.com/replicatedhq/replicated-sdk/pkg/config"
sdklicense "github.com/replicatedhq/replicated-sdk/pkg/license"
"github.com/replicatedhq/replicated-sdk/pkg/logger"
"github.com/spf13/cobra"
"github.com/spf13/viper"
Expand Down Expand Up @@ -38,7 +36,6 @@ func APICmd() *cobra.Command {
return errors.New("either config file or integration license id must be specified")
}

var err error
var replicatedConfig = new(config.ReplicatedConfig)
if configFilePath != "" {
configFile, err := os.ReadFile(configFilePath)
Expand All @@ -59,23 +56,10 @@ func APICmd() *cobra.Command {
return errors.New("only one of license in the config file or integration license id can be specified")
}

var license *kotsv1beta1.License
if replicatedConfig.License != "" {
if license, err = sdklicense.LoadLicenseFromBytes([]byte(replicatedConfig.License)); err != nil {
return errors.Wrap(err, "failed to parse license from base64")
}
} else if integrationLicenseID != "" {
if license, err = sdklicense.GetLicenseByID(integrationLicenseID, replicatedConfig.ReplicatedAppEndpoint); err != nil {
return errors.Wrap(err, "failed to get license by id for integration license id")
}
if license.Spec.LicenseType != "dev" {
return errors.New("integration license must be a dev license")
}
}

params := apiserver.APIServerParams{
Context: cmd.Context(),
License: license,
LicenseBytes: []byte(replicatedConfig.License),
IntegrationLicenseID: integrationLicenseID,
LicenseFields: replicatedConfig.LicenseFields,
AppName: replicatedConfig.AppName,
ChannelID: replicatedConfig.ChannelID,
Expand All @@ -87,6 +71,8 @@ func APICmd() *cobra.Command {
VersionLabel: replicatedConfig.VersionLabel,
ReplicatedAppEndpoint: replicatedConfig.ReplicatedAppEndpoint,
StatusInformers: replicatedConfig.StatusInformers,
ReplicatedID: replicatedConfig.ReplicatedID,
AppID: replicatedConfig.AppID,
Namespace: namespace,
}
apiserver.Start(params)
Expand Down
4 changes: 1 addition & 3 deletions pact/custom_metrics_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,7 @@ func TestSendCustomApplicationMetrics(t *testing.T) {
ChannelID: license.Spec.ChannelID,
ChannelSequence: channelSequence,
}
if err := store.InitInMemory(storeOptions); err != nil {
t.Fatalf("Error on InitInMemory: %v", err)
}
store.InitInMemory(storeOptions)
defer store.SetStore(nil)

if err := pact.Verify(func() error {
Expand Down
66 changes: 43 additions & 23 deletions pkg/apiserver/bootstrap.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package apiserver
import (
"github.com/cenkalti/backoff/v4"
"github.com/pkg/errors"
kotsv1beta1 "github.com/replicatedhq/kotskinds/apis/kots/v1beta1"
"github.com/replicatedhq/replicated-sdk/pkg/appstate"
appstatetypes "github.com/replicatedhq/replicated-sdk/pkg/appstate/types"
"github.com/replicatedhq/replicated-sdk/pkg/heartbeat"
Expand All @@ -18,7 +19,45 @@ import (
)

func bootstrap(params APIServerParams) error {
verifiedLicense, err := sdklicense.VerifySignature(params.License)
clientset, err := k8sutil.GetClientset()
if err != nil {
return errors.Wrap(err, "failed to get clientset")
}

replicatedID, appID := params.ReplicatedID, params.AppID
if replicatedID == "" || appID == "" {
// retrieve replicated and app ids
replicatedID, appID, err = util.GetReplicatedAndAppIDs(clientset, params.Namespace)
if err != nil {
return errors.Wrap(err, "failed to get replicated and app ids")
}
}
if replicatedID == "" {
return backoff.Permanent(errors.New("Replicated ID not found"))
}
if appID == "" {
return backoff.Permanent(errors.New("App ID not found"))
}

var unverifiedLicense *kotsv1beta1.License
if len(params.LicenseBytes) > 0 {
l, err := sdklicense.LoadLicenseFromBytes(params.LicenseBytes)
if err != nil {
return errors.Wrap(err, "failed to parse license from base64")
}
unverifiedLicense = l
} else if params.IntegrationLicenseID != "" {
l, err := sdklicense.GetLicenseByID(params.IntegrationLicenseID, params.ReplicatedAppEndpoint)
if err != nil {
return backoff.Permanent(errors.Wrap(err, "failed to get license by id for integration license id"))
}
if l.Spec.LicenseType != "dev" {
return errors.New("integration license must be a dev license")
}
unverifiedLicense = l
}

verifiedLicense, err := sdklicense.VerifySignature(unverifiedLicense)
if err != nil {
return backoff.Permanent(errors.Wrap(err, "failed to verify license signature"))
}
Expand All @@ -41,18 +80,6 @@ func bootstrap(params APIServerParams) error {
return backoff.Permanent(errors.New("License is expired"))
}

// retrieve replicated and app ids
replicatedID, appID, err := util.GetReplicatedAndAppIDs(params.Namespace)
if err != nil {
return errors.Wrap(err, "failed to get replicated and app ids")
}
if replicatedID == "" {
return backoff.Permanent(errors.New("Replicated ID not found"))
}
if appID == "" {
return backoff.Permanent(errors.New("App ID not found"))
}

channelID := params.ChannelID
if channelID == "" {
channelID = verifiedLicense.Spec.ChannelID
Expand All @@ -64,8 +91,6 @@ func bootstrap(params APIServerParams) error {
}

storeOptions := store.InitInMemoryStoreOptions{
ReplicatedID: replicatedID,
AppID: appID,
License: verifiedLicense,
LicenseFields: params.LicenseFields,
AppName: params.AppName,
Expand All @@ -78,15 +103,10 @@ func bootstrap(params APIServerParams) error {
VersionLabel: params.VersionLabel,
ReplicatedAppEndpoint: params.ReplicatedAppEndpoint,
Namespace: params.Namespace,
ReplicatedID: replicatedID,
AppID: appID,
}
if err := store.InitInMemory(storeOptions); err != nil {
return errors.Wrap(err, "failed to init store")
}

clientset, err := k8sutil.GetClientset()
if err != nil {
return errors.Wrap(err, "failed to get clientset")
}
store.InitInMemory(storeOptions)

isIntegrationModeEnabled, err := integration.IsEnabled(params.Context, clientset, store.GetStore().GetNamespace(), store.GetStore().GetLicense())
if err != nil {
Expand Down
6 changes: 4 additions & 2 deletions pkg/apiserver/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import (

"github.com/cenkalti/backoff/v4"
"github.com/gorilla/mux"
kotsv1beta1 "github.com/replicatedhq/kotskinds/apis/kots/v1beta1"
appstatetypes "github.com/replicatedhq/replicated-sdk/pkg/appstate/types"
"github.com/replicatedhq/replicated-sdk/pkg/buildversion"
"github.com/replicatedhq/replicated-sdk/pkg/handlers"
Expand All @@ -17,7 +16,8 @@ import (

type APIServerParams struct {
Context context.Context
License *kotsv1beta1.License
LicenseBytes []byte
IntegrationLicenseID string
LicenseFields sdklicensetypes.LicenseFields
AppName string
ChannelID string
Expand All @@ -29,6 +29,8 @@ type APIServerParams struct {
VersionLabel string
ReplicatedAppEndpoint string
StatusInformers []appstatetypes.StatusInformerString
ReplicatedID string
AppID string
Namespace string
}

Expand Down
4 changes: 4 additions & 0 deletions pkg/buildversion/buildversion.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package buildversion

import (
"fmt"
"os"
"runtime"
"time"
)
Expand Down Expand Up @@ -76,5 +77,8 @@ func getGoInfo() GoInfo {
}

func GetUserAgent() string {
if os.Getenv("REPLICATED_USER_AGENT") != "" {
return os.Getenv("REPLICATED_USER_AGENT")
}
return fmt.Sprintf("Replicated-SDK/%s", Version())
}
2 changes: 2 additions & 0 deletions pkg/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ type ReplicatedConfig struct {
VersionLabel string `yaml:"versionLabel"`
ReplicatedAppEndpoint string `yaml:"replicatedAppEndpoint"`
StatusInformers []appstatetypes.StatusInformerString `yaml:"statusInformers"`
ReplicatedID string `yaml:"replicatedID"`
AppID string `yaml:"appID"`
}

func ParseReplicatedConfig(config []byte) (*ReplicatedConfig, error) {
Expand Down
6 changes: 2 additions & 4 deletions pkg/store/memory_store.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,13 @@ type InitInMemoryStoreOptions struct {
Namespace string
}

func InitInMemory(options InitInMemoryStoreOptions) error {
func InitInMemory(options InitInMemoryStoreOptions) {
SetStore(&InMemoryStore{
replicatedID: options.ReplicatedID,
appID: options.AppID,
appSlug: options.License.Spec.AppSlug,
license: options.License,
licenseFields: options.LicenseFields,
appSlug: options.License.Spec.AppSlug,
appName: options.AppName,
channelID: options.ChannelID,
channelName: options.ChannelName,
Expand All @@ -62,8 +62,6 @@ func InitInMemory(options InitInMemoryStoreOptions) error {
replicatedAppEndpoint: options.ReplicatedAppEndpoint,
namespace: options.Namespace,
})

return nil
}

func (s *InMemoryStore) GetReplicatedID() string {
Expand Down
14 changes: 14 additions & 0 deletions pkg/store/mock/mock_store.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 2 additions & 7 deletions pkg/util/replicated.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ import (
"github.com/blang/semver"
"github.com/pkg/errors"
"github.com/replicatedhq/replicated-sdk/pkg/buildversion"
"github.com/replicatedhq/replicated-sdk/pkg/k8sutil"
"github.com/replicatedhq/replicated-sdk/pkg/logger"
kuberneteserrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
)

func GetLegacyReplicatedConfigMapName() string {
Expand All @@ -36,12 +36,7 @@ func GetReplicatedDeploymentName() string {
return "replicated"
}

func GetReplicatedAndAppIDs(namespace string) (string, string, error) {
clientset, err := k8sutil.GetClientset()
if err != nil {
return "", "", errors.Wrap(err, "failed to get clientset")
}

func GetReplicatedAndAppIDs(clientset kubernetes.Interface, namespace string) (string, string, error) {
cm, err := clientset.CoreV1().ConfigMaps(namespace).Get(context.TODO(), GetLegacyReplicatedConfigMapName(), metav1.GetOptions{})
if err != nil && !kuberneteserrors.IsNotFound(err) {
return "", "", errors.Wrap(err, "failed to get replicated-sdk configmap")
Expand Down
Loading