github.com/onosproject/onos-api/go@v0.10.32/onos/topo/topo.go (about) 1 // SPDX-FileCopyrightText: 2020-present Open Networking Foundation <info@opennetworking.org> 2 // 3 // SPDX-License-Identifier: Apache-2.0 4 5 package topo 6 7 import ( 8 "bytes" 9 "fmt" 10 "github.com/gogo/protobuf/jsonpb" 11 "github.com/gogo/protobuf/proto" 12 "github.com/gogo/protobuf/types" 13 "google.golang.org/grpc" 14 ) 15 16 // UUID represents a system-assigned unique identifier of a topology object. 17 type UUID string 18 19 // ID represents a client-assigned unique identifier. 20 type ID string 21 22 // String convert ID to string 23 func (id ID) String() string { 24 return string(id) 25 } 26 27 // NullID represents a null/empty/omitted identifier; usually an indicator for system to generate one. 28 const NullID = "" 29 30 // Revision is an object revision 31 type Revision uint64 32 33 // DEPRECATED Entity and Relation Kinds 34 const ( 35 // Relations 36 CONTROLS = "controls" 37 CONTAINS = "contains" 38 NEIGHBORS = "neighbors" 39 40 // RAN Entities 41 E2NODE = "e2node" 42 E2CELL = "e2cell" 43 E2T = "e2t" 44 XAPP = "xapp" 45 A1T = "a1t" 46 47 // onos-config entity 48 ONOS_CONFIG = "onos-config" 49 ) 50 51 // TODO UPPERCASE entity kinds and relations should be replaced gradually with CamelCase ones 52 const ( 53 ControlsKind = "controls" 54 ContainsKind = "contains" 55 HasKind = "has" 56 TerminatesKind = "terminates" 57 OriginatesKind = "originates" 58 NeighborsKind = "neighbors" 59 ConnectionKind = "connection" 60 61 // Fabric Entity kinds 62 PodKind = "pod" 63 RackKind = "rack" 64 NetworkLayerKind = "network-layer" 65 SwitchKind = "switch" 66 ServerKind = "server" 67 IPUKind = "ipu" 68 HostKind = "host" 69 RouterKind = "router" 70 PortKind = "port" 71 InterfaceKind = "interface" 72 LinkKind = "link" 73 ControllerKind = "controller" 74 ServiceKind = "service" 75 76 // onos-config entity 77 OnosConfigKind = "onos-config" 78 79 // RAN Entitiy kinds 80 E2NodeKind = "e2node" 81 E2CellKind = "e2cell" 82 E2tKind = "e2t" 83 XappKind = "xapp" 84 A1tKind = "a1t" 85 ) 86 87 // PolicyTypeID is an identifier of A1 policy type 88 type PolicyTypeID string 89 90 // PolicyTypeName is a name of A1 policy type 91 type PolicyTypeName string 92 93 // PolicyTypeVersion is a version of A1 policy type 94 type PolicyTypeVersion string 95 96 // PolicyTypeDescription describe what this A1 policy is 97 type PolicyTypeDescription string 98 99 // TopoClientFactory : Default EntityServiceClient creation. 100 var TopoClientFactory = func(cc *grpc.ClientConn) TopoClient { 101 return NewTopoClient(cc) 102 } 103 104 // CreateTopoClient creates and returns a new topo device client 105 func CreateTopoClient(cc *grpc.ClientConn) TopoClient { 106 return TopoClientFactory(cc) 107 } 108 109 // RelationID creates a unique relationship ID from the specified source, kind and target IDs 110 func RelationID(srcID ID, relationKind ID, tgtID ID) ID { 111 return ID(fmt.Sprintf("%s-%s-%s", srcID, relationKind, tgtID)) 112 } 113 114 // MultiRelationID creates a unique relationship ID from the specified source, kind and target IDs, 115 // and also from an additional discriminant to allow for multiples of same kinds of relations between 116 // the same two objects. 117 func MultiRelationID(srcID ID, relationKind ID, tgtID ID, discriminant uint8) ID { 118 return ID(fmt.Sprintf("%s-%s-%s-%d", srcID, relationKind, tgtID, discriminant)) 119 } 120 121 // NewEntity allocates a new topology entity using the specified ID and kind. 122 func NewEntity(id ID, kind ID, aspects ...proto.Message) *Object { 123 return &Object{ID: id, Type: Object_ENTITY, Obj: &Object_Entity{Entity: &Entity{KindID: kind}}} 124 } 125 126 // NewRelation allocates a new topology relation using the specified source, target, and kind. 127 func NewRelation(source ID, target ID, kind ID, aspects ...proto.Message) *Object { 128 return &Object{ 129 ID: RelationID(source, kind, target), 130 Type: Object_RELATION, 131 Obj: &Object_Relation{Relation: &Relation{SrcEntityID: source, TgtEntityID: target, KindID: kind}}, 132 } 133 } 134 135 // WithAspects applies the given aspects to the object. 136 func (obj *Object) WithAspects(aspects ...proto.Message) (*Object, error) { 137 for _, aspect := range aspects { 138 if err := obj.SetAspect(aspect); err != nil { 139 return obj, err 140 } 141 } 142 return obj, nil 143 } 144 145 // ToAny provides a convenience utility to convert an aspect message to protobuf types.Any 146 func ToAny(value proto.Message) *types.Any { 147 jm := jsonpb.Marshaler{} 148 writer := bytes.Buffer{} 149 if err := jm.Marshal(&writer, value); err != nil { 150 return nil 151 } 152 return &types.Any{ 153 TypeUrl: proto.MessageName(value), 154 Value: writer.Bytes(), 155 } 156 } 157 158 // GetAspect retrieves the specified aspect value from the given object. 159 func (obj *Object) GetAspect(destValue proto.Message) error { 160 if obj.Aspects == nil { 161 return fmt.Errorf("no aspects found on %s", obj.String()) 162 } 163 aspectType := proto.MessageName(destValue) 164 any := obj.Aspects[aspectType] 165 if any == nil { 166 return fmt.Errorf("aspect '%s' not found in %s", aspectType, obj.String()) 167 } 168 if any.TypeUrl != aspectType { 169 return fmt.Errorf("unexpected aspect type: %s", aspectType) 170 } 171 reader := bytes.NewReader(any.Value) 172 err := jsonpb.Unmarshal(reader, destValue) 173 if err != nil { 174 return fmt.Errorf("error '%s' when unmarshalling aspect %s: %v from %s", 175 err.Error(), aspectType, any.Value, obj.String()) 176 } 177 return nil 178 } 179 180 // GetAspectBytes applies the specified aspect as raw JSON bytes to the given object. 181 func (obj *Object) GetAspectBytes(aspectType string) ([]byte, error) { 182 if obj.Aspects == nil { 183 return nil, fmt.Errorf("no aspects found on %s", obj.String()) 184 } 185 any := obj.Aspects[aspectType] 186 if any == nil { 187 return nil, fmt.Errorf("aspect '%s' not found on %s", aspectType, obj.String()) 188 } 189 return any.Value, nil 190 } 191 192 // SetAspect applies the specified aspect value to the given object. 193 func (obj *Object) SetAspect(value proto.Message) error { 194 jm := jsonpb.Marshaler{} 195 writer := bytes.Buffer{} 196 err := jm.Marshal(&writer, value) 197 if err != nil { 198 return fmt.Errorf("error '%s' marshaling aspect %v on to %s", 199 err.Error(), value, obj.String()) 200 } 201 if obj.Aspects == nil { 202 obj.Aspects = make(map[string]*types.Any) 203 } 204 obj.Aspects[proto.MessageName(value)] = &types.Any{ 205 TypeUrl: proto.MessageName(value), 206 Value: writer.Bytes(), 207 } 208 return nil 209 } 210 211 // SetAspectBytes applies the specified aspect as raw JSON bytes to the given object. 212 func (obj *Object) SetAspectBytes(aspectType string, jsonValue []byte) error { 213 any := &types.Any{ 214 TypeUrl: aspectType, 215 Value: jsonValue, 216 } 217 if obj.Aspects == nil { 218 obj.Aspects = make(map[string]*types.Any) 219 } 220 obj.Aspects[aspectType] = any 221 return nil 222 }