diff --git a/Gopkg.lock b/Gopkg.lock new file mode 100644 index 00000000..1e56346c --- /dev/null +++ b/Gopkg.lock @@ -0,0 +1,15 @@ +# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. + + +[[projects]] + name = "github.com/ciscoecosystem/aci-go-client/container" + packages = ["."] + revision = "7a0fed31069aba77993a518cc2f37b28ee7aa883" + version = "1.1" + +[solve-meta] + analyzer-name = "dep" + analyzer-version = 1 + inputs-digest = "98e0da366d6909f347eb881658f2885d66855a8c22e4f4d1b846be031476d49a" + solver-name = "gps-cdcl" + solver-version = 1 diff --git a/Gopkg.toml b/Gopkg.toml new file mode 100644 index 00000000..b3bcc467 --- /dev/null +++ b/Gopkg.toml @@ -0,0 +1,29 @@ +# Gopkg.toml example +# +# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md +# for detailed Gopkg.toml documentation. +# +# required = ["github.com/user/thing/cmd/thing"] +# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"] +# +# [[constraint]] +# name = "github.com/user/project" +# version = "1.0.0" +# +# [[constraint]] +# name = "github.com/user/project2" +# branch = "dev" +# source = "github.com/myfork/project2" +# +# [[override]] +# name = "github.com/x/y" +# version = "2.4.0" +# +# [prune] +# non-go = false +# go-tests = true +# unused-packages = true + +[prune] + go-tests = true + unused-packages = true diff --git a/README.md b/README.md new file mode 100644 index 00000000..a2df661d --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +# aci-go-client + diff --git a/client/auth.go b/client/auth.go new file mode 100644 index 00000000..ef8dcd28 --- /dev/null +++ b/client/auth.go @@ -0,0 +1,156 @@ +package client + +import ( + "bytes" + "crypto" + "crypto/rsa" + "crypto/sha256" + "crypto/x509" + "encoding/base64" + "encoding/pem" + "errors" + "fmt" + "io/ioutil" + "net/http" + "time" +) + +type Auth struct { + Token string + Expiry time.Time + apicCreatedAt time.Time + realCreatedAt time.Time + offset int64 +} + +func (au *Auth) IsValid() bool { + if au.Token != "" && au.Expiry.Unix() > au.estimateExpireTime() { + return true + } + return false +} + +func (t *Auth) CalculateExpiry(willExpire int64) { + t.Expiry = time.Unix((t.apicCreatedAt.Unix() + willExpire), 0) +} +func (t *Auth) CaclulateOffset() { + t.offset = t.apicCreatedAt.Unix() - t.realCreatedAt.Unix() +} + +func (t *Auth) estimateExpireTime() int64 { + return time.Now().Unix() + t.offset +} + +func (client *Client) InjectAuthenticationHeader(req *http.Request, path string) (*http.Request, error) { + + if client.password != "" { + if client.AuthToken == nil || !client.AuthToken.IsValid() { + fmt.Println(client) + err := client.Authenticate() + fmt.Println(client) + if err != nil { + return nil, err + } + + } + req.AddCookie(&http.Cookie{ + Name: "APIC-Cookie", + Value: client.AuthToken.Token, + }) + return req, nil + } else if client.privatekey != "" && client.adminCert != "" { + buffer, _ := ioutil.ReadAll(req.Body) + rdr2 := ioutil.NopCloser(bytes.NewBuffer(buffer)) + + req.Body = rdr2 + bodyStr := string(buffer) + contentStr := "" + if bodyStr != "{}" { + contentStr = fmt.Sprintf("%s%s%s", req.Method, path, bodyStr) + } else { + contentStr = fmt.Sprintf("%s%s", req.Method, path) + + } + fmt.Println("Content " + contentStr) + content := []byte(contentStr) + + signature, err := createSignature(content, client.privatekey) + fmt.Println("sig" + signature) + if err != nil { + return req, err + } + req.AddCookie(&http.Cookie{ + Name: "APIC-Request-Signature", + Value: signature, + }) + req.AddCookie(&http.Cookie{ + Name: "APIC-Certificate-Algorithm", + Value: "v1.0", + }) + req.AddCookie(&http.Cookie{ + Name: "APIC-Certificate-Fingerprint", + Value: "fingerprint", + }) + req.AddCookie(&http.Cookie{ + Name: "APIC-Certificate-DN", + Value: fmt.Sprintf("uni/userext/user-%s/usercert-%s", client.username, client.adminCert), + }) + + return req, nil + + } else { + + return req, fmt.Errorf("Anyone of password or privatekey/certificate name is must.") + } + + return req, nil +} + +func createSignature(content []byte, keypath string) (string, error) { + hasher := sha256.New() + hasher.Write(content) + privkey, err := loadPrivateKey(keypath) + if err != nil { + return "", err + } + signedData, err := rsa.SignPKCS1v15(nil, privkey, crypto.SHA256, hasher.Sum(nil)) + if err != nil { + return "", err + } + + signature := base64.StdEncoding.EncodeToString(signedData) + return signature, nil +} + +func loadPrivateKey(path string) (*rsa.PrivateKey, error) { + data, err := ioutil.ReadFile(path) + if err != nil { + return nil, err + } + return parsePrivateKey(data) +} + +func parsePrivateKey(pemBytes []byte) (*rsa.PrivateKey, error) { + block, _ := pem.Decode(pemBytes) + if block == nil { + return nil, errors.New("ssh: no key found") + } + + switch block.Type { + case "RSA PRIVATE KEY": + privkey, err := x509.ParsePKCS1PrivateKey(block.Bytes) + if err != nil { + return nil, err + } + return privkey, err + case "PRIVATE KEY": + parsedresult, err := x509.ParsePKCS8PrivateKey(block.Bytes) + if err != nil { + return nil, err + } + privkey := parsedresult.(*rsa.PrivateKey) + return privkey, nil + default: + return nil, fmt.Errorf("ssh: unsupported key type %q", block.Type) + } +} diff --git a/client/client.go b/client/client.go new file mode 100644 index 00000000..8a8ed475 --- /dev/null +++ b/client/client.go @@ -0,0 +1,236 @@ +package client + +import ( + "bytes" + "crypto/tls" + "encoding/json" + "errors" + "fmt" + "log" + "net/http" + "net/url" + "strconv" + "strings" + "time" + + "github.com/ciscoecosystem/aci-go-client/container" +) + +const authPayload = `{ + "aaaUser" : { + "attributes" : { + "name" : "%s", + "pwd" : "%s" + } + } +}` + +const DefaultMOURL = "/api/node/mo" + +// Client is the main entry point +type Client struct { + BaseURL *url.URL + MOURL string + httpClient *http.Client + AuthToken *Auth + username string + password string + privatekey string + adminCert string + insecure bool + *ServiceManager +} + +// singleton implementation of a client +var clientImpl *Client + +type Option func(*Client) + +func Insecure(insecure bool) Option { + return func(client *Client) { + client.insecure = insecure + } +} + +func MoURL(moURL string) Option { + return func(sm *Client) { + sm.MOURL = moURL + } +} + +func Password(password string) Option { + return func(client *Client) { + client.password = password + } +} + +func PrivateKey(privatekey string) Option { + return func(client *Client) { + client.privatekey = privatekey + } +} + +func AdminCert(adminCert string) Option { + return func(client *Client) { + client.adminCert = adminCert + } +} + +func initClient(clientUrl, username string, options ...Option) *Client { + bUrl, err := url.Parse(clientUrl) + if err != nil { + // cannot move forward if url is undefined + log.Fatal(err) + } + client := &Client{ + BaseURL: bUrl, + username: username, + httpClient: http.DefaultClient, + MOURL: DefaultMOURL, + } + + for _, option := range options { + option(client) + } + + if client.insecure { + client.useInsecureHTTPClient() + } + client.ServiceManager = NewServiceManager(client.MOURL, client) + return client +} + +// GetClient returns a singleton +func GetClient(clientUrl, username string, options ...Option) *Client { + if clientImpl == nil { + clientImpl = initClient(clientUrl, username, options...) + } + return clientImpl +} + +func (c *Client) useInsecureHTTPClient() { + transport := &http.Transport{ + TLSClientConfig: &tls.Config{ + CipherSuites: []uint16{ + tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, + tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, + }, + PreferServerCipherSuites: true, + InsecureSkipVerify: true, + MinVersion: tls.VersionTLS11, + MaxVersion: tls.VersionTLS11, + }, + } + + c.httpClient = &http.Client{ + Transport: transport, + } + +} + +func (c *Client) MakeRestRequest(method string, path string, body *container.Container, authenticated bool) (*http.Request, error) { + + url, err := url.Parse(path) + if err != nil { + return nil, err + } + + fURL := c.BaseURL.ResolveReference(url) + + req, err := http.NewRequest(method, fURL.String(), bytes.NewBuffer(body.Bytes())) + + if err != nil { + return nil, err + } + + if authenticated { + + req, err = c.InjectAuthenticationHeader(req, path) + if err != nil { + return req, err + } + } + + return req, nil +} + +// Authenticate is used to +func (c *Client) Authenticate() error { + method := "POST" + path := "/api/aaaLogin.json" + body, err := container.ParseJSON([]byte(fmt.Sprintf(authPayload, c.username, c.password))) + + if err != nil { + return err + } + + fmt.Println(body.String()) + req, err := c.MakeRestRequest(method, path, body, false) + obj, _, err := c.Do(req) + + if err != nil { + return err + } + if obj == nil { + return errors.New("Empty response") + } + + token := obj.S("imdata").Index(0).S("aaaLogin", "attributes", "token").String() + creationTimeStr := stripQuotes(obj.S("imdata").Index(0).S("aaaLogin", "attributes", "creationTime").String()) + refreshTimeStr := stripQuotes(obj.S("imdata").Index(0).S("aaaLogin", "attributes", "refreshTimeoutSeconds").String()) + + creationTimeInt, err := StrtoInt(creationTimeStr, 10, 64) + if err != nil { + return err + } + refreshTimeInt, err := StrtoInt(refreshTimeStr, 10, 64) + if err != nil { + return err + } + if token == "" { + return errors.New("Invalid Username or Password") + } + + if c.AuthToken == nil { + c.AuthToken = &Auth{} + } + c.AuthToken.Token = stripQuotes(token) + c.AuthToken.apicCreatedAt = time.Unix(creationTimeInt, 0) + c.AuthToken.realCreatedAt = time.Now() + c.AuthToken.CalculateExpiry(refreshTimeInt) + c.AuthToken.CaclulateOffset() + + return nil +} +func StrtoInt(s string, startIndex int, bitSize int) (int64, error) { + return strconv.ParseInt(s, startIndex, bitSize) + +} +func (c *Client) Do(req *http.Request) (*container.Container, *http.Response, error) { + + resp, err := c.httpClient.Do(req) + if err != nil { + return nil, nil, err + } + defer resp.Body.Close() + + fmt.Printf("\nHTTP Request: %s %s \n", req.Method, req.URL.String()) + fmt.Printf("\nHTTP Response: %d %s \n", resp.StatusCode, resp.Status) + + decoder := json.NewDecoder(resp.Body) + obj, err := container.ParseJSONDecoder(decoder) + + if err != nil { + fmt.Println("Error occurred.") + return nil, resp, err + } + + return obj, resp, err +} + +func stripQuotes(word string) string { + if strings.HasPrefix(word, "\"") && strings.HasSuffix(word, "\"") { + return strings.TrimSuffix(strings.TrimPrefix(word, "\""), "\"") + } + return word +} diff --git a/client/client_test.go b/client/client_test.go new file mode 100644 index 00000000..6efc00b4 --- /dev/null +++ b/client/client_test.go @@ -0,0 +1,25 @@ +package client + +import ( + "testing" + + "github.com/ciscoecosystem/aci-go-client/client" +) + +func TestClientAuthenticate(t *testing.T) { + + client := GetTestClient() + err := client.Authenticate() + if err != nil { + t.Error(err) + } + + if client.AuthToken.Token == "" { + t.Error("Token is empty") + } +} + +func GetTestClient() *client.Client { + return client.GetClient("https://192.168.10.102", "admin", client.Password("cisco123"), client.Insecure(true)) + +} diff --git a/client/debug.test b/client/debug.test new file mode 100644 index 00000000..8c416217 Binary files /dev/null and b/client/debug.test differ diff --git a/client/fvAEPg_service.go b/client/fvAEPg_service.go new file mode 100644 index 00000000..eeaa7ca5 --- /dev/null +++ b/client/fvAEPg_service.go @@ -0,0 +1,61 @@ +package client + +import ( + "fmt" + + "github.com/ciscoecosystem/aci-go-client/models" +) + + + + + + + + + +func (sm *ServiceManager) CreateApplicationEPG(name string ,application_profile string ,tenant string ,description string, fvAEPgattr models.ApplicationEPGAttributes) (*models.ApplicationEPG, error) { + rn := fmt.Sprintf("epg-%s",name) + parentDn := fmt.Sprintf("uni/tn-%s/ap-%s", tenant ,application_profile ) + fvAEPg := models.NewApplicationEPG(rn, parentDn, description, fvAEPgattr) + err := sm.Save(fvAEPg) + return fvAEPg, err +} + +func (sm *ServiceManager) ReadApplicationEPG(name string ,application_profile string ,tenant string ) (*models.ApplicationEPG, error) { + dn := fmt.Sprintf("uni/tn-%s/ap-%s/epg-%s", tenant ,application_profile ,name ) + cont, err := sm.Get(dn) + if err != nil { + return nil, err + } + + fvAEPg := models.ApplicationEPGFromContainer(cont) + return fvAEPg, nil +} + +func (sm *ServiceManager) DeleteApplicationEPG(name string ,application_profile string ,tenant string ) error { + dn := fmt.Sprintf("uni/tn-%s/ap-%s/epg-%s", tenant ,application_profile ,name ) + return sm.DeleteByDn(dn, models.FvaepgClassName) +} + +func (sm *ServiceManager) UpdateApplicationEPG(name string ,application_profile string ,tenant string ,description string, fvAEPgattr models.ApplicationEPGAttributes) (*models.ApplicationEPG, error) { + rn := fmt.Sprintf("epg-%s",name) + parentDn := fmt.Sprintf("uni/tn-%s/ap-%s", tenant ,application_profile ) + fvAEPg := models.NewApplicationEPG(rn, parentDn, description, fvAEPgattr) + + fvAEPg.Status = "modified" + err := sm.Save(fvAEPg) + return fvAEPg, err + +} + +func (sm *ServiceManager) ListApplicationEPG(application_profile string ,tenant string ) ([]*models.ApplicationEPG, error) { + + baseurlStr := "/api/node/class" + dnUrl := fmt.Sprintf("%s/uni/tn-%s/ap-%s/fvAEPg.json", baseurlStr , tenant ,application_profile ) + + cont, err := sm.GetViaURL(dnUrl) + list := models.ApplicationEPGListFromContainer(cont) + + return list, err +} \ No newline at end of file diff --git a/client/fvAp_service.go b/client/fvAp_service.go new file mode 100644 index 00000000..83fa8831 --- /dev/null +++ b/client/fvAp_service.go @@ -0,0 +1,61 @@ +package client + +import ( + "fmt" + + "github.com/ciscoecosystem/aci-go-client/models" +) + + + + + + + + + +func (sm *ServiceManager) CreateApplicationProfile(name string ,tenant string ,description string, fvApattr models.ApplicationProfileAttributes) (*models.ApplicationProfile, error) { + rn := fmt.Sprintf("ap-%s",name) + parentDn := fmt.Sprintf("uni/tn-%s", tenant ) + fvAp := models.NewApplicationProfile(rn, parentDn, description, fvApattr) + err := sm.Save(fvAp) + return fvAp, err +} + +func (sm *ServiceManager) ReadApplicationProfile(name string ,tenant string ) (*models.ApplicationProfile, error) { + dn := fmt.Sprintf("uni/tn-%s/ap-%s", tenant ,name ) + cont, err := sm.Get(dn) + if err != nil { + return nil, err + } + + fvAp := models.ApplicationProfileFromContainer(cont) + return fvAp, nil +} + +func (sm *ServiceManager) DeleteApplicationProfile(name string ,tenant string ) error { + dn := fmt.Sprintf("uni/tn-%s/ap-%s", tenant ,name ) + return sm.DeleteByDn(dn, models.FvapClassName) +} + +func (sm *ServiceManager) UpdateApplicationProfile(name string ,tenant string ,description string, fvApattr models.ApplicationProfileAttributes) (*models.ApplicationProfile, error) { + rn := fmt.Sprintf("ap-%s",name) + parentDn := fmt.Sprintf("uni/tn-%s", tenant ) + fvAp := models.NewApplicationProfile(rn, parentDn, description, fvApattr) + + fvAp.Status = "modified" + err := sm.Save(fvAp) + return fvAp, err + +} + +func (sm *ServiceManager) ListApplicationProfile(tenant string ) ([]*models.ApplicationProfile, error) { + + baseurlStr := "/api/node/class" + dnUrl := fmt.Sprintf("%s/uni/tn-%s/fvAp.json", baseurlStr , tenant ) + + cont, err := sm.GetViaURL(dnUrl) + list := models.ApplicationProfileListFromContainer(cont) + + return list, err +} \ No newline at end of file diff --git a/client/fvBD_service.go b/client/fvBD_service.go new file mode 100644 index 00000000..95ea218f --- /dev/null +++ b/client/fvBD_service.go @@ -0,0 +1,61 @@ +package client + +import ( + "fmt" + + "github.com/ciscoecosystem/aci-go-client/models" +) + + + + + + + + + +func (sm *ServiceManager) CreateBridgeDomain(name string ,tenant string ,description string, fvBDattr models.BridgeDomainAttributes) (*models.BridgeDomain, error) { + rn := fmt.Sprintf("BD-%s",name) + parentDn := fmt.Sprintf("uni/tn-%s", tenant ) + fvBD := models.NewBridgeDomain(rn, parentDn, description, fvBDattr) + err := sm.Save(fvBD) + return fvBD, err +} + +func (sm *ServiceManager) ReadBridgeDomain(name string ,tenant string ) (*models.BridgeDomain, error) { + dn := fmt.Sprintf("uni/tn-%s/BD-%s", tenant ,name ) + cont, err := sm.Get(dn) + if err != nil { + return nil, err + } + + fvBD := models.BridgeDomainFromContainer(cont) + return fvBD, nil +} + +func (sm *ServiceManager) DeleteBridgeDomain(name string ,tenant string ) error { + dn := fmt.Sprintf("uni/tn-%s/BD-%s", tenant ,name ) + return sm.DeleteByDn(dn, models.FvbdClassName) +} + +func (sm *ServiceManager) UpdateBridgeDomain(name string ,tenant string ,description string, fvBDattr models.BridgeDomainAttributes) (*models.BridgeDomain, error) { + rn := fmt.Sprintf("BD-%s",name) + parentDn := fmt.Sprintf("uni/tn-%s", tenant ) + fvBD := models.NewBridgeDomain(rn, parentDn, description, fvBDattr) + + fvBD.Status = "modified" + err := sm.Save(fvBD) + return fvBD, err + +} + +func (sm *ServiceManager) ListBridgeDomain(tenant string ) ([]*models.BridgeDomain, error) { + + baseurlStr := "/api/node/class" + dnUrl := fmt.Sprintf("%s/uni/tn-%s/fvBD.json", baseurlStr , tenant ) + + cont, err := sm.GetViaURL(dnUrl) + list := models.BridgeDomainListFromContainer(cont) + + return list, err +} \ No newline at end of file diff --git a/client/fvSubnet_service.go b/client/fvSubnet_service.go new file mode 100644 index 00000000..ea7160d0 --- /dev/null +++ b/client/fvSubnet_service.go @@ -0,0 +1,61 @@ +package client + +import ( + "fmt" + + "github.com/ciscoecosystem/aci-go-client/models" +) + + + + + + + + + +func (sm *ServiceManager) CreateSubnet(ip string ,bridge_domain string ,tenant string ,description string, fvSubnetattr models.SubnetAttributes) (*models.Subnet, error) { + rn := fmt.Sprintf("subnet-[%s]",ip) + parentDn := fmt.Sprintf("uni/tn-%s/BD-%s", tenant ,bridge_domain ) + fvSubnet := models.NewSubnet(rn, parentDn, description, fvSubnetattr) + err := sm.Save(fvSubnet) + return fvSubnet, err +} + +func (sm *ServiceManager) ReadSubnet(ip string ,bridge_domain string ,tenant string ) (*models.Subnet, error) { + dn := fmt.Sprintf("uni/tn-%s/BD-%s/subnet-[%s]", tenant ,bridge_domain ,ip ) + cont, err := sm.Get(dn) + if err != nil { + return nil, err + } + + fvSubnet := models.SubnetFromContainer(cont) + return fvSubnet, nil +} + +func (sm *ServiceManager) DeleteSubnet(ip string ,bridge_domain string ,tenant string ) error { + dn := fmt.Sprintf("uni/tn-%s/BD-%s/subnet-[%s]", tenant ,bridge_domain ,ip ) + return sm.DeleteByDn(dn, models.FvsubnetClassName) +} + +func (sm *ServiceManager) UpdateSubnet(ip string ,bridge_domain string ,tenant string ,description string, fvSubnetattr models.SubnetAttributes) (*models.Subnet, error) { + rn := fmt.Sprintf("subnet-[%s]",ip) + parentDn := fmt.Sprintf("uni/tn-%s/BD-%s", tenant ,bridge_domain ) + fvSubnet := models.NewSubnet(rn, parentDn, description, fvSubnetattr) + + fvSubnet.Status = "modified" + err := sm.Save(fvSubnet) + return fvSubnet, err + +} + +func (sm *ServiceManager) ListSubnet(bridge_domain string ,tenant string ) ([]*models.Subnet, error) { + + baseurlStr := "/api/node/class" + dnUrl := fmt.Sprintf("%s/uni/tn-%s/BD-%s/fvSubnet.json", baseurlStr , tenant ,bridge_domain ) + + cont, err := sm.GetViaURL(dnUrl) + list := models.SubnetListFromContainer(cont) + + return list, err +} \ No newline at end of file diff --git a/client/fvTenant_service.go b/client/fvTenant_service.go new file mode 100644 index 00000000..49f5f11a --- /dev/null +++ b/client/fvTenant_service.go @@ -0,0 +1,53 @@ +package client + +import ( + "fmt" + + "github.com/ciscoecosystem/aci-go-client/models" +) + +func (sm *ServiceManager) CreateTenant(name string, description string, fvTenantattr models.TenantAttributes) (*models.Tenant, error) { + rn := fmt.Sprintf("tn-%s", name) + parentDn := fmt.Sprintf("uni") + fvTenant := models.NewTenant(rn, parentDn, description, fvTenantattr) + err := sm.Save(fvTenant) + return fvTenant, err +} + +func (sm *ServiceManager) ReadTenant(name string) (*models.Tenant, error) { + dn := fmt.Sprintf("uni/tn-%s", name) + cont, err := sm.Get(dn) + if err != nil { + return nil, err + } + + fvTenant := models.TenantFromContainer(cont) + return fvTenant, nil +} + +func (sm *ServiceManager) DeleteTenant(name string) error { + dn := fmt.Sprintf("uni/tn-%s", name) + return sm.DeleteByDn(dn, models.FvtenantClassName) +} + +func (sm *ServiceManager) UpdateTenant(name string, description string, fvTenantattr models.TenantAttributes) (*models.Tenant, error) { + rn := fmt.Sprintf("tn-%s", name) + parentDn := fmt.Sprintf("uni") + fvTenant := models.NewTenant(rn, parentDn, description, fvTenantattr) + + fvTenant.Status = "modified" + err := sm.Save(fvTenant) + return fvTenant, err + +} + +func (sm *ServiceManager) ListTenant() ([]*models.Tenant, error) { + + baseurlStr := "/api/node/class" + dnUrl := fmt.Sprintf("%s/uni/fvTenant.json", baseurlStr) + + cont, err := sm.GetViaURL(dnUrl) + list := models.TenantListFromContainer(cont) + + return list, err +} diff --git a/client/service b/client/service new file mode 100644 index 00000000..e69de29b diff --git a/client/service_manager.go b/client/service_manager.go new file mode 100644 index 00000000..e392cd0d --- /dev/null +++ b/client/service_manager.go @@ -0,0 +1,197 @@ +package client + +import ( + "errors" + "fmt" + "strconv" + + "github.com/ciscoecosystem/aci-go-client/container" + "github.com/ciscoecosystem/aci-go-client/models" +) + +type ServiceManager struct { + MOURL string + client *Client +} + +func NewServiceManager(moURL string, client *Client) *ServiceManager { + + sm := &ServiceManager{ + MOURL: moURL, + client: client, + } + return sm +} + +func (sm *ServiceManager) Get(dn string) (*container.Container, error) { + finalURL := fmt.Sprintf("%s/%s.json", sm.MOURL, dn) + req, err := sm.client.MakeRestRequest("GET", finalURL, nil, true) + + if err != nil { + return nil, err + } + + obj, _, err := sm.client.Do(req) + fmt.Println(obj) + if err != nil { + return nil, err + } + + if obj == nil { + return nil, errors.New("Empty response body") + } + return obj, CheckForErrors(obj, "GET") +} + +func createJsonPayload(payload map[string]string) (*container.Container, error) { + containerJSON := []byte(fmt.Sprintf(`{ + "%s": { + "attributes": { + } + } + }`, payload["classname"])) + + return container.ParseJSON(containerJSON) +} + +func (sm *ServiceManager) Save(obj models.Model) error { + + jsonPayload, _, err := sm.PrepareModel(obj) + + if err != nil { + return err + } + fmt.Println("MO" + sm.MOURL) + fmt.Println(sm.client) + fmt.Println(jsonPayload.String()) + req, err := sm.client.MakeRestRequest("POST", fmt.Sprintf("%s.json", sm.MOURL), jsonPayload, true) + if err != nil { + return err + } + + cont, _, err := sm.client.Do(req) + if err != nil { + return err + } + + return CheckForErrors(cont, "POST") +} + +// CheckForErrors parses the response and checks of there is an error attribute in the response +func CheckForErrors(cont *container.Container, method string) error { + number, err := strconv.Atoi(models.G(cont, "totalCount")) + if err != nil { + return err + } + imdata := cont.S("imdata").Index(0) + if number > 0 { + + if imdata.Exists("error") { + + if models.StripQuotes(imdata.Path("error.attributes.code").String()) == "103" { + return nil + } else { + return errors.New(models.StripQuotes(imdata.Path("error.attributes.text").String())) + } + } + + } + + if imdata.String() == "{}" && method == "GET" { + return errors.New("Error retriving Object: Object may not exists") + } + + return nil +} + +func (sm *ServiceManager) Delete(obj models.Model) error { + + jsonPayload, className, err := sm.PrepareModel(obj) + + if err != nil { + return err + } + fmt.Println(sm.MOURL) + fmt.Println(sm.client) + + jsonPayload.Set("deleted", className, "attributes", "status") + req, err := sm.client.MakeRestRequest("POST", fmt.Sprintf("%s.json", sm.MOURL), jsonPayload, true) + if err != nil { + return err + } + + cont, _, err := sm.client.Do(req) + if err != nil { + return err + } + fmt.Printf("%+v", cont) + + return nil +} + +func (sm *ServiceManager) GetViaURL(url string) (*container.Container, error) { + req, err := sm.client.MakeRestRequest("GET", url, nil, true) + + if err != nil { + return nil, err + } + + obj, _, err := sm.client.Do(req) + fmt.Println(obj) + if err != nil { + return nil, err + } + + if obj == nil { + return nil, errors.New("Empty response body") + } + return obj, CheckForErrors(obj, "GET") + +} + +func (sm *ServiceManager) DeleteByDn(dn, className string) error { + containerJSON := []byte(fmt.Sprintf(`{ + "%s": { + "attributes": { + "dn": "%s", + "status": "deleted" + } + } + }`, className, dn)) + + jsonPayload, err := container.ParseJSON(containerJSON) + if err != nil { + return err + } + + req, err := sm.client.MakeRestRequest("POST", fmt.Sprintf("%s.json", sm.MOURL), jsonPayload, true) + if err != nil { + return err + } + + cont, _, err := sm.client.Do(req) + if err != nil { + return err + } + fmt.Printf("%+v", cont) + + return nil + +} +func (sm *ServiceManager) PrepareModel(obj models.Model) (*container.Container, string, error) { + cont, err := obj.ToMap() + if err != nil { + return nil, "", err + } + jsonPayload, err := createJsonPayload(cont) + if err != nil { + return nil, "", err + } + className := cont["classname"] + delete(cont, "classname") + + for key, value := range cont { + jsonPayload.Set(value, className, "attributes", key) + } + return jsonPayload, className, nil +} diff --git a/client/service_manager_test.go b/client/service_manager_test.go new file mode 100644 index 00000000..da13c8ef --- /dev/null +++ b/client/service_manager_test.go @@ -0,0 +1 @@ +package client diff --git a/client/vzBrCP_service.go b/client/vzBrCP_service.go new file mode 100644 index 00000000..766933e0 --- /dev/null +++ b/client/vzBrCP_service.go @@ -0,0 +1,61 @@ +package client + +import ( + "fmt" + + "github.com/ciscoecosystem/aci-go-client/models" +) + + + + + + + + + +func (sm *ServiceManager) CreateContract(name string ,tenant string ,description string, vzBrCPattr models.ContractAttributes) (*models.Contract, error) { + rn := fmt.Sprintf("brc-%s",name) + parentDn := fmt.Sprintf("uni/tn-%s", tenant ) + vzBrCP := models.NewContract(rn, parentDn, description, vzBrCPattr) + err := sm.Save(vzBrCP) + return vzBrCP, err +} + +func (sm *ServiceManager) ReadContract(name string ,tenant string ) (*models.Contract, error) { + dn := fmt.Sprintf("uni/tn-%s/brc-%s", tenant ,name ) + cont, err := sm.Get(dn) + if err != nil { + return nil, err + } + + vzBrCP := models.ContractFromContainer(cont) + return vzBrCP, nil +} + +func (sm *ServiceManager) DeleteContract(name string ,tenant string ) error { + dn := fmt.Sprintf("uni/tn-%s/brc-%s", tenant ,name ) + return sm.DeleteByDn(dn, models.VzbrcpClassName) +} + +func (sm *ServiceManager) UpdateContract(name string ,tenant string ,description string, vzBrCPattr models.ContractAttributes) (*models.Contract, error) { + rn := fmt.Sprintf("brc-%s",name) + parentDn := fmt.Sprintf("uni/tn-%s", tenant ) + vzBrCP := models.NewContract(rn, parentDn, description, vzBrCPattr) + + vzBrCP.Status = "modified" + err := sm.Save(vzBrCP) + return vzBrCP, err + +} + +func (sm *ServiceManager) ListContract(tenant string ) ([]*models.Contract, error) { + + baseurlStr := "/api/node/class" + dnUrl := fmt.Sprintf("%s/uni/tn-%s/vzBrCP.json", baseurlStr , tenant ) + + cont, err := sm.GetViaURL(dnUrl) + list := models.ContractListFromContainer(cont) + + return list, err +} \ No newline at end of file diff --git a/client/vzEntry_service.go b/client/vzEntry_service.go new file mode 100644 index 00000000..f2803e1c --- /dev/null +++ b/client/vzEntry_service.go @@ -0,0 +1,61 @@ +package client + +import ( + "fmt" + + "github.com/ciscoecosystem/aci-go-client/models" +) + + + + + + + + + +func (sm *ServiceManager) CreateFilterEntry(name string ,filter string ,tenant string ,description string, vzEntryattr models.FilterEntryAttributes) (*models.FilterEntry, error) { + rn := fmt.Sprintf("e-%s",name) + parentDn := fmt.Sprintf("uni/tn-%s/flt-%s", tenant ,filter ) + vzEntry := models.NewFilterEntry(rn, parentDn, description, vzEntryattr) + err := sm.Save(vzEntry) + return vzEntry, err +} + +func (sm *ServiceManager) ReadFilterEntry(name string ,filter string ,tenant string ) (*models.FilterEntry, error) { + dn := fmt.Sprintf("uni/tn-%s/flt-%s/e-%s", tenant ,filter ,name ) + cont, err := sm.Get(dn) + if err != nil { + return nil, err + } + + vzEntry := models.FilterEntryFromContainer(cont) + return vzEntry, nil +} + +func (sm *ServiceManager) DeleteFilterEntry(name string ,filter string ,tenant string ) error { + dn := fmt.Sprintf("uni/tn-%s/flt-%s/e-%s", tenant ,filter ,name ) + return sm.DeleteByDn(dn, models.VzentryClassName) +} + +func (sm *ServiceManager) UpdateFilterEntry(name string ,filter string ,tenant string ,description string, vzEntryattr models.FilterEntryAttributes) (*models.FilterEntry, error) { + rn := fmt.Sprintf("e-%s",name) + parentDn := fmt.Sprintf("uni/tn-%s/flt-%s", tenant ,filter ) + vzEntry := models.NewFilterEntry(rn, parentDn, description, vzEntryattr) + + vzEntry.Status = "modified" + err := sm.Save(vzEntry) + return vzEntry, err + +} + +func (sm *ServiceManager) ListFilterEntry(filter string ,tenant string ) ([]*models.FilterEntry, error) { + + baseurlStr := "/api/node/class" + dnUrl := fmt.Sprintf("%s/uni/tn-%s/flt-%s/vzEntry.json", baseurlStr , tenant ,filter ) + + cont, err := sm.GetViaURL(dnUrl) + list := models.FilterEntryListFromContainer(cont) + + return list, err +} \ No newline at end of file diff --git a/client/vzFilter_service.go b/client/vzFilter_service.go new file mode 100644 index 00000000..2c83acfb --- /dev/null +++ b/client/vzFilter_service.go @@ -0,0 +1,61 @@ +package client + +import ( + "fmt" + + "github.com/ciscoecosystem/aci-go-client/models" +) + + + + + + + + + +func (sm *ServiceManager) CreateFilter(name string ,tenant string ,description string, vzFilterattr models.FilterAttributes) (*models.Filter, error) { + rn := fmt.Sprintf("flt-%s",name) + parentDn := fmt.Sprintf("uni/tn-%s", tenant ) + vzFilter := models.NewFilter(rn, parentDn, description, vzFilterattr) + err := sm.Save(vzFilter) + return vzFilter, err +} + +func (sm *ServiceManager) ReadFilter(name string ,tenant string ) (*models.Filter, error) { + dn := fmt.Sprintf("uni/tn-%s/flt-%s", tenant ,name ) + cont, err := sm.Get(dn) + if err != nil { + return nil, err + } + + vzFilter := models.FilterFromContainer(cont) + return vzFilter, nil +} + +func (sm *ServiceManager) DeleteFilter(name string ,tenant string ) error { + dn := fmt.Sprintf("uni/tn-%s/flt-%s", tenant ,name ) + return sm.DeleteByDn(dn, models.VzfilterClassName) +} + +func (sm *ServiceManager) UpdateFilter(name string ,tenant string ,description string, vzFilterattr models.FilterAttributes) (*models.Filter, error) { + rn := fmt.Sprintf("flt-%s",name) + parentDn := fmt.Sprintf("uni/tn-%s", tenant ) + vzFilter := models.NewFilter(rn, parentDn, description, vzFilterattr) + + vzFilter.Status = "modified" + err := sm.Save(vzFilter) + return vzFilter, err + +} + +func (sm *ServiceManager) ListFilter(tenant string ) ([]*models.Filter, error) { + + baseurlStr := "/api/node/class" + dnUrl := fmt.Sprintf("%s/uni/tn-%s/vzFilter.json", baseurlStr , tenant ) + + cont, err := sm.GetViaURL(dnUrl) + list := models.FilterListFromContainer(cont) + + return list, err +} \ No newline at end of file diff --git a/client/vzSubj_service.go b/client/vzSubj_service.go new file mode 100644 index 00000000..99e48318 --- /dev/null +++ b/client/vzSubj_service.go @@ -0,0 +1,61 @@ +package client + +import ( + "fmt" + + "github.com/ciscoecosystem/aci-go-client/models" +) + + + + + + + + + +func (sm *ServiceManager) CreateContractSubject(name string ,contract string ,tenant string ,description string, vzSubjattr models.ContractSubjectAttributes) (*models.ContractSubject, error) { + rn := fmt.Sprintf("subj-%s",name) + parentDn := fmt.Sprintf("uni/tn-%s/brc-%s", tenant ,contract ) + vzSubj := models.NewContractSubject(rn, parentDn, description, vzSubjattr) + err := sm.Save(vzSubj) + return vzSubj, err +} + +func (sm *ServiceManager) ReadContractSubject(name string ,contract string ,tenant string ) (*models.ContractSubject, error) { + dn := fmt.Sprintf("uni/tn-%s/brc-%s/subj-%s", tenant ,contract ,name ) + cont, err := sm.Get(dn) + if err != nil { + return nil, err + } + + vzSubj := models.ContractSubjectFromContainer(cont) + return vzSubj, nil +} + +func (sm *ServiceManager) DeleteContractSubject(name string ,contract string ,tenant string ) error { + dn := fmt.Sprintf("uni/tn-%s/brc-%s/subj-%s", tenant ,contract ,name ) + return sm.DeleteByDn(dn, models.VzsubjClassName) +} + +func (sm *ServiceManager) UpdateContractSubject(name string ,contract string ,tenant string ,description string, vzSubjattr models.ContractSubjectAttributes) (*models.ContractSubject, error) { + rn := fmt.Sprintf("subj-%s",name) + parentDn := fmt.Sprintf("uni/tn-%s/brc-%s", tenant ,contract ) + vzSubj := models.NewContractSubject(rn, parentDn, description, vzSubjattr) + + vzSubj.Status = "modified" + err := sm.Save(vzSubj) + return vzSubj, err + +} + +func (sm *ServiceManager) ListContractSubject(contract string ,tenant string ) ([]*models.ContractSubject, error) { + + baseurlStr := "/api/node/class" + dnUrl := fmt.Sprintf("%s/uni/tn-%s/brc-%s/vzSubj.json", baseurlStr , tenant ,contract ) + + cont, err := sm.GetViaURL(dnUrl) + list := models.ContractSubjectListFromContainer(cont) + + return list, err +} \ No newline at end of file diff --git a/container/gabs.go b/container/gabs.go new file mode 100644 index 00000000..37356b03 --- /dev/null +++ b/container/gabs.go @@ -0,0 +1,579 @@ +/* +Copyright (c) 2014 Ashley Jeffs + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +// Package container implements a simplified wrapper around creating and parsing JSON. +package container + +import ( + "bytes" + "encoding/json" + "errors" + "io" + "io/ioutil" + "strings" +) + +//-------------------------------------------------------------------------------------------------- + +var ( + // ErrOutOfBounds - Index out of bounds. + ErrOutOfBounds = errors.New("out of bounds") + + // ErrNotObjOrArray - The target is not an object or array type. + ErrNotObjOrArray = errors.New("not an object or array") + + // ErrNotObj - The target is not an object type. + ErrNotObj = errors.New("not an object") + + // ErrNotArray - The target is not an array type. + ErrNotArray = errors.New("not an array") + + // ErrPathCollision - Creating a path failed because an element collided with an existing value. + ErrPathCollision = errors.New("encountered value collision whilst building path") + + // ErrInvalidInputObj - The input value was not a map[string]interface{}. + ErrInvalidInputObj = errors.New("invalid input object") + + // ErrInvalidInputText - The input data could not be parsed. + ErrInvalidInputText = errors.New("input text could not be parsed") + + // ErrInvalidPath - The filepath was not valid. + ErrInvalidPath = errors.New("invalid file path") + + // ErrInvalidBuffer - The input buffer contained an invalid JSON string + ErrInvalidBuffer = errors.New("input buffer contained invalid JSON") +) + +//-------------------------------------------------------------------------------------------------- + +// Container - an internal structure that holds a reference to the core interface map of the parsed +// json. Use this container to move context. +type Container struct { + object interface{} +} + +// Data - Return the contained data as an interface{}. +func (g *Container) Data() interface{} { + if g == nil { + return nil + } + return g.object +} + +//-------------------------------------------------------------------------------------------------- + +// Path - Search for a value using dot notation. +func (g *Container) Path(path string) *Container { + return g.Search(strings.Split(path, ".")...) +} + +// Search - Attempt to find and return an object within the JSON structure by specifying the +// hierarchy of field names to locate the target. If the search encounters an array and has not +// reached the end target then it will iterate each object of the array for the target and return +// all of the results in a JSON array. +func (g *Container) Search(hierarchy ...string) *Container { + var object interface{} + + object = g.Data() + for target := 0; target < len(hierarchy); target++ { + if mmap, ok := object.(map[string]interface{}); ok { + object, ok = mmap[hierarchy[target]] + if !ok { + return nil + } + } else if marray, ok := object.([]interface{}); ok { + tmpArray := []interface{}{} + for _, val := range marray { + tmpcontainer := &Container{val} + res := tmpcontainer.Search(hierarchy[target:]...) + if res != nil { + tmpArray = append(tmpArray, res.Data()) + } + } + if len(tmpArray) == 0 { + return nil + } + return &Container{tmpArray} + } else { + return nil + } + } + return &Container{object} +} + +// S - Shorthand method, does the same thing as Search. +func (g *Container) S(hierarchy ...string) *Container { + return g.Search(hierarchy...) +} + +// Exists - Checks whether a path exists. +func (g *Container) Exists(hierarchy ...string) bool { + return g.Search(hierarchy...) != nil +} + +// ExistsP - Checks whether a dot notation path exists. +func (g *Container) ExistsP(path string) bool { + return g.Exists(strings.Split(path, ".")...) +} + +// Index - Attempt to find and return an object within a JSON array by index. +func (g *Container) Index(index int) *Container { + if array, ok := g.Data().([]interface{}); ok { + if index >= len(array) { + return &Container{nil} + } + return &Container{array[index]} + } + return &Container{nil} +} + +// Children - Return a slice of all the children of the array. This also works for objects, however, +// the children returned for an object will NOT be in order and you lose the names of the returned +// objects this way. +func (g *Container) Children() ([]*Container, error) { + if array, ok := g.Data().([]interface{}); ok { + children := make([]*Container, len(array)) + for i := 0; i < len(array); i++ { + children[i] = &Container{array[i]} + } + return children, nil + } + if mmap, ok := g.Data().(map[string]interface{}); ok { + children := []*Container{} + for _, obj := range mmap { + children = append(children, &Container{obj}) + } + return children, nil + } + return nil, ErrNotObjOrArray +} + +// ChildrenMap - Return a map of all the children of an object. +func (g *Container) ChildrenMap() (map[string]*Container, error) { + if mmap, ok := g.Data().(map[string]interface{}); ok { + children := map[string]*Container{} + for name, obj := range mmap { + children[name] = &Container{obj} + } + return children, nil + } + return nil, ErrNotObj +} + +//-------------------------------------------------------------------------------------------------- + +// Set - Set the value of a field at a JSON path, any parts of the path that do not exist will be +// constructed, and if a collision occurs with a non object type whilst iterating the path an error +// is returned. +func (g *Container) Set(value interface{}, path ...string) (*Container, error) { + if len(path) == 0 { + g.object = value + return g, nil + } + var object interface{} + if g.object == nil { + g.object = map[string]interface{}{} + } + object = g.object + for target := 0; target < len(path); target++ { + if mmap, ok := object.(map[string]interface{}); ok { + if target == len(path)-1 { + mmap[path[target]] = value + } else if mmap[path[target]] == nil { + mmap[path[target]] = map[string]interface{}{} + } + object = mmap[path[target]] + } else { + return &Container{nil}, ErrPathCollision + } + } + return &Container{object}, nil +} + +// SetP - Does the same as Set, but using a dot notation JSON path. +func (g *Container) SetP(value interface{}, path string) (*Container, error) { + return g.Set(value, strings.Split(path, ".")...) +} + +// SetIndex - Set a value of an array element based on the index. +func (g *Container) SetIndex(value interface{}, index int) (*Container, error) { + if array, ok := g.Data().([]interface{}); ok { + if index >= len(array) { + return &Container{nil}, ErrOutOfBounds + } + array[index] = value + return &Container{array[index]}, nil + } + return &Container{nil}, ErrNotArray +} + +// Object - Create a new JSON object at a path. Returns an error if the path contains a collision +// with a non object type. +func (g *Container) Object(path ...string) (*Container, error) { + return g.Set(map[string]interface{}{}, path...) +} + +// ObjectP - Does the same as Object, but using a dot notation JSON path. +func (g *Container) ObjectP(path string) (*Container, error) { + return g.Object(strings.Split(path, ".")...) +} + +// ObjectI - Create a new JSON object at an array index. Returns an error if the object is not an +// array or the index is out of bounds. +func (g *Container) ObjectI(index int) (*Container, error) { + return g.SetIndex(map[string]interface{}{}, index) +} + +// Array - Create a new JSON array at a path. Returns an error if the path contains a collision with +// a non object type. +func (g *Container) Array(path ...string) (*Container, error) { + return g.Set([]interface{}{}, path...) +} + +// ArrayP - Does the same as Array, but using a dot notation JSON path. +func (g *Container) ArrayP(path string) (*Container, error) { + return g.Array(strings.Split(path, ".")...) +} + +// ArrayI - Create a new JSON array at an array index. Returns an error if the object is not an +// array or the index is out of bounds. +func (g *Container) ArrayI(index int) (*Container, error) { + return g.SetIndex([]interface{}{}, index) +} + +// ArrayOfSize - Create a new JSON array of a particular size at a path. Returns an error if the +// path contains a collision with a non object type. +func (g *Container) ArrayOfSize(size int, path ...string) (*Container, error) { + a := make([]interface{}, size) + return g.Set(a, path...) +} + +// ArrayOfSizeP - Does the same as ArrayOfSize, but using a dot notation JSON path. +func (g *Container) ArrayOfSizeP(size int, path string) (*Container, error) { + return g.ArrayOfSize(size, strings.Split(path, ".")...) +} + +// ArrayOfSizeI - Create a new JSON array of a particular size at an array index. Returns an error +// if the object is not an array or the index is out of bounds. +func (g *Container) ArrayOfSizeI(size, index int) (*Container, error) { + a := make([]interface{}, size) + return g.SetIndex(a, index) +} + +// Delete - Delete an element at a JSON path, an error is returned if the element does not exist. +func (g *Container) Delete(path ...string) error { + var object interface{} + + if g.object == nil { + return ErrNotObj + } + object = g.object + for target := 0; target < len(path); target++ { + if mmap, ok := object.(map[string]interface{}); ok { + if target == len(path)-1 { + if _, ok := mmap[path[target]]; ok { + delete(mmap, path[target]) + } else { + return ErrNotObj + } + } + object = mmap[path[target]] + } else { + return ErrNotObj + } + } + return nil +} + +// DeleteP - Does the same as Delete, but using a dot notation JSON path. +func (g *Container) DeleteP(path string) error { + return g.Delete(strings.Split(path, ".")...) +} + +// Merge - Merges two container-containers +func (g *Container) Merge(toMerge *Container) error { + var recursiveFnc func(map[string]interface{}, []string) error + recursiveFnc = func(mmap map[string]interface{}, path []string) error { + for key, value := range mmap { + newPath := append(path, key) + if g.Exists(newPath...) { + target := g.Search(newPath...) + switch t := value.(type) { + case map[string]interface{}: + switch targetV := target.Data().(type) { + case map[string]interface{}: + if err := recursiveFnc(t, newPath); err != nil { + return err + } + case []interface{}: + g.Set(append(targetV, t), newPath...) + default: + newSlice := append([]interface{}{}, targetV) + g.Set(append(newSlice, t), newPath...) + } + case []interface{}: + for _, valueOfSlice := range t { + if err := g.ArrayAppend(valueOfSlice, newPath...); err != nil { + return err + } + } + default: + switch targetV := target.Data().(type) { + case []interface{}: + g.Set(append(targetV, t), newPath...) + default: + newSlice := append([]interface{}{}, targetV) + g.Set(append(newSlice, t), newPath...) + } + } + } else { + // path doesn't exist. So set the value + if _, err := g.Set(value, newPath...); err != nil { + return err + } + } + } + return nil + } + if mmap, ok := toMerge.Data().(map[string]interface{}); ok { + return recursiveFnc(mmap, []string{}) + } + return nil +} + +//-------------------------------------------------------------------------------------------------- + +/* +Array modification/search - Keeping these options simple right now, no need for anything more +complicated since you can just cast to []interface{}, modify and then reassign with Set. +*/ + +// ArrayAppend - Append a value onto a JSON array. If the target is not a JSON array then it will be +// converted into one, with its contents as the first element of the array. +func (g *Container) ArrayAppend(value interface{}, path ...string) error { + if array, ok := g.Search(path...).Data().([]interface{}); ok { + array = append(array, value) + _, err := g.Set(array, path...) + return err + } + + newArray := []interface{}{} + newArray = append(newArray, g.Search(path...).Data()) + newArray = append(newArray, value) + + _, err := g.Set(newArray, path...) + return err +} + +// ArrayAppendP - Append a value onto a JSON array using a dot notation JSON path. +func (g *Container) ArrayAppendP(value interface{}, path string) error { + return g.ArrayAppend(value, strings.Split(path, ".")...) +} + +// ArrayRemove - Remove an element from a JSON array. +func (g *Container) ArrayRemove(index int, path ...string) error { + if index < 0 { + return ErrOutOfBounds + } + array, ok := g.Search(path...).Data().([]interface{}) + if !ok { + return ErrNotArray + } + if index < len(array) { + array = append(array[:index], array[index+1:]...) + } else { + return ErrOutOfBounds + } + _, err := g.Set(array, path...) + return err +} + +// ArrayRemoveP - Remove an element from a JSON array using a dot notation JSON path. +func (g *Container) ArrayRemoveP(index int, path string) error { + return g.ArrayRemove(index, strings.Split(path, ".")...) +} + +// ArrayElement - Access an element from a JSON array. +func (g *Container) ArrayElement(index int, path ...string) (*Container, error) { + if index < 0 { + return &Container{nil}, ErrOutOfBounds + } + array, ok := g.Search(path...).Data().([]interface{}) + if !ok { + return &Container{nil}, ErrNotArray + } + if index < len(array) { + return &Container{array[index]}, nil + } + return &Container{nil}, ErrOutOfBounds +} + +// ArrayElementP - Access an element from a JSON array using a dot notation JSON path. +func (g *Container) ArrayElementP(index int, path string) (*Container, error) { + return g.ArrayElement(index, strings.Split(path, ".")...) +} + +// ArrayCount - Count the number of elements in a JSON array. +func (g *Container) ArrayCount(path ...string) (int, error) { + if array, ok := g.Search(path...).Data().([]interface{}); ok { + return len(array), nil + } + return 0, ErrNotArray +} + +// ArrayCountP - Count the number of elements in a JSON array using a dot notation JSON path. +func (g *Container) ArrayCountP(path string) (int, error) { + return g.ArrayCount(strings.Split(path, ".")...) +} + +//-------------------------------------------------------------------------------------------------- + +// Bytes - Converts the contained object back to a JSON []byte blob. +func (g *Container) Bytes() []byte { + if g.Data() != nil { + if bytes, err := json.Marshal(g.object); err == nil { + return bytes + } + } + return []byte("{}") +} + +// BytesIndent - Converts the contained object to a JSON []byte blob formatted with prefix, indent. +func (g *Container) BytesIndent(prefix string, indent string) []byte { + if g.object != nil { + if bytes, err := json.MarshalIndent(g.object, prefix, indent); err == nil { + return bytes + } + } + return []byte("{}") +} + +// String - Converts the contained object to a JSON formatted string. +func (g *Container) String() string { + return string(g.Bytes()) +} + +// StringIndent - Converts the contained object back to a JSON formatted string with prefix, indent. +func (g *Container) StringIndent(prefix string, indent string) string { + return string(g.BytesIndent(prefix, indent)) +} + +// EncodeOpt is a functional option for the EncodeJSON method. +type EncodeOpt func(e *json.Encoder) + +// EncodeOptHTMLEscape sets the encoder to escape the JSON for html. +func EncodeOptHTMLEscape(doEscape bool) EncodeOpt { + return func(e *json.Encoder) { + e.SetEscapeHTML(doEscape) + } +} + +// EncodeOptIndent sets the encoder to indent the JSON output. +func EncodeOptIndent(prefix string, indent string) EncodeOpt { + return func(e *json.Encoder) { + e.SetIndent(prefix, indent) + } +} + +// EncodeJSON - Encodes the contained object back to a JSON formatted []byte +// using a variant list of modifier functions for the encoder being used. +// Functions for modifying the output are prefixed with EncodeOpt, e.g. +// EncodeOptHTMLEscape. +func (g *Container) EncodeJSON(encodeOpts ...EncodeOpt) []byte { + var b bytes.Buffer + encoder := json.NewEncoder(&b) + encoder.SetEscapeHTML(false) // Do not escape by default. + for _, opt := range encodeOpts { + opt(encoder) + } + if err := encoder.Encode(g.object); err != nil { + return []byte("{}") + } + result := b.Bytes() + if len(result) > 0 { + result = result[:len(result)-1] + } + return result +} + +// New - Create a new container JSON object. +func New() *Container { + return &Container{map[string]interface{}{}} +} + +// Consume - Gobble up an already converted JSON object, or a fresh map[string]interface{} object. +func Consume(root interface{}) (*Container, error) { + return &Container{root}, nil +} + +// ParseJSON - Convert a string into a representation of the parsed JSON. +func ParseJSON(sample []byte) (*Container, error) { + var container Container + + if err := json.Unmarshal(sample, &container.object); err != nil { + return nil, err + } + + return &container, nil +} + +// ParseJSONDecoder - Convert a json.Decoder into a representation of the parsed JSON. +func ParseJSONDecoder(decoder *json.Decoder) (*Container, error) { + var container Container + + if err := decoder.Decode(&container.object); err != nil { + return nil, err + } + + return &container, nil +} + +// ParseJSONFile - Read a file and convert into a representation of the parsed JSON. +func ParseJSONFile(path string) (*Container, error) { + if len(path) > 0 { + cBytes, err := ioutil.ReadFile(path) + if err != nil { + return nil, err + } + + container, err := ParseJSON(cBytes) + if err != nil { + return nil, err + } + + return container, nil + } + return nil, ErrInvalidPath +} + +// ParseJSONBuffer - Read the contents of a buffer into a representation of the parsed JSON. +func ParseJSONBuffer(buffer io.Reader) (*Container, error) { + var container Container + jsonDecoder := json.NewDecoder(buffer) + if err := jsonDecoder.Decode(&container.object); err != nil { + return nil, err + } + + return &container, nil +} + +//-------------------------------------------------------------------------------------------------- diff --git a/models/aep.go b/models/aep.go new file mode 100644 index 00000000..2640e7f9 --- /dev/null +++ b/models/aep.go @@ -0,0 +1 @@ +package models diff --git a/models/base_attributes.go b/models/base_attributes.go new file mode 100644 index 00000000..7dbde652 --- /dev/null +++ b/models/base_attributes.go @@ -0,0 +1,52 @@ +package models + +import ( + "encoding/json" + "fmt" + + "github.com/ciscoecosystem/aci-go-client/container" +) + +const baPayload = ` + "dn": "%s", + "name": "%s", + "descr": "%s", +` + +type BaseAttributes struct { + DistinguishedName string `json:"dn"` + Status string `json:"status"` + Description string `json:"descr"` + ClassName string `json:"-"` + Rn string `json:"rn"` +} + +func (ba *BaseAttributes) ToJson() (string, error) { + data, err := json.Marshal(ba) + if err != nil { + return "", err + } + return string(data), nil +} + +func (ba *BaseAttributes) ToMap() (map[string]string, error) { + + jsonData, err := ba.ToJson() + if err != nil { + return nil, err + } + cont, err := container.ParseJSON([]byte(jsonData)) + + if err != nil { + return nil, err + } + // fmt.Printf("%+v", cont) + + cont.Set(ba.ClassName, "classname") + + if err != nil { + return nil, err + } + fmt.Printf("%+v", cont) + return toStringMap(cont.Data()), nil +} diff --git a/models/fv_ae_pg.go b/models/fv_ae_pg.go new file mode 100644 index 00000000..49e13511 --- /dev/null +++ b/models/fv_ae_pg.go @@ -0,0 +1,122 @@ +package models + + +import ( + "fmt" + "strconv" + + "github.com/ciscoecosystem/aci-go-client/container" +) + +const FvaepgClassName = "fvAEPg" + +type ApplicationEPG struct { + BaseAttributes + ApplicationEPGAttributes +} + +type ApplicationEPGAttributes struct { + Annotation string `json:",omitempty"` + ExceptionTag string `json:",omitempty"` + FloodOnEncap string `json:",omitempty"` + FwdCtrl string `json:",omitempty"` + HasMcastSource string `json:",omitempty"` + IsAttrBasedEPg string `json:",omitempty"` + MatchT string `json:",omitempty"` + NameAlias string `json:",omitempty"` + PcEnfPref string `json:",omitempty"` + PrefGrMemb string `json:",omitempty"` + Prio string `json:",omitempty"` + Shutdown string `json:",omitempty"` + +} + + +func NewApplicationEPG(fvAEPgRn, parentDn, description string, fvAEPgattr ApplicationEPGAttributes) *ApplicationEPG { + dn := fmt.Sprintf("%s/%s", parentDn, fvAEPgRn) + return &ApplicationEPG{ + BaseAttributes: BaseAttributes{ + DistinguishedName: dn, + Description: description, + Status: "created, modified", + ClassName: FvaepgClassName, + Rn: fvAEPgRn, + }, + + ApplicationEPGAttributes: fvAEPgattr, + + } +} + +func (fvAEPg *ApplicationEPG) ToMap() (map[string]string, error) { + fvAEPgMap, err := fvAEPg.BaseAttributes.ToMap() + if err != nil { + return nil, err + } + + A(fvAEPgMap, "annotation",fvAEPg.Annotation) + A(fvAEPgMap, "exceptionTag",fvAEPg.ExceptionTag) + A(fvAEPgMap, "floodOnEncap",fvAEPg.FloodOnEncap) + A(fvAEPgMap, "fwdCtrl",fvAEPg.FwdCtrl) + A(fvAEPgMap, "hasMcastSource",fvAEPg.HasMcastSource) + A(fvAEPgMap, "isAttrBasedEPg",fvAEPg.IsAttrBasedEPg) + A(fvAEPgMap, "matchT",fvAEPg.MatchT) + A(fvAEPgMap, "nameAlias",fvAEPg.NameAlias) + A(fvAEPgMap, "pcEnfPref",fvAEPg.PcEnfPref) + A(fvAEPgMap, "prefGrMemb",fvAEPg.PrefGrMemb) + A(fvAEPgMap, "prio",fvAEPg.Prio) + A(fvAEPgMap, "shutdown",fvAEPg.Shutdown) + + + + return fvAEPgMap, err +} + +func ApplicationEPGFromContainerList(cont *container.Container, index int) *ApplicationEPG { + + ApplicationEPGCont := cont.S("imdata").Index(index).S(FvaepgClassName, "attributes") + return &ApplicationEPG{ + BaseAttributes{ + DistinguishedName: G(ApplicationEPGCont, "dn"), + Description: G(ApplicationEPGCont, "descr"), + Status: G(ApplicationEPGCont, "status"), + ClassName: FvaepgClassName, + Rn: G(ApplicationEPGCont, "rn"), + }, + + ApplicationEPGAttributes{ + Annotation : G(ApplicationEPGCont, "annotation"), + ExceptionTag : G(ApplicationEPGCont, "exceptionTag"), + FloodOnEncap : G(ApplicationEPGCont, "floodOnEncap"), + FwdCtrl : G(ApplicationEPGCont, "fwdCtrl"), + HasMcastSource : G(ApplicationEPGCont, "hasMcastSource"), + IsAttrBasedEPg : G(ApplicationEPGCont, "isAttrBasedEPg"), + MatchT : G(ApplicationEPGCont, "matchT"), + NameAlias : G(ApplicationEPGCont, "nameAlias"), + PcEnfPref : G(ApplicationEPGCont, "pcEnfPref"), + PrefGrMemb : G(ApplicationEPGCont, "prefGrMemb"), + Prio : G(ApplicationEPGCont, "prio"), + Shutdown : G(ApplicationEPGCont, "shutdown"), + + }, + + } +} + +func ApplicationEPGFromContainer(cont *container.Container) *ApplicationEPG { + + return ApplicationEPGFromContainerList(cont, 0) +} + +func ApplicationEPGListFromContainer(cont *container.Container) []*ApplicationEPG { + length, _ := strconv.Atoi(G(cont, "totalCount")) + + arr := make([]*ApplicationEPG, length) + + for i := 0; i < length; i++ { + + arr[i] = ApplicationEPGFromContainerList(cont, i) + } + + return arr +} \ No newline at end of file diff --git a/models/fv_ap.go b/models/fv_ap.go new file mode 100644 index 00000000..4e0776e1 --- /dev/null +++ b/models/fv_ap.go @@ -0,0 +1,95 @@ +package models + + +import ( + "fmt" + "strconv" + + "github.com/ciscoecosystem/aci-go-client/container" +) + +const FvapClassName = "fvAp" + +type ApplicationProfile struct { + BaseAttributes + ApplicationProfileAttributes +} + +type ApplicationProfileAttributes struct { + Annotation string `json:",omitempty"` + NameAlias string `json:",omitempty"` + Prio string `json:",omitempty"` + +} + + +func NewApplicationProfile(fvApRn, parentDn, description string, fvApattr ApplicationProfileAttributes) *ApplicationProfile { + dn := fmt.Sprintf("%s/%s", parentDn, fvApRn) + return &ApplicationProfile{ + BaseAttributes: BaseAttributes{ + DistinguishedName: dn, + Description: description, + Status: "created, modified", + ClassName: FvapClassName, + Rn: fvApRn, + }, + + ApplicationProfileAttributes: fvApattr, + + } +} + +func (fvAp *ApplicationProfile) ToMap() (map[string]string, error) { + fvApMap, err := fvAp.BaseAttributes.ToMap() + if err != nil { + return nil, err + } + + A(fvApMap, "annotation",fvAp.Annotation) + A(fvApMap, "nameAlias",fvAp.NameAlias) + A(fvApMap, "prio",fvAp.Prio) + + + + return fvApMap, err +} + +func ApplicationProfileFromContainerList(cont *container.Container, index int) *ApplicationProfile { + + ApplicationProfileCont := cont.S("imdata").Index(index).S(FvapClassName, "attributes") + return &ApplicationProfile{ + BaseAttributes{ + DistinguishedName: G(ApplicationProfileCont, "dn"), + Description: G(ApplicationProfileCont, "descr"), + Status: G(ApplicationProfileCont, "status"), + ClassName: FvapClassName, + Rn: G(ApplicationProfileCont, "rn"), + }, + + ApplicationProfileAttributes{ + Annotation : G(ApplicationProfileCont, "annotation"), + NameAlias : G(ApplicationProfileCont, "nameAlias"), + Prio : G(ApplicationProfileCont, "prio"), + + }, + + } +} + +func ApplicationProfileFromContainer(cont *container.Container) *ApplicationProfile { + + return ApplicationProfileFromContainerList(cont, 0) +} + +func ApplicationProfileListFromContainer(cont *container.Container) []*ApplicationProfile { + length, _ := strconv.Atoi(G(cont, "totalCount")) + + arr := make([]*ApplicationProfile, length) + + for i := 0; i < length; i++ { + + arr[i] = ApplicationProfileFromContainerList(cont, i) + } + + return arr +} \ No newline at end of file diff --git a/models/fv_bd.go b/models/fv_bd.go new file mode 100644 index 00000000..ac5d4cd8 --- /dev/null +++ b/models/fv_bd.go @@ -0,0 +1,146 @@ +package models + + +import ( + "fmt" + "strconv" + + "github.com/ciscoecosystem/aci-go-client/container" +) + +const FvbdClassName = "fvBD" + +type BridgeDomain struct { + BaseAttributes + BridgeDomainAttributes +} + +type BridgeDomainAttributes struct { + OptimizeWanBandwidth string `json:",omitempty"` + Annotation string `json:",omitempty"` + ArpFlood string `json:",omitempty"` + EpClear string `json:",omitempty"` + EpMoveDetectMode string `json:",omitempty"` + HostBasedRouting string `json:",omitempty"` + IntersiteBumTrafficAllow string `json:",omitempty"` + IntersiteL2Stretch string `json:",omitempty"` + IpLearning string `json:",omitempty"` + LimitIpLearnToSubnets string `json:",omitempty"` + LlAddr string `json:",omitempty"` + Mac string `json:",omitempty"` + McastAllow string `json:",omitempty"` + MultiDstPktAct string `json:",omitempty"` + NameAlias string `json:",omitempty"` + Type string `json:",omitempty"` + UnicastRoute string `json:",omitempty"` + UnkMacUcastAct string `json:",omitempty"` + UnkMcastAct string `json:",omitempty"` + Vmac string `json:",omitempty"` + +} + + +func NewBridgeDomain(fvBDRn, parentDn, description string, fvBDattr BridgeDomainAttributes) *BridgeDomain { + dn := fmt.Sprintf("%s/%s", parentDn, fvBDRn) + return &BridgeDomain{ + BaseAttributes: BaseAttributes{ + DistinguishedName: dn, + Description: description, + Status: "created, modified", + ClassName: FvbdClassName, + Rn: fvBDRn, + }, + + BridgeDomainAttributes: fvBDattr, + + } +} + +func (fvBD *BridgeDomain) ToMap() (map[string]string, error) { + fvBDMap, err := fvBD.BaseAttributes.ToMap() + if err != nil { + return nil, err + } + + A(fvBDMap, "OptimizeWanBandwidth",fvBD.OptimizeWanBandwidth) + A(fvBDMap, "annotation",fvBD.Annotation) + A(fvBDMap, "arpFlood",fvBD.ArpFlood) + A(fvBDMap, "epClear",fvBD.EpClear) + A(fvBDMap, "epMoveDetectMode",fvBD.EpMoveDetectMode) + A(fvBDMap, "hostBasedRouting",fvBD.HostBasedRouting) + A(fvBDMap, "intersiteBumTrafficAllow",fvBD.IntersiteBumTrafficAllow) + A(fvBDMap, "intersiteL2Stretch",fvBD.IntersiteL2Stretch) + A(fvBDMap, "ipLearning",fvBD.IpLearning) + A(fvBDMap, "limitIpLearnToSubnets",fvBD.LimitIpLearnToSubnets) + A(fvBDMap, "llAddr",fvBD.LlAddr) + A(fvBDMap, "mac",fvBD.Mac) + A(fvBDMap, "mcastAllow",fvBD.McastAllow) + A(fvBDMap, "multiDstPktAct",fvBD.MultiDstPktAct) + A(fvBDMap, "nameAlias",fvBD.NameAlias) + A(fvBDMap, "type",fvBD.Type) + A(fvBDMap, "unicastRoute",fvBD.UnicastRoute) + A(fvBDMap, "unkMacUcastAct",fvBD.UnkMacUcastAct) + A(fvBDMap, "unkMcastAct",fvBD.UnkMcastAct) + A(fvBDMap, "vmac",fvBD.Vmac) + + + + return fvBDMap, err +} + +func BridgeDomainFromContainerList(cont *container.Container, index int) *BridgeDomain { + + BridgeDomainCont := cont.S("imdata").Index(index).S(FvbdClassName, "attributes") + return &BridgeDomain{ + BaseAttributes{ + DistinguishedName: G(BridgeDomainCont, "dn"), + Description: G(BridgeDomainCont, "descr"), + Status: G(BridgeDomainCont, "status"), + ClassName: FvbdClassName, + Rn: G(BridgeDomainCont, "rn"), + }, + + BridgeDomainAttributes{ + OptimizeWanBandwidth : G(BridgeDomainCont, "OptimizeWanBandwidth"), + Annotation : G(BridgeDomainCont, "annotation"), + ArpFlood : G(BridgeDomainCont, "arpFlood"), + EpClear : G(BridgeDomainCont, "epClear"), + EpMoveDetectMode : G(BridgeDomainCont, "epMoveDetectMode"), + HostBasedRouting : G(BridgeDomainCont, "hostBasedRouting"), + IntersiteBumTrafficAllow : G(BridgeDomainCont, "intersiteBumTrafficAllow"), + IntersiteL2Stretch : G(BridgeDomainCont, "intersiteL2Stretch"), + IpLearning : G(BridgeDomainCont, "ipLearning"), + LimitIpLearnToSubnets : G(BridgeDomainCont, "limitIpLearnToSubnets"), + LlAddr : G(BridgeDomainCont, "llAddr"), + Mac : G(BridgeDomainCont, "mac"), + McastAllow : G(BridgeDomainCont, "mcastAllow"), + MultiDstPktAct : G(BridgeDomainCont, "multiDstPktAct"), + NameAlias : G(BridgeDomainCont, "nameAlias"), + Type : G(BridgeDomainCont, "type"), + UnicastRoute : G(BridgeDomainCont, "unicastRoute"), + UnkMacUcastAct : G(BridgeDomainCont, "unkMacUcastAct"), + UnkMcastAct : G(BridgeDomainCont, "unkMcastAct"), + Vmac : G(BridgeDomainCont, "vmac"), + + }, + + } +} + +func BridgeDomainFromContainer(cont *container.Container) *BridgeDomain { + + return BridgeDomainFromContainerList(cont, 0) +} + +func BridgeDomainListFromContainer(cont *container.Container) []*BridgeDomain { + length, _ := strconv.Atoi(G(cont, "totalCount")) + + arr := make([]*BridgeDomain, length) + + for i := 0; i < length; i++ { + + arr[i] = BridgeDomainFromContainerList(cont, i) + } + + return arr +} \ No newline at end of file diff --git a/models/fv_subnet.go b/models/fv_subnet.go new file mode 100644 index 00000000..3a167359 --- /dev/null +++ b/models/fv_subnet.go @@ -0,0 +1,107 @@ +package models + + +import ( + "fmt" + "strconv" + + "github.com/ciscoecosystem/aci-go-client/container" +) + +const FvsubnetClassName = "fvSubnet" + +type Subnet struct { + BaseAttributes + SubnetAttributes +} + +type SubnetAttributes struct { + Annotation string `json:",omitempty"` + Ctrl string `json:",omitempty"` + Ip string `json:",omitempty"` + NameAlias string `json:",omitempty"` + Preferred string `json:",omitempty"` + Scope string `json:",omitempty"` + Virtual string `json:",omitempty"` + +} + + +func NewSubnet(fvSubnetRn, parentDn, description string, fvSubnetattr SubnetAttributes) *Subnet { + dn := fmt.Sprintf("%s/%s", parentDn, fvSubnetRn) + return &Subnet{ + BaseAttributes: BaseAttributes{ + DistinguishedName: dn, + Description: description, + Status: "created, modified", + ClassName: FvsubnetClassName, + Rn: fvSubnetRn, + }, + + SubnetAttributes: fvSubnetattr, + + } +} + +func (fvSubnet *Subnet) ToMap() (map[string]string, error) { + fvSubnetMap, err := fvSubnet.BaseAttributes.ToMap() + if err != nil { + return nil, err + } + + A(fvSubnetMap, "annotation",fvSubnet.Annotation) + A(fvSubnetMap, "ctrl",fvSubnet.Ctrl) + A(fvSubnetMap, "ip",fvSubnet.Ip) + A(fvSubnetMap, "nameAlias",fvSubnet.NameAlias) + A(fvSubnetMap, "preferred",fvSubnet.Preferred) + A(fvSubnetMap, "scope",fvSubnet.Scope) + A(fvSubnetMap, "virtual",fvSubnet.Virtual) + + + + return fvSubnetMap, err +} + +func SubnetFromContainerList(cont *container.Container, index int) *Subnet { + + SubnetCont := cont.S("imdata").Index(index).S(FvsubnetClassName, "attributes") + return &Subnet{ + BaseAttributes{ + DistinguishedName: G(SubnetCont, "dn"), + Description: G(SubnetCont, "descr"), + Status: G(SubnetCont, "status"), + ClassName: FvsubnetClassName, + Rn: G(SubnetCont, "rn"), + }, + + SubnetAttributes{ + Annotation : G(SubnetCont, "annotation"), + Ctrl : G(SubnetCont, "ctrl"), + Ip : G(SubnetCont, "ip"), + NameAlias : G(SubnetCont, "nameAlias"), + Preferred : G(SubnetCont, "preferred"), + Scope : G(SubnetCont, "scope"), + Virtual : G(SubnetCont, "virtual"), + + }, + + } +} + +func SubnetFromContainer(cont *container.Container) *Subnet { + + return SubnetFromContainerList(cont, 0) +} + +func SubnetListFromContainer(cont *container.Container) []*Subnet { + length, _ := strconv.Atoi(G(cont, "totalCount")) + + arr := make([]*Subnet, length) + + for i := 0; i < length; i++ { + + arr[i] = SubnetFromContainerList(cont, i) + } + + return arr +} \ No newline at end of file diff --git a/models/fv_tenant.go b/models/fv_tenant.go new file mode 100644 index 00000000..2afdd236 --- /dev/null +++ b/models/fv_tenant.go @@ -0,0 +1,88 @@ +package models + +import ( + "fmt" + "strconv" + + "github.com/ciscoecosystem/aci-go-client/container" +) + +const FvtenantClassName = "fvTenant" + +type Tenant struct { + BaseAttributes + TenantAttributes +} + +type TenantAttributes struct { + Annotation string `json:",omitempty"` + NameAlias string `json:",omitempty"` +} + +func FvTenant(tenantName string) string { + return fmt.Sprintf("tn-%s", tenantName) +} + +func NewTenant(fvTenantRn, parentDn, description string, fvTenantattr TenantAttributes) *Tenant { + dn := fmt.Sprintf("%s/%s", parentDn, fvTenantRn) + return &Tenant{ + BaseAttributes: BaseAttributes{ + DistinguishedName: dn, + Description: description, + Status: "created, modified", + ClassName: FvtenantClassName, + Rn: fvTenantRn, + }, + + TenantAttributes: fvTenantattr, + } +} + +func (fvTenant *Tenant) ToMap() (map[string]string, error) { + fvTenantMap, err := fvTenant.BaseAttributes.ToMap() + if err != nil { + return nil, err + } + + A(fvTenantMap, "annotation", fvTenant.Annotation) + A(fvTenantMap, "nameAlias", fvTenant.NameAlias) + + return fvTenantMap, err +} + +func TenantFromContainerList(cont *container.Container, index int) *Tenant { + + TenantCont := cont.S("imdata").Index(index).S(FvtenantClassName, "attributes") + return &Tenant{ + BaseAttributes{ + DistinguishedName: G(TenantCont, "dn"), + Description: G(TenantCont, "descr"), + Status: G(TenantCont, "status"), + ClassName: FvtenantClassName, + Rn: G(TenantCont, "rn"), + }, + + TenantAttributes{ + Annotation: G(TenantCont, "annotation"), + NameAlias: G(TenantCont, "nameAlias"), + }, + } +} + +func TenantFromContainer(cont *container.Container) *Tenant { + + return TenantFromContainerList(cont, 0) +} + +func TenantListFromContainer(cont *container.Container) []*Tenant { + length, _ := strconv.Atoi(G(cont, "totalCount")) + + arr := make([]*Tenant, length) + + for i := 0; i < length; i++ { + + arr[i] = TenantFromContainerList(cont, i) + } + + return arr +} diff --git a/models/model.go b/models/model.go new file mode 100644 index 00000000..cbb2467e --- /dev/null +++ b/models/model.go @@ -0,0 +1,5 @@ +package models + +type Model interface { + ToMap() (map[string]string, error) +} diff --git a/models/util.go b/models/util.go new file mode 100644 index 00000000..8a0cd9ab --- /dev/null +++ b/models/util.go @@ -0,0 +1,68 @@ +package models + +import ( + "fmt" + "strings" + + "github.com/ciscoecosystem/aci-go-client/container" +) + +func toStringMap(intf interface{}) map[string]string { + + result := make(map[string]string) + temp := intf.(map[string]interface{}) + + for key, value := range temp { + result[key] = value.(string) + } + + return result +} + +func StripQuotes(word string) string { + if strings.HasPrefix(word, "\"") && strings.HasSuffix(word, "\"") { + return strings.TrimSuffix(strings.TrimPrefix(word, "\""), "\"") + } + return word +} + +func stripSquareBrackets(word string) string { + if strings.HasPrefix(word, "[") && strings.HasSuffix(word, "]") { + return strings.TrimSuffix(strings.TrimPrefix(word, "["), "]") + } + return word +} + +func BoolToString(value bool) string { + if value { + return "yes" + } + return "no" +} + +func StringToBool(value string) bool { + if value == "yes" { + return true + } + return false +} + +func A(data map[string]string, key, value string) { + fmt.Println(key) + if value != "" { + data[key] = value + } +} + +func G(cont *container.Container, key string) string { + return StripQuotes(cont.S(key).String()) +} + +func GetMOName(dn string) string { + arr := strings.Split(dn, "/") + hashedName := arr[len(arr)-1] + nameArr := strings.Split(hashedName, "-") + name := strings.Join(nameArr[1:], "-") + return name + +} diff --git a/models/vz_br_cp.go b/models/vz_br_cp.go new file mode 100644 index 00000000..34cbe06d --- /dev/null +++ b/models/vz_br_cp.go @@ -0,0 +1,101 @@ +package models + + +import ( + "fmt" + "strconv" + + "github.com/ciscoecosystem/aci-go-client/container" +) + +const VzbrcpClassName = "vzBrCP" + +type Contract struct { + BaseAttributes + ContractAttributes +} + +type ContractAttributes struct { + Annotation string `json:",omitempty"` + NameAlias string `json:",omitempty"` + Prio string `json:",omitempty"` + Scope string `json:",omitempty"` + TargetDscp string `json:",omitempty"` + +} + + +func NewContract(vzBrCPRn, parentDn, description string, vzBrCPattr ContractAttributes) *Contract { + dn := fmt.Sprintf("%s/%s", parentDn, vzBrCPRn) + return &Contract{ + BaseAttributes: BaseAttributes{ + DistinguishedName: dn, + Description: description, + Status: "created, modified", + ClassName: VzbrcpClassName, + Rn: vzBrCPRn, + }, + + ContractAttributes: vzBrCPattr, + + } +} + +func (vzBrCP *Contract) ToMap() (map[string]string, error) { + vzBrCPMap, err := vzBrCP.BaseAttributes.ToMap() + if err != nil { + return nil, err + } + + A(vzBrCPMap, "annotation",vzBrCP.Annotation) + A(vzBrCPMap, "nameAlias",vzBrCP.NameAlias) + A(vzBrCPMap, "prio",vzBrCP.Prio) + A(vzBrCPMap, "scope",vzBrCP.Scope) + A(vzBrCPMap, "targetDscp",vzBrCP.TargetDscp) + + + + return vzBrCPMap, err +} + +func ContractFromContainerList(cont *container.Container, index int) *Contract { + + ContractCont := cont.S("imdata").Index(index).S(VzbrcpClassName, "attributes") + return &Contract{ + BaseAttributes{ + DistinguishedName: G(ContractCont, "dn"), + Description: G(ContractCont, "descr"), + Status: G(ContractCont, "status"), + ClassName: VzbrcpClassName, + Rn: G(ContractCont, "rn"), + }, + + ContractAttributes{ + Annotation : G(ContractCont, "annotation"), + NameAlias : G(ContractCont, "nameAlias"), + Prio : G(ContractCont, "prio"), + Scope : G(ContractCont, "scope"), + TargetDscp : G(ContractCont, "targetDscp"), + + }, + + } +} + +func ContractFromContainer(cont *container.Container) *Contract { + + return ContractFromContainerList(cont, 0) +} + +func ContractListFromContainer(cont *container.Container) []*Contract { + length, _ := strconv.Atoi(G(cont, "totalCount")) + + arr := make([]*Contract, length) + + for i := 0; i < length; i++ { + + arr[i] = ContractFromContainerList(cont, i) + } + + return arr +} \ No newline at end of file diff --git a/models/vz_entry.go b/models/vz_entry.go new file mode 100644 index 00000000..a9124e6f --- /dev/null +++ b/models/vz_entry.go @@ -0,0 +1,131 @@ +package models + + +import ( + "fmt" + "strconv" + + "github.com/ciscoecosystem/aci-go-client/container" +) + +const VzentryClassName = "vzEntry" + +type FilterEntry struct { + BaseAttributes + FilterEntryAttributes +} + +type FilterEntryAttributes struct { + Annotation string `json:",omitempty"` + ApplyToFrag string `json:",omitempty"` + ArpOpc string `json:",omitempty"` + DFromPort string `json:",omitempty"` + DToPort string `json:",omitempty"` + EtherT string `json:",omitempty"` + Icmpv4T string `json:",omitempty"` + Icmpv6T string `json:",omitempty"` + MatchDscp string `json:",omitempty"` + NameAlias string `json:",omitempty"` + Prot string `json:",omitempty"` + SFromPort string `json:",omitempty"` + SToPort string `json:",omitempty"` + Stateful string `json:",omitempty"` + TcpRules string `json:",omitempty"` + +} + + +func NewFilterEntry(vzEntryRn, parentDn, description string, vzEntryattr FilterEntryAttributes) *FilterEntry { + dn := fmt.Sprintf("%s/%s", parentDn, vzEntryRn) + return &FilterEntry{ + BaseAttributes: BaseAttributes{ + DistinguishedName: dn, + Description: description, + Status: "created, modified", + ClassName: VzentryClassName, + Rn: vzEntryRn, + }, + + FilterEntryAttributes: vzEntryattr, + + } +} + +func (vzEntry *FilterEntry) ToMap() (map[string]string, error) { + vzEntryMap, err := vzEntry.BaseAttributes.ToMap() + if err != nil { + return nil, err + } + + A(vzEntryMap, "annotation",vzEntry.Annotation) + A(vzEntryMap, "applyToFrag",vzEntry.ApplyToFrag) + A(vzEntryMap, "arpOpc",vzEntry.ArpOpc) + A(vzEntryMap, "dFromPort",vzEntry.DFromPort) + A(vzEntryMap, "dToPort",vzEntry.DToPort) + A(vzEntryMap, "etherT",vzEntry.EtherT) + A(vzEntryMap, "icmpv4T",vzEntry.Icmpv4T) + A(vzEntryMap, "icmpv6T",vzEntry.Icmpv6T) + A(vzEntryMap, "matchDscp",vzEntry.MatchDscp) + A(vzEntryMap, "nameAlias",vzEntry.NameAlias) + A(vzEntryMap, "prot",vzEntry.Prot) + A(vzEntryMap, "sFromPort",vzEntry.SFromPort) + A(vzEntryMap, "sToPort",vzEntry.SToPort) + A(vzEntryMap, "stateful",vzEntry.Stateful) + A(vzEntryMap, "tcpRules",vzEntry.TcpRules) + + + + return vzEntryMap, err +} + +func FilterEntryFromContainerList(cont *container.Container, index int) *FilterEntry { + + FilterEntryCont := cont.S("imdata").Index(index).S(VzentryClassName, "attributes") + return &FilterEntry{ + BaseAttributes{ + DistinguishedName: G(FilterEntryCont, "dn"), + Description: G(FilterEntryCont, "descr"), + Status: G(FilterEntryCont, "status"), + ClassName: VzentryClassName, + Rn: G(FilterEntryCont, "rn"), + }, + + FilterEntryAttributes{ + Annotation : G(FilterEntryCont, "annotation"), + ApplyToFrag : G(FilterEntryCont, "applyToFrag"), + ArpOpc : G(FilterEntryCont, "arpOpc"), + DFromPort : G(FilterEntryCont, "dFromPort"), + DToPort : G(FilterEntryCont, "dToPort"), + EtherT : G(FilterEntryCont, "etherT"), + Icmpv4T : G(FilterEntryCont, "icmpv4T"), + Icmpv6T : G(FilterEntryCont, "icmpv6T"), + MatchDscp : G(FilterEntryCont, "matchDscp"), + NameAlias : G(FilterEntryCont, "nameAlias"), + Prot : G(FilterEntryCont, "prot"), + SFromPort : G(FilterEntryCont, "sFromPort"), + SToPort : G(FilterEntryCont, "sToPort"), + Stateful : G(FilterEntryCont, "stateful"), + TcpRules : G(FilterEntryCont, "tcpRules"), + + }, + + } +} + +func FilterEntryFromContainer(cont *container.Container) *FilterEntry { + + return FilterEntryFromContainerList(cont, 0) +} + +func FilterEntryListFromContainer(cont *container.Container) []*FilterEntry { + length, _ := strconv.Atoi(G(cont, "totalCount")) + + arr := make([]*FilterEntry, length) + + for i := 0; i < length; i++ { + + arr[i] = FilterEntryFromContainerList(cont, i) + } + + return arr +} \ No newline at end of file diff --git a/models/vz_filter.go b/models/vz_filter.go new file mode 100644 index 00000000..5b8e00fb --- /dev/null +++ b/models/vz_filter.go @@ -0,0 +1,92 @@ +package models + + +import ( + "fmt" + "strconv" + + "github.com/ciscoecosystem/aci-go-client/container" +) + +const VzfilterClassName = "vzFilter" + +type Filter struct { + BaseAttributes + FilterAttributes +} + +type FilterAttributes struct { + Annotation string `json:",omitempty"` + NameAlias string `json:",omitempty"` + +} + + +func NewFilter(vzFilterRn, parentDn, description string, vzFilterattr FilterAttributes) *Filter { + dn := fmt.Sprintf("%s/%s", parentDn, vzFilterRn) + return &Filter{ + BaseAttributes: BaseAttributes{ + DistinguishedName: dn, + Description: description, + Status: "created, modified", + ClassName: VzfilterClassName, + Rn: vzFilterRn, + }, + + FilterAttributes: vzFilterattr, + + } +} + +func (vzFilter *Filter) ToMap() (map[string]string, error) { + vzFilterMap, err := vzFilter.BaseAttributes.ToMap() + if err != nil { + return nil, err + } + + A(vzFilterMap, "annotation",vzFilter.Annotation) + A(vzFilterMap, "nameAlias",vzFilter.NameAlias) + + + + return vzFilterMap, err +} + +func FilterFromContainerList(cont *container.Container, index int) *Filter { + + FilterCont := cont.S("imdata").Index(index).S(VzfilterClassName, "attributes") + return &Filter{ + BaseAttributes{ + DistinguishedName: G(FilterCont, "dn"), + Description: G(FilterCont, "descr"), + Status: G(FilterCont, "status"), + ClassName: VzfilterClassName, + Rn: G(FilterCont, "rn"), + }, + + FilterAttributes{ + Annotation : G(FilterCont, "annotation"), + NameAlias : G(FilterCont, "nameAlias"), + + }, + + } +} + +func FilterFromContainer(cont *container.Container) *Filter { + + return FilterFromContainerList(cont, 0) +} + +func FilterListFromContainer(cont *container.Container) []*Filter { + length, _ := strconv.Atoi(G(cont, "totalCount")) + + arr := make([]*Filter, length) + + for i := 0; i < length; i++ { + + arr[i] = FilterFromContainerList(cont, i) + } + + return arr +} \ No newline at end of file diff --git a/models/vz_subj.go b/models/vz_subj.go new file mode 100644 index 00000000..a1e5c2f5 --- /dev/null +++ b/models/vz_subj.go @@ -0,0 +1,107 @@ +package models + + +import ( + "fmt" + "strconv" + + "github.com/ciscoecosystem/aci-go-client/container" +) + +const VzsubjClassName = "vzSubj" + +type ContractSubject struct { + BaseAttributes + ContractSubjectAttributes +} + +type ContractSubjectAttributes struct { + Annotation string `json:",omitempty"` + ConsMatchT string `json:",omitempty"` + NameAlias string `json:",omitempty"` + Prio string `json:",omitempty"` + ProvMatchT string `json:",omitempty"` + RevFltPorts string `json:",omitempty"` + TargetDscp string `json:",omitempty"` + +} + + +func NewContractSubject(vzSubjRn, parentDn, description string, vzSubjattr ContractSubjectAttributes) *ContractSubject { + dn := fmt.Sprintf("%s/%s", parentDn, vzSubjRn) + return &ContractSubject{ + BaseAttributes: BaseAttributes{ + DistinguishedName: dn, + Description: description, + Status: "created, modified", + ClassName: VzsubjClassName, + Rn: vzSubjRn, + }, + + ContractSubjectAttributes: vzSubjattr, + + } +} + +func (vzSubj *ContractSubject) ToMap() (map[string]string, error) { + vzSubjMap, err := vzSubj.BaseAttributes.ToMap() + if err != nil { + return nil, err + } + + A(vzSubjMap, "annotation",vzSubj.Annotation) + A(vzSubjMap, "consMatchT",vzSubj.ConsMatchT) + A(vzSubjMap, "nameAlias",vzSubj.NameAlias) + A(vzSubjMap, "prio",vzSubj.Prio) + A(vzSubjMap, "provMatchT",vzSubj.ProvMatchT) + A(vzSubjMap, "revFltPorts",vzSubj.RevFltPorts) + A(vzSubjMap, "targetDscp",vzSubj.TargetDscp) + + + + return vzSubjMap, err +} + +func ContractSubjectFromContainerList(cont *container.Container, index int) *ContractSubject { + + ContractSubjectCont := cont.S("imdata").Index(index).S(VzsubjClassName, "attributes") + return &ContractSubject{ + BaseAttributes{ + DistinguishedName: G(ContractSubjectCont, "dn"), + Description: G(ContractSubjectCont, "descr"), + Status: G(ContractSubjectCont, "status"), + ClassName: VzsubjClassName, + Rn: G(ContractSubjectCont, "rn"), + }, + + ContractSubjectAttributes{ + Annotation : G(ContractSubjectCont, "annotation"), + ConsMatchT : G(ContractSubjectCont, "consMatchT"), + NameAlias : G(ContractSubjectCont, "nameAlias"), + Prio : G(ContractSubjectCont, "prio"), + ProvMatchT : G(ContractSubjectCont, "provMatchT"), + RevFltPorts : G(ContractSubjectCont, "revFltPorts"), + TargetDscp : G(ContractSubjectCont, "targetDscp"), + + }, + + } +} + +func ContractSubjectFromContainer(cont *container.Container) *ContractSubject { + + return ContractSubjectFromContainerList(cont, 0) +} + +func ContractSubjectListFromContainer(cont *container.Container) []*ContractSubject { + length, _ := strconv.Atoi(G(cont, "totalCount")) + + arr := make([]*ContractSubject, length) + + for i := 0; i < length; i++ { + + arr[i] = ContractSubjectFromContainerList(cont, i) + } + + return arr +} \ No newline at end of file diff --git a/tests/ap_test.go b/tests/ap_test.go new file mode 100644 index 00000000..a8bf48b6 --- /dev/null +++ b/tests/ap_test.go @@ -0,0 +1,187 @@ +package tests + +import "testing" +import "fmt" +import "github.com/ciscoecosystem/aci-go-client/client" +import "github.com/ciscoecosystem/aci-go-client/models" + +func createAp(c *client.Client, dn string, desc string, tenantName string) (*models.ApplicationProfile, error) { + + ap := models.NewApplicationProfile(dn, desc, tenantName) + err := c.Save(ap) + return ap, err +} + +func deleteAp(c *client.Client, tenant *models.Tenant, ap *models.ApplicationProfile) error { + err := c.Delete(ap) + + if err != nil { + return err + } + return deleteTenant(c, tenant) + +} + +func TestAPCreation(t *testing.T) { + client := GetTestClient() + tenant, err := createTenant(client, "terraform-test-tenant", "Test tenant created with golang aci-client-sdk.") + if err != nil { + t.Error(err) + } + + ap, err := createAp(client, "terrafrom-test-ap", "Test AP created with golang aci-client-sdk", models.GetMOName(tenant.DistinguishedName)) + if err != nil { + t.Error(err) + } + + err = deleteAp(client, tenant, ap) + if err != nil { + t.Error(err) + } +} + +func TestDuplicateAP(t *testing.T) { + client := GetTestClient() + tenant, err := createTenant(client, "terraform-test-tenant", "Test tenant created with golang aci-client-sdk.") + if err != nil { + t.Error(err) + } + + ap, err := createAp(client, "terrafrom-test-ap", "Test AP created with golang aci-client-sdk", models.GetMOName(tenant.DistinguishedName)) + if err != nil { + t.Error(err) + } + _, err = createAp(client, "terrafrom-test-ap", "Test AP created with golang aci-client-sdk", models.GetMOName(tenant.DistinguishedName)) + if err != nil { + t.Error(err) + } + + err = deleteAp(client, tenant, ap) + if err != nil { + t.Error(err) + } + +} + +func TestGetAPContainer(t *testing.T) { + client := GetTestClient() + tenant, err := createTenant(client, "terraform-test-tenant", "Test tenant created with golang aci-client-sdk.") + if err != nil { + t.Error(err) + } + + ap, err := createAp(client, "terrafrom-test-ap", "Test AP created with golang aci-clienr-sdk", models.GetMOName(tenant.DistinguishedName)) + if err != nil { + t.Error(err) + } + cont, err := client.Get(ap.DistinguishedName) + + if err != nil { + t.Fatal(err) + } + + t.Logf("%+v", cont) + err = deleteAp(client, tenant, ap) + if err != nil { + t.Error(err) + } +} + +func TestAPFromContainer(t *testing.T) { + client := GetTestClient() + tenant, err := createTenant(client, "terraform-test-tenant", "Test tenant created with golang aci-client-sdk.") + if err != nil { + t.Error(err) + } + + ap, err := createAp(client, "terrafrom-test-ap", "Test AP created with golang aci-clienr-sdk", models.GetMOName(tenant.DistinguishedName)) + if err != nil { + t.Error(err) + } + cont, err := client.Get(ap.DistinguishedName) + if err != nil { + t.Fatal(err) + } + + apCon := models.ApplicationProfileFromContainer(cont) + fmt.Println(apCon.DistinguishedName) + if apCon.DistinguishedName == "" { + t.Error("the application profile dn was empty") + + } + err = deleteAp(client, tenant, ap) + if err != nil { + t.Error(err) + } + +} + +func TestUpdateAP(t *testing.T) { + client := GetTestClient() + tenant, err := createTenant(client, "terraform-test-tenant", "Test tenant created with golang aci-client-sdk.") + if err != nil { + t.Error(err) + } + + ap, err := createAp(client, "terrafrom-test-ap", "Test AP created with golang aci-clienr-sdk", models.GetMOName(tenant.DistinguishedName)) + if err != nil { + t.Error(err) + } + cont, err := client.Get(ap.DistinguishedName) + if err != nil { + t.Fatal(err) + } + + apCon := models.ApplicationProfileFromContainer(cont) + fmt.Println(apCon.DistinguishedName) + if apCon.DistinguishedName == "" { + t.Error("the application profile dn was empty") + + } + + apCon.Description = "Updated the description" + err = client.Save(apCon) + if err != nil { + t.Error(err) + } + + fmt.Println("Updated AP") + err = deleteAp(client, tenant, ap) + if err != nil { + t.Error(err) + } + +} + +func TestAPDelete(t *testing.T) { + client := GetTestClient() + tenant, err := createTenant(client, "terraform-test-tenant", "Test tenant created with golang aci-client-sdk.") + if err != nil { + t.Error(err) + } + + ap, err := createAp(client, "terrafrom-test-ap", "Test AP created with golang aci-clienr-sdk", models.GetMOName(tenant.DistinguishedName)) + if err != nil { + t.Error(err) + } + cont, err := client.Get(ap.DistinguishedName) + if err != nil { + t.Fatal(err) + } + + apCon := models.ApplicationProfileFromContainer(cont) + fmt.Println(apCon.DistinguishedName) + if apCon.DistinguishedName == "" { + t.Error("the application profile dn was empty") + + } + + err = client.Delete(apCon) + if err != nil { + t.Error("the application profile was not removed") + } + err = deleteAp(client, tenant, ap) + if err != nil { + t.Error(err) + } +} diff --git a/tests/bd_test.go b/tests/bd_test.go new file mode 100644 index 00000000..7d46e8d0 --- /dev/null +++ b/tests/bd_test.go @@ -0,0 +1,137 @@ +package tests + +import ( + "fmt" + "testing" + + "github.com/ciscoecosystem/aci-go-client/client" + "github.com/ciscoecosystem/aci-go-client/models" +) + +func createBd(c *client.Client, dn string, desc string, parentDn string, bdattr models.BridgeDomainAttributes) (*models.BridgeDomain, error) { + + return c.CreateBridgeDomain(dn, desc, parentDn, bdattr) +} + +func deleteBd(c *client.Client, tenant *models.Tenant, bd *models.BridgeDomain) error { + err := c.DeleteBridgeDomain(models.GetMOName(bd.DistinguishedName), models.GetMOName(tenant.DistinguishedName)) + if err != nil { + return err + } + return deleteTenant(c, tenant) + +} + +func TestBDCreation(t *testing.T) { + client := GetTestClient() + tenant, err := createTenant(client, "terraform-test-tenant", "Test tenant created with golang aci-client-sdk.") + bdattr := models.BridgeDomainAttributes{} + bd, err := createBd(client, "terraform-test-bd", "Test Bridge Domain created with golang aci-client-sdk", models.GetMOName(tenant.DistinguishedName), bdattr) + if err != nil { + t.Error(err) + } + err = deleteBd(client, tenant, bd) + if err != nil { + t.Error(err) + } +} + +func TestDuplicateBD(t *testing.T) { + client := GetTestClient() + tenant, err := createTenant(client, "terraform-test-tenant", "Test tenant created with golang aci-client-sdk.") + bdattr := models.BridgeDomainAttributes{} + bd, err := createBd(client, "terraform-test-bd", "Test Bridge Domain created with golang aci-client-sdk", models.GetMOName(tenant.DistinguishedName), bdattr) + if err != nil { + t.Error(err) + } + _, err = createBd(client, "terraform-test-bd", "Test Bridge Domain created with golang aci-client-sdk", models.GetMOName(tenant.DistinguishedName), bdattr) + if err != nil { + t.Error(err) + } + err = deleteBd(client, tenant, bd) + if err != nil { + t.Error(err) + } + +} + +func TestBDUpdate(t *testing.T) { + client := GetTestClient() + tenant, err := createTenant(client, "terraform-test-tenant", "Test tenant created with golang aci-client-sdk.") + bdattr := models.BridgeDomainAttributes{} + bd, err := createBd(client, "terraform-test-bd", "Test Bridge Domain created with golang aci-client-sdk", models.GetMOName(tenant.DistinguishedName), bdattr) + bdCon, err := client.ReadBridgeDomain(models.GetMOName(bd.DistinguishedName), models.GetMOName(tenant.DistinguishedName)) + if err != nil { + t.Fatal(err) + } + + fmt.Println(bdCon.DistinguishedName) + if bdCon.DistinguishedName == "" { + t.Error("the Bridge Domain dn was empty") + + } + + bdCon.MAC = "00:22:BD:88:AA:BB" + _, err = client.UpdateBridgeDomain(models.GetMOName(bdCon.DistinguishedName), bdCon.Description, models.GetMOName(tenant.DistinguishedName), bdCon.BridgeDomainAttributes) + if err != nil { + t.Error(err) + } + fmt.Println("Updated the bd") + err = deleteBd(client, tenant, bd) + if err != nil { + t.Error(err) + } +} + +func TestBDDelete(t *testing.T) { + client := GetTestClient() + tenant, err := createTenant(client, "terraform-test-tenant", "Test tenant created with golang aci-client-sdk.") + bdattr := models.BridgeDomainAttributes{} + bd, err := createBd(client, "terraform-test-bd", "Test Bridge Domain created with golang aci-client-sdk", models.GetMOName(tenant.DistinguishedName), bdattr) + bdCon, err := client.ReadBridgeDomain(models.GetMOName(bd.DistinguishedName), models.GetMOName(tenant.DistinguishedName)) + if err != nil { + t.Fatal(err) + } + + fmt.Println(bdCon.DistinguishedName) + if bdCon.DistinguishedName == "" { + t.Error("the Bridge Domain dn was empty") + + } + + err = client.DeleteBridgeDomain(models.GetMOName(bdCon.DistinguishedName), models.GetMOName(tenant.DistinguishedName)) + if err != nil { + t.Error("the Bridge Domain was not removed") + } + err = deleteBd(client, tenant, bd) + if err != nil { + t.Error(err) + } +} + +func TestListBD(t *testing.T) { + client := GetTestClient() + tenant, err := createTenant(client, "terraform-test-tenant", "Test tenant created with golang aci-client-sdk.") + bdattr := models.BridgeDomainAttributes{} + bd, err := createBd(client, "terraform-test-bd", "Test Bridge Domain created with golang aci-client-sdk", models.GetMOName(tenant.DistinguishedName), bdattr) + bd1, err := createBd(client, "terraform-test-bd1", "Test Bridge Domain created with golang aci-client-sdk", models.GetMOName(tenant.DistinguishedName), bdattr) + bd2, err := createBd(client, "terraform-test-bd2", "Test Bridge Domain created with golang aci-client-sdk", models.GetMOName(tenant.DistinguishedName), bdattr) + + if err != nil { + t.Error(err) + } + + cont, err := client.ListBridgeDomain(models.GetMOName(tenant.DistinguishedName)) + + fmt.Printf("\n\n List %+v\n\n", cont) + if err != nil { + t.Error(err) + } + + err = deleteBd(client, tenant, bd) + err = deleteBd(client, tenant, bd1) + err = deleteBd(client, tenant, bd2) + + t.Error(err) + +} diff --git a/tests/contract_test.go b/tests/contract_test.go new file mode 100644 index 00000000..15db6c7c --- /dev/null +++ b/tests/contract_test.go @@ -0,0 +1,150 @@ +package tests + +import ( + "fmt" + "testing" + + "github.com/ciscoecosystem/aci-go-client/client" + "github.com/ciscoecosystem/aci-go-client/models" +) + +func createContract(c *client.Client, dn string, desc string, parentDn string, contractAttr models.ContractAttributes) (*models.Contract, error) { + contract := models.NewContract(dn, desc, parentDn, contractAttr) + err := c.Save(contract) + return contract, err +} + +func deleteContarct(c *client.Client, tenant *models.Tenant, contract *models.Contract) error { + err := c.Delete(contract) + if err != nil { + return err + } + return deleteTenant(c, tenant) +} +func TestContractCreation(t *testing.T) { + client := GetTestClient() + tenant, err := createTenant(client, "terraform-test-tenant", "Test tenant created with golang aci-client-sdk.") + contract, err := createContract(client, "terraform-test-contract", "Test Contarct created with golang aci-client-sdk", models.GetMOName(tenant.DistinguishedName), models.ContractAttributes{}) + + if err != nil { + t.Error(err) + } + err = deleteContarct(client, tenant, contract) + if err != nil { + t.Error(err) + } + +} + +func TestDuplicateContract(t *testing.T) { + client := GetTestClient() + tenant, err := createTenant(client, "terraform-test-tenant", "Test tenant created with golang aci-client-sdk.") + contract, err := createContract(client, "terraform-test-contract", "Test Contarct created with golang aci-client-sdk", models.GetMOName(tenant.DistinguishedName), models.ContractAttributes{}) + + if err != nil { + t.Error(err) + } + _, err = createContract(client, "terraform-test-contract", "Test Contarct created with golang aci-client-sdk", models.GetMOName(tenant.DistinguishedName), models.ContractAttributes{}) + if err != nil { + t.Error(err) + } + err = deleteContarct(client, tenant, contract) + if err != nil { + t.Error(err) + } + +} + +func TestGetContractContainer(t *testing.T) { + client := GetTestClient() + tenant, err := createTenant(client, "terraform-test-tenant", "Test tenant created with golang aci-client-sdk.") + contract, err := createContract(client, "terraform-test-contract", "Test Contarct created with golang aci-client-sdk", models.GetMOName(tenant.DistinguishedName), models.ContractAttributes{}) + cont, err := client.Get(contract.DistinguishedName) + + if err != nil { + t.Fatal(err) + } + + t.Logf("%+v", cont) + err = deleteContarct(client, tenant, contract) + if err != nil { + t.Error(err) + } +} + +func TestContractFromContainer(t *testing.T) { + client := GetTestClient() + tenant, err := createTenant(client, "terraform-test-tenant", "Test tenant created with golang aci-client-sdk.") + contract, err := createContract(client, "terraform-test-contract", "Test Contarct created with golang aci-client-sdk", models.GetMOName(tenant.DistinguishedName), models.ContractAttributes{}) + cont, err := client.Get(contract.DistinguishedName) + if err != nil { + t.Fatal(err) + } + + contractCon := models.ContractFromContainer(cont) + fmt.Println(contractCon.DistinguishedName) + if contractCon.DistinguishedName == "" { + t.Error("the contract dn was empty") + + } + err = deleteContarct(client, tenant, contract) + if err != nil { + t.Error(err) + } +} + +func TestContractUpdate(t *testing.T) { + client := GetTestClient() + tenant, err := createTenant(client, "terraform-test-tenant", "Test tenant created with golang aci-client-sdk.") + contract, err := createContract(client, "terraform-test-contract", "Test Contarct created with golang aci-client-sdk", models.GetMOName(tenant.DistinguishedName), models.ContractAttributes{}) + cont, err := client.Get(contract.DistinguishedName) + + if err != nil { + t.Fatal(err) + } + + contractCon := models.ContractFromContainer(cont) + fmt.Println(contractCon.DistinguishedName) + if contractCon.DistinguishedName == "" { + t.Error("the contract dn was empty") + + } + + contractCon.Scope = "tenant" + err = client.Save(contractCon) + if err != nil { + t.Error(err) + } + fmt.Println("Contract was Updated") + err = deleteContarct(client, tenant, contract) + if err != nil { + t.Error(err) + } + +} +func TestContractDelete(t *testing.T) { + client := GetTestClient() + tenant, err := createTenant(client, "terraform-test-tenant", "Test tenant created with golang aci-client-sdk.") + contract, err := createContract(client, "terraform-test-contract", "Test Contarct created with golang aci-client-sdk", models.GetMOName(tenant.DistinguishedName), models.ContractAttributes{}) + cont, err := client.Get(contract.DistinguishedName) + if err != nil { + t.Fatal(err) + } + + contractCon := models.ContractFromContainer(cont) + fmt.Println(contractCon.DistinguishedName) + if contractCon.DistinguishedName == "" { + t.Error("the contract dn was empty") + + } + + err = client.Delete(contractCon) + if err != nil { + t.Error("the contract was not removed") + } + err = deleteContarct(client, tenant, contract) + if err != nil { + t.Error(err) + } + +} diff --git a/tests/debug.test b/tests/debug.test new file mode 100644 index 00000000..27fabc43 Binary files /dev/null and b/tests/debug.test differ diff --git a/tests/entry_test.go b/tests/entry_test.go new file mode 100644 index 00000000..068cacf9 --- /dev/null +++ b/tests/entry_test.go @@ -0,0 +1,194 @@ +package tests + +import ( + "fmt" + "testing" + + "github.com/ciscoecosystem/aci-go-client/client" + "github.com/ciscoecosystem/aci-go-client/models" +) + +func createEntry(c *client.Client, dn, desc, tenantName, filterName string, entryAttr models.EntryAttributes) (*models.Entry, error) { + entry := models.NewEntry(dn, desc, tenantName, filterName, entryAttr) + err := c.Save(entry) + return entry, err +} + +func deleteEntry(c *client.Client, tenant *models.Tenant, filter *models.Filter, entry *models.Entry) error { + err := c.Delete(entry) + if err != nil { + return err + } + err = deleteFilter(c, tenant, filter) + if err != nil { + return err + } + return deleteTenant(c, tenant) +} + +func TestEntryCreation(t *testing.T) { + client := GetTestClient() + tenant, err := createTenant(client, "terraform-test-tenant", "Test tenant created with golang aci-client-sdk.") + filter, err := createFilter(client, "terrafrom-test-filter", "Test filter created with golang aci-clienr-sdk", models.GetMOName(tenant.DistinguishedName)) + + entry, err := createEntry(client, "terraform-test-entry", "Test Entry created with golang aci-client-sdk", models.GetMOName(tenant.DistinguishedName), models.GetMOName(filter.DistinguishedName), models.EntryAttributes{}) + + if err != nil { + t.Error(err) + } + err = deleteEntry(client, tenant, filter, entry) + if err != nil { + t.Error(err) + } + +} + +func TestDuplicateEntry(t *testing.T) { + client := GetTestClient() + tenant, err := createTenant(client, "terraform-test-tenant", "Test tenant created with golang aci-client-sdk.") + filter, err := createFilter(client, "terrafrom-test-filter", "Test filter created with golang aci-clienr-sdk", models.GetMOName(tenant.DistinguishedName)) + + entry, err := createEntry(client, "terraform-test-entry", "Test Entry created with golang aci-client-sdk", models.GetMOName(tenant.DistinguishedName), models.GetMOName(filter.DistinguishedName), models.EntryAttributes{}) + + if err != nil { + t.Error(err) + } + _, err = createEntry(client, "terraform-test-entry", "Test Entry created with golang aci-client-sdk", models.GetMOName(tenant.DistinguishedName), models.GetMOName(filter.DistinguishedName), models.EntryAttributes{}) + if err != nil { + t.Error(err) + } + err = deleteEntry(client, tenant, filter, entry) + if err != nil { + t.Error(err) + } + +} + +func TestGetEntryContainer(t *testing.T) { + client := GetTestClient() + tenant, err := createTenant(client, "terraform-test-tenant", "Test tenant created with golang aci-client-sdk.") + filter, err := createFilter(client, "terrafrom-test-filter", "Test filter created with golang aci-clienr-sdk", models.GetMOName(tenant.DistinguishedName)) + + entry, err := createEntry(client, "terraform-test-entry", "Test Entry created with golang aci-client-sdk", models.GetMOName(tenant.DistinguishedName), models.GetMOName(filter.DistinguishedName), models.EntryAttributes{}) + + if err != nil { + t.Error(err) + } + + cont, err := client.Get(entry.DistinguishedName) + + if err != nil { + t.Fatal(err) + } + + t.Logf("%+v", cont) + + err = deleteEntry(client, tenant, filter, entry) + if err != nil { + t.Error(err) + } + +} + +func TestEntryFromContainer(t *testing.T) { + + client := GetTestClient() + tenant, err := createTenant(client, "terraform-test-tenant", "Test tenant created with golang aci-client-sdk.") + filter, err := createFilter(client, "terrafrom-test-filter", "Test filter created with golang aci-clienr-sdk", models.GetMOName(tenant.DistinguishedName)) + + entry, err := createEntry(client, "terraform-test-entry", "Test Entry created with golang aci-client-sdk", models.GetMOName(tenant.DistinguishedName), models.GetMOName(filter.DistinguishedName), models.EntryAttributes{}) + + if err != nil { + t.Error(err) + } + + cont, err := client.Get(entry.DistinguishedName) + + if err != nil { + t.Fatal(err) + } + + entryCon := models.EntryFromContainer(cont) + fmt.Println(entryCon.DistinguishedName) + if entryCon.DistinguishedName == "" { + t.Error("the entry dn was empty") + + } + + err = deleteEntry(client, tenant, filter, entry) + if err != nil { + t.Error(err) + } +} + +func TestEntryUpdate(t *testing.T) { + client := GetTestClient() + tenant, err := createTenant(client, "terraform-test-tenant", "Test tenant created with golang aci-client-sdk.") + filter, err := createFilter(client, "terrafrom-test-filter", "Test filter created with golang aci-clienr-sdk", models.GetMOName(tenant.DistinguishedName)) + + entry, err := createEntry(client, "terraform-test-entry", "Test Entry created with golang aci-client-sdk", models.GetMOName(tenant.DistinguishedName), models.GetMOName(filter.DistinguishedName), models.EntryAttributes{}) + + if err != nil { + t.Error(err) + } + + cont, err := client.Get(entry.DistinguishedName) + + if err != nil { + t.Fatal(err) + } + + entryCon := models.EntryFromContainer(cont) + fmt.Println(entryCon.DistinguishedName) + if entryCon.DistinguishedName == "" { + t.Error("the entry dn was empty") + + } + entryCon.Description = "Updated the Entry" + err = client.Save(entryCon) + if err != nil { + t.Error(err) + } + fmt.Println("Entry was updated") + + err = deleteEntry(client, tenant, filter, entry) + if err != nil { + t.Error(err) + } + +} + +func TestEntryDelete(t *testing.T) { + client := GetTestClient() + tenant, err := createTenant(client, "terraform-test-tenant", "Test tenant created with golang aci-client-sdk.") + filter, err := createFilter(client, "terrafrom-test-filter", "Test filter created with golang aci-clienr-sdk", models.GetMOName(tenant.DistinguishedName)) + + entry, err := createEntry(client, "terraform-test-entry", "Test Entry created with golang aci-client-sdk", models.GetMOName(tenant.DistinguishedName), models.GetMOName(filter.DistinguishedName), models.EntryAttributes{}) + + if err != nil { + t.Error(err) + } + + cont, err := client.Get(entry.DistinguishedName) + + if err != nil { + t.Fatal(err) + } + + entryCon := models.EntryFromContainer(cont) + fmt.Println(entryCon.DistinguishedName) + if entryCon.DistinguishedName == "" { + t.Error("the entry dn was empty") + + } + err = client.Delete(entryCon) + if err != nil { + t.Error("the entry was not removed") + } + + err = deleteEntry(client, tenant, filter, entry) + if err != nil { + t.Error(err) + } + +} diff --git a/tests/epg_test.go b/tests/epg_test.go new file mode 100644 index 00000000..be1228cd --- /dev/null +++ b/tests/epg_test.go @@ -0,0 +1,171 @@ +package tests + +import ( + "fmt" + "testing" + + "github.com/ciscoecosystem/aci-go-client/client" + "github.com/ciscoecosystem/aci-go-client/models" +) + +func createEpg(c *client.Client, dn string, desc string, tenantName, apName string, epgAttr models.EPGAttributes) (*models.EPG, error) { + epg := models.NewEPG(dn, desc, tenantName, apName, epgAttr) + err := c.Save(epg) + return epg, err +} + +func deleteEpg(c *client.Client, tenant *models.Tenant, ap *models.ApplicationProfile, epg *models.EPG) error { + err := c.Delete(epg) + if err != nil { + return err + } + err = deleteAp(c, tenant, ap) + if err != nil { + return err + } + return deleteTenant(c, tenant) +} + +func TestEPGCreation(t *testing.T) { + client := GetTestClient() + tenant, err := createTenant(client, "terraform-test-tenant", "Test tenant created with golang aci-client-sdk.") + ap, err := createAp(client, "terrafrom-test-ap", "Test AP created with golang aci-clienr-sdk", models.GetMOName(tenant.DistinguishedName)) + + epgAttrs := models.DefaultEPGAttributes + epg, err := createEpg(client, "terraform-test-epg", "Test EPG created with golang aci-client-sdk", models.GetMOName(tenant.DistinguishedName), models.GetMOName(ap.DistinguishedName), epgAttrs) + + if err != nil { + t.Error(err) + } + err = deleteEpg(client, tenant, ap, epg) + if err != nil { + t.Error(err) + } + +} + +func TestDuplicateEPG(t *testing.T) { + client := GetTestClient() + tenant, err := createTenant(client, "terraform-test-tenant", "Test tenant created with golang aci-client-sdk.") + ap, err := createAp(client, "terrafrom-test-ap", "Test AP created with golang aci-clienr-sdk", models.GetMOName(tenant.DistinguishedName)) + + epgAttrs := models.DefaultEPGAttributes + epg, err := createEpg(client, "terraform-test-epg", "Test EPG created with golang aci-client-sdk", models.GetMOName(tenant.DistinguishedName), models.GetMOName(ap.DistinguishedName), epgAttrs) + + if err != nil { + t.Error(err) + } + _, err = createEpg(client, "terraform-test-epg", "Test EPG created with golang aci-client-sdk", models.GetMOName(tenant.DistinguishedName), models.GetMOName(ap.DistinguishedName), epgAttrs) + if err != nil { + t.Error(err) + } + err = deleteEpg(client, tenant, ap, epg) + if err != nil { + t.Error(err) + } + +} + +func TestGetEPGContainer(t *testing.T) { + client := GetTestClient() + tenant, err := createTenant(client, "terraform-test-tenant", "Test tenant created with golang aci-client-sdk.") + ap, err := createAp(client, "terrafrom-test-ap", "Test AP created with golang aci-clienr-sdk", models.GetMOName(tenant.DistinguishedName)) + + epgAttrs := models.DefaultEPGAttributes + epg, err := createEpg(client, "terraform-test-epg", "Test EPG created with golang aci-client-sdk", models.GetMOName(tenant.DistinguishedName), models.GetMOName(ap.DistinguishedName), epgAttrs) + cont, err := client.Get(epg.DistinguishedName) + + if err != nil { + t.Fatal(err) + } + + t.Logf("%+v", cont) + err = deleteEpg(client, tenant, ap, epg) + if err != nil { + t.Error(err) + } +} + +func TestEPGFromContainer(t *testing.T) { + client := GetTestClient() + tenant, err := createTenant(client, "terraform-test-tenant", "Test tenant created with golang aci-client-sdk.") + ap, err := createAp(client, "terrafrom-test-ap", "Test AP created with golang aci-clienr-sdk", models.GetMOName(tenant.DistinguishedName)) + + epgAttrs := models.DefaultEPGAttributes + epg, err := createEpg(client, "terraform-test-epg", "Test EPG created with golang aci-client-sdk", models.GetMOName(tenant.DistinguishedName), models.GetMOName(ap.DistinguishedName), epgAttrs) + cont, err := client.Get(epg.DistinguishedName) + if err != nil { + t.Fatal(err) + } + + epgCon := models.EPGFromContainer(cont) + fmt.Println(epgCon.DistinguishedName) + if epgCon.DistinguishedName == "" { + t.Error("the epg dn was empty") + + } + err = deleteEpg(client, tenant, ap, epg) + if err != nil { + t.Error(err) + } +} + +func TestEPGUpdate(t *testing.T) { + client := GetTestClient() + tenant, err := createTenant(client, "terraform-test-tenant", "Test tenant created with golang aci-client-sdk.") + ap, err := createAp(client, "terrafrom-test-ap", "Test AP created with golang aci-clienr-sdk", models.GetMOName(tenant.DistinguishedName)) + + epgAttrs := models.DefaultEPGAttributes + epg, err := createEpg(client, "terraform-test-epg", "Test EPG created with golang aci-client-sdk", models.GetMOName(tenant.DistinguishedName), models.GetMOName(ap.DistinguishedName), epgAttrs) + cont, err := client.Get(epg.DistinguishedName) + if err != nil { + t.Fatal(err) + } + + epgCon := models.EPGFromContainer(cont) + fmt.Println(epgCon.DistinguishedName) + if epgCon.DistinguishedName == "" { + t.Error("the epg dn was empty") + + } + + epgCon.LabelMatchCriteria = "AtmostOne" + err = client.Save(epgCon) + if err != nil { + t.Error(err) + } + fmt.Println("EPG was updated") + err = deleteEpg(client, tenant, ap, epg) + if err != nil { + t.Error(err) + } +} + +func TestEPGDelete(t *testing.T) { + client := GetTestClient() + tenant, err := createTenant(client, "terraform-test-tenant", "Test tenant created with golang aci-client-sdk.") + ap, err := createAp(client, "terrafrom-test-ap", "Test AP created with golang aci-clienr-sdk", models.GetMOName(tenant.DistinguishedName)) + + epgAttrs := models.DefaultEPGAttributes + epg, err := createEpg(client, "terraform-test-epg", "Test EPG created with golang aci-client-sdk", models.GetMOName(tenant.DistinguishedName), models.GetMOName(ap.DistinguishedName), epgAttrs) + cont, err := client.Get(epg.DistinguishedName) + if err != nil { + t.Fatal(err) + } + + epgCon := models.EPGFromContainer(cont) + fmt.Println(epgCon.DistinguishedName) + if epgCon.DistinguishedName == "" { + t.Error("the epg dn was empty") + + } + + err = client.Delete(epgCon) + if err != nil { + t.Error("the epg was not removed") + } + err = deleteEpg(client, tenant, ap, epg) + if err != nil { + t.Error(err) + } +} diff --git a/tests/filter_test.go b/tests/filter_test.go new file mode 100644 index 00000000..d61ca567 --- /dev/null +++ b/tests/filter_test.go @@ -0,0 +1,192 @@ +package tests + +import ( + "fmt" + "testing" + + "github.com/ciscoecosystem/aci-go-client/client" + "github.com/ciscoecosystem/aci-go-client/models" +) + +func createFilter(c *client.Client, dn, desc, parentDn string) (*models.Filter, error) { + filter := models.NewFilter(dn, desc, parentDn) + err := c.Save(filter) + return filter, err +} + +func deleteFilter(c *client.Client, tenant *models.Tenant, filter *models.Filter) error { + err := c.Delete(filter) + + if err != nil { + return err + } + return deleteTenant(c, tenant) + +} + +func TestFilterCreation(t *testing.T) { + client := GetTestClient() + tenant, err := createTenant(client, "terraform-test-tenant", "Test tenant created with golang aci-client-sdk.") + if err != nil { + t.Error(err) + } + + filter, err := createFilter(client, "terrafrom-test-filter", "Test Filter created with golang aci-clienr-sdk", models.GetMOName(tenant.DistinguishedName)) + if err != nil { + t.Error(err) + } + + err = deleteFilter(client, tenant, filter) + if err != nil { + t.Error(err) + } +} + +func TestDuplicateFilter(t *testing.T) { + client := GetTestClient() + tenant, err := createTenant(client, "terraform-test-tenant", "Test tenant created with golang aci-client-sdk.") + if err != nil { + t.Error(err) + } + + filter, err := createFilter(client, "terrafrom-test-filter", "Test Filter created with golang aci-clienr-sdk", models.GetMOName(tenant.DistinguishedName)) + if err != nil { + t.Error(err) + } + _, err = createFilter(client, "terrafrom-test-filter", "Test Filter created with golang aci-clienr-sdk", models.GetMOName(tenant.DistinguishedName)) + if err != nil { + t.Error(err) + } + + err = deleteFilter(client, tenant, filter) + if err != nil { + t.Error(err) + } + +} + +func TestGetFilterContainer(t *testing.T) { + client := GetTestClient() + tenant, err := createTenant(client, "terraform-test-tenant", "Test tenant created with golang aci-client-sdk.") + if err != nil { + t.Error(err) + } + + filter, err := createFilter(client, "terrafrom-test-filter", "Test Filter created with golang aci-clienr-sdk", models.GetMOName(tenant.DistinguishedName)) + + if err != nil { + t.Error(err) + } + cont, err := client.Get(filter.DistinguishedName) + + if err != nil { + t.Fatal(err) + } + + t.Logf("%+v", cont) + err = deleteFilter(client, tenant, filter) + if err != nil { + t.Error(err) + } +} + +func TestFilterFromContainer(t *testing.T) { + client := GetTestClient() + tenant, err := createTenant(client, "terraform-test-tenant", "Test tenant created with golang aci-client-sdk.") + if err != nil { + t.Error(err) + } + + filter, err := createFilter(client, "terrafrom-test-filter", "Test Filter created with golang aci-clienr-sdk", models.GetMOName(tenant.DistinguishedName)) + + if err != nil { + t.Error(err) + } + cont, err := client.Get(filter.DistinguishedName) + if err != nil { + t.Fatal(err) + } + + filterCon := models.FilterFromContainer(cont) + fmt.Println(filterCon.DistinguishedName) + if filterCon.DistinguishedName == "" { + t.Error("the filter dn was empty") + + } + err = deleteFilter(client, tenant, filter) + if err != nil { + t.Error(err) + } + +} + +func TestUpdateFilter(t *testing.T) { + client := GetTestClient() + tenant, err := createTenant(client, "terraform-test-tenant", "Test tenant created with golang aci-client-sdk.") + if err != nil { + t.Error(err) + } + + filter, err := createFilter(client, "terrafrom-test-filter", "Test Filter created with golang aci-clienr-sdk", models.GetMOName(tenant.DistinguishedName)) + + if err != nil { + t.Error(err) + } + cont, err := client.Get(filter.DistinguishedName) + if err != nil { + t.Fatal(err) + } + + filterCon := models.FilterFromContainer(cont) + fmt.Println(filterCon.DistinguishedName) + if filterCon.DistinguishedName == "" { + t.Error("the filter dn was empty") + + } + + filterCon.Description = "Updated the description" + err = client.Save(filterCon) + if err != nil { + t.Error(err) + } + + fmt.Println("Updated Filter") + err = deleteFilter(client, tenant, filter) + if err != nil { + t.Error(err) + } +} + +func TestFilterDelete(t *testing.T) { + client := GetTestClient() + tenant, err := createTenant(client, "terraform-test-tenant", "Test tenant created with golang aci-client-sdk.") + if err != nil { + t.Error(err) + } + + filter, err := createFilter(client, "terrafrom-test-filter", "Test Filter created with golang aci-clienr-sdk", models.GetMOName(tenant.DistinguishedName)) + + if err != nil { + t.Error(err) + } + cont, err := client.Get(filter.DistinguishedName) + if err != nil { + t.Fatal(err) + } + + filterCon := models.FilterFromContainer(cont) + fmt.Println(filterCon.DistinguishedName) + if filterCon.DistinguishedName == "" { + t.Error("the filter dn was empty") + + } + err = client.Delete(filterCon) + if err != nil { + t.Error("the filter was not removed") + } + err = deleteFilter(client, tenant, filter) + if err != nil { + t.Error(err) + } + +} diff --git a/tests/subject_test.go b/tests/subject_test.go new file mode 100644 index 00000000..7052564b --- /dev/null +++ b/tests/subject_test.go @@ -0,0 +1,163 @@ +package tests + +import ( + "fmt" + "testing" + + "github.com/ciscoecosystem/aci-go-client/client" + "github.com/ciscoecosystem/aci-go-client/models" +) + +func createSubject(c *client.Client, dn string, desc string, tenantName, contractName string, subjectAttrs models.SubjectAttributes) (*models.Subject, error) { + subject := models.NewSubject(dn, desc, tenantName, contractName, subjectAttrs) + err := c.Save(subject) + return subject, err +} + +func deleteSubject(c *client.Client, tenant *models.Tenant, contract *models.Contract, subject *models.Subject) error { + err := c.Delete(subject) + if err != nil { + return err + } + err = deleteContarct(c, tenant, contract) + if err != nil { + return err + } + return deleteTenant(c, tenant) +} + +func TestSubjectCreation(t *testing.T) { + client := GetTestClient() + tenant, err := createTenant(client, "terraform-test-tenant", "Test tenant created with golang aci-client-sdk.") + contract, err := createContract(client, "terraform-test-contract", "Test Contarct created with golang aci-client-sdk", models.GetMOName(tenant.DistinguishedName), models.ContractAttributes{}) + + subject, err := createSubject(client, "terraform-test-subject", "Test subject created with golang aci-client-sdk", models.GetMOName(tenant.DistinguishedName), models.GetMOName(contract.DistinguishedName), models.SubjectAttributes{}) + + if err != nil { + t.Error(err) + } + err = deleteSubject(client, tenant, contract, subject) + if err != nil { + t.Error(err) + } + +} + +func TestDupliateSubject(t *testing.T) { + client := GetTestClient() + tenant, err := createTenant(client, "terraform-test-tenant", "Test tenant created with golang aci-client-sdk.") + contract, err := createContract(client, "terraform-test-contract", "Test Contarct created with golang aci-client-sdk", models.GetMOName(tenant.DistinguishedName), models.ContractAttributes{}) + + subject, err := createSubject(client, "terraform-test-subject", "Test subject created with golang aci-client-sdk", models.GetMOName(tenant.DistinguishedName), models.GetMOName(contract.DistinguishedName), models.SubjectAttributes{}) + + if err != nil { + t.Error(err) + } + _, err = createSubject(client, "terraform-test-subject", "Test subject created with golang aci-client-sdk", models.GetMOName(tenant.DistinguishedName), models.GetMOName(contract.DistinguishedName), models.SubjectAttributes{}) + if err != nil { + t.Error(err) + } + err = deleteSubject(client, tenant, contract, subject) + if err != nil { + t.Error(err) + } + +} +func TestGetSubjectContainer(t *testing.T) { + client := GetTestClient() + tenant, err := createTenant(client, "terraform-test-tenant", "Test tenant created with golang aci-client-sdk.") + contract, err := createContract(client, "terraform-test-contract", "Test Contarct created with golang aci-client-sdk", models.GetMOName(tenant.DistinguishedName), models.ContractAttributes{}) + + subject, err := createSubject(client, "terraform-test-subject", "Test subject created with golang aci-client-sdk", models.GetMOName(tenant.DistinguishedName), models.GetMOName(contract.DistinguishedName), models.SubjectAttributes{}) + + cont, err := client.Get(subject.DistinguishedName) + + if err != nil { + t.Fatal(err) + } + t.Logf("%+v", cont) + err = deleteSubject(client, tenant, contract, subject) + if err != nil { + t.Error(err) + } +} + +func TestSubjectFromContainer(t *testing.T) { + client := GetTestClient() + tenant, err := createTenant(client, "terraform-test-tenant", "Test tenant created with golang aci-client-sdk.") + contract, err := createContract(client, "terraform-test-contract", "Test Contarct created with golang aci-client-sdk", models.GetMOName(tenant.DistinguishedName), models.ContractAttributes{}) + + subject, err := createSubject(client, "terraform-test-subject", "Test subject created with golang aci-client-sdk", models.GetMOName(tenant.DistinguishedName), models.GetMOName(contract.DistinguishedName), models.SubjectAttributes{}) + + cont, err := client.Get(subject.DistinguishedName) + + if err != nil { + t.Fatal(err) + } + subjectCon := models.SubjectFromContainer(cont) + fmt.Println(subjectCon.DistinguishedName) + if subjectCon.DistinguishedName == "" { + t.Error("the subject dn was empty") + } + err = deleteSubject(client, tenant, contract, subject) + if err != nil { + t.Error(err) + } +} + +func TestSubjectUpdate(t *testing.T) { + client := GetTestClient() + tenant, err := createTenant(client, "terraform-test-tenant", "Test tenant created with golang aci-client-sdk.") + contract, err := createContract(client, "terraform-test-contract", "Test Contarct created with golang aci-client-sdk", models.GetMOName(tenant.DistinguishedName), models.ContractAttributes{}) + + subject, err := createSubject(client, "terraform-test-subject", "Test subject created with golang aci-client-sdk", models.GetMOName(tenant.DistinguishedName), models.GetMOName(contract.DistinguishedName), models.SubjectAttributes{}) + + cont, err := client.Get(subject.DistinguishedName) + if err != nil { + t.Fatal(err) + } + subjectCon := models.SubjectFromContainer(cont) + fmt.Println(subjectCon.DistinguishedName) + if subjectCon.DistinguishedName == "" { + t.Error("the subject dn was empty") + } + + subjectCon.ProviderMatch = "AtleastOne" + err = client.Save(subjectCon) + if err != nil { + t.Error(err) + } + fmt.Println("subject was updated") + err = deleteSubject(client, tenant, contract, subject) + if err != nil { + t.Error(err) + } + +} + +func TestSubjectDelete(t *testing.T) { + client := GetTestClient() + tenant, err := createTenant(client, "terraform-test-tenant", "Test tenant created with golang aci-client-sdk.") + contract, err := createContract(client, "terraform-test-contract", "Test Contarct created with golang aci-client-sdk", models.GetMOName(tenant.DistinguishedName), models.ContractAttributes{}) + + subject, err := createSubject(client, "terraform-test-subject", "Test subject created with golang aci-client-sdk", models.GetMOName(tenant.DistinguishedName), models.GetMOName(contract.DistinguishedName), models.SubjectAttributes{}) + + cont, err := client.Get(subject.DistinguishedName) + if err != nil { + t.Fatal(err) + } + subjectCon := models.SubjectFromContainer(cont) + fmt.Println(subjectCon.DistinguishedName) + if subjectCon.DistinguishedName == "" { + t.Error("the subject dn was empty") + } + + err = client.Delete(subjectCon) + if err != nil { + t.Error("the subject was not removed") + } + err = deleteSubject(client, tenant, contract, subject) + if err != nil { + t.Error(err) + } +} diff --git a/tests/subnet_test.go b/tests/subnet_test.go new file mode 100644 index 00000000..593c8cd7 --- /dev/null +++ b/tests/subnet_test.go @@ -0,0 +1,164 @@ +package tests + +import ( + "fmt" + "testing" + + "github.com/ciscoecosystem/aci-go-client/client" + "github.com/ciscoecosystem/aci-go-client/models" +) + +func createSubnet(c *client.Client, dn string, desc string, tenantName, bdName string, subnetAttrs models.SubnetAttributes) (*models.Subnet, error) { + + subnet := models.NewSubnet(dn, desc, tenantName, bdName, subnetAttrs) + err := c.Save(subnet) + return subnet, err +} + +func deleteSubnet(c *client.Client, tenant *models.Tenant, bd *models.BridgeDomain, subnet *models.Subnet) error { + err := c.Delete(subnet) + if err != nil { + return err + } + err = deleteBd(c, tenant, bd) + if err != nil { + return err + } + return deleteTenant(c, tenant) +} + +func TestSubnetCreation(t *testing.T) { + client := GetTestClient() + tenant, err := createTenant(client, "terraform-test-tenant", "Test tenant created with golang aci-client-sdk.") + bdattr := models.BridgeDomainAttributes{} + bd, err := createBd(client, "terraform-test-bd", "Test Bridge Domain created with golang aci-client-sdk", models.GetMOName(tenant.DistinguishedName), bdattr) + subnet, err := createSubnet(client, "[10.0.0.29/27]", "Test subnet created with golang aci-client-sdk", models.GetMOName(tenant.DistinguishedName), models.GetMOName(bd.DistinguishedName), models.SubnetAttributes{}) + + if err != nil { + t.Error(err) + } + err = deleteSubnet(client, tenant, bd, subnet) + if err != nil { + t.Error(err) + } +} + +func TestDuplicateSubnet(t *testing.T){ + client := GetTestClient() + tenant, err := createTenant(client, "terraform-test-tenant", "Test tenant created with golang aci-client-sdk.") + bdattr := models.BridgeDomainAttributes{} + bd, err := createBd(client, "terraform-test-bd", "Test Bridge Domain created with golang aci-client-sdk", models.GetMOName(tenant.DistinguishedName), bdattr) + subnet, err := createSubnet(client, "[10.0.0.29/27]", "Test subnet created with golang aci-client-sdk", models.GetMOName(tenant.DistinguishedName), models.GetMOName(bd.DistinguishedName), models.SubnetAttributes{}) + + if err != nil { + t.Error(err) + } + _, err = createSubnet(client, "[10.0.0.29/27]", "Test subnet created with golang aci-client-sdk", models.GetMOName(tenant.DistinguishedName), models.GetMOName(bd.DistinguishedName), models.SubnetAttributes{}) + if err != nil { + t.Error(err) + } + err = deleteSubnet(client, tenant, bd, subnet) + if err != nil { + t.Error(err) + } + +} + +func TestGetSubnetContainer(t *testing.T) { + client := GetTestClient() + tenant, err := createTenant(client, "terraform-test-tenant", "Test tenant created with golang aci-client-sdk.") + bdattr := models.BridgeDomainAttributes{} + bd, err := createBd(client, "terraform-test-bd", "Test Bridge Domain created with golang aci-client-sdk", models.GetMOName(tenant.DistinguishedName), bdattr) + subnet, err := createSubnet(client, "[10.0.0.29/27]", "Test subnet created with golang aci-client-sdk", models.GetMOName(tenant.DistinguishedName), models.GetMOName(bd.DistinguishedName), models.SubnetAttributes{}) + cont, err := client.Get(subnet.DistinguishedName) + + if err != nil { + t.Fatal(err) + } + + t.Logf("%+v", cont) + err = deleteSubnet(client, tenant, bd, subnet) + if err != nil { + t.Error(err) + } +} + +func TestSubnetFromContainer(t *testing.T) { + client := GetTestClient() + tenant, err := createTenant(client, "terraform-test-tenant", "Test tenant created with golang aci-client-sdk.") + bdattr := models.BridgeDomainAttributes{} + bd, err := createBd(client, "terraform-test-bd", "Test Bridge Domain created with golang aci-client-sdk", models.GetMOName(tenant.DistinguishedName), bdattr) + subnet, err := createSubnet(client, "[10.0.0.29/27]", "Test subnet created with golang aci-client-sdk", models.GetMOName(tenant.DistinguishedName), models.GetMOName(bd.DistinguishedName), models.SubnetAttributes{}) + cont, err := client.Get(subnet.DistinguishedName) + if err != nil { + t.Fatal(err) + } + + subnetCon := models.SubnetFromContainer(cont) + fmt.Println(subnetCon.DistinguishedName) + if subnetCon.DistinguishedName == "" { + t.Error("The subnet dn was empty") + } + err = deleteSubnet(client, tenant, bd, subnet) + if err != nil { + t.Error(err) + } +} + +func TestSubnetUpdate(t *testing.T) { + client := GetTestClient() + tenant, err := createTenant(client, "terraform-test-tenant", "Test tenant created with golang aci-client-sdk.") + bdattr := models.BridgeDomainAttributes{} + bd, err := createBd(client, "terraform-test-bd", "Test Bridge Domain created with golang aci-client-sdk", models.GetMOName(tenant.DistinguishedName), bdattr) + subnet, err := createSubnet(client, "[10.0.0.29/27]", "Test subnet created with golang aci-client-sdk", models.GetMOName(tenant.DistinguishedName), models.GetMOName(bd.DistinguishedName), models.SubnetAttributes{}) + cont, err := client.Get(subnet.DistinguishedName) + if err != nil { + t.Fatal(err) + } + + subnetCon := models.SubnetFromContainer(cont) + fmt.Println(subnetCon.DistinguishedName) + if subnetCon.DistinguishedName == "" { + t.Error("The subnet dn was empty") + } + + var scopes []string + scopes = append(scopes, "public") + subnetCon.Scope = scopes + err = client.Save(subnetCon) + if err != nil { + t.Error(err) + } + fmt.Println("subnet was updated") + err = deleteSubnet(client, tenant, bd, subnet) + if err != nil { + t.Error(err) + } +} + +func TestSubnetDelete(t *testing.T) { + client := GetTestClient() + tenant, err := createTenant(client, "terraform-test-tenant", "Test tenant created with golang aci-client-sdk.") + bdattr := models.BridgeDomainAttributes{} + bd, err := createBd(client, "terraform-test-bd", "Test Bridge Domain created with golang aci-client-sdk", models.GetMOName(tenant.DistinguishedName), bdattr) + subnet, err := createSubnet(client, "[10.0.0.29/27]", "Test subnet created with golang aci-client-sdk", models.GetMOName(tenant.DistinguishedName), models.GetMOName(bd.DistinguishedName), models.SubnetAttributes{}) + cont, err := client.Get(subnet.DistinguishedName) + if err != nil { + t.Fatal(err) + } + + subnetCon := models.SubnetFromContainer(cont) + fmt.Println(subnetCon.DistinguishedName) + if subnetCon.DistinguishedName == "" { + t.Error("The subnet dn was empty") + } + + err = client.Delete(subnetCon) + if err != nil { + t.Error("The subnet was not removed") + } + err = deleteSubnet(client, tenant, bd, subnet) + if err != nil { + t.Error(err) + } +} diff --git a/tests/tenant_test.go b/tests/tenant_test.go new file mode 100644 index 00000000..6aad5e71 --- /dev/null +++ b/tests/tenant_test.go @@ -0,0 +1,157 @@ +package tests + +import ( + "fmt" + "testing" + + "github.com/ciscoecosystem/aci-go-client/client" + "github.com/ciscoecosystem/aci-go-client/models" +) + +// func GetTestClient() *client.Client { +// return client.GetClient("https://192.168.10.102", "admin", client.Insecure(true), client.PrivateKey("C:\\Users\\Crest\\Desktop\\certtest\\admin.key"), client.AdminCert("test.crt")) + +// } + +func GetTestClient() *client.Client { + return client.GetClient("https://192.168.10.102", "admin", client.Insecure(true), client.Password("cisco123")) + +} + +func TestTenantPrepareModel(t *testing.T) { + c := GetTestClient() + + cont, _, err := c.PrepareModel(models.NewTenant("terraform-test-tenant", "A test tenant created with aci-client-sdk.")) + + if err != nil { + t.Error(err) + } + if !cont.ExistsP("FvTenant.attributes.dn") { + t.Error("malformed model") + } +} + +func createTenant(c *client.Client, dn string, desc string) (*models.Tenant, error) { + tenant := models.NewTenant(dn, desc) + err := c.Save(tenant) + return tenant, err +} + +func deleteTenant(c *client.Client, tenant *models.Tenant) error { + return c.Delete(tenant) +} + +func TestTenantCreation(t *testing.T) { + c := GetTestClient() + tenant, err := createTenant(c, "terraform-test-tenant", "A test tenant created with aci-client-sdk.") + + if err != nil { + t.Error(err) + } + + err = deleteTenant(c, tenant) + if err != nil { + t.Error(err) + } +} + +func TestDuplicateTenant(t *testing.T) { + c := GetTestClient() + tenant1, err := createTenant(c, "terraform-test-tenant", "A test tenant created with aci-client-sdk.") + if err != nil { + t.Error(err) + } + _, err = createTenant(c, "terraform-test-tenant", "A test tenant created with aci-client-sdk.") + if err != nil { + t.Error(err) + } + + err = deleteTenant(c, tenant1) + if err != nil { + t.Error(err) + } + +} + +func TestGetTenantContainer(t *testing.T) { + + c := GetTestClient() + tenant, _ := createTenant(c, "terraform-test-tenant", "A test tenant created with aci-client-sdk.") + cont, err := c.Get("uni/tn-terraform-test-tenant") + + if err != nil { + t.Fatal(err) + } + t.Logf("%+v", cont) + + err = deleteTenant(c, tenant) + if err != nil { + t.Error(err) + } +} + +func TestTenantFromContainer(t *testing.T) { + c := GetTestClient() + tenant, _ := createTenant(c, "terraform-test-tenant", "A test tenant created with aci-client-sdk.") + cont, err := c.Get("uni/tn-terraform-test-tenant") + if err != nil { + t.Error(err) + } + tenantCon := models.TenantFromContainer(cont) + fmt.Println(tenantCon.DistinguishedName) + if tenantCon.DistinguishedName == "" { + t.Error("the tenant dn was empty") + } + err = deleteTenant(c, tenant) + if err != nil { + t.Error(err) + } +} + +func TestUpdateTenant(t *testing.T) { + client := GetTestClient() + tenant, _ := createTenant(client, "terraform-test-tenant", "A test tenant created with aci-client-sdk.") + cont, err := client.Get("uni/tn-terraform-test-tenant") + if err != nil { + t.Error(err) + } + tenantCon := models.TenantFromContainer(cont) + if tenantCon.DistinguishedName == "" { + t.Error("the tenant dn was empty") + } + tenantCon.Description = "Updated the description " + err = client.Save(tenantCon) + if err != nil { + t.Error(err) + } + + fmt.Println("Description Updated for tenant") + err = deleteTenant(client, tenant) + if err != nil { + t.Error(err) + } +} + +func TestTenantDelete(t *testing.T) { + c := GetTestClient() + tenant, _ := createTenant(c, "terraform-test-tenant", "A test tenant created with aci-client-sdk.") + cont, err := c.Get("uni/tn-terraform-test-tenant") + if err != nil { + t.Error(err) + } + tenantCon := models.TenantFromContainer(cont) + fmt.Println(tenantCon.DistinguishedName) + if tenantCon.DistinguishedName == "" { + t.Error("the tenant dn was empty") + } + + err = c.Delete(tenant) + if err != nil { + t.Error("the tenant was not remove") + } + err = deleteTenant(c, tenant) + if err != nil { + t.Error(err) + } + +} diff --git a/tests/test_utils.go b/tests/test_utils.go new file mode 100644 index 00000000..ca8701d2 --- /dev/null +++ b/tests/test_utils.go @@ -0,0 +1 @@ +package tests