github.com/Axway/agent-sdk@v1.1.101/pkg/apic/apiserver/models/api/v1/resourcemeta.go (about)

     1  package v1
     2  
     3  import (
     4  	"encoding/json"
     5  	"strings"
     6  )
     7  
     8  const (
     9  	ResourceDeleting = "DELETING"
    10  	Inactive         = "inactive"
    11  	Active           = "active"
    12  )
    13  
    14  // Meta interface for API Server resource metadata
    15  type Meta interface {
    16  	GetName() string
    17  	GetGroupVersionKind() GroupVersionKind
    18  	GetMetadata() Metadata
    19  	SetScopeName(string)
    20  	GetAttributes() map[string]string
    21  	SetAttributes(map[string]string)
    22  	GetTags() []string
    23  	SetTags([]string)
    24  	GetSubResource(key string) interface{}
    25  	SetSubResource(key string, resource interface{})
    26  	GetReferenceByGVK(GroupVersionKind) Reference
    27  }
    28  
    29  // ResourceMeta metadata for a ResourceInstance
    30  type ResourceMeta struct {
    31  	GroupVersionKind
    32  	Name  string `json:"name,omitempty"`
    33  	Title string `json:"title,omitempty"`
    34  	// Metadata the metadata for the resource
    35  	Metadata Metadata `json:"metadata,omitempty"`
    36  	// Custom attributes for a resource.
    37  	Attributes map[string]string `json:"attributes"`
    38  	// List of tags.
    39  	Tags []string `json:"tags"`
    40  	// Finalizer on the API server resource
    41  	Finalizers []Finalizer `json:"finalizers"`
    42  	// SubResources contains all of the unique sub resources that may be added to a resource
    43  	SubResources map[string]interface{} `json:"-"`
    44  }
    45  
    46  // GetName gets the name of a resource
    47  func (rm *ResourceMeta) GetName() string {
    48  	if rm == nil {
    49  		return ""
    50  	}
    51  
    52  	return rm.Name
    53  }
    54  
    55  // SetName sets the name of a resource
    56  func (rm *ResourceMeta) SetName(name string) {
    57  	rm.Name = name
    58  }
    59  
    60  // SetScopeName sets the name of a resource
    61  func (rm *ResourceMeta) SetScopeName(name string) {
    62  	rm.Metadata.Scope.Name = name
    63  }
    64  
    65  // GetMetadata gets the resource metadata
    66  func (rm *ResourceMeta) GetMetadata() Metadata {
    67  	if rm == nil {
    68  		return Metadata{}
    69  	}
    70  
    71  	return rm.Metadata
    72  }
    73  
    74  // GetSelfLink gets the resource metadata selflink
    75  func (rm *ResourceMeta) GetSelfLink() string {
    76  	if rm == nil {
    77  		return ""
    78  	}
    79  
    80  	// return the self lnk if we have it
    81  	if rm.GetMetadata().SelfLink != "" {
    82  		return rm.Metadata.SelfLink
    83  	}
    84  
    85  	if kindLink := rm.GetKindLink(); kindLink != "" {
    86  		return strings.Join([]string{kindLink, rm.Name}, "/")
    87  	}
    88  	return ""
    89  }
    90  
    91  // GetKindLink gets the link to resource kind
    92  func (rm *ResourceMeta) GetKindLink() string {
    93  	if rm == nil {
    94  		return ""
    95  	}
    96  
    97  	// can't continue if group kind or version are blank
    98  	if rm.Group == "" || rm.Kind == "" || rm.APIVersion == "" {
    99  		return ""
   100  	}
   101  
   102  	// empty string to prepend with /
   103  	pathItems := []string{"", rm.Group, rm.APIVersion}
   104  
   105  	plural, _ := GetPluralFromKind(rm.Kind)
   106  
   107  	if rm.Metadata.Scope.Kind == "" {
   108  		scope, ok := GetScope(rm.GetGroupVersionKind().GroupKind)
   109  		if ok && scope != "" {
   110  			scopePlural, _ := GetPluralFromKind(scope)
   111  			pathItems = append(pathItems, []string{scopePlural, rm.Metadata.Scope.Name}...)
   112  		}
   113  	} else {
   114  		scopePlural, _ := GetPluralFromKind(rm.Metadata.Scope.Kind)
   115  		pathItems = append(pathItems, []string{scopePlural, rm.Metadata.Scope.Name}...)
   116  	}
   117  
   118  	pathItems = append(pathItems, plural)
   119  
   120  	return strings.Join(pathItems, "/")
   121  }
   122  
   123  // GetGroupVersionKind gets the group, version, and kind of the resource
   124  func (rm *ResourceMeta) GetGroupVersionKind() GroupVersionKind {
   125  	if rm == nil {
   126  		return GroupVersionKind{}
   127  	}
   128  
   129  	return rm.GroupVersionKind
   130  }
   131  
   132  // GetAttributes gets the attributes of a resource
   133  func (rm *ResourceMeta) GetAttributes() map[string]string {
   134  	if rm == nil {
   135  		return map[string]string{}
   136  	}
   137  
   138  	return rm.Attributes
   139  }
   140  
   141  // SetAttributes sets the attributes of a resource
   142  func (rm *ResourceMeta) SetAttributes(attrs map[string]string) {
   143  	if rm == nil {
   144  		return
   145  	}
   146  
   147  	rm.Attributes = attrs
   148  }
   149  
   150  // GetTags gets the tags of the resource
   151  func (rm *ResourceMeta) GetTags() []string {
   152  	if rm == nil {
   153  		return []string{}
   154  	}
   155  
   156  	return rm.Tags
   157  }
   158  
   159  // SetTags adds tags to the resource
   160  func (rm *ResourceMeta) SetTags(tags []string) {
   161  	if rm == nil {
   162  		return
   163  	}
   164  
   165  	rm.Tags = tags
   166  }
   167  
   168  // GetSubResource get a sub resource by name
   169  func (rm *ResourceMeta) GetSubResource(key string) interface{} {
   170  	if rm == nil || rm.SubResources == nil {
   171  		return nil
   172  	}
   173  	return rm.SubResources[key]
   174  }
   175  
   176  // SetSubResource saves a value to a sub resource by name and overrides the current value.
   177  // To update a SubResource first call GetSubResource and modify it, then save it.
   178  func (rm *ResourceMeta) SetSubResource(name string, value interface{}) {
   179  	if rm == nil {
   180  		return
   181  	}
   182  
   183  	if rm.SubResources == nil {
   184  		rm.SubResources = make(map[string]interface{})
   185  	}
   186  	rm.SubResources[name] = value
   187  }
   188  
   189  // GetReferenceByGVK returns the first found reference that matches the GroupKind argument.
   190  func (rm *ResourceMeta) GetReferenceByGVK(gvk GroupVersionKind) Reference {
   191  	for _, ref := range rm.Metadata.References {
   192  		if ref.Group == gvk.Group && ref.Kind == gvk.Kind {
   193  			return ref
   194  		}
   195  	}
   196  	return Reference{}
   197  }
   198  
   199  // MarshalJSON marshals the ResourceMeta to properly set the SubResources
   200  func (rm *ResourceMeta) MarshalJSON() ([]byte, error) {
   201  	rawSubs := map[string]interface{}{}
   202  	subResources := rm.SubResources
   203  
   204  	for key, value := range subResources {
   205  		rawSubs[key] = value
   206  	}
   207  
   208  	// create an alias for *ResourceMeta to avoid a circular reference while marshalling.
   209  	type Alias ResourceMeta
   210  	v := &struct{ *Alias }{
   211  		Alias: (*Alias)(rm),
   212  	}
   213  
   214  	metaBts, err := json.Marshal(v)
   215  	if err != nil {
   216  		return metaBts, err
   217  	}
   218  
   219  	rawMeta := map[string]interface{}{}
   220  	err = json.Unmarshal(metaBts, &rawMeta)
   221  	if err != nil {
   222  		return metaBts, nil
   223  	}
   224  
   225  	for k, v := range rawSubs {
   226  		if v != nil {
   227  			rawMeta[k] = v
   228  		}
   229  	}
   230  
   231  	return json.Marshal(rawMeta)
   232  }
   233  
   234  // UnmarshalJSON unmarshalls the ResourceMeta to properly set the SubResources
   235  func (rm *ResourceMeta) UnmarshalJSON(data []byte) error {
   236  	type Alias ResourceMeta
   237  	// create an alias for *ResourceMeta to avoid a circular reference while unmarshalling.
   238  	v := &struct{ *Alias }{
   239  		Alias: (*Alias)(rm),
   240  	}
   241  
   242  	// unmarshal data to the alias. The SubResources will not be unmarshalled since they are not defined.
   243  	err := json.Unmarshal(data, v)
   244  	if err != nil {
   245  		return err
   246  	}
   247  
   248  	bts, err := json.Marshal(v)
   249  	if err != nil {
   250  		return err
   251  	}
   252  
   253  	// all contains all the defined keys of ResourceMeta. The keys will be used to identify the values
   254  	// that do not belong in the SubResources map.
   255  	all := map[string]interface{}{}
   256  	err = json.Unmarshal(bts, &all)
   257  	if err != nil {
   258  		return err
   259  	}
   260  
   261  	// unmarshal data again to a map[string]interface{} to get all the values and the unique sub resources
   262  	rawSubs := map[string]interface{}{}
   263  	err = json.Unmarshal(data, &rawSubs)
   264  	if err != nil {
   265  		return err
   266  	}
   267  
   268  	// all contains all keys but the sub resources. rawSubs contains all keys, but should only contain the subresource keys.
   269  	// delete the keys from subs that are not sub resource keys
   270  	for k := range all {
   271  		delete(rawSubs, k)
   272  	}
   273  	delete(rawSubs, "owner")
   274  	delete(rawSubs, "spec")
   275  
   276  	if len(rawSubs) > 0 && rm.SubResources == nil {
   277  		rm.SubResources = make(map[string]interface{})
   278  	}
   279  
   280  	for k, v := range rawSubs {
   281  		if v != nil {
   282  			rm.SubResources[k] = v
   283  		}
   284  	}
   285  
   286  	return nil
   287  }