| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441 |
- package opencost
- import (
- "fmt"
- "strings"
- "github.com/opencost/opencost/core/pkg/util/promutil"
- )
- // AssetProperty is a kind of property belonging to an Asset
- type AssetProperty string
- const (
- // AssetNilProp is the zero-value of AssetProperty
- AssetNilProp AssetProperty = ""
- // AssetAccountProp describes the account of the Asset
- AssetAccountProp AssetProperty = "account"
- // AssetCategoryProp describes the category of the Asset
- AssetCategoryProp AssetProperty = "category"
- // AssetClusterProp describes the cluster of the Asset
- AssetClusterProp AssetProperty = "cluster"
- // AssetNameProp describes the name of the Asset
- AssetNameProp AssetProperty = "name"
- // AssetNodeProp describes the node of the Asset
- AssetNodeProp AssetProperty = "node"
- // AssetProjectProp describes the project of the Asset
- AssetProjectProp AssetProperty = "project"
- // AssetProviderProp describes the provider of the Asset
- AssetProviderProp AssetProperty = "provider"
- // AssetProviderIDProp describes the providerID of the Asset
- AssetProviderIDProp AssetProperty = "providerID"
- // AssetServiceProp describes the service of the Asset
- AssetServiceProp AssetProperty = "service"
- // AssetTypeProp describes the type of the Asset
- AssetTypeProp AssetProperty = "type"
- // AssetLabelProp describes a single label within an Asset.
- AssetLabelProp AssetProperty = "label"
- // AssetDepartmentProp describes the department of the Asset
- AssetDepartmentProp AssetProperty = "department"
- // AssetEnvironmentProp describes the environment of the Asset
- AssetEnvironmentProp AssetProperty = "environment"
- // AssetOwnerProp describes the owner of the Asset
- AssetOwnerProp AssetProperty = "owner"
- // AssetProductProp describes the product of the Asset
- AssetProductProp AssetProperty = "product"
- // AssetTeamProp describes the team of the Asset
- AssetTeamProp AssetProperty = "team"
- )
- // IsLabel returns true if the allocation property has a label prefix
- func (apt *AssetProperty) IsLabel() bool {
- return strings.HasPrefix(string(*apt), "label:")
- }
- // GetLabel returns the label string associated with the label property if it exists.
- // Otherwise, empty string is returned.
- func (apt *AssetProperty) GetLabel() string {
- if apt.IsLabel() {
- return strings.TrimSpace(strings.TrimPrefix(string(*apt), "label:"))
- }
- return ""
- }
- func ParseAssetProperties(values []string) ([]AssetProperty, error) {
- props := []AssetProperty{}
- for _, value := range values {
- p, err := ParseAssetProperty(value)
- if err != nil {
- return nil, err
- }
- props = append(props, p)
- }
- return props, nil
- }
- // ParseAssetProperty attempts to parse a string into an AssetProperty
- func ParseAssetProperty(text string) (AssetProperty, error) {
- switch strings.TrimSpace(strings.ToLower(text)) {
- case "account":
- return AssetAccountProp, nil
- case "category":
- return AssetCategoryProp, nil
- case "cluster":
- return AssetClusterProp, nil
- case "name":
- return AssetNameProp, nil
- case "project":
- return AssetProjectProp, nil
- case "provider":
- return AssetProviderProp, nil
- case "providerid":
- return AssetProviderIDProp, nil
- case "service":
- return AssetServiceProp, nil
- case "type":
- return AssetTypeProp, nil
- case "department":
- return AssetDepartmentProp, nil
- case "environment":
- return AssetEnvironmentProp, nil
- case "owner":
- return AssetOwnerProp, nil
- case "product":
- return AssetProductProp, nil
- case "team":
- return AssetTeamProp, nil
- }
- if strings.HasPrefix(text, "label:") {
- label := promutil.SanitizeLabelName(strings.TrimSpace(strings.TrimPrefix(text, "label:")))
- return AssetProperty(fmt.Sprintf("label:%s", label)), nil
- }
- return AssetNilProp, fmt.Errorf("invalid asset property: %s", text)
- }
- // Category options
- // ComputeCategory signifies the Compute Category
- const ComputeCategory = "Compute"
- // StorageCategory signifies the Storage Category
- const StorageCategory = "Storage"
- // NetworkCategory signifies the Network Category
- const NetworkCategory = "Network"
- // ManagementCategory signifies the Management Category
- const ManagementCategory = "Management"
- // SharedCategory signifies an unassigned Category
- const SharedCategory = "Shared"
- // OtherCategory signifies an unassigned Category
- const OtherCategory = "Other"
- // Provider options
- // AWSProvider describes the provider AWS
- const AWSProvider = "AWS"
- // describes how AWS labels nodepool nodes
- const EKSNodepoolLabel = "eks.amazonaws.com/nodegroup"
- // GCPProvider describes the provider GCP
- const GCPProvider = "GCP"
- // describes how nodepool nodes are labeled in GKE
- const GKENodePoolLabel = "cloud.google.com/gke-nodepool"
- // AzureProvider describes the provider Azure
- const AzureProvider = "Azure"
- // describes how Azure labels nodepool nodes
- const AKSNodepoolLabel = "kubernetes.azure.com/agentpool"
- // AlibabaProvider describes the provider for Alibaba Cloud
- const AlibabaProvider = "Alibaba"
- // CSVProvider describes the provider a CSV
- const CSVProvider = "CSV"
- // CustomProvider describes a custom provider
- const CustomProvider = "custom"
- // ScalewayProvider describes the provider Scaleway
- const ScalewayProvider = "Scaleway"
- // OracleProvider describes the provider Oracle
- const OracleProvider = "Oracle"
- // OTCProvider describes the provider OTC
- const OTCProvider = "OTC"
- // DigitalOceanProvider describes the provider DigitalOcean
- const DigitalOceanProvider = "DigitalOcean"
- // OVHProvider describes the provider OVH
- const OVHProvider = "OVH"
- // NilProvider describes unknown provider
- const NilProvider = "-"
- // Service options
- const KubernetesService = "Kubernetes"
- // ParseProvider attempts to parse and return a known provider, given a string
- func ParseProvider(str string) string {
- switch strings.ToLower(strings.TrimSpace(str)) {
- case "aws", "eks", "amazon":
- return AWSProvider
- case "gcp", "gke", "google":
- return GCPProvider
- case "azure":
- return AzureProvider
- case "scaleway", "scw", "kapsule":
- return ScalewayProvider
- case "oci", "oracle":
- return OracleProvider
- case "digitalocean", "doks", "do":
- return DigitalOceanProvider
- case "ovh", "ovhcloud", "ovh-mks":
- return OVHProvider
- default:
- return NilProvider
- }
- }
- // AssetProperties describes all properties assigned to an Asset.
- type AssetProperties struct {
- Category string `json:"category,omitempty"`
- Provider string `json:"provider,omitempty"`
- Account string `json:"account,omitempty"`
- Project string `json:"project,omitempty"`
- Service string `json:"service,omitempty"`
- Cluster string `json:"cluster,omitempty"`
- Name string `json:"name,omitempty"`
- ProviderID string `json:"providerID,omitempty"`
- }
- // Clone returns a cloned instance of the given AssetProperties
- func (ap *AssetProperties) Clone() *AssetProperties {
- if ap == nil {
- return nil
- }
- clone := &AssetProperties{}
- clone.Category = ap.Category
- clone.Provider = ap.Provider
- clone.Account = ap.Account
- clone.Project = ap.Project
- clone.Service = ap.Service
- clone.Cluster = ap.Cluster
- clone.Name = ap.Name
- clone.ProviderID = ap.ProviderID
- return clone
- }
- // Equal returns true only if both AssetProperties are matches
- func (ap *AssetProperties) Equal(that *AssetProperties) bool {
- if ap == nil && that == nil {
- return true
- }
- if ap == nil || that == nil {
- return false
- }
- if ap.Category != that.Category {
- return false
- }
- if ap.Provider != that.Provider {
- return false
- }
- if ap.Account != that.Account {
- return false
- }
- if ap.Project != that.Project {
- return false
- }
- if ap.Service != that.Service {
- return false
- }
- if ap.Cluster != that.Cluster {
- return false
- }
- if ap.Name != that.Name {
- return false
- }
- if ap.ProviderID != that.ProviderID {
- return false
- }
- return true
- }
- // Keys returns the list of string values used to key the Asset based on the
- // list of properties provided.
- func (ap *AssetProperties) Keys(props []AssetProperty) []string {
- keys := []string{}
- if ap == nil {
- return keys
- }
- if (props == nil || hasProp(props, AssetCategoryProp)) && ap.Category != "" {
- keys = append(keys, ap.Category)
- }
- if (props == nil || hasProp(props, AssetProviderProp)) && ap.Provider != "" {
- keys = append(keys, ap.Provider)
- }
- if (props == nil || hasProp(props, AssetAccountProp)) && ap.Account != "" {
- keys = append(keys, ap.Account)
- }
- if (props == nil || hasProp(props, AssetProjectProp)) && ap.Project != "" {
- keys = append(keys, ap.Project)
- }
- if (props == nil || hasProp(props, AssetServiceProp)) && ap.Service != "" {
- keys = append(keys, ap.Service)
- }
- if (props == nil || hasProp(props, AssetClusterProp)) && ap.Cluster != "" {
- keys = append(keys, ap.Cluster)
- }
- if (props == nil || hasProp(props, AssetNameProp)) && ap.Name != "" {
- keys = append(keys, ap.Name)
- }
- if (props == nil || hasProp(props, AssetProviderIDProp)) && ap.ProviderID != "" {
- keys = append(keys, ap.ProviderID)
- }
- return keys
- }
- // Merge retains only the properties shared with the given AssetProperties
- func (ap *AssetProperties) Merge(that *AssetProperties) *AssetProperties {
- if ap == nil || that == nil {
- return nil
- }
- result := &AssetProperties{}
- if ap.Category == that.Category {
- result.Category = ap.Category
- }
- if ap.Provider == that.Provider {
- result.Provider = ap.Provider
- }
- if ap.Account == that.Account {
- result.Account = ap.Account
- }
- if ap.Project == that.Project {
- result.Project = ap.Project
- }
- if ap.Service == that.Service {
- result.Service = ap.Service
- }
- if ap.Cluster == that.Cluster {
- result.Cluster = ap.Cluster
- }
- if ap.Name == that.Name {
- result.Name = ap.Name
- }
- if ap.ProviderID == that.ProviderID {
- result.ProviderID = ap.ProviderID
- }
- return result
- }
- // String represents the properties as a string
- func (ap *AssetProperties) String() string {
- if ap == nil {
- return "<nil>"
- }
- strs := []string{}
- if ap.Category != "" {
- strs = append(strs, "Category:"+ap.Category)
- }
- if ap.Provider != "" {
- strs = append(strs, "Provider:"+ap.Provider)
- }
- if ap.Account != "" {
- strs = append(strs, "Account:"+ap.Account)
- }
- if ap.Project != "" {
- strs = append(strs, "Project:"+ap.Project)
- }
- if ap.Service != "" {
- strs = append(strs, "Service:"+ap.Service)
- }
- if ap.Cluster != "" {
- strs = append(strs, "Cluster:"+ap.Cluster)
- }
- if ap.Name != "" {
- strs = append(strs, "Name:"+ap.Name)
- }
- if ap.ProviderID != "" {
- strs = append(strs, "ProviderID:"+ap.ProviderID)
- }
- return strings.Join(strs, ",")
- }
- func hasProp(props []AssetProperty, prop AssetProperty) bool {
- for _, p := range props {
- if p == prop {
- return true
- }
- }
- return false
- }
|