diff --git a/pulsaradmin/alias.go b/pulsaradmin/alias.go deleted file mode 100644 index 53c8d93e05..0000000000 --- a/pulsaradmin/alias.go +++ /dev/null @@ -1,34 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. - -package pulsaradmin - -import ( - "github.com/apache/pulsar-client-go/pulsaradmin/pkg/admin" - "github.com/apache/pulsar-client-go/pulsaradmin/pkg/admin/config" -) - -// Client contains all admin interfaces for operating pulsar resources -type Client = admin.Client - -// Config are the arguments for creating a new admin Client -type Config = config.Config - -var ( - // NewClient returns a new admin Client for operating pulsar resources - NewClient = admin.New -) diff --git a/pulsaradmin/pkg/utils/allocator_stats.go b/pulsaradmin/allocator_stats.go similarity index 99% rename from pulsaradmin/pkg/utils/allocator_stats.go rename to pulsaradmin/allocator_stats.go index 4c2a7fb521..8d7f95d704 100644 --- a/pulsaradmin/pkg/utils/allocator_stats.go +++ b/pulsaradmin/allocator_stats.go @@ -15,7 +15,7 @@ // specific language governing permissions and limitations // under the License. -package utils +package pulsaradmin type AllocatorStats struct { NumDirectArenas int `json:"numDirectArenas"` diff --git a/pulsaradmin/pkg/admin/broker_stats.go b/pulsaradmin/api_broker_stats.go similarity index 56% rename from pulsaradmin/pkg/admin/broker_stats.go rename to pulsaradmin/api_broker_stats.go index c9f9cb01e3..be3ad585c4 100644 --- a/pulsaradmin/pkg/admin/broker_stats.go +++ b/pulsaradmin/api_broker_stats.go @@ -15,47 +15,45 @@ // specific language governing permissions and limitations // under the License. -package admin - -import ( - "github.com/apache/pulsar-client-go/pulsaradmin/pkg/utils" -) +package pulsaradmin // BrokerStats is admin interface for broker stats management type BrokerStats interface { // GetMetrics returns Monitoring metrics - GetMetrics() ([]utils.Metrics, error) + GetMetrics() ([]Metrics, error) // GetMBeans requests JSON string server mbean dump - GetMBeans() ([]utils.Metrics, error) + GetMBeans() ([]Metrics, error) // GetTopics returns JSON string topics stats GetTopics() (string, error) // GetLoadReport returns load report of broker - GetLoadReport() (*utils.LocalBrokerData, error) + GetLoadReport() (*LocalBrokerData, error) // GetAllocatorStats returns stats from broker - GetAllocatorStats(allocatorName string) (*utils.AllocatorStats, error) + GetAllocatorStats(allocatorName string) (*AllocatorStats, error) } type brokerStats struct { - pulsar *pulsarClient - basePath string + pulsar *pulsarClient + basePath string + apiVersion APIVersion } // BrokerStats is used to access the broker stats endpoints func (c *pulsarClient) BrokerStats() BrokerStats { return &brokerStats{ - pulsar: c, - basePath: "/broker-stats", + pulsar: c, + basePath: "/broker-stats", + apiVersion: c.apiProfile.BrokerStats, } } -func (bs *brokerStats) GetMetrics() ([]utils.Metrics, error) { - endpoint := bs.pulsar.endpoint(bs.basePath, "/metrics") - var response []utils.Metrics - err := bs.pulsar.Client.Get(endpoint, &response) +func (bs *brokerStats) GetMetrics() ([]Metrics, error) { + endpoint := bs.pulsar.endpoint(bs.apiVersion, bs.basePath, "/metrics") + var response []Metrics + err := bs.pulsar.restClient.Get(endpoint, &response) if err != nil { return nil, err } @@ -63,10 +61,10 @@ func (bs *brokerStats) GetMetrics() ([]utils.Metrics, error) { return response, nil } -func (bs *brokerStats) GetMBeans() ([]utils.Metrics, error) { - endpoint := bs.pulsar.endpoint(bs.basePath, "/mbeans") - var response []utils.Metrics - err := bs.pulsar.Client.Get(endpoint, &response) +func (bs *brokerStats) GetMBeans() ([]Metrics, error) { + endpoint := bs.pulsar.endpoint(bs.apiVersion, bs.basePath, "/mbeans") + var response []Metrics + err := bs.pulsar.restClient.Get(endpoint, &response) if err != nil { return nil, err } @@ -75,8 +73,8 @@ func (bs *brokerStats) GetMBeans() ([]utils.Metrics, error) { } func (bs *brokerStats) GetTopics() (string, error) { - endpoint := bs.pulsar.endpoint(bs.basePath, "/topics") - buf, err := bs.pulsar.Client.GetWithQueryParams(endpoint, nil, nil, false) + endpoint := bs.pulsar.endpoint(bs.apiVersion, bs.basePath, "/topics") + buf, err := bs.pulsar.restClient.GetWithQueryParams(endpoint, nil, nil, false) if err != nil { return "", err } @@ -84,20 +82,20 @@ func (bs *brokerStats) GetTopics() (string, error) { return string(buf), nil } -func (bs *brokerStats) GetLoadReport() (*utils.LocalBrokerData, error) { - endpoint := bs.pulsar.endpoint(bs.basePath, "/load-report") - response := utils.NewLocalBrokerData() - err := bs.pulsar.Client.Get(endpoint, &response) +func (bs *brokerStats) GetLoadReport() (*LocalBrokerData, error) { + endpoint := bs.pulsar.endpoint(bs.apiVersion, bs.basePath, "/load-report") + response := NewLocalBrokerData() + err := bs.pulsar.restClient.Get(endpoint, &response) if err != nil { return nil, nil } return &response, nil } -func (bs *brokerStats) GetAllocatorStats(allocatorName string) (*utils.AllocatorStats, error) { - endpoint := bs.pulsar.endpoint(bs.basePath, "/allocator-stats", allocatorName) - var allocatorStats utils.AllocatorStats - err := bs.pulsar.Client.Get(endpoint, &allocatorStats) +func (bs *brokerStats) GetAllocatorStats(allocatorName string) (*AllocatorStats, error) { + endpoint := bs.pulsar.endpoint(bs.apiVersion, bs.basePath, "/allocator-stats", allocatorName) + var allocatorStats AllocatorStats + err := bs.pulsar.restClient.Get(endpoint, &allocatorStats) if err != nil { return nil, err } diff --git a/pulsaradmin/pkg/admin/brokers.go b/pulsaradmin/api_brokers.go similarity index 67% rename from pulsaradmin/pkg/admin/brokers.go rename to pulsaradmin/api_brokers.go index 79fcb092ef..d408282cac 100644 --- a/pulsaradmin/pkg/admin/brokers.go +++ b/pulsaradmin/api_brokers.go @@ -15,14 +15,12 @@ // specific language governing permissions and limitations // under the License. -package admin +package pulsaradmin import ( "fmt" "net/url" "strings" - - "github.com/apache/pulsar-client-go/pulsaradmin/pkg/utils" ) // Brokers is admin interface for brokers management @@ -34,7 +32,7 @@ type Brokers interface { GetDynamicConfigurationNames() ([]string, error) // GetOwnedNamespaces returns the map of owned namespaces and their status from a single broker in the cluster - GetOwnedNamespaces(cluster, brokerURL string) (map[string]utils.NamespaceOwnershipStatus, error) + GetOwnedNamespaces(cluster, brokerURL string) (map[string]NamespaceOwnershipStatus, error) // UpdateDynamicConfiguration updates dynamic configuration value in to Zk that triggers watch on // brokers and all brokers can update {@link ServiceConfiguration} value locally @@ -48,7 +46,7 @@ type Brokers interface { GetRuntimeConfigurations() (map[string]string, error) // GetInternalConfigurationData returns the internal configuration data - GetInternalConfigurationData() (*utils.InternalConfigurationData, error) + GetInternalConfigurationData() (*InternalConfigurationData, error) // GetAllDynamicConfigurations returns values of all overridden dynamic-configs GetAllDynamicConfigurations() (map[string]string, error) @@ -58,22 +56,24 @@ type Brokers interface { } type broker struct { - pulsar *pulsarClient - basePath string + pulsar *pulsarClient + basePath string + apiVersion APIVersion } // Brokers is used to access the brokers endpoints func (c *pulsarClient) Brokers() Brokers { return &broker{ - pulsar: c, - basePath: "/brokers", + pulsar: c, + basePath: "/brokers", + apiVersion: c.apiProfile.Brokers, } } func (b *broker) GetActiveBrokers(cluster string) ([]string, error) { - endpoint := b.pulsar.endpoint(b.basePath, cluster) + endpoint := b.pulsar.endpoint(b.apiVersion, b.basePath, cluster) var res []string - err := b.pulsar.Client.Get(endpoint, &res) + err := b.pulsar.restClient.Get(endpoint, &res) if err != nil { return nil, err } @@ -81,19 +81,19 @@ func (b *broker) GetActiveBrokers(cluster string) ([]string, error) { } func (b *broker) GetDynamicConfigurationNames() ([]string, error) { - endpoint := b.pulsar.endpoint(b.basePath, "/configuration/") + endpoint := b.pulsar.endpoint(b.apiVersion, b.basePath, "/configuration/") var res []string - err := b.pulsar.Client.Get(endpoint, &res) + err := b.pulsar.restClient.Get(endpoint, &res) if err != nil { return nil, err } return res, nil } -func (b *broker) GetOwnedNamespaces(cluster, brokerURL string) (map[string]utils.NamespaceOwnershipStatus, error) { - endpoint := b.pulsar.endpoint(b.basePath, cluster, brokerURL, "ownedNamespaces") - var res map[string]utils.NamespaceOwnershipStatus - err := b.pulsar.Client.Get(endpoint, &res) +func (b *broker) GetOwnedNamespaces(cluster, brokerURL string) (map[string]NamespaceOwnershipStatus, error) { + endpoint := b.pulsar.endpoint(b.apiVersion, b.basePath, cluster, brokerURL, "ownedNamespaces") + var res map[string]NamespaceOwnershipStatus + err := b.pulsar.restClient.Get(endpoint, &res) if err != nil { return nil, err } @@ -102,29 +102,29 @@ func (b *broker) GetOwnedNamespaces(cluster, brokerURL string) (map[string]utils func (b *broker) UpdateDynamicConfiguration(configName, configValue string) error { value := url.QueryEscape(configValue) - endpoint := b.pulsar.endpoint(b.basePath, "/configuration/", configName, value) - return b.pulsar.Client.Post(endpoint, nil) + endpoint := b.pulsar.endpoint(b.apiVersion, b.basePath, "/configuration/", configName, value) + return b.pulsar.restClient.Post(endpoint, nil) } func (b *broker) DeleteDynamicConfiguration(configName string) error { - endpoint := b.pulsar.endpoint(b.basePath, "/configuration/", configName) - return b.pulsar.Client.Delete(endpoint) + endpoint := b.pulsar.endpoint(b.apiVersion, b.basePath, "/configuration/", configName) + return b.pulsar.restClient.Delete(endpoint) } func (b *broker) GetRuntimeConfigurations() (map[string]string, error) { - endpoint := b.pulsar.endpoint(b.basePath, "/configuration/", "runtime") + endpoint := b.pulsar.endpoint(b.apiVersion, b.basePath, "/configuration/", "runtime") var res map[string]string - err := b.pulsar.Client.Get(endpoint, &res) + err := b.pulsar.restClient.Get(endpoint, &res) if err != nil { return nil, err } return res, nil } -func (b *broker) GetInternalConfigurationData() (*utils.InternalConfigurationData, error) { - endpoint := b.pulsar.endpoint(b.basePath, "/internal-configuration") - var res utils.InternalConfigurationData - err := b.pulsar.Client.Get(endpoint, &res) +func (b *broker) GetInternalConfigurationData() (*InternalConfigurationData, error) { + endpoint := b.pulsar.endpoint(b.apiVersion, b.basePath, "/internal-configuration") + var res InternalConfigurationData + err := b.pulsar.restClient.Get(endpoint, &res) if err != nil { return nil, err } @@ -132,9 +132,9 @@ func (b *broker) GetInternalConfigurationData() (*utils.InternalConfigurationDat } func (b *broker) GetAllDynamicConfigurations() (map[string]string, error) { - endpoint := b.pulsar.endpoint(b.basePath, "/configuration/", "values") + endpoint := b.pulsar.endpoint(b.apiVersion, b.basePath, "/configuration/", "values") var res map[string]string - err := b.pulsar.Client.Get(endpoint, &res) + err := b.pulsar.restClient.Get(endpoint, &res) if err != nil { return nil, err } @@ -142,9 +142,9 @@ func (b *broker) GetAllDynamicConfigurations() (map[string]string, error) { } func (b *broker) HealthCheck() error { - endpoint := b.pulsar.endpoint(b.basePath, "/health") + endpoint := b.pulsar.endpoint(b.apiVersion, b.basePath, "/health") - buf, err := b.pulsar.Client.GetWithQueryParams(endpoint, nil, nil, false) + buf, err := b.pulsar.restClient.GetWithQueryParams(endpoint, nil, nil, false) if err != nil { return err } diff --git a/pulsaradmin/api_cluster.go b/pulsaradmin/api_cluster.go new file mode 100644 index 0000000000..13c7d127a6 --- /dev/null +++ b/pulsaradmin/api_cluster.go @@ -0,0 +1,141 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package pulsaradmin + +// Clusters is admin interface for clusters management +type Clusters interface { + // List returns the list of clusters + List() ([]string, error) + + // Get the configuration data for the specified cluster + Get(string) (ClusterData, error) + + // Create a new cluster + Create(ClusterData) error + + // Delete an existing cluster + Delete(string) error + + // Update the configuration for a cluster + Update(ClusterData) error + + // UpdatePeerClusters updates peer cluster names. + UpdatePeerClusters(string, []string) error + + // GetPeerClusters returns peer-cluster names + GetPeerClusters(string) ([]string, error) + + // CreateFailureDomain creates a domain into cluster + CreateFailureDomain(FailureDomainData) error + + // GetFailureDomain returns the domain registered into a cluster + GetFailureDomain(clusterName, domainName string) (FailureDomainData, error) + + // ListFailureDomains returns all registered domains in cluster + ListFailureDomains(string) (FailureDomainMap, error) + + // DeleteFailureDomain deletes a domain in cluster + DeleteFailureDomain(FailureDomainData) error + + // UpdateFailureDomain updates a domain into cluster + UpdateFailureDomain(FailureDomainData) error +} + +type clusters struct { + pulsar *pulsarClient + basePath string + apiVersion APIVersion +} + +// Clusters is used to access the cluster endpoints. +func (c *pulsarClient) Clusters() Clusters { + return &clusters{ + pulsar: c, + basePath: "/clusters", + apiVersion: c.apiProfile.Clusters, + } +} + +func (c *clusters) List() ([]string, error) { + var clusters []string + err := c.pulsar.restClient.Get(c.pulsar.endpoint(c.apiVersion, c.basePath), &clusters) + return clusters, err +} + +func (c *clusters) Get(name string) (ClusterData, error) { + cdata := ClusterData{} + endpoint := c.pulsar.endpoint(c.apiVersion, c.basePath, name) + err := c.pulsar.restClient.Get(endpoint, &cdata) + return cdata, err +} + +func (c *clusters) Create(cdata ClusterData) error { + endpoint := c.pulsar.endpoint(c.apiVersion, c.basePath, cdata.Name) + return c.pulsar.restClient.Put(endpoint, &cdata) +} + +func (c *clusters) Delete(name string) error { + endpoint := c.pulsar.endpoint(c.apiVersion, c.basePath, name) + return c.pulsar.restClient.Delete(endpoint) +} + +func (c *clusters) Update(cdata ClusterData) error { + endpoint := c.pulsar.endpoint(c.apiVersion, c.basePath, cdata.Name) + return c.pulsar.restClient.Post(endpoint, &cdata) +} + +func (c *clusters) GetPeerClusters(name string) ([]string, error) { + var peerClusters []string + endpoint := c.pulsar.endpoint(c.apiVersion, c.basePath, name, "peers") + err := c.pulsar.restClient.Get(endpoint, &peerClusters) + return peerClusters, err +} + +func (c *clusters) UpdatePeerClusters(cluster string, peerClusters []string) error { + endpoint := c.pulsar.endpoint(c.apiVersion, c.basePath, cluster, "peers") + return c.pulsar.restClient.Post(endpoint, peerClusters) +} + +func (c *clusters) CreateFailureDomain(data FailureDomainData) error { + endpoint := c.pulsar.endpoint(c.apiVersion, c.basePath, data.ClusterName, "failureDomains", data.DomainName) + return c.pulsar.restClient.Post(endpoint, &data) +} + +func (c *clusters) GetFailureDomain(clusterName string, domainName string) (FailureDomainData, error) { + var res FailureDomainData + endpoint := c.pulsar.endpoint(c.apiVersion, c.basePath, clusterName, "failureDomains", domainName) + err := c.pulsar.restClient.Get(endpoint, &res) + return res, err +} + +func (c *clusters) ListFailureDomains(clusterName string) (FailureDomainMap, error) { + var domainData FailureDomainMap + endpoint := c.pulsar.endpoint(c.apiVersion, c.basePath, clusterName, "failureDomains") + err := c.pulsar.restClient.Get(endpoint, &domainData) + return domainData, err +} + +func (c *clusters) DeleteFailureDomain(data FailureDomainData) error { + endpoint := c.pulsar.endpoint(c.apiVersion, c.basePath, data.ClusterName, "failureDomains", data.DomainName) + return c.pulsar.restClient.Delete(endpoint) +} + +func (c *clusters) UpdateFailureDomain(data FailureDomainData) error { + endpoint := c.pulsar.endpoint(c.apiVersion, c.basePath, data.ClusterName, "failureDomains", data.DomainName) + return c.pulsar.restClient.Post(endpoint, &data) +} diff --git a/pulsaradmin/pkg/admin/functions.go b/pulsaradmin/api_functions.go similarity index 72% rename from pulsaradmin/pkg/admin/functions.go rename to pulsaradmin/api_functions.go index cbaaf6be4e..a3add4a806 100644 --- a/pulsaradmin/pkg/admin/functions.go +++ b/pulsaradmin/api_functions.go @@ -15,7 +15,7 @@ // specific language governing permissions and limitations // under the License. -package admin +package pulsaradmin import ( "bytes" @@ -27,14 +27,12 @@ import ( "os" "path/filepath" "strings" - - "github.com/apache/pulsar-client-go/pulsaradmin/pkg/utils" ) // Functions is admin interface for functions management type Functions interface { // CreateFunc create a new function. - CreateFunc(data *utils.FunctionConfig, fileName string) error + CreateFunc(data *FunctionConfig, fileName string) error // CreateFuncWithURL create a new function by providing url from which fun-pkg can be downloaded. // supported url: http/file @@ -46,7 +44,7 @@ type Functions interface { // the function configuration object // @param pkgURL // url from which pkg can be downloaded - CreateFuncWithURL(data *utils.FunctionConfig, pkgURL string) error + CreateFuncWithURL(data *FunctionConfig, pkgURL string) error // StopFunction stop all function instances StopFunction(tenant, namespace, name string) error @@ -91,35 +89,35 @@ type Functions interface { GetFunctions(tenant, namespace string) ([]string, error) // GetFunction returns the configuration for the specified function - GetFunction(tenant, namespace, name string) (utils.FunctionConfig, error) + GetFunction(tenant, namespace, name string) (FunctionConfig, error) // GetFunctionStatus returns the current status of a function - GetFunctionStatus(tenant, namespace, name string) (utils.FunctionStatus, error) + GetFunctionStatus(tenant, namespace, name string) (FunctionStatus, error) // GetFunctionStatusWithInstanceID returns the current status of a function instance GetFunctionStatusWithInstanceID(tenant, namespace, name string, instanceID int) ( - utils.FunctionInstanceStatusData, error) + FunctionInstanceStatusData, error) // GetFunctionStats returns the current stats of a function - GetFunctionStats(tenant, namespace, name string) (utils.FunctionStats, error) + GetFunctionStats(tenant, namespace, name string) (FunctionStats, error) // GetFunctionStatsWithInstanceID gets the current stats of a function instance - GetFunctionStatsWithInstanceID(tenant, namespace, name string, instanceID int) (utils.FunctionInstanceStatsData, error) + GetFunctionStatsWithInstanceID(tenant, namespace, name string, instanceID int) (FunctionInstanceStatsData, error) // GetFunctionState fetch the current state associated with a Pulsar Function // // Response Example: // { "value : 12, version : 2"} - GetFunctionState(tenant, namespace, name, key string) (utils.FunctionState, error) + GetFunctionState(tenant, namespace, name, key string) (FunctionState, error) // PutFunctionState puts the given state associated with a Pulsar Function - PutFunctionState(tenant, namespace, name string, state utils.FunctionState) error + PutFunctionState(tenant, namespace, name string, state FunctionState) error // TriggerFunction triggers the function by writing to the input topic TriggerFunction(tenant, namespace, name, topic, triggerValue, triggerFile string) (string, error) // UpdateFunction updates the configuration for a function. - UpdateFunction(functionConfig *utils.FunctionConfig, fileName string, updateOptions *utils.UpdateOptions) error + UpdateFunction(functionConfig *FunctionConfig, fileName string, updateOptions *UpdateOptions) error // UpdateFunctionWithURL updates the configuration for a function. // @@ -127,22 +125,24 @@ type Functions interface { // eg: // File: file:/dir/fileName.jar // Http: http://www.repo.com/fileName.jar - UpdateFunctionWithURL(functionConfig *utils.FunctionConfig, pkgURL string, updateOptions *utils.UpdateOptions) error + UpdateFunctionWithURL(functionConfig *FunctionConfig, pkgURL string, updateOptions *UpdateOptions) error // Upload function to Pulsar Upload(sourceFile, path string) error } type functions struct { - pulsar *pulsarClient - basePath string + pulsar *pulsarClient + basePath string + apiVersion APIVersion } // Functions is used to access the functions endpoints func (c *pulsarClient) Functions() Functions { return &functions{ - pulsar: c, - basePath: "/functions", + pulsar: c, + basePath: "/functions", + apiVersion: c.apiProfile.Functions, } } @@ -160,8 +160,8 @@ func (f *functions) createTextFromFiled(w *multipart.Writer, value string) (io.W return w.CreatePart(h) } -func (f *functions) CreateFunc(funcConf *utils.FunctionConfig, fileName string) error { - endpoint := f.pulsar.endpoint(f.basePath, funcConf.Tenant, funcConf.Namespace, funcConf.Name) +func (f *functions) CreateFunc(funcConf *FunctionConfig, fileName string) error { + endpoint := f.pulsar.endpoint(f.apiVersion, f.basePath, funcConf.Tenant, funcConf.Namespace, funcConf.Name) // buffer to store our request as bytes bodyBuf := bytes.NewBufferString("") @@ -192,7 +192,6 @@ func (f *functions) CreateFunc(funcConf *utils.FunctionConfig, fileName string) defer file.Close() part, err := multiPartWriter.CreateFormFile("data", filepath.Base(file.Name())) - if err != nil { return err } @@ -211,7 +210,7 @@ func (f *functions) CreateFunc(funcConf *utils.FunctionConfig, fileName string) } contentType := multiPartWriter.FormDataContentType() - err = f.pulsar.Client.PostWithMultiPart(endpoint, nil, bodyBuf, contentType) + err = f.pulsar.restClient.PostWithMultiPart(endpoint, nil, bodyBuf, contentType) if err != nil { return err } @@ -219,8 +218,8 @@ func (f *functions) CreateFunc(funcConf *utils.FunctionConfig, fileName string) return nil } -func (f *functions) CreateFuncWithURL(funcConf *utils.FunctionConfig, pkgURL string) error { - endpoint := f.pulsar.endpoint(f.basePath, funcConf.Tenant, funcConf.Namespace, funcConf.Name) +func (f *functions) CreateFuncWithURL(funcConf *FunctionConfig, pkgURL string) error { + endpoint := f.pulsar.endpoint(f.apiVersion, f.basePath, funcConf.Tenant, funcConf.Namespace, funcConf.Name) // buffer to store our request as bytes bodyBuf := bytes.NewBufferString("") @@ -256,7 +255,7 @@ func (f *functions) CreateFuncWithURL(funcConf *utils.FunctionConfig, pkgURL str } contentType := multiPartWriter.FormDataContentType() - err = f.pulsar.Client.PostWithMultiPart(endpoint, nil, bodyBuf, contentType) + err = f.pulsar.restClient.PostWithMultiPart(endpoint, nil, bodyBuf, contentType) if err != nil { return err } @@ -265,24 +264,24 @@ func (f *functions) CreateFuncWithURL(funcConf *utils.FunctionConfig, pkgURL str } func (f *functions) StopFunction(tenant, namespace, name string) error { - endpoint := f.pulsar.endpoint(f.basePath, tenant, namespace, name) - return f.pulsar.Client.Post(endpoint+"/stop", nil) + endpoint := f.pulsar.endpoint(f.apiVersion, f.basePath, tenant, namespace, name) + return f.pulsar.restClient.Post(endpoint+"/stop", nil) } func (f *functions) StopFunctionWithID(tenant, namespace, name string, instanceID int) error { id := fmt.Sprintf("%d", instanceID) - endpoint := f.pulsar.endpoint(f.basePath, tenant, namespace, name, id) + endpoint := f.pulsar.endpoint(f.apiVersion, f.basePath, tenant, namespace, name, id) - return f.pulsar.Client.Post(endpoint+"/stop", nil) + return f.pulsar.restClient.Post(endpoint+"/stop", nil) } func (f *functions) DeleteFunction(tenant, namespace, name string) error { - endpoint := f.pulsar.endpoint(f.basePath, tenant, namespace, name) - return f.pulsar.Client.Delete(endpoint) + endpoint := f.pulsar.endpoint(f.apiVersion, f.basePath, tenant, namespace, name) + return f.pulsar.restClient.Delete(endpoint) } func (f *functions) DownloadFunction(path, destinationFile string) error { - endpoint := f.pulsar.endpoint(f.basePath, "download") + endpoint := f.pulsar.endpoint(f.apiVersion, f.basePath, "download") _, err := os.Open(destinationFile) if err != nil { if !os.IsNotExist(err) { @@ -298,7 +297,7 @@ func (f *functions) DownloadFunction(path, destinationFile string) error { tmpMap := make(map[string]string) tmpMap["path"] = path - _, err = f.pulsar.Client.GetWithOptions(endpoint, nil, tmpMap, false, file) + _, err = f.pulsar.restClient.GetWithOptions(endpoint, nil, tmpMap, false, file) if err != nil { return err } @@ -306,7 +305,7 @@ func (f *functions) DownloadFunction(path, destinationFile string) error { } func (f *functions) DownloadFunctionByNs(destinationFile, tenant, namespace, function string) error { - endpoint := f.pulsar.endpoint(f.basePath, tenant, namespace, function, "download") + endpoint := f.pulsar.endpoint(f.apiVersion, f.basePath, tenant, namespace, function, "download") _, err := os.Open(destinationFile) if err != nil { if !os.IsNotExist(err) { @@ -319,7 +318,7 @@ func (f *functions) DownloadFunctionByNs(destinationFile, tenant, namespace, fun return err } - _, err = f.pulsar.Client.GetWithOptions(endpoint, nil, nil, false, file) + _, err = f.pulsar.restClient.GetWithOptions(endpoint, nil, nil, false, file) if err != nil { return err } @@ -328,46 +327,48 @@ func (f *functions) DownloadFunctionByNs(destinationFile, tenant, namespace, fun } func (f *functions) StartFunction(tenant, namespace, name string) error { - endpoint := f.pulsar.endpoint(f.basePath, tenant, namespace, name) - return f.pulsar.Client.Post(endpoint+"/start", nil) + endpoint := f.pulsar.endpoint(f.apiVersion, f.basePath, tenant, namespace, name) + return f.pulsar.restClient.Post(endpoint+"/start", nil) } func (f *functions) StartFunctionWithID(tenant, namespace, name string, instanceID int) error { id := fmt.Sprintf("%d", instanceID) - endpoint := f.pulsar.endpoint(f.basePath, tenant, namespace, name, id) + endpoint := f.pulsar.endpoint(f.apiVersion, f.basePath, tenant, namespace, name, id) - return f.pulsar.Client.Post(endpoint+"/start", nil) + return f.pulsar.restClient.Post(endpoint+"/start", nil) } func (f *functions) RestartFunction(tenant, namespace, name string) error { - endpoint := f.pulsar.endpoint(f.basePath, tenant, namespace, name) - return f.pulsar.Client.Post(endpoint+"/restart", nil) + endpoint := f.pulsar.endpoint(f.apiVersion, f.basePath, tenant, namespace, name) + return f.pulsar.restClient.Post(endpoint+"/restart", nil) } func (f *functions) RestartFunctionWithID(tenant, namespace, name string, instanceID int) error { id := fmt.Sprintf("%d", instanceID) - endpoint := f.pulsar.endpoint(f.basePath, tenant, namespace, name, id) + endpoint := f.pulsar.endpoint(f.apiVersion, f.basePath, tenant, namespace, name, id) - return f.pulsar.Client.Post(endpoint+"/restart", nil) + return f.pulsar.restClient.Post(endpoint+"/restart", nil) } func (f *functions) GetFunctions(tenant, namespace string) ([]string, error) { var functions []string - endpoint := f.pulsar.endpoint(f.basePath, tenant, namespace) - err := f.pulsar.Client.Get(endpoint, &functions) + endpoint := f.pulsar.endpoint(f.apiVersion, f.basePath, tenant, namespace) + err := f.pulsar.restClient.Get(endpoint, &functions) return functions, err } -func (f *functions) GetFunction(tenant, namespace, name string) (utils.FunctionConfig, error) { - var functionConfig utils.FunctionConfig - endpoint := f.pulsar.endpoint(f.basePath, tenant, namespace, name) - err := f.pulsar.Client.Get(endpoint, &functionConfig) +func (f *functions) GetFunction(tenant, namespace, name string) (FunctionConfig, error) { + var functionConfig FunctionConfig + endpoint := f.pulsar.endpoint(f.apiVersion, f.basePath, tenant, namespace, name) + err := f.pulsar.restClient.Get(endpoint, &functionConfig) return functionConfig, err } -func (f *functions) UpdateFunction(functionConfig *utils.FunctionConfig, fileName string, - updateOptions *utils.UpdateOptions) error { - endpoint := f.pulsar.endpoint(f.basePath, functionConfig.Tenant, functionConfig.Namespace, functionConfig.Name) +func (f *functions) UpdateFunction(functionConfig *FunctionConfig, fileName string, + updateOptions *UpdateOptions, +) error { + endpoint := f.pulsar.endpoint(f.apiVersion, f.basePath, functionConfig.Tenant, functionConfig.Namespace, + functionConfig.Name) // buffer to store our request as bytes bodyBuf := bytes.NewBufferString("") @@ -414,7 +415,6 @@ func (f *functions) UpdateFunction(functionConfig *utils.FunctionConfig, fileNam defer file.Close() part, err := multiPartWriter.CreateFormFile("data", filepath.Base(file.Name())) - if err != nil { return err } @@ -433,7 +433,7 @@ func (f *functions) UpdateFunction(functionConfig *utils.FunctionConfig, fileNam } contentType := multiPartWriter.FormDataContentType() - err = f.pulsar.Client.PutWithMultiPart(endpoint, bodyBuf, contentType) + err = f.pulsar.restClient.PutWithMultiPart(endpoint, bodyBuf, contentType) if err != nil { return err } @@ -441,9 +441,11 @@ func (f *functions) UpdateFunction(functionConfig *utils.FunctionConfig, fileNam return nil } -func (f *functions) UpdateFunctionWithURL(functionConfig *utils.FunctionConfig, pkgURL string, - updateOptions *utils.UpdateOptions) error { - endpoint := f.pulsar.endpoint(f.basePath, functionConfig.Tenant, functionConfig.Namespace, functionConfig.Name) +func (f *functions) UpdateFunctionWithURL(functionConfig *FunctionConfig, pkgURL string, + updateOptions *UpdateOptions, +) error { + endpoint := f.pulsar.endpoint(f.apiVersion, f.basePath, functionConfig.Tenant, functionConfig.Namespace, + functionConfig.Name) // buffer to store our request as bytes bodyBuf := bytes.NewBufferString("") @@ -498,7 +500,7 @@ func (f *functions) UpdateFunctionWithURL(functionConfig *utils.FunctionConfig, } contentType := multiPartWriter.FormDataContentType() - err = f.pulsar.Client.PutWithMultiPart(endpoint, bodyBuf, contentType) + err = f.pulsar.restClient.PutWithMultiPart(endpoint, bodyBuf, contentType) if err != nil { return err } @@ -506,47 +508,49 @@ func (f *functions) UpdateFunctionWithURL(functionConfig *utils.FunctionConfig, return nil } -func (f *functions) GetFunctionStatus(tenant, namespace, name string) (utils.FunctionStatus, error) { - var functionStatus utils.FunctionStatus - endpoint := f.pulsar.endpoint(f.basePath, tenant, namespace, name) - err := f.pulsar.Client.Get(endpoint+"/status", &functionStatus) +func (f *functions) GetFunctionStatus(tenant, namespace, name string) (FunctionStatus, error) { + var functionStatus FunctionStatus + endpoint := f.pulsar.endpoint(f.apiVersion, f.basePath, tenant, namespace, name) + err := f.pulsar.restClient.Get(endpoint+"/status", &functionStatus) return functionStatus, err } func (f *functions) GetFunctionStatusWithInstanceID(tenant, namespace, name string, - instanceID int) (utils.FunctionInstanceStatusData, error) { - var functionInstanceStatusData utils.FunctionInstanceStatusData + instanceID int, +) (FunctionInstanceStatusData, error) { + var functionInstanceStatusData FunctionInstanceStatusData id := fmt.Sprintf("%d", instanceID) - endpoint := f.pulsar.endpoint(f.basePath, tenant, namespace, name, id) - err := f.pulsar.Client.Get(endpoint+"/status", &functionInstanceStatusData) + endpoint := f.pulsar.endpoint(f.apiVersion, f.basePath, tenant, namespace, name, id) + err := f.pulsar.restClient.Get(endpoint+"/status", &functionInstanceStatusData) return functionInstanceStatusData, err } -func (f *functions) GetFunctionStats(tenant, namespace, name string) (utils.FunctionStats, error) { - var functionStats utils.FunctionStats - endpoint := f.pulsar.endpoint(f.basePath, tenant, namespace, name) - err := f.pulsar.Client.Get(endpoint+"/stats", &functionStats) +func (f *functions) GetFunctionStats(tenant, namespace, name string) (FunctionStats, error) { + var functionStats FunctionStats + endpoint := f.pulsar.endpoint(f.apiVersion, f.basePath, tenant, namespace, name) + err := f.pulsar.restClient.Get(endpoint+"/stats", &functionStats) return functionStats, err } func (f *functions) GetFunctionStatsWithInstanceID(tenant, namespace, name string, - instanceID int) (utils.FunctionInstanceStatsData, error) { - var functionInstanceStatsData utils.FunctionInstanceStatsData + instanceID int, +) (FunctionInstanceStatsData, error) { + var functionInstanceStatsData FunctionInstanceStatsData id := fmt.Sprintf("%d", instanceID) - endpoint := f.pulsar.endpoint(f.basePath, tenant, namespace, name, id) - err := f.pulsar.Client.Get(endpoint+"/stats", &functionInstanceStatsData) + endpoint := f.pulsar.endpoint(f.apiVersion, f.basePath, tenant, namespace, name, id) + err := f.pulsar.restClient.Get(endpoint+"/stats", &functionInstanceStatsData) return functionInstanceStatsData, err } -func (f *functions) GetFunctionState(tenant, namespace, name, key string) (utils.FunctionState, error) { - var functionState utils.FunctionState - endpoint := f.pulsar.endpoint(f.basePath, tenant, namespace, name, "state", key) - err := f.pulsar.Client.Get(endpoint, &functionState) +func (f *functions) GetFunctionState(tenant, namespace, name, key string) (FunctionState, error) { + var functionState FunctionState + endpoint := f.pulsar.endpoint(f.apiVersion, f.basePath, tenant, namespace, name, "state", key) + err := f.pulsar.restClient.Get(endpoint, &functionState) return functionState, err } -func (f *functions) PutFunctionState(tenant, namespace, name string, state utils.FunctionState) error { - endpoint := f.pulsar.endpoint(f.basePath, tenant, namespace, name, "state", state.Key) +func (f *functions) PutFunctionState(tenant, namespace, name string, state FunctionState) error { + endpoint := f.pulsar.endpoint(f.apiVersion, f.basePath, tenant, namespace, name, "state", state.Key) // buffer to store our request as bytes bodyBuf := bytes.NewBufferString("") @@ -554,7 +558,6 @@ func (f *functions) PutFunctionState(tenant, namespace, name string, state utils multiPartWriter := multipart.NewWriter(bodyBuf) stateData, err := json.Marshal(state) - if err != nil { return err } @@ -578,7 +581,7 @@ func (f *functions) PutFunctionState(tenant, namespace, name string, state utils contentType := multiPartWriter.FormDataContentType() - err = f.pulsar.Client.PostWithMultiPart(endpoint, nil, bodyBuf, contentType) + err = f.pulsar.restClient.PostWithMultiPart(endpoint, nil, bodyBuf, contentType) if err != nil { return err @@ -588,7 +591,7 @@ func (f *functions) PutFunctionState(tenant, namespace, name string, state utils } func (f *functions) TriggerFunction(tenant, namespace, name, topic, triggerValue, triggerFile string) (string, error) { - endpoint := f.pulsar.endpoint(f.basePath, tenant, namespace, name, "trigger") + endpoint := f.pulsar.endpoint(f.apiVersion, f.basePath, tenant, namespace, name, "trigger") // buffer to store our request as bytes bodyBuf := bytes.NewBufferString("") @@ -603,7 +606,6 @@ func (f *functions) TriggerFunction(tenant, namespace, name, topic, triggerValue defer file.Close() part, err := multiPartWriter.CreateFormFile("dataStream", filepath.Base(file.Name())) - if err != nil { return "", err } @@ -647,7 +649,7 @@ func (f *functions) TriggerFunction(tenant, namespace, name, topic, triggerValue contentType := multiPartWriter.FormDataContentType() var str string - err := f.pulsar.Client.PostWithMultiPart(endpoint, &str, bodyBuf, contentType) + err := f.pulsar.restClient.PostWithMultiPart(endpoint, &str, bodyBuf, contentType) if err != nil { return "", err } @@ -664,7 +666,7 @@ func (f *functions) Upload(sourceFile, path string) error { return err } defer file.Close() - endpoint := f.pulsar.endpoint(f.basePath, "upload") + endpoint := f.pulsar.endpoint(f.apiVersion, f.basePath, "upload") var b bytes.Buffer w := multipart.NewWriter(&b) writer, err := w.CreateFormFile("data", file.Name()) @@ -682,5 +684,5 @@ func (f *functions) Upload(sourceFile, path string) error { if err != nil { return err } - return f.pulsar.Client.PostWithMultiPart(endpoint, nil, &b, w.FormDataContentType()) + return f.pulsar.restClient.PostWithMultiPart(endpoint, nil, &b, w.FormDataContentType()) } diff --git a/pulsaradmin/pkg/admin/functions_worker.go b/pulsaradmin/api_functions_worker.go similarity index 58% rename from pulsaradmin/pkg/admin/functions_worker.go rename to pulsaradmin/api_functions_worker.go index 3cad65de82..1ba2ee99aa 100644 --- a/pulsaradmin/pkg/admin/functions_worker.go +++ b/pulsaradmin/api_functions_worker.go @@ -15,24 +15,20 @@ // specific language governing permissions and limitations // under the License. -package admin - -import ( - "github.com/apache/pulsar-client-go/pulsaradmin/pkg/utils" -) +package pulsaradmin type FunctionsWorker interface { // Get all functions stats on a worker - GetFunctionsStats() ([]*utils.WorkerFunctionInstanceStats, error) + GetFunctionsStats() ([]*WorkerFunctionInstanceStats, error) // Get worker metrics - GetMetrics() ([]*utils.Metrics, error) + GetMetrics() ([]*Metrics, error) // Get List of all workers belonging to this cluster - GetCluster() ([]*utils.WorkerInfo, error) + GetCluster() ([]*WorkerInfo, error) // Get the worker who is the leader of the clusterv - GetClusterLeader() (*utils.WorkerInfo, error) + GetClusterLeader() (*WorkerInfo, error) // Get the function assignment among the cluster GetAssignments() (map[string][]string, error) @@ -42,6 +38,7 @@ type worker struct { pulsar *pulsarClient workerPath string workerStatsPath string + apiVersion APIVersion } func (c *pulsarClient) FunctionsWorker() FunctionsWorker { @@ -49,43 +46,44 @@ func (c *pulsarClient) FunctionsWorker() FunctionsWorker { pulsar: c, workerPath: "/worker", workerStatsPath: "/worker-stats", + apiVersion: c.apiProfile.FunctionsWorker, } } -func (w *worker) GetFunctionsStats() ([]*utils.WorkerFunctionInstanceStats, error) { - endpoint := w.pulsar.endpoint(w.workerStatsPath, "functionsmetrics") - var workerStats []*utils.WorkerFunctionInstanceStats - err := w.pulsar.Client.Get(endpoint, &workerStats) +func (w *worker) GetFunctionsStats() ([]*WorkerFunctionInstanceStats, error) { + endpoint := w.pulsar.endpoint(w.apiVersion, w.workerStatsPath, "functionsmetrics") + var workerStats []*WorkerFunctionInstanceStats + err := w.pulsar.restClient.Get(endpoint, &workerStats) if err != nil { return nil, err } return workerStats, nil } -func (w *worker) GetMetrics() ([]*utils.Metrics, error) { - endpoint := w.pulsar.endpoint(w.workerStatsPath, "metrics") - var metrics []*utils.Metrics - err := w.pulsar.Client.Get(endpoint, &metrics) +func (w *worker) GetMetrics() ([]*Metrics, error) { + endpoint := w.pulsar.endpoint(w.apiVersion, w.workerStatsPath, "metrics") + var metrics []*Metrics + err := w.pulsar.restClient.Get(endpoint, &metrics) if err != nil { return nil, err } return metrics, nil } -func (w *worker) GetCluster() ([]*utils.WorkerInfo, error) { - endpoint := w.pulsar.endpoint(w.workerPath, "cluster") - var workersInfo []*utils.WorkerInfo - err := w.pulsar.Client.Get(endpoint, &workersInfo) +func (w *worker) GetCluster() ([]*WorkerInfo, error) { + endpoint := w.pulsar.endpoint(w.apiVersion, w.workerPath, "cluster") + var workersInfo []*WorkerInfo + err := w.pulsar.restClient.Get(endpoint, &workersInfo) if err != nil { return nil, err } return workersInfo, nil } -func (w *worker) GetClusterLeader() (*utils.WorkerInfo, error) { - endpoint := w.pulsar.endpoint(w.workerPath, "cluster", "leader") - var workerInfo utils.WorkerInfo - err := w.pulsar.Client.Get(endpoint, &workerInfo) +func (w *worker) GetClusterLeader() (*WorkerInfo, error) { + endpoint := w.pulsar.endpoint(w.apiVersion, w.workerPath, "cluster", "leader") + var workerInfo WorkerInfo + err := w.pulsar.restClient.Get(endpoint, &workerInfo) if err != nil { return nil, err } @@ -93,9 +91,9 @@ func (w *worker) GetClusterLeader() (*utils.WorkerInfo, error) { } func (w *worker) GetAssignments() (map[string][]string, error) { - endpoint := w.pulsar.endpoint(w.workerPath, "assignments") + endpoint := w.pulsar.endpoint(w.apiVersion, w.workerPath, "assignments") var assignments map[string][]string - err := w.pulsar.Client.Get(endpoint, &assignments) + err := w.pulsar.restClient.Get(endpoint, &assignments) if err != nil { return nil, err } diff --git a/pulsaradmin/api_namespace.go b/pulsaradmin/api_namespace.go new file mode 100644 index 0000000000..cc18a8352b --- /dev/null +++ b/pulsaradmin/api_namespace.go @@ -0,0 +1,882 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package pulsaradmin + +import ( + "net/url" + "strconv" + "strings" +) + +// Namespaces is admin interface for namespaces management +type Namespaces interface { + // GetNamespaces returns the list of all the namespaces for a certain tenant + GetNamespaces(tenant string) ([]string, error) + + // GetTopics returns the list of all the topics under a certain namespace + GetTopics(namespace string) ([]string, error) + + // GetPolicies returns the dump all the policies specified for a namespace + GetPolicies(namespace string) (*Policies, error) + + // CreateNamespace creates a new empty namespace with no policies attached + CreateNamespace(namespace string) error + + // CreateNsWithNumBundles creates a new empty namespace with no policies attached + CreateNsWithNumBundles(namespace string, numBundles int) error + + // CreateNsWithPolices creates a new namespace with the specified policies + CreateNsWithPolices(namespace string, polices Policies) error + + // CreateNsWithBundlesData creates a new empty namespace with no policies attached + CreateNsWithBundlesData(namespace string, bundleData *BundlesData) error + + // DeleteNamespace deletes an existing namespace + DeleteNamespace(namespace string) error + + // DeleteNamespaceBundle deletes an existing bundle in a namespace + DeleteNamespaceBundle(namespace string, bundleRange string) error + + // SetNamespaceMessageTTL sets the messages Time to Live for all the topics within a namespace + SetNamespaceMessageTTL(namespace string, ttlInSeconds int) error + + // GetNamespaceMessageTTL returns the message TTL for a namespace + GetNamespaceMessageTTL(namespace string) (int, error) + + // GetRetention returns the retention configuration for a namespace + GetRetention(namespace string) (*RetentionPolicies, error) + + // SetRetention sets the retention configuration for all the topics on a namespace + SetRetention(namespace string, policy RetentionPolicies) error + + // GetBacklogQuotaMap returns backlog quota map on a namespace + GetBacklogQuotaMap(namespace string) (map[BacklogQuotaType]BacklogQuota, error) + + // SetBacklogQuota sets a backlog quota for all the topics on a namespace + SetBacklogQuota(namespace string, backlogQuota BacklogQuota, backlogQuotaType BacklogQuotaType) error + + // RemoveBacklogQuota removes a backlog quota policy from a namespace + RemoveBacklogQuota(namespace string) error + + // SetTopicAutoCreation sets topic auto-creation config for a namespace, overriding broker settings + SetTopicAutoCreation(namespace NameSpaceName, config TopicAutoCreationConfig) error + + // RemoveTopicAutoCreation removes topic auto-creation config for a namespace, defaulting to broker settings + RemoveTopicAutoCreation(namespace NameSpaceName) error + + // SetSchemaValidationEnforced sets schema validation enforced for namespace + SetSchemaValidationEnforced(namespace NameSpaceName, schemaValidationEnforced bool) error + + // GetSchemaValidationEnforced returns schema validation enforced for namespace + GetSchemaValidationEnforced(namespace NameSpaceName) (bool, error) + + // SetSchemaAutoUpdateCompatibilityStrategy sets the strategy used to check the a new schema provided + // by a producer is compatible with the current schema before it is installed + SetSchemaAutoUpdateCompatibilityStrategy(namespace NameSpaceName, + strategy SchemaCompatibilityStrategy) error + + // GetSchemaAutoUpdateCompatibilityStrategy returns the strategy used to check the a new schema provided + // by a producer is compatible with the current schema before it is installed + GetSchemaAutoUpdateCompatibilityStrategy(namespace NameSpaceName) (SchemaCompatibilityStrategy, error) + + // ClearOffloadDeleteLag clears the offload deletion lag for a namespace. + ClearOffloadDeleteLag(namespace NameSpaceName) error + + // SetOffloadDeleteLag sets the offload deletion lag for a namespace + SetOffloadDeleteLag(namespace NameSpaceName, timeMs int64) error + + // GetOffloadDeleteLag returns the offload deletion lag for a namespace, in milliseconds + GetOffloadDeleteLag(namespace NameSpaceName) (int64, error) + + // SetOffloadThreshold sets the offloadThreshold for a namespace + SetOffloadThreshold(namespace NameSpaceName, threshold int64) error + + // GetOffloadThreshold returns the offloadThreshold for a namespace + GetOffloadThreshold(namespace NameSpaceName) (int64, error) + + // SetCompactionThreshold sets the compactionThreshold for a namespace + SetCompactionThreshold(namespace NameSpaceName, threshold int64) error + + // GetCompactionThreshold returns the compactionThreshold for a namespace + GetCompactionThreshold(namespace NameSpaceName) (int64, error) + + // SetMaxConsumersPerSubscription sets maxConsumersPerSubscription for a namespace. + SetMaxConsumersPerSubscription(namespace NameSpaceName, max int) error + + // GetMaxConsumersPerSubscription returns the maxConsumersPerSubscription for a namespace. + GetMaxConsumersPerSubscription(namespace NameSpaceName) (int, error) + + // SetMaxConsumersPerTopic sets maxConsumersPerTopic for a namespace. + SetMaxConsumersPerTopic(namespace NameSpaceName, max int) error + + // GetMaxConsumersPerTopic returns the maxProducersPerTopic for a namespace. + GetMaxConsumersPerTopic(namespace NameSpaceName) (int, error) + + // SetMaxProducersPerTopic sets maxProducersPerTopic for a namespace. + SetMaxProducersPerTopic(namespace NameSpaceName, max int) error + + // GetMaxProducersPerTopic returns the maxProducersPerTopic for a namespace. + GetMaxProducersPerTopic(namespace NameSpaceName) (int, error) + + // GetNamespaceReplicationClusters returns the replication clusters for a namespace + GetNamespaceReplicationClusters(namespace string) ([]string, error) + + // SetNamespaceReplicationClusters returns the replication clusters for a namespace + SetNamespaceReplicationClusters(namespace string, clusterIds []string) error + + // SetNamespaceAntiAffinityGroup sets anti-affinity group name for a namespace + SetNamespaceAntiAffinityGroup(namespace string, namespaceAntiAffinityGroup string) error + + // GetAntiAffinityNamespaces returns all namespaces that grouped with given anti-affinity group + GetAntiAffinityNamespaces(tenant, cluster, namespaceAntiAffinityGroup string) ([]string, error) + + // GetNamespaceAntiAffinityGroup returns anti-affinity group name for a namespace + GetNamespaceAntiAffinityGroup(namespace string) (string, error) + + // DeleteNamespaceAntiAffinityGroup deletes anti-affinity group name for a namespace + DeleteNamespaceAntiAffinityGroup(namespace string) error + + // SetDeduplicationStatus sets the deduplication status for all topics within a namespace + // When deduplication is enabled, the broker will prevent to store the same Message multiple times + SetDeduplicationStatus(namespace string, enableDeduplication bool) error + + // SetPersistence sets the persistence configuration for all the topics on a namespace + SetPersistence(namespace string, persistence PersistencePolicies) error + + // GetPersistence returns the persistence configuration for a namespace + GetPersistence(namespace string) (*PersistencePolicies, error) + + // SetBookieAffinityGroup sets bookie affinity group for a namespace to isolate namespace write to bookies that are + // part of given affinity group + SetBookieAffinityGroup(namespace string, bookieAffinityGroup BookieAffinityGroupData) error + + // DeleteBookieAffinityGroup deletes bookie affinity group configured for a namespace + DeleteBookieAffinityGroup(namespace string) error + + // GetBookieAffinityGroup returns bookie affinity group configured for a namespace + GetBookieAffinityGroup(namespace string) (*BookieAffinityGroupData, error) + + // Unload a namespace from the current serving broker + Unload(namespace string) error + + // UnloadNamespaceBundle unloads namespace bundle + UnloadNamespaceBundle(namespace, bundle string) error + + // SplitNamespaceBundle splits namespace bundle + SplitNamespaceBundle(namespace, bundle string, unloadSplitBundles bool) error + + // GetNamespacePermissions returns permissions on a namespace + GetNamespacePermissions(namespace NameSpaceName) (map[string][]AuthAction, error) + + // GrantNamespacePermission grants permission on a namespace. + GrantNamespacePermission(namespace NameSpaceName, role string, action []AuthAction) error + + // RevokeNamespacePermission revokes permissions on a namespace. + RevokeNamespacePermission(namespace NameSpaceName, role string) error + + // GrantSubPermission grants permission to role to access subscription's admin-api + GrantSubPermission(namespace NameSpaceName, sName string, roles []string) error + + // RevokeSubPermission revoke permissions on a subscription's admin-api access + RevokeSubPermission(namespace NameSpaceName, sName, role string) error + + // SetSubscriptionAuthMode sets the given subscription auth mode on all topics on a namespace + SetSubscriptionAuthMode(namespace NameSpaceName, mode SubscriptionAuthMode) error + + // SetEncryptionRequiredStatus sets the encryption required status for all topics within a namespace + SetEncryptionRequiredStatus(namespace NameSpaceName, encrypt bool) error + + // UnsubscribeNamespace unsubscribe the given subscription on all topics on a namespace + UnsubscribeNamespace(namespace NameSpaceName, sName string) error + + // UnsubscribeNamespaceBundle unsubscribe the given subscription on all topics on a namespace bundle + UnsubscribeNamespaceBundle(namespace NameSpaceName, bundle, sName string) error + + // ClearNamespaceBundleBacklogForSubscription clears backlog for a given subscription on all + // topics on a namespace bundle + ClearNamespaceBundleBacklogForSubscription(namespace NameSpaceName, bundle, sName string) error + + // ClearNamespaceBundleBacklog clears backlog for all topics on a namespace bundle + ClearNamespaceBundleBacklog(namespace NameSpaceName, bundle string) error + + // ClearNamespaceBacklogForSubscription clears backlog for a given subscription on all topics on a namespace + ClearNamespaceBacklogForSubscription(namespace NameSpaceName, sName string) error + + // ClearNamespaceBacklog clears backlog for all topics on a namespace + ClearNamespaceBacklog(namespace NameSpaceName) error + + // SetReplicatorDispatchRate sets replicator-Message-dispatch-rate (Replicators under this namespace + // can dispatch this many messages per second) + SetReplicatorDispatchRate(namespace NameSpaceName, rate DispatchRate) error + + // Get replicator-Message-dispatch-rate (Replicators under this namespace + // can dispatch this many messages per second) + GetReplicatorDispatchRate(namespace NameSpaceName) (DispatchRate, error) + + // SetSubscriptionDispatchRate sets subscription-Message-dispatch-rate (subscriptions under this namespace + // can dispatch this many messages per second) + SetSubscriptionDispatchRate(namespace NameSpaceName, rate DispatchRate) error + + // GetSubscriptionDispatchRate returns subscription-Message-dispatch-rate (subscriptions under this namespace + // can dispatch this many messages per second) + GetSubscriptionDispatchRate(namespace NameSpaceName) (DispatchRate, error) + + // SetSubscribeRate sets namespace-subscribe-rate (topics under this namespace will limit by subscribeRate) + SetSubscribeRate(namespace NameSpaceName, rate SubscribeRate) error + + // GetSubscribeRate returns namespace-subscribe-rate (topics under this namespace allow subscribe + // times per consumer in a period) + GetSubscribeRate(namespace NameSpaceName) (SubscribeRate, error) + + // SetDispatchRate sets Message-dispatch-rate (topics under this namespace can dispatch + // this many messages per second) + SetDispatchRate(namespace NameSpaceName, rate DispatchRate) error + + // GetDispatchRate returns Message-dispatch-rate (topics under this namespace can dispatch + // this many messages per second) + GetDispatchRate(namespace NameSpaceName) (DispatchRate, error) + + // SetPublishRate sets the maximum rate or number of messages that producers can publish to topics in this namespace + SetPublishRate(namespace NameSpaceName, pubRate PublishRate) error + + // GetPublishRate gets the maximum rate or number of messages that producer can publish to topics in the namespace + GetPublishRate(namespace NameSpaceName) (PublishRate, error) + + // SetIsAllowAutoUpdateSchema sets whether to allow auto update schema on a namespace + SetIsAllowAutoUpdateSchema(namespace NameSpaceName, isAllowAutoUpdateSchema bool) error + + // GetIsAllowAutoUpdateSchema gets whether to allow auto update schema on a namespace + GetIsAllowAutoUpdateSchema(namespace NameSpaceName) (bool, error) + + // GetInactiveTopicPolicies gets the inactive topic policies on a namespace + GetInactiveTopicPolicies(namespace NameSpaceName) (InactiveTopicPolicies, error) + + // RemoveInactiveTopicPolicies removes inactive topic policies from a namespace + RemoveInactiveTopicPolicies(namespace NameSpaceName) error + + // SetInactiveTopicPolicies sets the inactive topic policies on a namespace + SetInactiveTopicPolicies(namespace NameSpaceName, data InactiveTopicPolicies) error +} + +type namespaces struct { + pulsar *pulsarClient + basePath string + apiVersion APIVersion +} + +// Namespaces is used to access the namespaces endpoints +func (c *pulsarClient) Namespaces() Namespaces { + return &namespaces{ + pulsar: c, + basePath: "/namespaces", + apiVersion: c.apiProfile.Namespaces, + } +} + +func (n *namespaces) GetNamespaces(tenant string) ([]string, error) { + var namespaces []string + endpoint := n.pulsar.endpoint(n.apiVersion, n.basePath, tenant) + err := n.pulsar.restClient.Get(endpoint, &namespaces) + return namespaces, err +} + +func (n *namespaces) GetTopics(namespace string) ([]string, error) { + var topics []string + ns, err := GetNamespaceName(namespace) + if err != nil { + return nil, err + } + endpoint := n.pulsar.endpoint(n.apiVersion, n.basePath, ns.String(), "topics") + err = n.pulsar.restClient.Get(endpoint, &topics) + return topics, err +} + +func (n *namespaces) GetPolicies(namespace string) (*Policies, error) { + var police Policies + ns, err := GetNamespaceName(namespace) + if err != nil { + return nil, err + } + endpoint := n.pulsar.endpoint(n.apiVersion, n.basePath, ns.String()) + err = n.pulsar.restClient.Get(endpoint, &police) + return &police, err +} + +func (n *namespaces) CreateNsWithNumBundles(namespace string, numBundles int) error { + return n.CreateNsWithBundlesData(namespace, NewBundlesDataWithNumBundles(numBundles)) +} + +func (n *namespaces) CreateNsWithPolices(namespace string, policies Policies) error { + ns, err := GetNamespaceName(namespace) + if err != nil { + return err + } + endpoint := n.pulsar.endpoint(n.apiVersion, n.basePath, ns.String()) + return n.pulsar.restClient.Put(endpoint, &policies) +} + +func (n *namespaces) CreateNsWithBundlesData(namespace string, bundleData *BundlesData) error { + ns, err := GetNamespaceName(namespace) + if err != nil { + return err + } + endpoint := n.pulsar.endpoint(n.apiVersion, n.basePath, ns.String()) + polices := new(Policies) + polices.Bundles = bundleData + + return n.pulsar.restClient.Put(endpoint, &polices) +} + +func (n *namespaces) CreateNamespace(namespace string) error { + ns, err := GetNamespaceName(namespace) + if err != nil { + return err + } + endpoint := n.pulsar.endpoint(n.apiVersion, n.basePath, ns.String()) + return n.pulsar.restClient.Put(endpoint, nil) +} + +func (n *namespaces) DeleteNamespace(namespace string) error { + ns, err := GetNamespaceName(namespace) + if err != nil { + return err + } + endpoint := n.pulsar.endpoint(n.apiVersion, n.basePath, ns.String()) + return n.pulsar.restClient.Delete(endpoint) +} + +func (n *namespaces) DeleteNamespaceBundle(namespace string, bundleRange string) error { + ns, err := GetNamespaceName(namespace) + if err != nil { + return err + } + endpoint := n.pulsar.endpoint(n.apiVersion, n.basePath, ns.String(), bundleRange) + return n.pulsar.restClient.Delete(endpoint) +} + +func (n *namespaces) GetNamespaceMessageTTL(namespace string) (int, error) { + var ttl int + nsName, err := GetNamespaceName(namespace) + if err != nil { + return 0, err + } + endpoint := n.pulsar.endpoint(n.apiVersion, n.basePath, nsName.String(), "messageTTL") + err = n.pulsar.restClient.Get(endpoint, &ttl) + return ttl, err +} + +func (n *namespaces) SetNamespaceMessageTTL(namespace string, ttlInSeconds int) error { + nsName, err := GetNamespaceName(namespace) + if err != nil { + return err + } + + endpoint := n.pulsar.endpoint(n.apiVersion, n.basePath, nsName.String(), "messageTTL") + return n.pulsar.restClient.Post(endpoint, &ttlInSeconds) +} + +func (n *namespaces) SetRetention(namespace string, policy RetentionPolicies) error { + nsName, err := GetNamespaceName(namespace) + if err != nil { + return err + } + endpoint := n.pulsar.endpoint(n.apiVersion, n.basePath, nsName.String(), "retention") + return n.pulsar.restClient.Post(endpoint, &policy) +} + +func (n *namespaces) GetRetention(namespace string) (*RetentionPolicies, error) { + var policy RetentionPolicies + nsName, err := GetNamespaceName(namespace) + if err != nil { + return nil, err + } + endpoint := n.pulsar.endpoint(n.apiVersion, n.basePath, nsName.String(), "retention") + err = n.pulsar.restClient.Get(endpoint, &policy) + return &policy, err +} + +func (n *namespaces) GetBacklogQuotaMap(namespace string) (map[BacklogQuotaType]BacklogQuota, error) { + var backlogQuotaMap map[BacklogQuotaType]BacklogQuota + nsName, err := GetNamespaceName(namespace) + if err != nil { + return nil, err + } + endpoint := n.pulsar.endpoint(n.apiVersion, n.basePath, nsName.String(), "backlogQuotaMap") + err = n.pulsar.restClient.Get(endpoint, &backlogQuotaMap) + return backlogQuotaMap, err +} + +func (n *namespaces) SetBacklogQuota(namespace string, backlogQuota BacklogQuota, + backlogQuotaType BacklogQuotaType, +) error { + nsName, err := GetNamespaceName(namespace) + if err != nil { + return err + } + endpoint := n.pulsar.endpoint(n.apiVersion, n.basePath, nsName.String(), "backlogQuota") + params := make(map[string]string) + params["backlogQuotaType"] = string(backlogQuotaType) + return n.pulsar.restClient.PostWithQueryParams(endpoint, &backlogQuota, params) +} + +func (n *namespaces) RemoveBacklogQuota(namespace string) error { + nsName, err := GetNamespaceName(namespace) + if err != nil { + return err + } + endpoint := n.pulsar.endpoint(n.apiVersion, n.basePath, nsName.String(), "backlogQuota") + params := map[string]string{ + "backlogQuotaType": string(DestinationStorage), + } + return n.pulsar.restClient.DeleteWithQueryParams(endpoint, params) +} + +func (n *namespaces) SetTopicAutoCreation(namespace NameSpaceName, config TopicAutoCreationConfig) error { + endpoint := n.pulsar.endpoint(n.apiVersion, n.basePath, namespace.String(), "autoTopicCreation") + return n.pulsar.restClient.Post(endpoint, &config) +} + +func (n *namespaces) RemoveTopicAutoCreation(namespace NameSpaceName) error { + endpoint := n.pulsar.endpoint(n.apiVersion, n.basePath, namespace.String(), "autoTopicCreation") + return n.pulsar.restClient.Delete(endpoint) +} + +func (n *namespaces) SetSchemaValidationEnforced(namespace NameSpaceName, schemaValidationEnforced bool) error { + endpoint := n.pulsar.endpoint(n.apiVersion, n.basePath, namespace.String(), "schemaValidationEnforced") + return n.pulsar.restClient.Post(endpoint, schemaValidationEnforced) +} + +func (n *namespaces) GetSchemaValidationEnforced(namespace NameSpaceName) (bool, error) { + var result bool + endpoint := n.pulsar.endpoint(n.apiVersion, n.basePath, namespace.String(), "schemaValidationEnforced") + err := n.pulsar.restClient.Get(endpoint, &result) + return result, err +} + +func (n *namespaces) SetSchemaAutoUpdateCompatibilityStrategy(namespace NameSpaceName, + strategy SchemaCompatibilityStrategy, +) error { + endpoint := n.pulsar.endpoint(n.apiVersion, n.basePath, namespace.String(), "schemaAutoUpdateCompatibilityStrategy") + return n.pulsar.restClient.Put(endpoint, strategy.String()) +} + +func (n *namespaces) GetSchemaAutoUpdateCompatibilityStrategy(namespace NameSpaceName) ( + SchemaCompatibilityStrategy, error, +) { + endpoint := n.pulsar.endpoint(n.apiVersion, n.basePath, namespace.String(), "schemaAutoUpdateCompatibilityStrategy") + b, err := n.pulsar.restClient.GetWithQueryParams(endpoint, nil, nil, false) + if err != nil { + return "", err + } + s, err := ParseSchemaAutoUpdateCompatibilityStrategy(strings.ReplaceAll(string(b), "\"", "")) + if err != nil { + return "", err + } + return s, nil +} + +func (n *namespaces) ClearOffloadDeleteLag(namespace NameSpaceName) error { + endpoint := n.pulsar.endpoint(n.apiVersion, n.basePath, namespace.String(), "offloadDeletionLagMs") + return n.pulsar.restClient.Delete(endpoint) +} + +func (n *namespaces) SetOffloadDeleteLag(namespace NameSpaceName, timeMs int64) error { + endpoint := n.pulsar.endpoint(n.apiVersion, n.basePath, namespace.String(), "offloadDeletionLagMs") + return n.pulsar.restClient.Put(endpoint, timeMs) +} + +func (n *namespaces) GetOffloadDeleteLag(namespace NameSpaceName) (int64, error) { + var result int64 + endpoint := n.pulsar.endpoint(n.apiVersion, n.basePath, namespace.String(), "offloadDeletionLagMs") + err := n.pulsar.restClient.Get(endpoint, &result) + return result, err +} + +func (n *namespaces) SetMaxConsumersPerSubscription(namespace NameSpaceName, max int) error { + endpoint := n.pulsar.endpoint(n.apiVersion, n.basePath, namespace.String(), "maxConsumersPerSubscription") + return n.pulsar.restClient.Post(endpoint, max) +} + +func (n *namespaces) GetMaxConsumersPerSubscription(namespace NameSpaceName) (int, error) { + var result int + endpoint := n.pulsar.endpoint(n.apiVersion, n.basePath, namespace.String(), "maxConsumersPerSubscription") + err := n.pulsar.restClient.Get(endpoint, &result) + return result, err +} + +func (n *namespaces) SetOffloadThreshold(namespace NameSpaceName, threshold int64) error { + endpoint := n.pulsar.endpoint(n.apiVersion, n.basePath, namespace.String(), "offloadThreshold") + return n.pulsar.restClient.Put(endpoint, threshold) +} + +func (n *namespaces) GetOffloadThreshold(namespace NameSpaceName) (int64, error) { + var result int64 + endpoint := n.pulsar.endpoint(n.apiVersion, n.basePath, namespace.String(), "offloadThreshold") + err := n.pulsar.restClient.Get(endpoint, &result) + return result, err +} + +func (n *namespaces) SetMaxConsumersPerTopic(namespace NameSpaceName, max int) error { + endpoint := n.pulsar.endpoint(n.apiVersion, n.basePath, namespace.String(), "maxConsumersPerTopic") + return n.pulsar.restClient.Post(endpoint, max) +} + +func (n *namespaces) GetMaxConsumersPerTopic(namespace NameSpaceName) (int, error) { + var result int + endpoint := n.pulsar.endpoint(n.apiVersion, n.basePath, namespace.String(), "maxConsumersPerTopic") + err := n.pulsar.restClient.Get(endpoint, &result) + return result, err +} + +func (n *namespaces) SetCompactionThreshold(namespace NameSpaceName, threshold int64) error { + endpoint := n.pulsar.endpoint(n.apiVersion, n.basePath, namespace.String(), "compactionThreshold") + return n.pulsar.restClient.Put(endpoint, threshold) +} + +func (n *namespaces) GetCompactionThreshold(namespace NameSpaceName) (int64, error) { + var result int64 + endpoint := n.pulsar.endpoint(n.apiVersion, n.basePath, namespace.String(), "compactionThreshold") + err := n.pulsar.restClient.Get(endpoint, &result) + return result, err +} + +func (n *namespaces) SetMaxProducersPerTopic(namespace NameSpaceName, max int) error { + endpoint := n.pulsar.endpoint(n.apiVersion, n.basePath, namespace.String(), "maxProducersPerTopic") + return n.pulsar.restClient.Post(endpoint, max) +} + +func (n *namespaces) GetMaxProducersPerTopic(namespace NameSpaceName) (int, error) { + var result int + endpoint := n.pulsar.endpoint(n.apiVersion, n.basePath, namespace.String(), "maxProducersPerTopic") + err := n.pulsar.restClient.Get(endpoint, &result) + return result, err +} + +func (n *namespaces) GetNamespaceReplicationClusters(namespace string) ([]string, error) { + var data []string + nsName, err := GetNamespaceName(namespace) + if err != nil { + return nil, err + } + endpoint := n.pulsar.endpoint(n.apiVersion, n.basePath, nsName.String(), "replication") + err = n.pulsar.restClient.Get(endpoint, &data) + return data, err +} + +func (n *namespaces) SetNamespaceReplicationClusters(namespace string, clusterIds []string) error { + nsName, err := GetNamespaceName(namespace) + if err != nil { + return err + } + endpoint := n.pulsar.endpoint(n.apiVersion, n.basePath, nsName.String(), "replication") + return n.pulsar.restClient.Post(endpoint, &clusterIds) +} + +func (n *namespaces) SetNamespaceAntiAffinityGroup(namespace string, namespaceAntiAffinityGroup string) error { + nsName, err := GetNamespaceName(namespace) + if err != nil { + return err + } + endpoint := n.pulsar.endpoint(n.apiVersion, n.basePath, nsName.String(), "antiAffinity") + return n.pulsar.restClient.Post(endpoint, namespaceAntiAffinityGroup) +} + +func (n *namespaces) GetAntiAffinityNamespaces(tenant, cluster, namespaceAntiAffinityGroup string) ([]string, error) { + var data []string + endpoint := n.pulsar.endpoint(n.apiVersion, n.basePath, cluster, "antiAffinity", namespaceAntiAffinityGroup) + params := map[string]string{ + "property": tenant, + } + _, err := n.pulsar.restClient.GetWithQueryParams(endpoint, &data, params, false) + return data, err +} + +func (n *namespaces) GetNamespaceAntiAffinityGroup(namespace string) (string, error) { + nsName, err := GetNamespaceName(namespace) + if err != nil { + return "", err + } + endpoint := n.pulsar.endpoint(n.apiVersion, n.basePath, nsName.String(), "antiAffinity") + data, err := n.pulsar.restClient.GetWithQueryParams(endpoint, nil, nil, false) + return string(data), err +} + +func (n *namespaces) DeleteNamespaceAntiAffinityGroup(namespace string) error { + nsName, err := GetNamespaceName(namespace) + if err != nil { + return err + } + endpoint := n.pulsar.endpoint(n.apiVersion, n.basePath, nsName.String(), "antiAffinity") + return n.pulsar.restClient.Delete(endpoint) +} + +func (n *namespaces) SetDeduplicationStatus(namespace string, enableDeduplication bool) error { + nsName, err := GetNamespaceName(namespace) + if err != nil { + return err + } + endpoint := n.pulsar.endpoint(n.apiVersion, n.basePath, nsName.String(), "deduplication") + return n.pulsar.restClient.Post(endpoint, enableDeduplication) +} + +func (n *namespaces) SetPersistence(namespace string, persistence PersistencePolicies) error { + nsName, err := GetNamespaceName(namespace) + if err != nil { + return err + } + endpoint := n.pulsar.endpoint(n.apiVersion, n.basePath, nsName.String(), "persistence") + return n.pulsar.restClient.Post(endpoint, &persistence) +} + +func (n *namespaces) SetBookieAffinityGroup(namespace string, bookieAffinityGroup BookieAffinityGroupData) error { + nsName, err := GetNamespaceName(namespace) + if err != nil { + return err + } + endpoint := n.pulsar.endpoint(n.apiVersion, n.basePath, nsName.String(), "persistence", "bookieAffinity") + return n.pulsar.restClient.Post(endpoint, &bookieAffinityGroup) +} + +func (n *namespaces) DeleteBookieAffinityGroup(namespace string) error { + nsName, err := GetNamespaceName(namespace) + if err != nil { + return err + } + endpoint := n.pulsar.endpoint(n.apiVersion, n.basePath, nsName.String(), "persistence", "bookieAffinity") + return n.pulsar.restClient.Delete(endpoint) +} + +func (n *namespaces) GetBookieAffinityGroup(namespace string) (*BookieAffinityGroupData, error) { + var data BookieAffinityGroupData + nsName, err := GetNamespaceName(namespace) + if err != nil { + return nil, err + } + endpoint := n.pulsar.endpoint(n.apiVersion, n.basePath, nsName.String(), "persistence", "bookieAffinity") + err = n.pulsar.restClient.Get(endpoint, &data) + return &data, err +} + +func (n *namespaces) GetPersistence(namespace string) (*PersistencePolicies, error) { + var persistence PersistencePolicies + nsName, err := GetNamespaceName(namespace) + if err != nil { + return nil, err + } + endpoint := n.pulsar.endpoint(n.apiVersion, n.basePath, nsName.String(), "persistence") + err = n.pulsar.restClient.Get(endpoint, &persistence) + return &persistence, err +} + +func (n *namespaces) Unload(namespace string) error { + nsName, err := GetNamespaceName(namespace) + if err != nil { + return err + } + endpoint := n.pulsar.endpoint(n.apiVersion, n.basePath, nsName.String(), "unload") + return n.pulsar.restClient.Put(endpoint, nil) +} + +func (n *namespaces) UnloadNamespaceBundle(namespace, bundle string) error { + nsName, err := GetNamespaceName(namespace) + if err != nil { + return err + } + endpoint := n.pulsar.endpoint(n.apiVersion, n.basePath, nsName.String(), bundle, "unload") + return n.pulsar.restClient.Put(endpoint, nil) +} + +func (n *namespaces) SplitNamespaceBundle(namespace, bundle string, unloadSplitBundles bool) error { + nsName, err := GetNamespaceName(namespace) + if err != nil { + return err + } + endpoint := n.pulsar.endpoint(n.apiVersion, n.basePath, nsName.String(), bundle, "split") + params := map[string]string{ + "unload": strconv.FormatBool(unloadSplitBundles), + } + return n.pulsar.restClient.PutWithQueryParams(endpoint, nil, nil, params) +} + +func (n *namespaces) GetNamespacePermissions(namespace NameSpaceName) (map[string][]AuthAction, error) { + endpoint := n.pulsar.endpoint(n.apiVersion, n.basePath, namespace.String(), "permissions") + var permissions map[string][]AuthAction + err := n.pulsar.restClient.Get(endpoint, &permissions) + return permissions, err +} + +func (n *namespaces) GrantNamespacePermission(namespace NameSpaceName, role string, + action []AuthAction, +) error { + endpoint := n.pulsar.endpoint(n.apiVersion, n.basePath, namespace.String(), "permissions", role) + s := make([]string, 0) + for _, v := range action { + s = append(s, v.String()) + } + return n.pulsar.restClient.Post(endpoint, s) +} + +func (n *namespaces) RevokeNamespacePermission(namespace NameSpaceName, role string) error { + endpoint := n.pulsar.endpoint(n.apiVersion, n.basePath, namespace.String(), "permissions", role) + return n.pulsar.restClient.Delete(endpoint) +} + +func (n *namespaces) GrantSubPermission(namespace NameSpaceName, sName string, roles []string) error { + endpoint := n.pulsar.endpoint(n.apiVersion, n.basePath, namespace.String(), "permissions", + "subscription", sName) + return n.pulsar.restClient.Post(endpoint, roles) +} + +func (n *namespaces) RevokeSubPermission(namespace NameSpaceName, sName, role string) error { + endpoint := n.pulsar.endpoint(n.apiVersion, n.basePath, namespace.String(), "permissions", + "subscription", sName, role) + return n.pulsar.restClient.Delete(endpoint) +} + +func (n *namespaces) SetSubscriptionAuthMode(namespace NameSpaceName, mode SubscriptionAuthMode) error { + endpoint := n.pulsar.endpoint(n.apiVersion, n.basePath, namespace.String(), "subscriptionAuthMode") + return n.pulsar.restClient.Post(endpoint, mode.String()) +} + +func (n *namespaces) SetEncryptionRequiredStatus(namespace NameSpaceName, encrypt bool) error { + endpoint := n.pulsar.endpoint(n.apiVersion, n.basePath, namespace.String(), "encryptionRequired") + return n.pulsar.restClient.Post(endpoint, strconv.FormatBool(encrypt)) +} + +func (n *namespaces) UnsubscribeNamespace(namespace NameSpaceName, sName string) error { + endpoint := n.pulsar.endpoint(n.apiVersion, n.basePath, namespace.String(), "unsubscribe", url.QueryEscape(sName)) + return n.pulsar.restClient.Post(endpoint, nil) +} + +func (n *namespaces) UnsubscribeNamespaceBundle(namespace NameSpaceName, bundle, sName string) error { + endpoint := n.pulsar.endpoint(n.apiVersion, n.basePath, namespace.String(), bundle, "unsubscribe", + url.QueryEscape(sName)) + return n.pulsar.restClient.Post(endpoint, nil) +} + +func (n *namespaces) ClearNamespaceBundleBacklogForSubscription(namespace NameSpaceName, + bundle, sName string, +) error { + endpoint := n.pulsar.endpoint(n.apiVersion, n.basePath, namespace.String(), bundle, "clearBacklog", + url.QueryEscape(sName)) + return n.pulsar.restClient.Post(endpoint, nil) +} + +func (n *namespaces) ClearNamespaceBundleBacklog(namespace NameSpaceName, bundle string) error { + endpoint := n.pulsar.endpoint(n.apiVersion, n.basePath, namespace.String(), bundle, "clearBacklog") + return n.pulsar.restClient.Post(endpoint, nil) +} + +func (n *namespaces) ClearNamespaceBacklogForSubscription(namespace NameSpaceName, sName string) error { + endpoint := n.pulsar.endpoint(n.apiVersion, n.basePath, namespace.String(), "clearBacklog", url.QueryEscape(sName)) + return n.pulsar.restClient.Post(endpoint, nil) +} + +func (n *namespaces) ClearNamespaceBacklog(namespace NameSpaceName) error { + endpoint := n.pulsar.endpoint(n.apiVersion, n.basePath, namespace.String(), "clearBacklog") + return n.pulsar.restClient.Post(endpoint, nil) +} + +func (n *namespaces) SetReplicatorDispatchRate(namespace NameSpaceName, rate DispatchRate) error { + endpoint := n.pulsar.endpoint(n.apiVersion, n.basePath, namespace.String(), "replicatorDispatchRate") + return n.pulsar.restClient.Post(endpoint, rate) +} + +func (n *namespaces) GetReplicatorDispatchRate(namespace NameSpaceName) (DispatchRate, error) { + endpoint := n.pulsar.endpoint(n.apiVersion, n.basePath, namespace.String(), "replicatorDispatchRate") + var rate DispatchRate + err := n.pulsar.restClient.Get(endpoint, &rate) + return rate, err +} + +func (n *namespaces) SetSubscriptionDispatchRate(namespace NameSpaceName, rate DispatchRate) error { + endpoint := n.pulsar.endpoint(n.apiVersion, n.basePath, namespace.String(), "subscriptionDispatchRate") + return n.pulsar.restClient.Post(endpoint, rate) +} + +func (n *namespaces) GetSubscriptionDispatchRate(namespace NameSpaceName) (DispatchRate, error) { + endpoint := n.pulsar.endpoint(n.apiVersion, n.basePath, namespace.String(), "subscriptionDispatchRate") + var rate DispatchRate + err := n.pulsar.restClient.Get(endpoint, &rate) + return rate, err +} + +func (n *namespaces) SetSubscribeRate(namespace NameSpaceName, rate SubscribeRate) error { + endpoint := n.pulsar.endpoint(n.apiVersion, n.basePath, namespace.String(), "subscribeRate") + return n.pulsar.restClient.Post(endpoint, rate) +} + +func (n *namespaces) GetSubscribeRate(namespace NameSpaceName) (SubscribeRate, error) { + endpoint := n.pulsar.endpoint(n.apiVersion, n.basePath, namespace.String(), "subscribeRate") + var rate SubscribeRate + err := n.pulsar.restClient.Get(endpoint, &rate) + return rate, err +} + +func (n *namespaces) SetDispatchRate(namespace NameSpaceName, rate DispatchRate) error { + endpoint := n.pulsar.endpoint(n.apiVersion, n.basePath, namespace.String(), "dispatchRate") + return n.pulsar.restClient.Post(endpoint, rate) +} + +func (n *namespaces) GetDispatchRate(namespace NameSpaceName) (DispatchRate, error) { + endpoint := n.pulsar.endpoint(n.apiVersion, n.basePath, namespace.String(), "dispatchRate") + var rate DispatchRate + err := n.pulsar.restClient.Get(endpoint, &rate) + return rate, err +} + +func (n *namespaces) SetPublishRate(namespace NameSpaceName, pubRate PublishRate) error { + endpoint := n.pulsar.endpoint(n.apiVersion, n.basePath, namespace.String(), "publishRate") + return n.pulsar.restClient.Post(endpoint, pubRate) +} + +func (n *namespaces) GetPublishRate(namespace NameSpaceName) (PublishRate, error) { + endpoint := n.pulsar.endpoint(n.apiVersion, n.basePath, namespace.String(), "publishRate") + var pubRate PublishRate + err := n.pulsar.restClient.Get(endpoint, &pubRate) + return pubRate, err +} + +func (n *namespaces) SetIsAllowAutoUpdateSchema(namespace NameSpaceName, isAllowAutoUpdateSchema bool) error { + endpoint := n.pulsar.endpoint(n.apiVersion, n.basePath, namespace.String(), "isAllowAutoUpdateSchema") + return n.pulsar.restClient.Post(endpoint, &isAllowAutoUpdateSchema) +} + +func (n *namespaces) GetIsAllowAutoUpdateSchema(namespace NameSpaceName) (bool, error) { + endpoint := n.pulsar.endpoint(n.apiVersion, n.basePath, namespace.String(), "isAllowAutoUpdateSchema") + var result bool + err := n.pulsar.restClient.Get(endpoint, &result) + return result, err +} + +func (n *namespaces) GetInactiveTopicPolicies(namespace NameSpaceName) (InactiveTopicPolicies, error) { + var out InactiveTopicPolicies + endpoint := n.pulsar.endpoint(n.apiVersion, n.basePath, namespace.String(), "inactiveTopicPolicies") + err := n.pulsar.restClient.Get(endpoint, &out) + return out, err +} + +func (n *namespaces) RemoveInactiveTopicPolicies(namespace NameSpaceName) error { + endpoint := n.pulsar.endpoint(n.apiVersion, n.basePath, namespace.String(), "inactiveTopicPolicies") + return n.pulsar.restClient.Delete(endpoint) +} + +func (n *namespaces) SetInactiveTopicPolicies(namespace NameSpaceName, data InactiveTopicPolicies) error { + endpoint := n.pulsar.endpoint(n.apiVersion, n.basePath, namespace.String(), "inactiveTopicPolicies") + return n.pulsar.restClient.Post(endpoint, data) +} diff --git a/pulsaradmin/pkg/admin/ns_isolation_policy.go b/pulsaradmin/api_ns_isolation_policy.go similarity index 55% rename from pulsaradmin/pkg/admin/ns_isolation_policy.go rename to pulsaradmin/api_ns_isolation_policy.go index d8897f9f63..94b4a797a4 100644 --- a/pulsaradmin/pkg/admin/ns_isolation_policy.go +++ b/pulsaradmin/api_ns_isolation_policy.go @@ -15,65 +15,66 @@ // specific language governing permissions and limitations // under the License. -package admin - -import ( - "github.com/apache/pulsar-client-go/pulsaradmin/pkg/utils" -) +package pulsaradmin type NsIsolationPolicy interface { // Create a namespace isolation policy for a cluster - CreateNamespaceIsolationPolicy(cluster, policyName string, namespaceIsolationData utils.NamespaceIsolationData) error + CreateNamespaceIsolationPolicy(cluster, policyName string, namespaceIsolationData NamespaceIsolationData) error // Delete a namespace isolation policy for a cluster DeleteNamespaceIsolationPolicy(cluster, policyName string) error // Get a single namespace isolation policy for a cluster - GetNamespaceIsolationPolicy(cluster, policyName string) (*utils.NamespaceIsolationData, error) + GetNamespaceIsolationPolicy(cluster, policyName string) (*NamespaceIsolationData, error) // Get the namespace isolation policies of a cluster - GetNamespaceIsolationPolicies(cluster string) (map[string]utils.NamespaceIsolationData, error) + GetNamespaceIsolationPolicies(cluster string) (map[string]NamespaceIsolationData, error) // Returns list of active brokers with namespace-isolation policies attached to it. - GetBrokersWithNamespaceIsolationPolicy(cluster string) ([]utils.BrokerNamespaceIsolationData, error) + GetBrokersWithNamespaceIsolationPolicy(cluster string) ([]BrokerNamespaceIsolationData, error) // Returns active broker with namespace-isolation policies attached to it. - GetBrokerWithNamespaceIsolationPolicy(cluster, broker string) (*utils.BrokerNamespaceIsolationData, error) + GetBrokerWithNamespaceIsolationPolicy(cluster, broker string) (*BrokerNamespaceIsolationData, error) } type nsIsolationPolicy struct { - pulsar *pulsarClient - basePath string + pulsar *pulsarClient + basePath string + apiVersion APIVersion } func (c *pulsarClient) NsIsolationPolicy() NsIsolationPolicy { return &nsIsolationPolicy{ - pulsar: c, - basePath: "/clusters", + pulsar: c, + basePath: "/clusters", + apiVersion: c.apiProfile.NsIsolationPolicy, } } func (n *nsIsolationPolicy) CreateNamespaceIsolationPolicy(cluster, policyName string, - namespaceIsolationData utils.NamespaceIsolationData) error { + namespaceIsolationData NamespaceIsolationData, +) error { return n.setNamespaceIsolationPolicy(cluster, policyName, namespaceIsolationData) } func (n *nsIsolationPolicy) setNamespaceIsolationPolicy(cluster, policyName string, - namespaceIsolationData utils.NamespaceIsolationData) error { - endpoint := n.pulsar.endpoint(n.basePath, cluster, "namespaceIsolationPolicies", policyName) - return n.pulsar.Client.Post(endpoint, &namespaceIsolationData) + namespaceIsolationData NamespaceIsolationData, +) error { + endpoint := n.pulsar.endpoint(n.apiVersion, n.basePath, cluster, "namespaceIsolationPolicies", policyName) + return n.pulsar.restClient.Post(endpoint, &namespaceIsolationData) } func (n *nsIsolationPolicy) DeleteNamespaceIsolationPolicy(cluster, policyName string) error { - endpoint := n.pulsar.endpoint(n.basePath, cluster, "namespaceIsolationPolicies", policyName) - return n.pulsar.Client.Delete(endpoint) + endpoint := n.pulsar.endpoint(n.apiVersion, n.basePath, cluster, "namespaceIsolationPolicies", policyName) + return n.pulsar.restClient.Delete(endpoint) } func (n *nsIsolationPolicy) GetNamespaceIsolationPolicy(cluster, policyName string) ( - *utils.NamespaceIsolationData, error) { - endpoint := n.pulsar.endpoint(n.basePath, cluster, "namespaceIsolationPolicies", policyName) - var nsIsolationData utils.NamespaceIsolationData - err := n.pulsar.Client.Get(endpoint, &nsIsolationData) + *NamespaceIsolationData, error, +) { + endpoint := n.pulsar.endpoint(n.apiVersion, n.basePath, cluster, "namespaceIsolationPolicies", policyName) + var nsIsolationData NamespaceIsolationData + err := n.pulsar.restClient.Get(endpoint, &nsIsolationData) if err != nil { return nil, err } @@ -81,10 +82,11 @@ func (n *nsIsolationPolicy) GetNamespaceIsolationPolicy(cluster, policyName stri } func (n *nsIsolationPolicy) GetNamespaceIsolationPolicies(cluster string) ( - map[string]utils.NamespaceIsolationData, error) { - endpoint := n.pulsar.endpoint(n.basePath, cluster, "namespaceIsolationPolicies") - var tmpMap map[string]utils.NamespaceIsolationData - err := n.pulsar.Client.Get(endpoint, &tmpMap) + map[string]NamespaceIsolationData, error, +) { + endpoint := n.pulsar.endpoint(n.apiVersion, n.basePath, cluster, "namespaceIsolationPolicies") + var tmpMap map[string]NamespaceIsolationData + err := n.pulsar.restClient.Get(endpoint, &tmpMap) if err != nil { return nil, err } @@ -92,10 +94,11 @@ func (n *nsIsolationPolicy) GetNamespaceIsolationPolicies(cluster string) ( } func (n *nsIsolationPolicy) GetBrokersWithNamespaceIsolationPolicy(cluster string) ( - []utils.BrokerNamespaceIsolationData, error) { - endpoint := n.pulsar.endpoint(n.basePath, cluster, "namespaceIsolationPolicies", "brokers") - var res []utils.BrokerNamespaceIsolationData - err := n.pulsar.Client.Get(endpoint, &res) + []BrokerNamespaceIsolationData, error, +) { + endpoint := n.pulsar.endpoint(n.apiVersion, n.basePath, cluster, "namespaceIsolationPolicies", "brokers") + var res []BrokerNamespaceIsolationData + err := n.pulsar.restClient.Get(endpoint, &res) if err != nil { return nil, err } @@ -103,10 +106,11 @@ func (n *nsIsolationPolicy) GetBrokersWithNamespaceIsolationPolicy(cluster strin } func (n *nsIsolationPolicy) GetBrokerWithNamespaceIsolationPolicy(cluster, - broker string) (*utils.BrokerNamespaceIsolationData, error) { - endpoint := n.pulsar.endpoint(n.basePath, cluster, "namespaceIsolationPolicies", "brokers", broker) - var brokerNamespaceIsolationData utils.BrokerNamespaceIsolationData - err := n.pulsar.Client.Get(endpoint, &brokerNamespaceIsolationData) + broker string, +) (*BrokerNamespaceIsolationData, error) { + endpoint := n.pulsar.endpoint(n.apiVersion, n.basePath, cluster, "namespaceIsolationPolicies", "brokers", broker) + var brokerNamespaceIsolationData BrokerNamespaceIsolationData + err := n.pulsar.restClient.Get(endpoint, &brokerNamespaceIsolationData) if err != nil { return nil, err } diff --git a/pulsaradmin/pkg/admin/packages.go b/pulsaradmin/api_packages.go similarity index 75% rename from pulsaradmin/pkg/admin/packages.go rename to pulsaradmin/api_packages.go index c7a0fd5ff1..172425ce59 100644 --- a/pulsaradmin/pkg/admin/packages.go +++ b/pulsaradmin/api_packages.go @@ -15,7 +15,7 @@ // specific language governing permissions and limitations // under the License. -package admin +package pulsaradmin import ( "bytes" @@ -30,8 +30,6 @@ import ( "strings" "github.com/pkg/errors" - - "github.com/apache/pulsar-client-go/pulsaradmin/pkg/utils" ) // Packages is admin interface for functions management @@ -66,15 +64,16 @@ type Packages interface { Delete(packageURL string) error // GetMetadata get a package metadata information - GetMetadata(packageURL string) (utils.PackageMetadata, error) + GetMetadata(packageURL string) (PackageMetadata, error) // UpdateMetadata update a package metadata information UpdateMetadata(packageURL, description, contact string, properties map[string]string) error } type packages struct { - pulsar *pulsarClient - basePath string + pulsar *pulsarClient + basePath string + apiVersion APIVersion } func (p *packages) createStringFromField(w *multipart.Writer, value string) (io.Writer, error) { @@ -87,22 +86,23 @@ func (p *packages) createStringFromField(w *multipart.Writer, value string) (io. // Packages is used to access the functions endpoints func (c *pulsarClient) Packages() Packages { return &packages{ - pulsar: c, - basePath: "/packages", + pulsar: c, + basePath: "/packages", + apiVersion: c.apiProfile.Packages, } } func (p packages) Download(packageURL, destinationFile string) error { - packageName, err := utils.GetPackageName(packageURL) + packageName, err := GetPackageName(packageURL) if err != nil { return err } - endpoint := p.pulsar.endpoint(p.basePath, string(packageName.GetType()), packageName.GetTenant(), + endpoint := p.pulsar.endpoint(p.apiVersion, p.basePath, string(packageName.GetType()), packageName.GetTenant(), packageName.GetNamespace(), packageName.GetName(), packageName.GetVersion()) parent := path.Dir(destinationFile) if parent != "." { - err = os.MkdirAll(parent, 0755) + err = os.MkdirAll(parent, 0o755) if err != nil { return fmt.Errorf("failed to create parent directory %s: %w", parent, err) } @@ -120,7 +120,7 @@ func (p packages) Download(packageURL, destinationFile string) error { return err } - _, err = p.pulsar.Client.GetWithOptions(endpoint, nil, nil, false, file) + _, err = p.pulsar.restClient.GetWithOptions(endpoint, nil, nil, false, file) if err != nil { return err } @@ -134,13 +134,13 @@ func (p packages) Upload(packageURL, filePath, description, contact string, prop if strings.TrimSpace(packageURL) == "" { return errors.New("package URL is empty") } - packageName, err := utils.GetPackageName(packageURL) + packageName, err := GetPackageName(packageURL) if err != nil { return err } - endpoint := p.pulsar.endpoint(p.basePath, string(packageName.GetType()), packageName.GetTenant(), + endpoint := p.pulsar.endpoint(p.apiVersion, p.basePath, string(packageName.GetType()), packageName.GetTenant(), packageName.GetNamespace(), packageName.GetName(), packageName.GetVersion()) - metadata := utils.PackageMetadata{ + metadata := PackageMetadata{ Description: description, Contact: contact, Properties: properties, @@ -172,7 +172,6 @@ func (p packages) Upload(packageURL, filePath, description, contact string, prop defer file.Close() part, err := multiPartWriter.CreateFormFile("file", filepath.Base(file.Name())) - if err != nil { return err } @@ -188,7 +187,7 @@ func (p packages) Upload(packageURL, filePath, description, contact string, prop } contentType := multiPartWriter.FormDataContentType() - err = p.pulsar.Client.PostWithMultiPart(endpoint, nil, bodyBuf, contentType) + err = p.pulsar.restClient.PostWithMultiPart(endpoint, nil, bodyBuf, contentType) if err != nil { return err } @@ -198,58 +197,58 @@ func (p packages) Upload(packageURL, filePath, description, contact string, prop func (p packages) List(typeName, namespace string) ([]string, error) { var packageList []string - endpoint := p.pulsar.endpoint(p.basePath, typeName, namespace) - err := p.pulsar.Client.Get(endpoint, &packageList) + endpoint := p.pulsar.endpoint(p.apiVersion, p.basePath, typeName, namespace) + err := p.pulsar.restClient.Get(endpoint, &packageList) return packageList, err } func (p packages) ListVersions(packageURL string) ([]string, error) { var versionList []string - packageName, err := utils.GetPackageName(packageURL) + packageName, err := GetPackageName(packageURL) if err != nil { return versionList, err } - endpoint := p.pulsar.endpoint(p.basePath, string(packageName.GetType()), packageName.GetTenant(), + endpoint := p.pulsar.endpoint(p.apiVersion, p.basePath, string(packageName.GetType()), packageName.GetTenant(), packageName.GetNamespace(), packageName.GetName()) - err = p.pulsar.Client.Get(endpoint, &versionList) + err = p.pulsar.restClient.Get(endpoint, &versionList) return versionList, err } func (p packages) Delete(packageURL string) error { - packageName, err := utils.GetPackageName(packageURL) + packageName, err := GetPackageName(packageURL) if err != nil { return err } - endpoint := p.pulsar.endpoint(p.basePath, string(packageName.GetType()), packageName.GetTenant(), + endpoint := p.pulsar.endpoint(p.apiVersion, p.basePath, string(packageName.GetType()), packageName.GetTenant(), packageName.GetNamespace(), packageName.GetName(), packageName.GetVersion()) - return p.pulsar.Client.Delete(endpoint) + return p.pulsar.restClient.Delete(endpoint) } -func (p packages) GetMetadata(packageURL string) (utils.PackageMetadata, error) { - var metadata utils.PackageMetadata - packageName, err := utils.GetPackageName(packageURL) +func (p packages) GetMetadata(packageURL string) (PackageMetadata, error) { + var metadata PackageMetadata + packageName, err := GetPackageName(packageURL) if err != nil { return metadata, err } - endpoint := p.pulsar.endpoint(p.basePath, string(packageName.GetType()), packageName.GetTenant(), + endpoint := p.pulsar.endpoint(p.apiVersion, p.basePath, string(packageName.GetType()), packageName.GetTenant(), packageName.GetNamespace(), packageName.GetName(), packageName.GetVersion(), "metadata") - err = p.pulsar.Client.Get(endpoint, &metadata) + err = p.pulsar.restClient.Get(endpoint, &metadata) return metadata, err } func (p packages) UpdateMetadata(packageURL, description, contact string, properties map[string]string) error { - metadata := utils.PackageMetadata{ + metadata := PackageMetadata{ Description: description, Contact: contact, Properties: properties, } - packageName, err := utils.GetPackageName(packageURL) + packageName, err := GetPackageName(packageURL) if err != nil { return err } - endpoint := p.pulsar.endpoint(p.basePath, string(packageName.GetType()), packageName.GetTenant(), + endpoint := p.pulsar.endpoint(p.apiVersion, p.basePath, string(packageName.GetType()), packageName.GetTenant(), packageName.GetNamespace(), packageName.GetName(), packageName.GetVersion(), "metadata") - return p.pulsar.Client.Put(endpoint, &metadata) + return p.pulsar.restClient.Put(endpoint, &metadata) } diff --git a/pulsaradmin/pkg/admin/resource_quotas.go b/pulsaradmin/api_resource_quotas.go similarity index 57% rename from pulsaradmin/pkg/admin/resource_quotas.go rename to pulsaradmin/api_resource_quotas.go index fc5209b54b..19bd7eb93e 100644 --- a/pulsaradmin/pkg/admin/resource_quotas.go +++ b/pulsaradmin/api_resource_quotas.go @@ -15,72 +15,70 @@ // specific language governing permissions and limitations // under the License. -package admin - -import ( - "github.com/apache/pulsar-client-go/pulsaradmin/pkg/utils" -) +package pulsaradmin type ResourceQuotas interface { // Get default resource quota for new resource bundles. - GetDefaultResourceQuota() (*utils.ResourceQuota, error) + GetDefaultResourceQuota() (*ResourceQuota, error) // Set default resource quota for new namespace bundles. - SetDefaultResourceQuota(quota utils.ResourceQuota) error + SetDefaultResourceQuota(quota ResourceQuota) error // Get resource quota of a namespace bundle. - GetNamespaceBundleResourceQuota(namespace, bundle string) (*utils.ResourceQuota, error) + GetNamespaceBundleResourceQuota(namespace, bundle string) (*ResourceQuota, error) // Set resource quota for a namespace bundle. - SetNamespaceBundleResourceQuota(namespace, bundle string, quota utils.ResourceQuota) error + SetNamespaceBundleResourceQuota(namespace, bundle string, quota ResourceQuota) error // Reset resource quota for a namespace bundle to default value. ResetNamespaceBundleResourceQuota(namespace, bundle string) error } type resource struct { - pulsar *pulsarClient - basePath string + pulsar *pulsarClient + basePath string + apiVersion APIVersion } func (c *pulsarClient) ResourceQuotas() ResourceQuotas { return &resource{ - pulsar: c, - basePath: "/resource-quotas", + pulsar: c, + basePath: "/resource-quotas", + apiVersion: c.apiProfile.ResourceQuotas, } } -func (r *resource) GetDefaultResourceQuota() (*utils.ResourceQuota, error) { - endpoint := r.pulsar.endpoint(r.basePath) - var quota utils.ResourceQuota - err := r.pulsar.Client.Get(endpoint, "a) +func (r *resource) GetDefaultResourceQuota() (*ResourceQuota, error) { + endpoint := r.pulsar.endpoint(r.apiVersion, r.basePath) + var quota ResourceQuota + err := r.pulsar.restClient.Get(endpoint, "a) if err != nil { return nil, err } return "a, nil } -func (r *resource) SetDefaultResourceQuota(quota utils.ResourceQuota) error { - endpoint := r.pulsar.endpoint(r.basePath) - return r.pulsar.Client.Post(endpoint, "a) +func (r *resource) SetDefaultResourceQuota(quota ResourceQuota) error { + endpoint := r.pulsar.endpoint(r.apiVersion, r.basePath) + return r.pulsar.restClient.Post(endpoint, "a) } -func (r *resource) GetNamespaceBundleResourceQuota(namespace, bundle string) (*utils.ResourceQuota, error) { - endpoint := r.pulsar.endpoint(r.basePath, namespace, bundle) - var quota utils.ResourceQuota - err := r.pulsar.Client.Get(endpoint, "a) +func (r *resource) GetNamespaceBundleResourceQuota(namespace, bundle string) (*ResourceQuota, error) { + endpoint := r.pulsar.endpoint(r.apiVersion, r.basePath, namespace, bundle) + var quota ResourceQuota + err := r.pulsar.restClient.Get(endpoint, "a) if err != nil { return nil, err } return "a, nil } -func (r *resource) SetNamespaceBundleResourceQuota(namespace, bundle string, quota utils.ResourceQuota) error { - endpoint := r.pulsar.endpoint(r.basePath, namespace, bundle) - return r.pulsar.Client.Post(endpoint, "a) +func (r *resource) SetNamespaceBundleResourceQuota(namespace, bundle string, quota ResourceQuota) error { + endpoint := r.pulsar.endpoint(r.apiVersion, r.basePath, namespace, bundle) + return r.pulsar.restClient.Post(endpoint, "a) } func (r *resource) ResetNamespaceBundleResourceQuota(namespace, bundle string) error { - endpoint := r.pulsar.endpoint(r.basePath, namespace, bundle) - return r.pulsar.Client.Delete(endpoint) + endpoint := r.pulsar.endpoint(r.apiVersion, r.basePath, namespace, bundle) + return r.pulsar.restClient.Delete(endpoint) } diff --git a/pulsaradmin/pkg/admin/schema.go b/pulsaradmin/api_schema.go similarity index 53% rename from pulsaradmin/pkg/admin/schema.go rename to pulsaradmin/api_schema.go index 1465526841..cd8a072c37 100644 --- a/pulsaradmin/pkg/admin/schema.go +++ b/pulsaradmin/api_schema.go @@ -15,124 +15,125 @@ // specific language governing permissions and limitations // under the License. -package admin +package pulsaradmin import ( "fmt" "strconv" - - "github.com/apache/pulsar-client-go/pulsaradmin/pkg/utils" ) // Schema is admin interface for schema management type Schema interface { // GetSchemaInfo retrieves the latest schema of a topic - GetSchemaInfo(topic string) (*utils.SchemaInfo, error) + GetSchemaInfo(topic string) (*SchemaInfo, error) // GetSchemaInfoWithVersion retrieves the latest schema with version of a topic - GetSchemaInfoWithVersion(topic string) (*utils.SchemaInfoWithVersion, error) + GetSchemaInfoWithVersion(topic string) (*SchemaInfoWithVersion, error) // GetSchemaInfoByVersion retrieves the schema of a topic at a given version - GetSchemaInfoByVersion(topic string, version int64) (*utils.SchemaInfo, error) + GetSchemaInfoByVersion(topic string, version int64) (*SchemaInfo, error) // DeleteSchema deletes the schema associated with a given topic DeleteSchema(topic string) error // CreateSchemaByPayload creates a schema for a given topic - CreateSchemaByPayload(topic string, schemaPayload utils.PostSchemaPayload) error + CreateSchemaByPayload(topic string, schemaPayload PostSchemaPayload) error } type schemas struct { - pulsar *pulsarClient - basePath string + pulsar *pulsarClient + basePath string + apiVersion APIVersion } // Schemas is used to access the schemas endpoints func (c *pulsarClient) Schemas() Schema { return &schemas{ - pulsar: c, - basePath: "/schemas", + pulsar: c, + basePath: "/schemas", + apiVersion: c.apiProfile.Schemas, } } -func (s *schemas) GetSchemaInfo(topic string) (*utils.SchemaInfo, error) { - topicName, err := utils.GetTopicName(topic) +func (s *schemas) GetSchemaInfo(topic string) (*SchemaInfo, error) { + topicName, err := GetTopicName(topic) if err != nil { return nil, err } - var response utils.GetSchemaResponse - endpoint := s.pulsar.endpoint(s.basePath, topicName.GetTenant(), topicName.GetNamespace(), + var response GetSchemaResponse + endpoint := s.pulsar.endpoint(s.apiVersion, s.basePath, topicName.GetTenant(), topicName.GetNamespace(), topicName.GetLocalName(), "schema") - err = s.pulsar.Client.Get(endpoint, &response) + err = s.pulsar.restClient.Get(endpoint, &response) if err != nil { return nil, err } - info := utils.ConvertGetSchemaResponseToSchemaInfo(topicName, response) + info := ConvertGetSchemaResponseToSchemaInfo(topicName, response) return info, nil } -func (s *schemas) GetSchemaInfoWithVersion(topic string) (*utils.SchemaInfoWithVersion, error) { - topicName, err := utils.GetTopicName(topic) +func (s *schemas) GetSchemaInfoWithVersion(topic string) (*SchemaInfoWithVersion, error) { + topicName, err := GetTopicName(topic) if err != nil { return nil, err } - var response utils.GetSchemaResponse - endpoint := s.pulsar.endpoint(s.basePath, topicName.GetTenant(), topicName.GetNamespace(), + var response GetSchemaResponse + endpoint := s.pulsar.endpoint(s.apiVersion, s.basePath, topicName.GetTenant(), topicName.GetNamespace(), topicName.GetLocalName(), "schema") - err = s.pulsar.Client.Get(endpoint, &response) + err = s.pulsar.restClient.Get(endpoint, &response) if err != nil { fmt.Println("err:", err.Error()) return nil, err } - info := utils.ConvertGetSchemaResponseToSchemaInfoWithVersion(topicName, response) + info := ConvertGetSchemaResponseToSchemaInfoWithVersion(topicName, response) return info, nil } -func (s *schemas) GetSchemaInfoByVersion(topic string, version int64) (*utils.SchemaInfo, error) { - topicName, err := utils.GetTopicName(topic) +func (s *schemas) GetSchemaInfoByVersion(topic string, version int64) (*SchemaInfo, error) { + topicName, err := GetTopicName(topic) if err != nil { return nil, err } - var response utils.GetSchemaResponse - endpoint := s.pulsar.endpoint(s.basePath, topicName.GetTenant(), topicName.GetNamespace(), topicName.GetLocalName(), + var response GetSchemaResponse + endpoint := s.pulsar.endpoint(s.apiVersion, s.basePath, topicName.GetTenant(), topicName.GetNamespace(), + topicName.GetLocalName(), "schema", strconv.FormatInt(version, 10)) - err = s.pulsar.Client.Get(endpoint, &response) + err = s.pulsar.restClient.Get(endpoint, &response) if err != nil { return nil, err } - info := utils.ConvertGetSchemaResponseToSchemaInfo(topicName, response) + info := ConvertGetSchemaResponseToSchemaInfo(topicName, response) return info, nil } func (s *schemas) DeleteSchema(topic string) error { - topicName, err := utils.GetTopicName(topic) + topicName, err := GetTopicName(topic) if err != nil { return err } - endpoint := s.pulsar.endpoint(s.basePath, topicName.GetTenant(), topicName.GetNamespace(), + endpoint := s.pulsar.endpoint(s.apiVersion, s.basePath, topicName.GetTenant(), topicName.GetNamespace(), topicName.GetLocalName(), "schema") fmt.Println(endpoint) - return s.pulsar.Client.Delete(endpoint) + return s.pulsar.restClient.Delete(endpoint) } -func (s *schemas) CreateSchemaByPayload(topic string, schemaPayload utils.PostSchemaPayload) error { - topicName, err := utils.GetTopicName(topic) +func (s *schemas) CreateSchemaByPayload(topic string, schemaPayload PostSchemaPayload) error { + topicName, err := GetTopicName(topic) if err != nil { return err } - endpoint := s.pulsar.endpoint(s.basePath, topicName.GetTenant(), topicName.GetNamespace(), + endpoint := s.pulsar.endpoint(s.apiVersion, s.basePath, topicName.GetTenant(), topicName.GetNamespace(), topicName.GetLocalName(), "schema") - return s.pulsar.Client.Post(endpoint, &schemaPayload) + return s.pulsar.restClient.Post(endpoint, &schemaPayload) } diff --git a/pulsaradmin/pkg/admin/sinks.go b/pulsaradmin/api_sinks.go similarity index 68% rename from pulsaradmin/pkg/admin/sinks.go rename to pulsaradmin/api_sinks.go index acbf83113b..356e022711 100644 --- a/pulsaradmin/pkg/admin/sinks.go +++ b/pulsaradmin/api_sinks.go @@ -15,7 +15,7 @@ // specific language governing permissions and limitations // under the License. -package admin +package pulsaradmin import ( "bytes" @@ -27,8 +27,6 @@ import ( "os" "path/filepath" "strings" - - "github.com/apache/pulsar-client-go/pulsaradmin/pkg/utils" ) // Sinks is admin interface for sinks management @@ -37,28 +35,28 @@ type Sinks interface { ListSinks(tenant, namespace string) ([]string, error) // GetSink returns the configuration for the specified sink - GetSink(tenant, namespace, Sink string) (utils.SinkConfig, error) + GetSink(tenant, namespace, Sink string) (SinkConfig, error) // CreateSink creates a new sink - CreateSink(config *utils.SinkConfig, fileName string) error + CreateSink(config *SinkConfig, fileName string) error // CreateSinkWithURL creates a new sink by providing url from which fun-pkg can be downloaded. supported url: http/file - CreateSinkWithURL(config *utils.SinkConfig, pkgURL string) error + CreateSinkWithURL(config *SinkConfig, pkgURL string) error // UpdateSink updates the configuration for a sink. - UpdateSink(config *utils.SinkConfig, fileName string, options *utils.UpdateOptions) error + UpdateSink(config *SinkConfig, fileName string, options *UpdateOptions) error // UpdateSinkWithURL updates a sink by providing url from which fun-pkg can be downloaded. supported url: http/file - UpdateSinkWithURL(config *utils.SinkConfig, pkgURL string, options *utils.UpdateOptions) error + UpdateSinkWithURL(config *SinkConfig, pkgURL string, options *UpdateOptions) error // DeleteSink deletes an existing sink DeleteSink(tenant, namespace, Sink string) error // GetSinkStatus returns the current status of a sink. - GetSinkStatus(tenant, namespace, Sink string) (utils.SinkStatus, error) + GetSinkStatus(tenant, namespace, Sink string) (SinkStatus, error) // GetSinkStatusWithID returns the current status of a sink instance. - GetSinkStatusWithID(tenant, namespace, Sink string, id int) (utils.SinkInstanceStatusData, error) + GetSinkStatusWithID(tenant, namespace, Sink string, id int) (SinkInstanceStatusData, error) // RestartSink restarts all sink instances RestartSink(tenant, namespace, Sink string) error @@ -79,22 +77,24 @@ type Sinks interface { StartSinkWithID(tenant, namespace, Sink string, id int) error // GetBuiltInSinks fetches a list of supported Pulsar IO sinks currently running in cluster mode - GetBuiltInSinks() ([]*utils.ConnectorDefinition, error) + GetBuiltInSinks() ([]*ConnectorDefinition, error) // ReloadBuiltInSinks reload the available built-in connectors, include Source and Sink ReloadBuiltInSinks() error } type sinks struct { - pulsar *pulsarClient - basePath string + pulsar *pulsarClient + basePath string + apiVersion APIVersion } // Sinks is used to access the sinks endpoints func (c *pulsarClient) Sinks() Sinks { return &sinks{ - pulsar: c, - basePath: "/sinks", + pulsar: c, + basePath: "/sinks", + apiVersion: c.apiProfile.Sinks, } } @@ -114,20 +114,20 @@ func (s *sinks) createTextFromFiled(w *multipart.Writer, value string) (io.Write func (s *sinks) ListSinks(tenant, namespace string) ([]string, error) { var sinks []string - endpoint := s.pulsar.endpoint(s.basePath, tenant, namespace) - err := s.pulsar.Client.Get(endpoint, &sinks) + endpoint := s.pulsar.endpoint(s.apiVersion, s.basePath, tenant, namespace) + err := s.pulsar.restClient.Get(endpoint, &sinks) return sinks, err } -func (s *sinks) GetSink(tenant, namespace, sink string) (utils.SinkConfig, error) { - var sinkConfig utils.SinkConfig - endpoint := s.pulsar.endpoint(s.basePath, tenant, namespace, sink) - err := s.pulsar.Client.Get(endpoint, &sinkConfig) +func (s *sinks) GetSink(tenant, namespace, sink string) (SinkConfig, error) { + var sinkConfig SinkConfig + endpoint := s.pulsar.endpoint(s.apiVersion, s.basePath, tenant, namespace, sink) + err := s.pulsar.restClient.Get(endpoint, &sinkConfig) return sinkConfig, err } -func (s *sinks) CreateSink(config *utils.SinkConfig, fileName string) error { - endpoint := s.pulsar.endpoint(s.basePath, config.Tenant, config.Namespace, config.Name) +func (s *sinks) CreateSink(config *SinkConfig, fileName string) error { + endpoint := s.pulsar.endpoint(s.apiVersion, s.basePath, config.Tenant, config.Namespace, config.Name) // buffer to store our request as bytes bodyBuf := bytes.NewBufferString("") @@ -157,7 +157,6 @@ func (s *sinks) CreateSink(config *utils.SinkConfig, fileName string) error { defer file.Close() part, err := multiPartWriter.CreateFormFile("data", filepath.Base(file.Name())) - if err != nil { return err } @@ -176,7 +175,7 @@ func (s *sinks) CreateSink(config *utils.SinkConfig, fileName string) error { } contentType := multiPartWriter.FormDataContentType() - err = s.pulsar.Client.PostWithMultiPart(endpoint, nil, bodyBuf, contentType) + err = s.pulsar.restClient.PostWithMultiPart(endpoint, nil, bodyBuf, contentType) if err != nil { return err } @@ -184,8 +183,8 @@ func (s *sinks) CreateSink(config *utils.SinkConfig, fileName string) error { return nil } -func (s *sinks) CreateSinkWithURL(config *utils.SinkConfig, pkgURL string) error { - endpoint := s.pulsar.endpoint(s.basePath, config.Tenant, config.Namespace, config.Name) +func (s *sinks) CreateSinkWithURL(config *SinkConfig, pkgURL string) error { + endpoint := s.pulsar.endpoint(s.apiVersion, s.basePath, config.Tenant, config.Namespace, config.Name) // buffer to store our request as bytes bodyBuf := bytes.NewBufferString("") @@ -221,7 +220,7 @@ func (s *sinks) CreateSinkWithURL(config *utils.SinkConfig, pkgURL string) error } contentType := multiPartWriter.FormDataContentType() - err = s.pulsar.Client.PostWithMultiPart(endpoint, nil, bodyBuf, contentType) + err = s.pulsar.restClient.PostWithMultiPart(endpoint, nil, bodyBuf, contentType) if err != nil { return err } @@ -229,8 +228,8 @@ func (s *sinks) CreateSinkWithURL(config *utils.SinkConfig, pkgURL string) error return nil } -func (s *sinks) UpdateSink(config *utils.SinkConfig, fileName string, updateOptions *utils.UpdateOptions) error { - endpoint := s.pulsar.endpoint(s.basePath, config.Tenant, config.Namespace, config.Name) +func (s *sinks) UpdateSink(config *SinkConfig, fileName string, updateOptions *UpdateOptions) error { + endpoint := s.pulsar.endpoint(s.apiVersion, s.basePath, config.Tenant, config.Namespace, config.Name) // buffer to store our request as bytes bodyBuf := bytes.NewBufferString("") @@ -277,7 +276,6 @@ func (s *sinks) UpdateSink(config *utils.SinkConfig, fileName string, updateOpti defer file.Close() part, err := multiPartWriter.CreateFormFile("data", filepath.Base(file.Name())) - if err != nil { return err } @@ -296,7 +294,7 @@ func (s *sinks) UpdateSink(config *utils.SinkConfig, fileName string, updateOpti } contentType := multiPartWriter.FormDataContentType() - err = s.pulsar.Client.PutWithMultiPart(endpoint, bodyBuf, contentType) + err = s.pulsar.restClient.PutWithMultiPart(endpoint, bodyBuf, contentType) if err != nil { return err } @@ -304,8 +302,8 @@ func (s *sinks) UpdateSink(config *utils.SinkConfig, fileName string, updateOpti return nil } -func (s *sinks) UpdateSinkWithURL(config *utils.SinkConfig, pkgURL string, updateOptions *utils.UpdateOptions) error { - endpoint := s.pulsar.endpoint(s.basePath, config.Tenant, config.Namespace, config.Name) +func (s *sinks) UpdateSinkWithURL(config *SinkConfig, pkgURL string, updateOptions *UpdateOptions) error { + endpoint := s.pulsar.endpoint(s.apiVersion, s.basePath, config.Tenant, config.Namespace, config.Name) // buffer to store our request as bytes bodyBuf := bytes.NewBufferString("") @@ -360,7 +358,7 @@ func (s *sinks) UpdateSinkWithURL(config *utils.SinkConfig, pkgURL string, updat } contentType := multiPartWriter.FormDataContentType() - err = s.pulsar.Client.PutWithMultiPart(endpoint, bodyBuf, contentType) + err = s.pulsar.restClient.PutWithMultiPart(endpoint, bodyBuf, contentType) if err != nil { return err } @@ -369,69 +367,69 @@ func (s *sinks) UpdateSinkWithURL(config *utils.SinkConfig, pkgURL string, updat } func (s *sinks) DeleteSink(tenant, namespace, sink string) error { - endpoint := s.pulsar.endpoint(s.basePath, tenant, namespace, sink) - return s.pulsar.Client.Delete(endpoint) + endpoint := s.pulsar.endpoint(s.apiVersion, s.basePath, tenant, namespace, sink) + return s.pulsar.restClient.Delete(endpoint) } -func (s *sinks) GetSinkStatus(tenant, namespace, sink string) (utils.SinkStatus, error) { - var sinkStatus utils.SinkStatus - endpoint := s.pulsar.endpoint(s.basePath, tenant, namespace, sink) - err := s.pulsar.Client.Get(endpoint+"/status", &sinkStatus) +func (s *sinks) GetSinkStatus(tenant, namespace, sink string) (SinkStatus, error) { + var sinkStatus SinkStatus + endpoint := s.pulsar.endpoint(s.apiVersion, s.basePath, tenant, namespace, sink) + err := s.pulsar.restClient.Get(endpoint+"/status", &sinkStatus) return sinkStatus, err } -func (s *sinks) GetSinkStatusWithID(tenant, namespace, sink string, id int) (utils.SinkInstanceStatusData, error) { - var sinkInstanceStatusData utils.SinkInstanceStatusData +func (s *sinks) GetSinkStatusWithID(tenant, namespace, sink string, id int) (SinkInstanceStatusData, error) { + var sinkInstanceStatusData SinkInstanceStatusData instanceID := fmt.Sprintf("%d", id) - endpoint := s.pulsar.endpoint(s.basePath, tenant, namespace, sink, instanceID) - err := s.pulsar.Client.Get(endpoint+"/status", &sinkInstanceStatusData) + endpoint := s.pulsar.endpoint(s.apiVersion, s.basePath, tenant, namespace, sink, instanceID) + err := s.pulsar.restClient.Get(endpoint+"/status", &sinkInstanceStatusData) return sinkInstanceStatusData, err } func (s *sinks) RestartSink(tenant, namespace, sink string) error { - endpoint := s.pulsar.endpoint(s.basePath, tenant, namespace, sink) - return s.pulsar.Client.Post(endpoint+"/restart", nil) + endpoint := s.pulsar.endpoint(s.apiVersion, s.basePath, tenant, namespace, sink) + return s.pulsar.restClient.Post(endpoint+"/restart", nil) } func (s *sinks) RestartSinkWithID(tenant, namespace, sink string, instanceID int) error { id := fmt.Sprintf("%d", instanceID) - endpoint := s.pulsar.endpoint(s.basePath, tenant, namespace, sink, id) + endpoint := s.pulsar.endpoint(s.apiVersion, s.basePath, tenant, namespace, sink, id) - return s.pulsar.Client.Post(endpoint+"/restart", nil) + return s.pulsar.restClient.Post(endpoint+"/restart", nil) } func (s *sinks) StopSink(tenant, namespace, sink string) error { - endpoint := s.pulsar.endpoint(s.basePath, tenant, namespace, sink) - return s.pulsar.Client.Post(endpoint+"/stop", nil) + endpoint := s.pulsar.endpoint(s.apiVersion, s.basePath, tenant, namespace, sink) + return s.pulsar.restClient.Post(endpoint+"/stop", nil) } func (s *sinks) StopSinkWithID(tenant, namespace, sink string, instanceID int) error { id := fmt.Sprintf("%d", instanceID) - endpoint := s.pulsar.endpoint(s.basePath, tenant, namespace, sink, id) + endpoint := s.pulsar.endpoint(s.apiVersion, s.basePath, tenant, namespace, sink, id) - return s.pulsar.Client.Post(endpoint+"/stop", nil) + return s.pulsar.restClient.Post(endpoint+"/stop", nil) } func (s *sinks) StartSink(tenant, namespace, sink string) error { - endpoint := s.pulsar.endpoint(s.basePath, tenant, namespace, sink) - return s.pulsar.Client.Post(endpoint+"/start", nil) + endpoint := s.pulsar.endpoint(s.apiVersion, s.basePath, tenant, namespace, sink) + return s.pulsar.restClient.Post(endpoint+"/start", nil) } func (s *sinks) StartSinkWithID(tenant, namespace, sink string, instanceID int) error { id := fmt.Sprintf("%d", instanceID) - endpoint := s.pulsar.endpoint(s.basePath, tenant, namespace, sink, id) + endpoint := s.pulsar.endpoint(s.apiVersion, s.basePath, tenant, namespace, sink, id) - return s.pulsar.Client.Post(endpoint+"/start", nil) + return s.pulsar.restClient.Post(endpoint+"/start", nil) } -func (s *sinks) GetBuiltInSinks() ([]*utils.ConnectorDefinition, error) { - var connectorDefinition []*utils.ConnectorDefinition - endpoint := s.pulsar.endpoint(s.basePath, "builtinsinks") - err := s.pulsar.Client.Get(endpoint, &connectorDefinition) +func (s *sinks) GetBuiltInSinks() ([]*ConnectorDefinition, error) { + var connectorDefinition []*ConnectorDefinition + endpoint := s.pulsar.endpoint(s.apiVersion, s.basePath, "builtinsinks") + err := s.pulsar.restClient.Get(endpoint, &connectorDefinition) return connectorDefinition, err } func (s *sinks) ReloadBuiltInSinks() error { - endpoint := s.pulsar.endpoint(s.basePath, "reloadBuiltInSinks") - return s.pulsar.Client.Post(endpoint, nil) + endpoint := s.pulsar.endpoint(s.apiVersion, s.basePath, "reloadBuiltInSinks") + return s.pulsar.restClient.Post(endpoint, nil) } diff --git a/pulsaradmin/pkg/admin/sources.go b/pulsaradmin/api_source.go similarity index 69% rename from pulsaradmin/pkg/admin/sources.go rename to pulsaradmin/api_source.go index e10d1da061..2756418ab9 100644 --- a/pulsaradmin/pkg/admin/sources.go +++ b/pulsaradmin/api_source.go @@ -15,7 +15,7 @@ // specific language governing permissions and limitations // under the License. -package admin +package pulsaradmin import ( "bytes" @@ -27,8 +27,6 @@ import ( "os" "path/filepath" "strings" - - "github.com/apache/pulsar-client-go/pulsaradmin/pkg/utils" ) // Sources is admin interface for sources management @@ -37,29 +35,29 @@ type Sources interface { ListSources(tenant, namespace string) ([]string, error) // GetSource return the configuration for the specified source - GetSource(tenant, namespace, source string) (utils.SourceConfig, error) + GetSource(tenant, namespace, source string) (SourceConfig, error) // CreateSource creates a new source - CreateSource(config *utils.SourceConfig, fileName string) error + CreateSource(config *SourceConfig, fileName string) error // CreateSourceWithURL creates a new source by providing url from which fun-pkg can be downloaded. // supported url: http/file - CreateSourceWithURL(config *utils.SourceConfig, pkgURL string) error + CreateSourceWithURL(config *SourceConfig, pkgURL string) error // UpdateSource updates the configuration for a source. - UpdateSource(config *utils.SourceConfig, fileName string, options *utils.UpdateOptions) error + UpdateSource(config *SourceConfig, fileName string, options *UpdateOptions) error // UpdateSourceWithURL updates a source by providing url from which fun-pkg can be downloaded. supported url: http/file - UpdateSourceWithURL(config *utils.SourceConfig, pkgURL string, options *utils.UpdateOptions) error + UpdateSourceWithURL(config *SourceConfig, pkgURL string, options *UpdateOptions) error // DeleteSource deletes an existing source DeleteSource(tenant, namespace, source string) error // GetSourceStatus returns the current status of a source. - GetSourceStatus(tenant, namespace, source string) (utils.SourceStatus, error) + GetSourceStatus(tenant, namespace, source string) (SourceStatus, error) // GetSourceStatusWithID returns the current status of a source instance. - GetSourceStatusWithID(tenant, namespace, source string, id int) (utils.SourceInstanceStatusData, error) + GetSourceStatusWithID(tenant, namespace, source string, id int) (SourceInstanceStatusData, error) // RestartSource restarts all source instances RestartSource(tenant, namespace, source string) error @@ -80,22 +78,24 @@ type Sources interface { StartSourceWithID(tenant, namespace, source string, id int) error // GetBuiltInSources fetches a list of supported Pulsar IO sources currently running in cluster mode - GetBuiltInSources() ([]*utils.ConnectorDefinition, error) + GetBuiltInSources() ([]*ConnectorDefinition, error) // ReloadBuiltInSources reloads the available built-in connectors, include Source and Sink ReloadBuiltInSources() error } type sources struct { - pulsar *pulsarClient - basePath string + pulsar *pulsarClient + basePath string + apiVersion APIVersion } // Sources is used to access the sources endpoints func (c *pulsarClient) Sources() Sources { return &sources{ - pulsar: c, - basePath: "/sources", + pulsar: c, + basePath: "/sources", + apiVersion: c.apiProfile.Sources, } } @@ -115,20 +115,20 @@ func (s *sources) createTextFromFiled(w *multipart.Writer, value string) (io.Wri func (s *sources) ListSources(tenant, namespace string) ([]string, error) { var sources []string - endpoint := s.pulsar.endpoint(s.basePath, tenant, namespace) - err := s.pulsar.Client.Get(endpoint, &sources) + endpoint := s.pulsar.endpoint(s.apiVersion, s.basePath, tenant, namespace) + err := s.pulsar.restClient.Get(endpoint, &sources) return sources, err } -func (s *sources) GetSource(tenant, namespace, source string) (utils.SourceConfig, error) { - var sourceConfig utils.SourceConfig - endpoint := s.pulsar.endpoint(s.basePath, tenant, namespace, source) - err := s.pulsar.Client.Get(endpoint, &sourceConfig) +func (s *sources) GetSource(tenant, namespace, source string) (SourceConfig, error) { + var sourceConfig SourceConfig + endpoint := s.pulsar.endpoint(s.apiVersion, s.basePath, tenant, namespace, source) + err := s.pulsar.restClient.Get(endpoint, &sourceConfig) return sourceConfig, err } -func (s *sources) CreateSource(config *utils.SourceConfig, fileName string) error { - endpoint := s.pulsar.endpoint(s.basePath, config.Tenant, config.Namespace, config.Name) +func (s *sources) CreateSource(config *SourceConfig, fileName string) error { + endpoint := s.pulsar.endpoint(s.apiVersion, s.basePath, config.Tenant, config.Namespace, config.Name) // buffer to store our request as bytes bodyBuf := bytes.NewBufferString("") @@ -158,7 +158,6 @@ func (s *sources) CreateSource(config *utils.SourceConfig, fileName string) erro defer file.Close() part, err := multiPartWriter.CreateFormFile("data", filepath.Base(file.Name())) - if err != nil { return err } @@ -177,7 +176,7 @@ func (s *sources) CreateSource(config *utils.SourceConfig, fileName string) erro } contentType := multiPartWriter.FormDataContentType() - err = s.pulsar.Client.PostWithMultiPart(endpoint, nil, bodyBuf, contentType) + err = s.pulsar.restClient.PostWithMultiPart(endpoint, nil, bodyBuf, contentType) if err != nil { return err } @@ -185,8 +184,8 @@ func (s *sources) CreateSource(config *utils.SourceConfig, fileName string) erro return nil } -func (s *sources) CreateSourceWithURL(config *utils.SourceConfig, pkgURL string) error { - endpoint := s.pulsar.endpoint(s.basePath, config.Tenant, config.Namespace, config.Name) +func (s *sources) CreateSourceWithURL(config *SourceConfig, pkgURL string) error { + endpoint := s.pulsar.endpoint(s.apiVersion, s.basePath, config.Tenant, config.Namespace, config.Name) // buffer to store our request as bytes bodyBuf := bytes.NewBufferString("") @@ -222,7 +221,7 @@ func (s *sources) CreateSourceWithURL(config *utils.SourceConfig, pkgURL string) } contentType := multiPartWriter.FormDataContentType() - err = s.pulsar.Client.PostWithMultiPart(endpoint, nil, bodyBuf, contentType) + err = s.pulsar.restClient.PostWithMultiPart(endpoint, nil, bodyBuf, contentType) if err != nil { return err } @@ -230,8 +229,8 @@ func (s *sources) CreateSourceWithURL(config *utils.SourceConfig, pkgURL string) return nil } -func (s *sources) UpdateSource(config *utils.SourceConfig, fileName string, updateOptions *utils.UpdateOptions) error { - endpoint := s.pulsar.endpoint(s.basePath, config.Tenant, config.Namespace, config.Name) +func (s *sources) UpdateSource(config *SourceConfig, fileName string, updateOptions *UpdateOptions) error { + endpoint := s.pulsar.endpoint(s.apiVersion, s.basePath, config.Tenant, config.Namespace, config.Name) // buffer to store our request as bytes bodyBuf := bytes.NewBufferString("") @@ -278,7 +277,6 @@ func (s *sources) UpdateSource(config *utils.SourceConfig, fileName string, upda defer file.Close() part, err := multiPartWriter.CreateFormFile("data", filepath.Base(file.Name())) - if err != nil { return err } @@ -297,7 +295,7 @@ func (s *sources) UpdateSource(config *utils.SourceConfig, fileName string, upda } contentType := multiPartWriter.FormDataContentType() - err = s.pulsar.Client.PutWithMultiPart(endpoint, bodyBuf, contentType) + err = s.pulsar.restClient.PutWithMultiPart(endpoint, bodyBuf, contentType) if err != nil { return err } @@ -305,9 +303,10 @@ func (s *sources) UpdateSource(config *utils.SourceConfig, fileName string, upda return nil } -func (s *sources) UpdateSourceWithURL(config *utils.SourceConfig, pkgURL string, - updateOptions *utils.UpdateOptions) error { - endpoint := s.pulsar.endpoint(s.basePath, config.Tenant, config.Namespace, config.Name) +func (s *sources) UpdateSourceWithURL(config *SourceConfig, pkgURL string, + updateOptions *UpdateOptions, +) error { + endpoint := s.pulsar.endpoint(s.apiVersion, s.basePath, config.Tenant, config.Namespace, config.Name) // buffer to store our request as bytes bodyBuf := bytes.NewBufferString("") @@ -362,7 +361,7 @@ func (s *sources) UpdateSourceWithURL(config *utils.SourceConfig, pkgURL string, } contentType := multiPartWriter.FormDataContentType() - err = s.pulsar.Client.PutWithMultiPart(endpoint, bodyBuf, contentType) + err = s.pulsar.restClient.PutWithMultiPart(endpoint, bodyBuf, contentType) if err != nil { return err } @@ -371,70 +370,71 @@ func (s *sources) UpdateSourceWithURL(config *utils.SourceConfig, pkgURL string, } func (s *sources) DeleteSource(tenant, namespace, source string) error { - endpoint := s.pulsar.endpoint(s.basePath, tenant, namespace, source) - return s.pulsar.Client.Delete(endpoint) + endpoint := s.pulsar.endpoint(s.apiVersion, s.basePath, tenant, namespace, source) + return s.pulsar.restClient.Delete(endpoint) } -func (s *sources) GetSourceStatus(tenant, namespace, source string) (utils.SourceStatus, error) { - var sourceStatus utils.SourceStatus - endpoint := s.pulsar.endpoint(s.basePath, tenant, namespace, source) - err := s.pulsar.Client.Get(endpoint+"/status", &sourceStatus) +func (s *sources) GetSourceStatus(tenant, namespace, source string) (SourceStatus, error) { + var sourceStatus SourceStatus + endpoint := s.pulsar.endpoint(s.apiVersion, s.basePath, tenant, namespace, source) + err := s.pulsar.restClient.Get(endpoint+"/status", &sourceStatus) return sourceStatus, err } func (s *sources) GetSourceStatusWithID(tenant, namespace, source string, id int) ( - utils.SourceInstanceStatusData, error) { - var sourceInstanceStatusData utils.SourceInstanceStatusData + SourceInstanceStatusData, error, +) { + var sourceInstanceStatusData SourceInstanceStatusData instanceID := fmt.Sprintf("%d", id) - endpoint := s.pulsar.endpoint(s.basePath, tenant, namespace, source, instanceID) - err := s.pulsar.Client.Get(endpoint+"/status", &sourceInstanceStatusData) + endpoint := s.pulsar.endpoint(s.apiVersion, s.basePath, tenant, namespace, source, instanceID) + err := s.pulsar.restClient.Get(endpoint+"/status", &sourceInstanceStatusData) return sourceInstanceStatusData, err } func (s *sources) RestartSource(tenant, namespace, source string) error { - endpoint := s.pulsar.endpoint(s.basePath, tenant, namespace, source) - return s.pulsar.Client.Post(endpoint+"/restart", nil) + endpoint := s.pulsar.endpoint(s.apiVersion, s.basePath, tenant, namespace, source) + return s.pulsar.restClient.Post(endpoint+"/restart", nil) } func (s *sources) RestartSourceWithID(tenant, namespace, source string, instanceID int) error { id := fmt.Sprintf("%d", instanceID) - endpoint := s.pulsar.endpoint(s.basePath, tenant, namespace, source, id) + endpoint := s.pulsar.endpoint(s.apiVersion, s.basePath, tenant, namespace, source, id) - return s.pulsar.Client.Post(endpoint+"/restart", nil) + return s.pulsar.restClient.Post(endpoint+"/restart", nil) } func (s *sources) StopSource(tenant, namespace, source string) error { - endpoint := s.pulsar.endpoint(s.basePath, tenant, namespace, source) - return s.pulsar.Client.Post(endpoint+"/stop", nil) + endpoint := s.pulsar.endpoint(s.apiVersion, s.basePath, tenant, namespace, source) + return s.pulsar.restClient.Post(endpoint+"/stop", nil) } func (s *sources) StopSourceWithID(tenant, namespace, source string, instanceID int) error { id := fmt.Sprintf("%d", instanceID) - endpoint := s.pulsar.endpoint(s.basePath, tenant, namespace, source, id) + endpoint := s.pulsar.endpoint(s.apiVersion, s.basePath, tenant, namespace, source, id) - return s.pulsar.Client.Post(endpoint+"/stop", nil) + return s.pulsar.restClient.Post(endpoint+"/stop", nil) } func (s *sources) StartSource(tenant, namespace, source string) error { - endpoint := s.pulsar.endpoint(s.basePath, tenant, namespace, source) - return s.pulsar.Client.Post(endpoint+"/start", nil) + endpoint := s.pulsar.endpoint(s.apiVersion, s.basePath, tenant, namespace, source) + return s.pulsar.restClient.Post(endpoint+"/start", nil) } func (s *sources) StartSourceWithID(tenant, namespace, source string, instanceID int) error { id := fmt.Sprintf("%d", instanceID) - endpoint := s.pulsar.endpoint(s.basePath, tenant, namespace, source, id) + endpoint := s.pulsar.endpoint(s.apiVersion, s.basePath, tenant, namespace, source, id) - return s.pulsar.Client.Post(endpoint+"/start", nil) + return s.pulsar.restClient.Post(endpoint+"/start", nil) } -func (s *sources) GetBuiltInSources() ([]*utils.ConnectorDefinition, error) { - var connectorDefinition []*utils.ConnectorDefinition - endpoint := s.pulsar.endpoint(s.basePath, "builtinsources") - err := s.pulsar.Client.Get(endpoint, &connectorDefinition) +func (s *sources) GetBuiltInSources() ([]*ConnectorDefinition, error) { + var connectorDefinition []*ConnectorDefinition + endpoint := s.pulsar.endpoint(s.apiVersion, s.basePath, "builtinsources") + err := s.pulsar.restClient.Get(endpoint, &connectorDefinition) return connectorDefinition, err } func (s *sources) ReloadBuiltInSources() error { - endpoint := s.pulsar.endpoint(s.basePath, "reloadBuiltInSources") - return s.pulsar.Client.Post(endpoint, nil) + endpoint := s.pulsar.endpoint(s.apiVersion, s.basePath, "reloadBuiltInSources") + return s.pulsar.restClient.Post(endpoint, nil) } diff --git a/pulsaradmin/pkg/admin/subscription.go b/pulsaradmin/api_subscription.go similarity index 60% rename from pulsaradmin/pkg/admin/subscription.go rename to pulsaradmin/api_subscription.go index 456de46cdb..cd2dca01ef 100644 --- a/pulsaradmin/pkg/admin/subscription.go +++ b/pulsaradmin/api_subscription.go @@ -15,7 +15,7 @@ // specific language governing permissions and limitations // under the License. -package admin +package pulsaradmin import ( "bytes" @@ -27,59 +27,58 @@ import ( "strings" "github.com/golang/protobuf/proto" //nolint:staticcheck - - "github.com/apache/pulsar-client-go/pulsaradmin/pkg/utils" ) // Subscriptions is admin interface for subscriptions management type Subscriptions interface { // Create a new subscription on a topic - Create(utils.TopicName, string, utils.MessageID) error + Create(TopicName, string, MessageID) error // Delete a subscription. // Delete a persistent subscription from a topic. There should not be any active consumers on the subscription - Delete(utils.TopicName, string) error + Delete(TopicName, string) error // ForceDelete deletes a subscription forcefully - ForceDelete(utils.TopicName, string) error + ForceDelete(TopicName, string) error // List returns the list of subscriptions - List(utils.TopicName) ([]string, error) + List(TopicName) ([]string, error) // ResetCursorToMessageID resets cursor position on a topic subscription // @param // messageID reset subscription to messageId (or previous nearest messageId if given messageId is not valid) - ResetCursorToMessageID(utils.TopicName, string, utils.MessageID) error + ResetCursorToMessageID(TopicName, string, MessageID) error // ResetCursorToTimestamp resets cursor position on a topic subscription // @param // time reset subscription to position closest to time in ms since epoch - ResetCursorToTimestamp(utils.TopicName, string, int64) error + ResetCursorToTimestamp(TopicName, string, int64) error // ClearBacklog skips all messages on a topic subscription - ClearBacklog(utils.TopicName, string) error + ClearBacklog(TopicName, string) error // SkipMessages skips messages on a topic subscription - SkipMessages(utils.TopicName, string, int64) error + SkipMessages(TopicName, string, int64) error // ExpireMessages expires all messages older than given N (expireTimeInSeconds) seconds for a given subscription - ExpireMessages(utils.TopicName, string, int64) error + ExpireMessages(TopicName, string, int64) error // ExpireAllMessages expires all messages older than given N (expireTimeInSeconds) seconds for all // subscriptions of the persistent-topic - ExpireAllMessages(utils.TopicName, int64) error + ExpireAllMessages(TopicName, int64) error // PeekMessages peeks messages from a topic subscription - PeekMessages(utils.TopicName, string, int) ([]*utils.Message, error) + PeekMessages(TopicName, string, int) ([]*Message, error) // GetMessageByID gets message by its ledgerID and entryID - GetMessageByID(topic utils.TopicName, ledgerID, entryID int64) (*utils.Message, error) + GetMessageByID(topic TopicName, ledgerID, entryID int64) (*Message, error) } type subscriptions struct { pulsar *pulsarClient basePath string SubPath string + topicAPI APIVersion } // Subscriptions is used to access the subscriptions endpoints @@ -88,76 +87,78 @@ func (c *pulsarClient) Subscriptions() Subscriptions { pulsar: c, basePath: "", SubPath: "subscription", + topicAPI: c.apiProfile.Topics, } } -func (s *subscriptions) Create(topic utils.TopicName, sName string, messageID utils.MessageID) error { - endpoint := s.pulsar.endpoint(s.basePath, topic.GetRestPath(), s.SubPath, url.PathEscape(sName)) - return s.pulsar.Client.Put(endpoint, messageID) +func (s *subscriptions) Create(topic TopicName, sName string, messageID MessageID) error { + endpoint := s.pulsar.endpoint(s.topicAPI, s.basePath, topic.GetRestPath(), s.SubPath, url.PathEscape(sName)) + return s.pulsar.restClient.Put(endpoint, messageID) } -func (s *subscriptions) delete(topic utils.TopicName, subName string, force bool) error { - endpoint := s.pulsar.endpoint(s.basePath, topic.GetRestPath(), s.SubPath, url.PathEscape(subName)) +func (s *subscriptions) delete(topic TopicName, subName string, force bool) error { + endpoint := s.pulsar.endpoint(s.topicAPI, s.basePath, topic.GetRestPath(), s.SubPath, url.PathEscape(subName)) queryParams := make(map[string]string) queryParams["force"] = strconv.FormatBool(force) - return s.pulsar.Client.DeleteWithQueryParams(endpoint, queryParams) + return s.pulsar.restClient.DeleteWithQueryParams(endpoint, queryParams) } -func (s *subscriptions) Delete(topic utils.TopicName, sName string) error { +func (s *subscriptions) Delete(topic TopicName, sName string) error { return s.delete(topic, sName, false) } -func (s *subscriptions) ForceDelete(topic utils.TopicName, sName string) error { +func (s *subscriptions) ForceDelete(topic TopicName, sName string) error { return s.delete(topic, sName, true) } -func (s *subscriptions) List(topic utils.TopicName) ([]string, error) { - endpoint := s.pulsar.endpoint(s.basePath, topic.GetRestPath(), "subscriptions") +func (s *subscriptions) List(topic TopicName) ([]string, error) { + endpoint := s.pulsar.endpoint(s.topicAPI, s.basePath, topic.GetRestPath(), "subscriptions") var list []string - return list, s.pulsar.Client.Get(endpoint, &list) + return list, s.pulsar.restClient.Get(endpoint, &list) } -func (s *subscriptions) ResetCursorToMessageID(topic utils.TopicName, sName string, id utils.MessageID) error { - endpoint := s.pulsar.endpoint(s.basePath, topic.GetRestPath(), s.SubPath, url.PathEscape(sName), "resetcursor") - return s.pulsar.Client.Post(endpoint, id) +func (s *subscriptions) ResetCursorToMessageID(topic TopicName, sName string, id MessageID) error { + endpoint := s.pulsar.endpoint(s.topicAPI, s.basePath, topic.GetRestPath(), s.SubPath, url.PathEscape(sName), + "resetcursor") + return s.pulsar.restClient.Post(endpoint, id) } -func (s *subscriptions) ResetCursorToTimestamp(topic utils.TopicName, sName string, timestamp int64) error { - endpoint := s.pulsar.endpoint( +func (s *subscriptions) ResetCursorToTimestamp(topic TopicName, sName string, timestamp int64) error { + endpoint := s.pulsar.endpoint(s.topicAPI, s.basePath, topic.GetRestPath(), s.SubPath, url.PathEscape(sName), "resetcursor", strconv.FormatInt(timestamp, 10)) - return s.pulsar.Client.Post(endpoint, nil) + return s.pulsar.restClient.Post(endpoint, nil) } -func (s *subscriptions) ClearBacklog(topic utils.TopicName, sName string) error { - endpoint := s.pulsar.endpoint( +func (s *subscriptions) ClearBacklog(topic TopicName, sName string) error { + endpoint := s.pulsar.endpoint(s.topicAPI, s.basePath, topic.GetRestPath(), s.SubPath, url.PathEscape(sName), "skip_all") - return s.pulsar.Client.Post(endpoint, nil) + return s.pulsar.restClient.Post(endpoint, nil) } -func (s *subscriptions) SkipMessages(topic utils.TopicName, sName string, n int64) error { - endpoint := s.pulsar.endpoint( +func (s *subscriptions) SkipMessages(topic TopicName, sName string, n int64) error { + endpoint := s.pulsar.endpoint(s.topicAPI, s.basePath, topic.GetRestPath(), s.SubPath, url.PathEscape(sName), "skip", strconv.FormatInt(n, 10)) - return s.pulsar.Client.Post(endpoint, nil) + return s.pulsar.restClient.Post(endpoint, nil) } -func (s *subscriptions) ExpireMessages(topic utils.TopicName, sName string, expire int64) error { - endpoint := s.pulsar.endpoint( +func (s *subscriptions) ExpireMessages(topic TopicName, sName string, expire int64) error { + endpoint := s.pulsar.endpoint(s.topicAPI, s.basePath, topic.GetRestPath(), s.SubPath, url.PathEscape(sName), "expireMessages", strconv.FormatInt(expire, 10)) - return s.pulsar.Client.Post(endpoint, nil) + return s.pulsar.restClient.Post(endpoint, nil) } -func (s *subscriptions) ExpireAllMessages(topic utils.TopicName, expire int64) error { - endpoint := s.pulsar.endpoint( +func (s *subscriptions) ExpireAllMessages(topic TopicName, expire int64) error { + endpoint := s.pulsar.endpoint(s.topicAPI, s.basePath, topic.GetRestPath(), "all_subscription", "expireMessages", strconv.FormatInt(expire, 10)) - return s.pulsar.Client.Post(endpoint, nil) + return s.pulsar.restClient.Post(endpoint, nil) } -func (s *subscriptions) PeekMessages(topic utils.TopicName, sName string, n int) ([]*utils.Message, error) { - var msgs []*utils.Message +func (s *subscriptions) PeekMessages(topic TopicName, sName string, n int) ([]*Message, error) { + var msgs []*Message count := 1 for n > 0 { @@ -173,11 +174,11 @@ func (s *subscriptions) PeekMessages(topic utils.TopicName, sName string, n int) return msgs, nil } -func (s *subscriptions) peekNthMessage(topic utils.TopicName, sName string, pos int) ([]*utils.Message, error) { - endpoint := s.pulsar.endpoint(s.basePath, topic.GetRestPath(), "subscription", url.PathEscape(sName), +func (s *subscriptions) peekNthMessage(topic TopicName, sName string, pos int) ([]*Message, error) { + endpoint := s.pulsar.endpoint(s.topicAPI, s.basePath, topic.GetRestPath(), "subscription", url.PathEscape(sName), "position", strconv.Itoa(pos)) - resp, err := s.pulsar.Client.MakeRequest(http.MethodGet, endpoint) + resp, err := s.pulsar.restClient.MakeRequest(http.MethodGet, endpoint) if err != nil { return nil, err } @@ -186,12 +187,12 @@ func (s *subscriptions) peekNthMessage(topic utils.TopicName, sName string, pos return handleResp(topic, resp) } -func (s *subscriptions) GetMessageByID(topic utils.TopicName, ledgerID, entryID int64) (*utils.Message, error) { +func (s *subscriptions) GetMessageByID(topic TopicName, ledgerID, entryID int64) (*Message, error) { ledgerIDStr := strconv.FormatInt(ledgerID, 10) entryIDStr := strconv.FormatInt(entryID, 10) - endpoint := s.pulsar.endpoint(s.basePath, topic.GetRestPath(), "ledger", ledgerIDStr, "entry", entryIDStr) - resp, err := s.pulsar.Client.MakeRequest(http.MethodGet, endpoint) + endpoint := s.pulsar.endpoint(s.topicAPI, s.basePath, topic.GetRestPath(), "ledger", ledgerIDStr, "entry", entryIDStr) + resp, err := s.pulsar.restClient.MakeRequest(http.MethodGet, endpoint) if err != nil { return nil, err } @@ -222,9 +223,9 @@ const ( PropertyPrefix = "X-Pulsar-Property-" ) -func handleResp(topic utils.TopicName, resp *http.Response) ([]*utils.Message, error) { +func handleResp(topic TopicName, resp *http.Response) ([]*Message, error) { msgID := resp.Header.Get("X-Pulsar-Message-ID") - ID, err := utils.ParseMessageID(msgID) + ID, err := ParseMessageID(msgID) if err != nil { return nil, err } @@ -255,18 +256,18 @@ func handleResp(topic utils.TopicName, resp *http.Response) ([]*utils.Message, e } } - return []*utils.Message{utils.NewMessage(topic.String(), *ID, payload, properties)}, nil + return []*Message{NewMessage(topic.String(), *ID, payload, properties)}, nil } -func getIndividualMsgsFromBatch(topic utils.TopicName, msgID *utils.MessageID, data []byte, - properties map[string]string) ([]*utils.Message, error) { - +func getIndividualMsgsFromBatch(topic TopicName, msgID *MessageID, data []byte, + properties map[string]string, +) ([]*Message, error) { batchSize, err := strconv.Atoi(properties[BatchHeader]) if err != nil { return nil, nil } - msgs := make([]*utils.Message, 0, batchSize) + msgs := make([]*Message, 0, batchSize) // read all messages in batch buf32 := make([]byte, 4) @@ -285,7 +286,7 @@ func getIndividualMsgsFromBatch(topic utils.TopicName, msgID *utils.MessageID, d return nil, err } - singleMeta := new(utils.SingleMessageMetadata) + singleMeta := new(SingleMessageMetadata) if err := proto.Unmarshal(singleMetaBuf, singleMeta); err != nil { return nil, err } @@ -304,7 +305,7 @@ func getIndividualMsgsFromBatch(topic utils.TopicName, msgID *utils.MessageID, d return nil, err } - msgs = append(msgs, &utils.Message{ + msgs = append(msgs, &Message{ Topic: topic.String(), MessageID: *msgID, Payload: singlePayload, diff --git a/pulsaradmin/pkg/admin/tenant.go b/pulsaradmin/api_tenant.go similarity index 58% rename from pulsaradmin/pkg/admin/tenant.go rename to pulsaradmin/api_tenant.go index 62e176bcbc..d1a66b30a6 100644 --- a/pulsaradmin/pkg/admin/tenant.go +++ b/pulsaradmin/api_tenant.go @@ -15,68 +15,66 @@ // specific language governing permissions and limitations // under the License. -package admin - -import ( - "github.com/apache/pulsar-client-go/pulsaradmin/pkg/utils" -) +package pulsaradmin // Tenants is admin interface for tenants management type Tenants interface { // Create a new tenant - Create(utils.TenantData) error + Create(TenantData) error // Delete an existing tenant Delete(string) error // Update the admins for a tenant - Update(utils.TenantData) error + Update(TenantData) error // List returns the list of tenants List() ([]string, error) // Get returns the config of the tenant. - Get(string) (utils.TenantData, error) + Get(string) (TenantData, error) } type tenants struct { - pulsar *pulsarClient - basePath string + pulsar *pulsarClient + basePath string + apiVersion APIVersion } // Tenants is used to access the tenants endpoints func (c *pulsarClient) Tenants() Tenants { return &tenants{ - pulsar: c, - basePath: "/tenants", + pulsar: c, + basePath: "/tenants", + apiVersion: c.apiProfile.Tenants, } } -func (c *tenants) Create(data utils.TenantData) error { - endpoint := c.pulsar.endpoint(c.basePath, data.Name) - return c.pulsar.Client.Put(endpoint, &data) +func (c *tenants) Create(data TenantData) error { + endpoint := c.pulsar.endpoint(c.apiVersion, c.basePath, data.Name) + return c.pulsar.restClient.Put(endpoint, &data) } func (c *tenants) Delete(name string) error { - endpoint := c.pulsar.endpoint(c.basePath, name) - return c.pulsar.Client.Delete(endpoint) + endpoint := c.pulsar.endpoint(c.apiVersion, c.basePath, name) + return c.pulsar.restClient.Delete(endpoint) } -func (c *tenants) Update(data utils.TenantData) error { - endpoint := c.pulsar.endpoint(c.basePath, data.Name) - return c.pulsar.Client.Post(endpoint, &data) +func (c *tenants) Update(data TenantData) error { + endpoint := c.pulsar.endpoint(c.apiVersion, c.basePath, data.Name) + return c.pulsar.restClient.Post(endpoint, &data) } func (c *tenants) List() ([]string, error) { var tenantList []string - endpoint := c.pulsar.endpoint(c.basePath, "") - err := c.pulsar.Client.Get(endpoint, &tenantList) + endpoint := c.pulsar.endpoint(c.apiVersion, c.basePath, "") + err := c.pulsar.restClient.Get(endpoint, &tenantList) return tenantList, err } -func (c *tenants) Get(name string) (utils.TenantData, error) { - var data utils.TenantData - endpoint := c.pulsar.endpoint(c.basePath, name) - err := c.pulsar.Client.Get(endpoint, &data) +func (c *tenants) Get(name string) (TenantData, error) { + var data TenantData + endpoint := c.pulsar.endpoint(c.apiVersion, c.basePath, name) + err := c.pulsar.restClient.Get(endpoint, &data) return data, err } diff --git a/pulsaradmin/api_topic.go b/pulsaradmin/api_topic.go new file mode 100644 index 0000000000..c7fd7b2801 --- /dev/null +++ b/pulsaradmin/api_topic.go @@ -0,0 +1,730 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package pulsaradmin + +import ( + "fmt" + "strconv" +) + +// Topics is admin interface for topics management +type Topics interface { + // Create a topic + Create(TopicName, int) error + + // Delete a topic + Delete(TopicName, bool, bool) error + + // Update number of partitions of a non-global partitioned topic + // It requires partitioned-topic to be already exist and number of new partitions must be greater than existing + // number of partitions. Decrementing number of partitions requires deletion of topic which is not supported. + Update(TopicName, int) error + + // GetMetadata returns metadata of a partitioned topic + GetMetadata(TopicName) (PartitionedTopicMetadata, error) + + // List returns the list of topics under a namespace + List(NameSpaceName) ([]string, []string, error) + + // GetInternalInfo returns the internal metadata info for the topic + GetInternalInfo(TopicName) (ManagedLedgerInfo, error) + + // GetPermissions returns permissions on a topic + // Retrieve the effective permissions for a topic. These permissions are defined by the permissions set at the + // namespace level combined (union) with any eventual specific permission set on the topic. + GetPermissions(TopicName) (map[string][]AuthAction, error) + + // GrantPermission grants a new permission to a client role on a single topic + GrantPermission(TopicName, string, []AuthAction) error + + // RevokePermission revokes permissions to a client role on a single topic. If the permission + // was not set at the topic level, but rather at the namespace level, this operation will + // return an error (HTTP status code 412). + RevokePermission(TopicName, string) error + + // Lookup a topic returns the broker URL that serves the topic + Lookup(TopicName) (LookupData, error) + + // GetBundleRange returns a bundle range of a topic + GetBundleRange(TopicName) (string, error) + + // GetLastMessageID returns the last commit message Id of a topic + GetLastMessageID(TopicName) (MessageID, error) + + // GetMessageID returns the message Id by timestamp(ms) of a topic + GetMessageID(TopicName, int64) (MessageID, error) + + // GetStats returns the stats for the topic + // All the rates are computed over a 1 minute window and are relative the last completed 1 minute period + GetStats(TopicName) (TopicStats, error) + + // GetInternalStats returns the internal stats for the topic. + GetInternalStats(TopicName) (PersistentTopicInternalStats, error) + + // GetPartitionedStats returns the stats for the partitioned topic + // All the rates are computed over a 1 minute window and are relative the last completed 1 minute period + GetPartitionedStats(TopicName, bool) (PartitionedTopicStats, error) + + // Terminate the topic and prevent any more messages being published on it + Terminate(TopicName) (MessageID, error) + + // Offload triggers offloading messages in topic to longterm storage + Offload(TopicName, MessageID) error + + // OffloadStatus checks the status of an ongoing offloading operation for a topic + OffloadStatus(TopicName) (OffloadProcessStatus, error) + + // Unload a topic + Unload(TopicName) error + + // Compact triggers compaction to run for a topic. A single topic can only have one instance of compaction + // running at any time. Any attempt to trigger another will be met with a ConflictException. + Compact(TopicName) error + + // CompactStatus checks the status of an ongoing compaction for a topic + CompactStatus(TopicName) (LongRunningProcessStatus, error) + + // GetMessageTTL Get the message TTL for a topic + GetMessageTTL(TopicName) (int, error) + + // SetMessageTTL Set the message TTL for a topic + SetMessageTTL(TopicName, int) error + + // RemoveMessageTTL Remove the message TTL for a topic + RemoveMessageTTL(TopicName) error + + // GetMaxProducers Get max number of producers for a topic + GetMaxProducers(TopicName) (int, error) + + // SetMaxProducers Set max number of producers for a topic + SetMaxProducers(TopicName, int) error + + // RemoveMaxProducers Remove max number of producers for a topic + RemoveMaxProducers(TopicName) error + + // GetMaxConsumers Get max number of consumers for a topic + GetMaxConsumers(TopicName) (int, error) + + // SetMaxConsumers Set max number of consumers for a topic + SetMaxConsumers(TopicName, int) error + + // RemoveMaxConsumers Remove max number of consumers for a topic + RemoveMaxConsumers(TopicName) error + + // GetMaxUnackMessagesPerConsumer Get max unacked messages policy on consumer for a topic + GetMaxUnackMessagesPerConsumer(TopicName) (int, error) + + // SetMaxUnackMessagesPerConsumer Set max unacked messages policy on consumer for a topic + SetMaxUnackMessagesPerConsumer(TopicName, int) error + + // RemoveMaxUnackMessagesPerConsumer Remove max unacked messages policy on consumer for a topic + RemoveMaxUnackMessagesPerConsumer(TopicName) error + + // GetMaxUnackMessagesPerSubscription Get max unacked messages policy on subscription for a topic + GetMaxUnackMessagesPerSubscription(TopicName) (int, error) + + // SetMaxUnackMessagesPerSubscription Set max unacked messages policy on subscription for a topic + SetMaxUnackMessagesPerSubscription(TopicName, int) error + + // RemoveMaxUnackMessagesPerSubscription Remove max unacked messages policy on subscription for a topic + RemoveMaxUnackMessagesPerSubscription(TopicName) error + + // GetPersistence Get the persistence policies for a topic + GetPersistence(TopicName) (*PersistenceData, error) + + // SetPersistence Set the persistence policies for a topic + SetPersistence(TopicName, PersistenceData) error + + // RemovePersistence Remove the persistence policies for a topic + RemovePersistence(TopicName) error + + // GetDelayedDelivery Get the delayed delivery policy for a topic + GetDelayedDelivery(TopicName) (*DelayedDeliveryData, error) + + // SetDelayedDelivery Set the delayed delivery policy on a topic + SetDelayedDelivery(TopicName, DelayedDeliveryData) error + + // RemoveDelayedDelivery Remove the delayed delivery policy on a topic + RemoveDelayedDelivery(TopicName) error + + // GetDispatchRate Get message dispatch rate for a topic + GetDispatchRate(TopicName) (*DispatchRateData, error) + + // SetDispatchRate Set message dispatch rate for a topic + SetDispatchRate(TopicName, DispatchRateData) error + + // RemoveDispatchRate Remove message dispatch rate for a topic + RemoveDispatchRate(TopicName) error + + // GetPublishRate Get message publish rate for a topic + GetPublishRate(TopicName) (*PublishRateData, error) + + // SetPublishRate Set message publish rate for a topic + SetPublishRate(TopicName, PublishRateData) error + + // RemovePublishRate Remove message publish rate for a topic + RemovePublishRate(TopicName) error + + // GetDeduplicationStatus Get the deduplication policy for a topic + GetDeduplicationStatus(TopicName) (bool, error) + + // SetDeduplicationStatus Set the deduplication policy for a topic + SetDeduplicationStatus(TopicName, bool) error + + // RemoveDeduplicationStatus Remove the deduplication policy for a topic + RemoveDeduplicationStatus(TopicName) error + + // GetRetention returns the retention configuration for a topic + GetRetention(TopicName, bool) (*RetentionPolicies, error) + + // RemoveRetention removes the retention configuration on a topic + RemoveRetention(TopicName) error + + // SetRetention sets the retention policy for a topic + SetRetention(TopicName, RetentionPolicies) error + + // Get the compaction threshold for a topic + GetCompactionThreshold(topic TopicName, applied bool) (int64, error) + + // Set the compaction threshold for a topic + SetCompactionThreshold(topic TopicName, threshold int64) error + + // Remove compaction threshold for a topic + RemoveCompactionThreshold(TopicName) error + + // GetBacklogQuotaMap returns backlog quota map for a topic + GetBacklogQuotaMap(topic TopicName, applied bool) (map[BacklogQuotaType]BacklogQuota, error) + + // SetBacklogQuota sets a backlog quota for a topic + SetBacklogQuota(TopicName, BacklogQuota, BacklogQuotaType) error + + // RemoveBacklogQuota removes a backlog quota policy from a topic + RemoveBacklogQuota(TopicName, BacklogQuotaType) error + + // GetInactiveTopicPolicies gets the inactive topic policies on a topic + GetInactiveTopicPolicies(topic TopicName, applied bool) (InactiveTopicPolicies, error) + + // RemoveInactiveTopicPolicies removes inactive topic policies from a topic + RemoveInactiveTopicPolicies(TopicName) error + + // SetInactiveTopicPolicies sets the inactive topic policies on a topic + SetInactiveTopicPolicies(topic TopicName, data InactiveTopicPolicies) error + + // GetReplicationClusters get the replication clusters of a topic + GetReplicationClusters(topic TopicName) ([]string, error) + + // SetReplicationClusters sets the replication clusters on a topic + SetReplicationClusters(topic TopicName, data []string) error +} + +type topics struct { + pulsar *pulsarClient + basePath string + persistentPath string + nonPersistentPath string + lookupPath string + apiVersion APIVersion +} + +// Check whether the topics struct implements the Topics interface. +var _ Topics = &topics{} + +// Topics is used to access the topics endpoints +func (c *pulsarClient) Topics() Topics { + return &topics{ + pulsar: c, + basePath: "", + persistentPath: "/persistent", + nonPersistentPath: "/non-persistent", + lookupPath: "/lookup/" + c.apiProfile.Topics.String() + "/topic", + apiVersion: c.apiProfile.Topics, + } +} + +func (t *topics) Create(topic TopicName, partitions int) error { + endpoint := t.pulsar.endpoint(t.apiVersion, t.basePath, topic.GetRestPath(), "partitions") + data := &partitions + if partitions == 0 { + endpoint = t.pulsar.endpoint(t.apiVersion, t.basePath, topic.GetRestPath()) + data = nil + } + + return t.pulsar.restClient.Put(endpoint, data) +} + +func (t *topics) Delete(topic TopicName, force bool, nonPartitioned bool) error { + endpoint := t.pulsar.endpoint(t.apiVersion, t.basePath, topic.GetRestPath(), "partitions") + if nonPartitioned { + endpoint = t.pulsar.endpoint(t.apiVersion, t.basePath, topic.GetRestPath()) + } + params := map[string]string{ + "force": strconv.FormatBool(force), + } + return t.pulsar.restClient.DeleteWithQueryParams(endpoint, params) +} + +func (t *topics) Update(topic TopicName, partitions int) error { + endpoint := t.pulsar.endpoint(t.apiVersion, t.basePath, topic.GetRestPath(), "partitions") + return t.pulsar.restClient.Post(endpoint, partitions) +} + +func (t *topics) GetMetadata(topic TopicName) (PartitionedTopicMetadata, error) { + endpoint := t.pulsar.endpoint(t.apiVersion, t.basePath, topic.GetRestPath(), "partitions") + var partitionedMeta PartitionedTopicMetadata + err := t.pulsar.restClient.Get(endpoint, &partitionedMeta) + return partitionedMeta, err +} + +func (t *topics) List(namespace NameSpaceName) ([]string, []string, error) { + var partitionedTopics, nonPartitionedTopics []string + partitionedTopicsChan := make(chan []string) + nonPartitionedTopicsChan := make(chan []string) + errChan := make(chan error) + + pp := t.pulsar.endpoint(t.apiVersion, t.persistentPath, namespace.String(), "partitioned") + np := t.pulsar.endpoint(t.apiVersion, t.nonPersistentPath, namespace.String(), "partitioned") + p := t.pulsar.endpoint(t.apiVersion, t.persistentPath, namespace.String()) + n := t.pulsar.endpoint(t.apiVersion, t.nonPersistentPath, namespace.String()) + + go t.getTopics(pp, partitionedTopicsChan, errChan) + go t.getTopics(np, partitionedTopicsChan, errChan) + go t.getTopics(p, nonPartitionedTopicsChan, errChan) + go t.getTopics(n, nonPartitionedTopicsChan, errChan) + + requestCount := 4 + for { + select { + case err := <-errChan: + if err != nil { + return nil, nil, err + } + continue + case pTopic := <-partitionedTopicsChan: + requestCount-- + partitionedTopics = append(partitionedTopics, pTopic...) + case npTopic := <-nonPartitionedTopicsChan: + requestCount-- + nonPartitionedTopics = append(nonPartitionedTopics, npTopic...) + } + if requestCount == 0 { + break + } + } + return partitionedTopics, nonPartitionedTopics, nil +} + +func (t *topics) getTopics(endpoint string, out chan<- []string, err chan<- error) { + var topics []string + err <- t.pulsar.restClient.Get(endpoint, &topics) + out <- topics +} + +func (t *topics) GetInternalInfo(topic TopicName) (ManagedLedgerInfo, error) { + endpoint := t.pulsar.endpoint(t.apiVersion, t.basePath, topic.GetRestPath(), "internal-info") + var info ManagedLedgerInfo + err := t.pulsar.restClient.Get(endpoint, &info) + return info, err +} + +func (t *topics) GetPermissions(topic TopicName) (map[string][]AuthAction, error) { + var permissions map[string][]AuthAction + endpoint := t.pulsar.endpoint(t.apiVersion, t.basePath, topic.GetRestPath(), "permissions") + err := t.pulsar.restClient.Get(endpoint, &permissions) + return permissions, err +} + +func (t *topics) GrantPermission(topic TopicName, role string, action []AuthAction) error { + endpoint := t.pulsar.endpoint(t.apiVersion, t.basePath, topic.GetRestPath(), "permissions", role) + s := []string{} + for _, v := range action { + s = append(s, v.String()) + } + return t.pulsar.restClient.Post(endpoint, s) +} + +func (t *topics) RevokePermission(topic TopicName, role string) error { + endpoint := t.pulsar.endpoint(t.apiVersion, t.basePath, topic.GetRestPath(), "permissions", role) + return t.pulsar.restClient.Delete(endpoint) +} + +func (t *topics) Lookup(topic TopicName) (LookupData, error) { + var lookup LookupData + endpoint := fmt.Sprintf("%s/%s", t.lookupPath, topic.GetRestPath()) + err := t.pulsar.restClient.Get(endpoint, &lookup) + return lookup, err +} + +func (t *topics) GetBundleRange(topic TopicName) (string, error) { + endpoint := fmt.Sprintf("%s/%s/%s", t.lookupPath, topic.GetRestPath(), "bundle") + data, err := t.pulsar.restClient.GetWithQueryParams(endpoint, nil, nil, false) + return string(data), err +} + +func (t *topics) GetLastMessageID(topic TopicName) (MessageID, error) { + var messageID MessageID + endpoint := t.pulsar.endpoint(t.apiVersion, t.basePath, topic.GetRestPath(), "lastMessageId") + err := t.pulsar.restClient.Get(endpoint, &messageID) + return messageID, err +} + +func (t *topics) GetMessageID(topic TopicName, timestamp int64) (MessageID, error) { + var messageID MessageID + endpoint := t.pulsar.endpoint(t.apiVersion, t.basePath, topic.GetRestPath(), "messageid", + strconv.FormatInt(timestamp, 10)) + err := t.pulsar.restClient.Get(endpoint, &messageID) + return messageID, err +} + +func (t *topics) GetStats(topic TopicName) (TopicStats, error) { + var stats TopicStats + endpoint := t.pulsar.endpoint(t.apiVersion, t.basePath, topic.GetRestPath(), "stats") + err := t.pulsar.restClient.Get(endpoint, &stats) + return stats, err +} + +func (t *topics) GetInternalStats(topic TopicName) (PersistentTopicInternalStats, error) { + var stats PersistentTopicInternalStats + endpoint := t.pulsar.endpoint(t.apiVersion, t.basePath, topic.GetRestPath(), "internalStats") + err := t.pulsar.restClient.Get(endpoint, &stats) + return stats, err +} + +func (t *topics) GetPartitionedStats(topic TopicName, perPartition bool) (PartitionedTopicStats, error) { + var stats PartitionedTopicStats + endpoint := t.pulsar.endpoint(t.apiVersion, t.basePath, topic.GetRestPath(), "partitioned-stats") + params := map[string]string{ + "perPartition": strconv.FormatBool(perPartition), + } + _, err := t.pulsar.restClient.GetWithQueryParams(endpoint, &stats, params, true) + return stats, err +} + +func (t *topics) Terminate(topic TopicName) (MessageID, error) { + endpoint := t.pulsar.endpoint(t.apiVersion, t.basePath, topic.GetRestPath(), "terminate") + var messageID MessageID + err := t.pulsar.restClient.PostWithObj(endpoint, nil, &messageID) + return messageID, err +} + +func (t *topics) Offload(topic TopicName, messageID MessageID) error { + endpoint := t.pulsar.endpoint(t.apiVersion, t.basePath, topic.GetRestPath(), "offload") + return t.pulsar.restClient.Put(endpoint, messageID) +} + +func (t *topics) OffloadStatus(topic TopicName) (OffloadProcessStatus, error) { + endpoint := t.pulsar.endpoint(t.apiVersion, t.basePath, topic.GetRestPath(), "offload") + var status OffloadProcessStatus + err := t.pulsar.restClient.Get(endpoint, &status) + return status, err +} + +func (t *topics) Unload(topic TopicName) error { + endpoint := t.pulsar.endpoint(t.apiVersion, t.basePath, topic.GetRestPath(), "unload") + return t.pulsar.restClient.Put(endpoint, nil) +} + +func (t *topics) Compact(topic TopicName) error { + endpoint := t.pulsar.endpoint(t.apiVersion, t.basePath, topic.GetRestPath(), "compaction") + return t.pulsar.restClient.Put(endpoint, nil) +} + +func (t *topics) CompactStatus(topic TopicName) (LongRunningProcessStatus, error) { + endpoint := t.pulsar.endpoint(t.apiVersion, t.basePath, topic.GetRestPath(), "compaction") + var status LongRunningProcessStatus + err := t.pulsar.restClient.Get(endpoint, &status) + return status, err +} + +func (t *topics) GetMessageTTL(topic TopicName) (int, error) { + var ttl int + endpoint := t.pulsar.endpoint(t.apiVersion, t.basePath, topic.GetRestPath(), "messageTTL") + err := t.pulsar.restClient.Get(endpoint, &ttl) + return ttl, err +} + +func (t *topics) SetMessageTTL(topic TopicName, messageTTL int) error { + endpoint := t.pulsar.endpoint(t.apiVersion, t.basePath, topic.GetRestPath(), "messageTTL") + params := make(map[string]string) + params["messageTTL"] = strconv.Itoa(messageTTL) + err := t.pulsar.restClient.PostWithQueryParams(endpoint, nil, params) + return err +} + +func (t *topics) RemoveMessageTTL(topic TopicName) error { + endpoint := t.pulsar.endpoint(t.apiVersion, t.basePath, topic.GetRestPath(), "messageTTL") + params := make(map[string]string) + params["messageTTL"] = strconv.Itoa(0) + err := t.pulsar.restClient.DeleteWithQueryParams(endpoint, params) + return err +} + +func (t *topics) GetMaxProducers(topic TopicName) (int, error) { + var maxProducers int + endpoint := t.pulsar.endpoint(t.apiVersion, t.basePath, topic.GetRestPath(), "maxProducers") + err := t.pulsar.restClient.Get(endpoint, &maxProducers) + return maxProducers, err +} + +func (t *topics) SetMaxProducers(topic TopicName, maxProducers int) error { + endpoint := t.pulsar.endpoint(t.apiVersion, t.basePath, topic.GetRestPath(), "maxProducers") + err := t.pulsar.restClient.Post(endpoint, &maxProducers) + return err +} + +func (t *topics) RemoveMaxProducers(topic TopicName) error { + endpoint := t.pulsar.endpoint(t.apiVersion, t.basePath, topic.GetRestPath(), "maxProducers") + err := t.pulsar.restClient.Delete(endpoint) + return err +} + +func (t *topics) GetMaxConsumers(topic TopicName) (int, error) { + var maxConsumers int + endpoint := t.pulsar.endpoint(t.apiVersion, t.basePath, topic.GetRestPath(), "maxConsumers") + err := t.pulsar.restClient.Get(endpoint, &maxConsumers) + return maxConsumers, err +} + +func (t *topics) SetMaxConsumers(topic TopicName, maxConsumers int) error { + endpoint := t.pulsar.endpoint(t.apiVersion, t.basePath, topic.GetRestPath(), "maxConsumers") + err := t.pulsar.restClient.Post(endpoint, &maxConsumers) + return err +} + +func (t *topics) RemoveMaxConsumers(topic TopicName) error { + endpoint := t.pulsar.endpoint(t.apiVersion, t.basePath, topic.GetRestPath(), "maxConsumers") + err := t.pulsar.restClient.Delete(endpoint) + return err +} + +func (t *topics) GetMaxUnackMessagesPerConsumer(topic TopicName) (int, error) { + var maxNum int + endpoint := t.pulsar.endpoint(t.apiVersion, t.basePath, topic.GetRestPath(), "maxUnackedMessagesOnConsumer") + err := t.pulsar.restClient.Get(endpoint, &maxNum) + return maxNum, err +} + +func (t *topics) SetMaxUnackMessagesPerConsumer(topic TopicName, maxUnackedNum int) error { + endpoint := t.pulsar.endpoint(t.apiVersion, t.basePath, topic.GetRestPath(), "maxUnackedMessagesOnConsumer") + return t.pulsar.restClient.Post(endpoint, &maxUnackedNum) +} + +func (t *topics) RemoveMaxUnackMessagesPerConsumer(topic TopicName) error { + endpoint := t.pulsar.endpoint(t.apiVersion, t.basePath, topic.GetRestPath(), "maxUnackedMessagesOnConsumer") + return t.pulsar.restClient.Delete(endpoint) +} + +func (t *topics) GetMaxUnackMessagesPerSubscription(topic TopicName) (int, error) { + var maxNum int + endpoint := t.pulsar.endpoint(t.apiVersion, t.basePath, topic.GetRestPath(), "maxUnackedMessagesOnSubscription") + err := t.pulsar.restClient.Get(endpoint, &maxNum) + return maxNum, err +} + +func (t *topics) SetMaxUnackMessagesPerSubscription(topic TopicName, maxUnackedNum int) error { + endpoint := t.pulsar.endpoint(t.apiVersion, t.basePath, topic.GetRestPath(), "maxUnackedMessagesOnSubscription") + return t.pulsar.restClient.Post(endpoint, &maxUnackedNum) +} + +func (t *topics) RemoveMaxUnackMessagesPerSubscription(topic TopicName) error { + endpoint := t.pulsar.endpoint(t.apiVersion, t.basePath, topic.GetRestPath(), "maxUnackedMessagesOnSubscription") + return t.pulsar.restClient.Delete(endpoint) +} + +func (t *topics) GetPersistence(topic TopicName) (*PersistenceData, error) { + var persistenceData PersistenceData + endpoint := t.pulsar.endpoint(t.apiVersion, t.basePath, topic.GetRestPath(), "persistence") + err := t.pulsar.restClient.Get(endpoint, &persistenceData) + return &persistenceData, err +} + +func (t *topics) SetPersistence(topic TopicName, persistenceData PersistenceData) error { + endpoint := t.pulsar.endpoint(t.apiVersion, t.basePath, topic.GetRestPath(), "persistence") + return t.pulsar.restClient.Post(endpoint, &persistenceData) +} + +func (t *topics) RemovePersistence(topic TopicName) error { + endpoint := t.pulsar.endpoint(t.apiVersion, t.basePath, topic.GetRestPath(), "persistence") + return t.pulsar.restClient.Delete(endpoint) +} + +func (t *topics) GetDelayedDelivery(topic TopicName) (*DelayedDeliveryData, error) { + var delayedDeliveryData DelayedDeliveryData + endpoint := t.pulsar.endpoint(t.apiVersion, t.basePath, topic.GetRestPath(), "delayedDelivery") + err := t.pulsar.restClient.Get(endpoint, &delayedDeliveryData) + return &delayedDeliveryData, err +} + +func (t *topics) SetDelayedDelivery(topic TopicName, delayedDeliveryData DelayedDeliveryData) error { + endpoint := t.pulsar.endpoint(t.apiVersion, t.basePath, topic.GetRestPath(), "delayedDelivery") + return t.pulsar.restClient.Post(endpoint, &delayedDeliveryData) +} + +func (t *topics) RemoveDelayedDelivery(topic TopicName) error { + endpoint := t.pulsar.endpoint(t.apiVersion, t.basePath, topic.GetRestPath(), "delayedDelivery") + return t.pulsar.restClient.Delete(endpoint) +} + +func (t *topics) GetDispatchRate(topic TopicName) (*DispatchRateData, error) { + var dispatchRateData DispatchRateData + endpoint := t.pulsar.endpoint(t.apiVersion, t.basePath, topic.GetRestPath(), "dispatchRate") + err := t.pulsar.restClient.Get(endpoint, &dispatchRateData) + return &dispatchRateData, err +} + +func (t *topics) SetDispatchRate(topic TopicName, dispatchRateData DispatchRateData) error { + endpoint := t.pulsar.endpoint(t.apiVersion, t.basePath, topic.GetRestPath(), "dispatchRate") + return t.pulsar.restClient.Post(endpoint, &dispatchRateData) +} + +func (t *topics) RemoveDispatchRate(topic TopicName) error { + endpoint := t.pulsar.endpoint(t.apiVersion, t.basePath, topic.GetRestPath(), "dispatchRate") + return t.pulsar.restClient.Delete(endpoint) +} + +func (t *topics) GetPublishRate(topic TopicName) (*PublishRateData, error) { + var publishRateData PublishRateData + endpoint := t.pulsar.endpoint(t.apiVersion, t.basePath, topic.GetRestPath(), "publishRate") + err := t.pulsar.restClient.Get(endpoint, &publishRateData) + return &publishRateData, err +} + +func (t *topics) SetPublishRate(topic TopicName, publishRateData PublishRateData) error { + endpoint := t.pulsar.endpoint(t.apiVersion, t.basePath, topic.GetRestPath(), "publishRate") + return t.pulsar.restClient.Post(endpoint, &publishRateData) +} + +func (t *topics) RemovePublishRate(topic TopicName) error { + endpoint := t.pulsar.endpoint(t.apiVersion, t.basePath, topic.GetRestPath(), "publishRate") + return t.pulsar.restClient.Delete(endpoint) +} + +func (t *topics) GetDeduplicationStatus(topic TopicName) (bool, error) { + var enabled bool + endpoint := t.pulsar.endpoint(t.apiVersion, t.basePath, topic.GetRestPath(), "deduplicationEnabled") + err := t.pulsar.restClient.Get(endpoint, &enabled) + return enabled, err +} + +func (t *topics) SetDeduplicationStatus(topic TopicName, enabled bool) error { + endpoint := t.pulsar.endpoint(t.apiVersion, t.basePath, topic.GetRestPath(), "deduplicationEnabled") + return t.pulsar.restClient.Post(endpoint, enabled) +} + +func (t *topics) RemoveDeduplicationStatus(topic TopicName) error { + endpoint := t.pulsar.endpoint(t.apiVersion, t.basePath, topic.GetRestPath(), "deduplicationEnabled") + return t.pulsar.restClient.Delete(endpoint) +} + +func (t *topics) GetRetention(topic TopicName, applied bool) (*RetentionPolicies, error) { + var policy RetentionPolicies + endpoint := t.pulsar.endpoint(t.apiVersion, t.basePath, topic.GetRestPath(), "retention") + _, err := t.pulsar.restClient.GetWithQueryParams(endpoint, &policy, map[string]string{ + "applied": strconv.FormatBool(applied), + }, true) + return &policy, err +} + +func (t *topics) RemoveRetention(topic TopicName) error { + endpoint := t.pulsar.endpoint(t.apiVersion, t.basePath, topic.GetRestPath(), "retention") + return t.pulsar.restClient.Delete(endpoint) +} + +func (t *topics) SetRetention(topic TopicName, data RetentionPolicies) error { + endpoint := t.pulsar.endpoint(t.apiVersion, t.basePath, topic.GetRestPath(), "retention") + return t.pulsar.restClient.Post(endpoint, data) +} + +func (t *topics) GetCompactionThreshold(topic TopicName, applied bool) (int64, error) { + var threshold int64 + endpoint := t.pulsar.endpoint(t.apiVersion, t.basePath, topic.GetRestPath(), "compactionThreshold") + _, err := t.pulsar.restClient.GetWithQueryParams(endpoint, &threshold, map[string]string{ + "applied": strconv.FormatBool(applied), + }, true) + return threshold, err +} + +func (t *topics) SetCompactionThreshold(topic TopicName, threshold int64) error { + endpoint := t.pulsar.endpoint(t.apiVersion, t.basePath, topic.GetRestPath(), "compactionThreshold") + err := t.pulsar.restClient.Post(endpoint, threshold) + return err +} + +func (t *topics) RemoveCompactionThreshold(topic TopicName) error { + endpoint := t.pulsar.endpoint(t.apiVersion, t.basePath, topic.GetRestPath(), "compactionThreshold") + err := t.pulsar.restClient.Delete(endpoint) + return err +} + +func (t *topics) GetBacklogQuotaMap(topic TopicName, applied bool) (map[BacklogQuotaType]BacklogQuota, + error, +) { + var backlogQuotaMap map[BacklogQuotaType]BacklogQuota + endpoint := t.pulsar.endpoint(t.apiVersion, t.basePath, topic.GetRestPath(), "backlogQuotaMap") + + queryParams := map[string]string{"applied": strconv.FormatBool(applied)} + _, err := t.pulsar.restClient.GetWithQueryParams(endpoint, &backlogQuotaMap, queryParams, true) + + return backlogQuotaMap, err +} + +func (t *topics) SetBacklogQuota(topic TopicName, backlogQuota BacklogQuota, + backlogQuotaType BacklogQuotaType, +) error { + endpoint := t.pulsar.endpoint(t.apiVersion, t.basePath, topic.GetRestPath(), "backlogQuota") + params := make(map[string]string) + params["backlogQuotaType"] = string(backlogQuotaType) + return t.pulsar.restClient.PostWithQueryParams(endpoint, &backlogQuota, params) +} + +func (t *topics) RemoveBacklogQuota(topic TopicName, backlogQuotaType BacklogQuotaType) error { + endpoint := t.pulsar.endpoint(t.apiVersion, t.basePath, topic.GetRestPath(), "backlogQuota") + return t.pulsar.restClient.DeleteWithQueryParams(endpoint, map[string]string{ + "backlogQuotaType": string(backlogQuotaType), + }) +} + +func (t *topics) GetInactiveTopicPolicies(topic TopicName, applied bool) (InactiveTopicPolicies, error) { + var out InactiveTopicPolicies + endpoint := t.pulsar.endpoint(t.apiVersion, t.basePath, topic.GetRestPath(), "inactiveTopicPolicies") + _, err := t.pulsar.restClient.GetWithQueryParams(endpoint, &out, map[string]string{ + "applied": strconv.FormatBool(applied), + }, true) + return out, err +} + +func (t *topics) RemoveInactiveTopicPolicies(topic TopicName) error { + endpoint := t.pulsar.endpoint(t.apiVersion, t.basePath, topic.GetRestPath(), "inactiveTopicPolicies") + return t.pulsar.restClient.Delete(endpoint) +} + +func (t *topics) SetInactiveTopicPolicies(topic TopicName, data InactiveTopicPolicies) error { + endpoint := t.pulsar.endpoint(t.apiVersion, t.basePath, topic.GetRestPath(), "inactiveTopicPolicies") + return t.pulsar.restClient.Post(endpoint, data) +} + +func (t *topics) SetReplicationClusters(topic TopicName, data []string) error { + endpoint := t.pulsar.endpoint(t.apiVersion, t.basePath, topic.GetRestPath(), "replication") + return t.pulsar.restClient.Post(endpoint, data) +} + +func (t *topics) GetReplicationClusters(topic TopicName) ([]string, error) { + var data []string + endpoint := t.pulsar.endpoint(t.apiVersion, t.basePath, topic.GetRestPath(), "replication") + err := t.pulsar.restClient.Get(endpoint, &data) + return data, err +} diff --git a/pulsaradmin/pkg/utils/auth_action.go b/pulsaradmin/auth_action.go similarity index 76% rename from pulsaradmin/pkg/utils/auth_action.go rename to pulsaradmin/auth_action.go index 7f2bf25735..9bf51b2690 100644 --- a/pulsaradmin/pkg/utils/auth_action.go +++ b/pulsaradmin/auth_action.go @@ -15,35 +15,35 @@ // specific language governing permissions and limitations // under the License. -package utils +package pulsaradmin import "github.com/pkg/errors" type AuthAction string const ( - produce AuthAction = "produce" - consume AuthAction = "consume" - functionsAuth AuthAction = "functions" - packages AuthAction = "packages" - sinks AuthAction = "sinks" - sources AuthAction = "sources" + authProduce AuthAction = "produce" + authConsume AuthAction = "consume" + authFunctions AuthAction = "functions" + authPackages AuthAction = "packages" + authSinks AuthAction = "sinks" + authSources AuthAction = "sources" ) func ParseAuthAction(action string) (AuthAction, error) { switch action { case "produce": - return produce, nil + return authProduce, nil case "consume": - return consume, nil + return authConsume, nil case "functions": - return functionsAuth, nil + return authFunctions, nil case "packages": - return packages, nil + return authPackages, nil case "sinks": - return sinks, nil + return authSinks, nil case "sources": - return sources, nil + return authSources, nil default: return "", errors.Errorf("The auth action only can be specified as 'produce', "+ "'consume', 'sources', 'sinks', 'packages', or 'functions'. Invalid auth action '%s'", action) diff --git a/pulsaradmin/pkg/utils/auth_polices.go b/pulsaradmin/auth_polices.go similarity index 98% rename from pulsaradmin/pkg/utils/auth_polices.go rename to pulsaradmin/auth_polices.go index 065b3c434d..9a6de3a162 100644 --- a/pulsaradmin/pkg/utils/auth_polices.go +++ b/pulsaradmin/auth_polices.go @@ -15,7 +15,7 @@ // specific language governing permissions and limitations // under the License. -package utils +package pulsaradmin type AuthPolicies struct { NamespaceAuth map[string][]AuthAction `json:"namespace_auth"` diff --git a/pulsaradmin/pkg/utils/auth_polices_test.go b/pulsaradmin/auth_polices_test.go similarity index 99% rename from pulsaradmin/pkg/utils/auth_polices_test.go rename to pulsaradmin/auth_polices_test.go index 014f594bdc..6c4a681a5e 100644 --- a/pulsaradmin/pkg/utils/auth_polices_test.go +++ b/pulsaradmin/auth_polices_test.go @@ -15,7 +15,7 @@ // specific language governing permissions and limitations // under the License. -package utils +package pulsaradmin import ( "encoding/json" diff --git a/pulsaradmin/pkg/utils/backlog_quota.go b/pulsaradmin/backlog_quota.go similarity index 99% rename from pulsaradmin/pkg/utils/backlog_quota.go rename to pulsaradmin/backlog_quota.go index 1930cad8ce..3256a05e6f 100644 --- a/pulsaradmin/pkg/utils/backlog_quota.go +++ b/pulsaradmin/backlog_quota.go @@ -15,7 +15,7 @@ // specific language governing permissions and limitations // under the License. -package utils +package pulsaradmin import "github.com/pkg/errors" diff --git a/pulsaradmin/pkg/utils/batch_source_config.go b/pulsaradmin/batch_source_config.go similarity index 98% rename from pulsaradmin/pkg/utils/batch_source_config.go rename to pulsaradmin/batch_source_config.go index 3db2db697c..e9bbd50f86 100644 --- a/pulsaradmin/pkg/utils/batch_source_config.go +++ b/pulsaradmin/batch_source_config.go @@ -15,7 +15,7 @@ // specific language governing permissions and limitations // under the License. -package utils +package pulsaradmin const ( BatchsourceConfigKey string = "__BATCHSOURCECONFIGS__" diff --git a/pulsaradmin/pkg/utils/broker_ns_isolation_data.go b/pulsaradmin/broker_ns_isolation_data.go similarity index 98% rename from pulsaradmin/pkg/utils/broker_ns_isolation_data.go rename to pulsaradmin/broker_ns_isolation_data.go index 1381647b6b..d60fef0065 100644 --- a/pulsaradmin/pkg/utils/broker_ns_isolation_data.go +++ b/pulsaradmin/broker_ns_isolation_data.go @@ -15,7 +15,7 @@ // specific language governing permissions and limitations // under the License. -package utils +package pulsaradmin type BrokerNamespaceIsolationData struct { BrokerName string `json:"brokerName"` diff --git a/pulsaradmin/pkg/utils/bundles_data.go b/pulsaradmin/bundles_data.go similarity index 98% rename from pulsaradmin/pkg/utils/bundles_data.go rename to pulsaradmin/bundles_data.go index 2bba7ae493..9afcc39d31 100644 --- a/pulsaradmin/pkg/utils/bundles_data.go +++ b/pulsaradmin/bundles_data.go @@ -15,7 +15,7 @@ // specific language governing permissions and limitations // under the License. -package utils +package pulsaradmin type BundlesData struct { Boundaries []string `json:"boundaries"` diff --git a/pulsaradmin/pkg/admin/admin.go b/pulsaradmin/client.go similarity index 52% rename from pulsaradmin/pkg/admin/admin.go rename to pulsaradmin/client.go index a22b22c62d..f4cb943daa 100644 --- a/pulsaradmin/pkg/admin/admin.go +++ b/pulsaradmin/client.go @@ -15,31 +15,27 @@ // specific language governing permissions and limitations // under the License. -package admin +package pulsaradmin import ( + "fmt" "net/http" "net/url" "path" "time" - "github.com/apache/pulsar-client-go/pulsaradmin/pkg/admin/auth" - "github.com/apache/pulsar-client-go/pulsaradmin/pkg/admin/config" - "github.com/apache/pulsar-client-go/pulsaradmin/pkg/rest" - "github.com/apache/pulsar-client-go/pulsaradmin/pkg/utils" + "github.com/apache/pulsar-client-go/pulsaradmin/internal/rest" ) const ( DefaultWebServiceURL = "http://localhost:8080" + DefaultBKWebServiceURL = "pulsar://localhost:6650" DefaultHTTPTimeOutDuration = 5 * time.Minute + Product = "pulsar-admin-go" ReleaseVersion = "None" + adminBasePath = `/admin` ) -type TLSOptions struct { - TrustCertsFilePath string - AllowInsecureConnection bool -} - // Client provides a client to the Pulsar Restful API type Client interface { Clusters() Clusters @@ -60,55 +56,58 @@ type Client interface { } type pulsarClient struct { - Client *rest.Client - APIVersion config.APIVersion + restClient *rest.Client + apiProfile APIProfile } -// New returns a new client -func New(config *config.Config) (Client, error) { - authProvider, err := auth.GetAuthProvider(config) - if err != nil { - return nil, err +// NewClient returns a new client +func NewClient(config ClientConfig) (Client, error) { + if config.WebServiceURL == "" { + config.WebServiceURL = DefaultWebServiceURL + } + if config.BKWebServiceURL == "" { + config.BKWebServiceURL = DefaultBKWebServiceURL + } + if config.APIProfile == nil { + config.APIProfile = defaultAPIProfile() } - return NewPulsarClientWithAuthProvider(config, authProvider) -} -// NewWithAuthProvider creates a client with auth provider. -// Deprecated: Use NewPulsarClientWithAuthProvider instead. -func NewWithAuthProvider(config *config.Config, authProvider auth.Provider) Client { - client, err := NewPulsarClientWithAuthProvider(config, authProvider) - if err != nil { - panic(err) + baseTransport := config.CustomTransport + if baseTransport == nil { + defaultTransport, err := defaultTransport(config) + if err != nil { + return nil, fmt.Errorf("initializing default transport: %w", err) + } + baseTransport = defaultTransport } - return client -} -// NewPulsarClientWithAuthProvider create a client with auth provider. -func NewPulsarClientWithAuthProvider(config *config.Config, authProvider auth.Provider) (Client, error) { - if len(config.WebServiceURL) == 0 { - config.WebServiceURL = DefaultWebServiceURL + clientTransport := http.RoundTripper(baseTransport) + + if config.AuthProvider != nil { + authTransport, err := config.AuthProvider(baseTransport) + if err != nil { + return nil, fmt.Errorf("auth provider: %w", err) + } + if authTransport != nil { + clientTransport = authTransport + } } return &pulsarClient{ - APIVersion: config.PulsarAPIVersion, - Client: &rest.Client{ - ServiceURL: config.WebServiceURL, - VersionInfo: ReleaseVersion, - HTTPClient: &http.Client{ - Timeout: DefaultHTTPTimeOutDuration, - Transport: authProvider, - }, - }, + restClient: rest.NewClient(clientTransport, config.WebServiceURL, Product+`/`+ReleaseVersion), + apiProfile: *config.APIProfile, }, nil } -func (c *pulsarClient) endpoint(componentPath string, parts ...string) string { +func (c *pulsarClient) endpoint(apiVersion APIVersion, componentPath string, parts ...string) string { escapedParts := make([]string, len(parts)) for i, part := range parts { escapedParts[i] = url.PathEscape(part) } return path.Join( - utils.MakeHTTPPath(c.APIVersion.String(), componentPath), + adminBasePath, + apiVersion.String(), + componentPath, path.Join(escapedParts...), ) } diff --git a/pulsaradmin/client_auth_providers.go b/pulsaradmin/client_auth_providers.go new file mode 100644 index 0000000000..dc26399c02 --- /dev/null +++ b/pulsaradmin/client_auth_providers.go @@ -0,0 +1,145 @@ +package pulsaradmin + +import ( + "encoding/json" + "fmt" + "net/http" + + "github.com/apache/pulsar-client-go/pulsaradmin/internal/auth" +) + +// The following are the valid values for pluginName in calls to [AuthProviderPlugin] +const ( + AuthPluginTLS = "tls" + AuthPluginClassTLS = "org.apache.pulsar.client.impl.auth.AuthenticationTls" + AuthPluginOAuth2 = "oauth2" + AuthPluginClassOAuth2 = "org.apache.pulsar.client.impl.auth.oauth2.AuthenticationOAuth2" + AuthPluginToken = "token" + AuthPluginClassToken = "org.apache.pulsar.client.impl.auth.AuthenticationToken" + AuthPluginDisabled = "disabled" + AuthPluginClassDisabled = "org.apache.pulsar.client.impl.auth.AuthenticationDisabled" +) + +// AuthProvider is a function that receives a default HTTP transport and returns +// a new transport that handles auth. Implementations should remember to clone +// any requests before modifying them. +type AuthProvider func(*http.Transport) (http.RoundTripper, error) + +// AuthProviderPlugin returns an AuthProvider that will inspect a +// Pulsar auth plugin/class name and JSON params and initialize the appropriate +// authentication provider +func AuthProviderPlugin(pluginName string, authParams string) AuthProvider { + return func(transport *http.Transport) (http.RoundTripper, error) { + switch pluginName { + case AuthPluginTLS, AuthPluginClassTLS: + params := &AuthParamsTLS{} + if seemsJSON(authParams) { + if err := unmarshalParams(authParams, params); err != nil { + return nil, err + } + return auth.NewTLSTransport(params.TLSCertFile, params.TLSKeyFile, transport) + } + // also supports KV + return auth.NewTLSTransportFromKV(authParams, transport) + case AuthPluginToken, AuthPluginClassToken: + params := &AuthParamsToken{} + if seemsJSON(authParams) { + if err := unmarshalParams(authParams, params); err != nil { + return nil, err + } + return auth.NewTokenTransport(params.Token, transport) + } + // also supports KV + return auth.NewTokenTransportFromKV(authParams, transport) + case AuthPluginOAuth2, AuthPluginClassOAuth2: + params := &AuthParamsOAuth2{} + if err := unmarshalParams(authParams, params); err != nil { + return nil, err + } + return auth.NewOauth2Provider(params.IssuerURL, params.Audience, + params.Scope, params.ClientID, params.PrivateKey, transport) + case AuthPluginDisabled, AuthPluginClassDisabled: + return nil, nil + } + return nil, fmt.Errorf("unknown AuthPlugin %q", pluginName) + } +} + +// AuthParamsTLS represents the JSON data needed to initialize a client with +// AuthProviderPlugin and TLS authentication. +// +// It can also be provided as a string in the format of: +// +// :,: +// +// ex: "tlsCertFile:/path/to/cert,tlsKeyFile:/path/to/key" +type AuthParamsTLS struct { + TLSCertFile string `json:"tlsCertFile"` + TLSKeyFile string `json:"tlsKeyFile"` +} + +// AuthProviderTLS returns a TLS-based authentication provider from a +// TLS certificate and key file. +func AuthProviderTLS(certFile, keyFile string) AuthProvider { + return func(transport *http.Transport) (http.RoundTripper, error) { + return auth.NewTLSTransport(certFile, keyFile, transport) + } +} + +// AuthParamsOAuth2 represents the JSON data needed to initialize a client with +// OAuth2 Authentication +type AuthParamsOAuth2 struct { + IssuerURL string `json:"issuerUrl,omitempty"` + ClientID string `json:"clientId,omitempty"` + Audience string `json:"audience,omitempty"` + Scope string `json:"scope,omitempty"` + PrivateKey string `json:"privateKey,omitempty"` +} + +// AuthProviderOAuth2 returns an OAuth2-based authentication provider with +// optional private key. +func AuthProviderOAuth2(params AuthParamsOAuth2) AuthProvider { + return func(transport *http.Transport) (http.RoundTripper, error) { + return auth.NewOauth2Provider(params.IssuerURL, params.Audience, + params.Scope, params.ClientID, params.PrivateKey, transport) + } +} + +// AuthParamsToken represents the JSON data needed to initialize a client with +// AuthProviderPlugin and Token auth. +// +// It can also be provided as a string in the format of: +// +// token: +// or +// file: +type AuthParamsToken struct { + Token string `json:"token"` +} + +// AuthProviderToken returns a token-based authentication provider from raw +// token data. +func AuthProviderToken(token string) AuthProvider { + return func(transport *http.Transport) (http.RoundTripper, error) { + return auth.NewTokenTransport(token, transport) + } +} + +// AuthProviderTokenFile returns a token-based authentication provider from a +// token stored in a file. +func AuthProviderTokenFile(tokenPath string) AuthProvider { + return func(transport *http.Transport) (http.RoundTripper, error) { + return auth.NewTokenTransportFromFile(tokenPath, transport) + } +} + +func unmarshalParams(jsonStr string, v any) error { + return json.Unmarshal([]byte(jsonStr), v) +} + +func seemsJSON(str string) bool { + if len(str) > 0 && str[0] == '{' { + return true + } + return false +} diff --git a/pulsaradmin/client_config.go b/pulsaradmin/client_config.go new file mode 100644 index 0000000000..e553675adc --- /dev/null +++ b/pulsaradmin/client_config.go @@ -0,0 +1,91 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package pulsaradmin + +import "net/http" + +type ClientConfig struct { + // the web service url that pulsarctl connects to. Default is http://localhost:8080 + WebServiceURL string + // the bookkeeper service url that pulsarctl connects to. + BKWebServiceURL string + // TLS Config + TLSConfig TLSConfig + // optional auth provider + AuthProvider AuthProvider + // optional custom HTTP transport + CustomTransport *http.Transport + // optional custom API profile to use different versions of different APIs + APIProfile *APIProfile +} + +type TLSConfig struct { + TrustCertsFilePath string + AllowInsecureConnection bool + EnableHostnameVerification bool +} + +type APIVersion int + +const ( + undefined APIVersion = iota + APIV1 + APIV2 + APIV3 +) + +const DefaultAPIVersion = "v2" + +func (v APIVersion) String() string { + switch v { + case undefined: + return DefaultAPIVersion + case APIV1: + return "" + case APIV2: + return "v2" + case APIV3: + return "v3" + } + + return DefaultAPIVersion +} + +type APIProfile struct { + Clusters APIVersion + Functions APIVersion + Tenants APIVersion + Topics APIVersion + Sources APIVersion + Sinks APIVersion + Namespaces APIVersion + Schemas APIVersion + NsIsolationPolicy APIVersion + Brokers APIVersion + BrokerStats APIVersion + ResourceQuotas APIVersion + FunctionsWorker APIVersion + Packages APIVersion +} + +func defaultAPIProfile() *APIProfile { + return &APIProfile{ + Functions: APIV3, + Packages: APIV3, + } +} diff --git a/pulsaradmin/pkg/admin/config/api_version_test.go b/pulsaradmin/client_config_test.go similarity index 88% rename from pulsaradmin/pkg/admin/config/api_version_test.go rename to pulsaradmin/client_config_test.go index e1dc7bdb69..34af0d45d9 100644 --- a/pulsaradmin/pkg/admin/config/api_version_test.go +++ b/pulsaradmin/client_config_test.go @@ -15,7 +15,7 @@ // specific language governing permissions and limitations // under the License. -package config +package pulsaradmin import ( "testing" @@ -24,9 +24,9 @@ import ( ) func TestApiVersion_String(t *testing.T) { - assert.Equal(t, "", V1.String()) - assert.Equal(t, "v2", V2.String()) - assert.Equal(t, "v3", V3.String()) + assert.Equal(t, "", APIV1.String()) + assert.Equal(t, "v2", APIV2.String()) + assert.Equal(t, "v3", APIV3.String()) var undefinedAPIVersion APIVersion assert.Equal(t, DefaultAPIVersion, undefinedAPIVersion.String()) } diff --git a/pulsaradmin/client_test.go b/pulsaradmin/client_test.go new file mode 100644 index 0000000000..f4439bc69a --- /dev/null +++ b/pulsaradmin/client_test.go @@ -0,0 +1,111 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package pulsaradmin + +import ( + "net/http" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestPulsarClientEndpointEscapes(t *testing.T) { + client := pulsarClient{restClient: nil} + actual := client.endpoint(APIV2, "/myendpoint", "abc%? /def", "ghi") + expected := "/admin/v2/myendpoint/abc%25%3F%20%2Fdef/ghi" + assert.Equal(t, expected, actual) +} + +func TestNew(t *testing.T) { + config := ClientConfig{} + admin, err := NewClient(config) + require.NoError(t, err) + require.NotNil(t, admin) +} + +func TestNewClientWithAuthProvider(t *testing.T) { + provider := AuthProviderToken("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9." + + "eyJzdWIiOiJhZG1pbiIsImlhdCI6MTUxNjIzOTAyMn0.sVt6cyu3HKd89LcQvZVMNbqT0DTl3FvG9oYbj8hBDqU") + + transport, err := provider(&http.Transport{}) + require.NoError(t, err) + require.NotNil(t, transport) + + client, err := NewClient(ClientConfig{ + AuthProvider: provider, + }) + require.NoError(t, err) + require.NotNil(t, client) +} + +type customAuthTransport struct { + T http.RoundTripper +} + +func (c *customAuthTransport) RoundTrip(req *http.Request) (*http.Response, error) { + panic("implement me") +} + +func customAuthProvider(t *http.Transport) (http.RoundTripper, error) { + return &customAuthTransport{t}, nil +} + +func TestNewWithCustomAuthProviderWithTransport(t *testing.T) { + config := ClientConfig{ + AuthProvider: customAuthProvider, + APIProfile: &APIProfile{}, + } + defaultTransport, err := defaultTransport(config) + require.NoError(t, err) + + config.CustomTransport = defaultTransport + + client, err := NewClient(config) + require.NoError(t, err) + require.NotNil(t, client) + + underlyingClient, ok := client.(*pulsarClient) + require.True(t, ok) + require.NotNil(t, underlyingClient) + require.NotNil(t, underlyingClient.restClient) + require.NotNil(t, underlyingClient.restClient.HTTPClient) + require.NotNil(t, underlyingClient.restClient.HTTPClient.Transport) + require.IsType(t, &customAuthTransport{}, underlyingClient.restClient.HTTPClient.Transport) + // Expected the custom transport will be retained + require.Equal(t, defaultTransport, underlyingClient.restClient.HTTPClient.Transport.(*customAuthTransport).T) +} + +func TestNewWithTlsAllowInsecure(t *testing.T) { + client, err := NewClient(ClientConfig{ + TLSConfig: TLSConfig{ + AllowInsecureConnection: true, + }, + }) + require.NoError(t, err) + require.NotNil(t, client) + + underlyingClient, ok := client.(*pulsarClient) + require.True(t, ok) + require.NotNil(t, underlyingClient) + require.NotNil(t, underlyingClient.restClient.HTTPClient.Transport) + tr, ok := underlyingClient.restClient.HTTPClient.Transport.(*http.Transport) + require.True(t, ok) + require.NotNil(t, tr.TLSClientConfig) + require.True(t, tr.TLSClientConfig.InsecureSkipVerify) +} diff --git a/pulsaradmin/client_transport.go b/pulsaradmin/client_transport.go new file mode 100644 index 0000000000..b542c4a221 --- /dev/null +++ b/pulsaradmin/client_transport.go @@ -0,0 +1,28 @@ +package pulsaradmin + +import ( + "crypto/tls" + "crypto/x509" + "net/http" + "os" +) + +func defaultTransport(config ClientConfig) (*http.Transport, error) { + transport := http.DefaultTransport.(*http.Transport).Clone() + + tlsConfig := &tls.Config{ + InsecureSkipVerify: config.TLSConfig.AllowInsecureConnection, + } + + if len(config.TLSConfig.TrustCertsFilePath) > 0 { + rootCA, err := os.ReadFile(config.TLSConfig.TrustCertsFilePath) + if err != nil { + return nil, err + } + tlsConfig.RootCAs = x509.NewCertPool() + tlsConfig.RootCAs.AppendCertsFromPEM(rootCA) + } + transport.MaxIdleConnsPerHost = 10 + transport.TLSClientConfig = tlsConfig + return transport, nil +} diff --git a/pulsaradmin/pkg/utils/connector_definition.go b/pulsaradmin/connector_definition.go similarity index 98% rename from pulsaradmin/pkg/utils/connector_definition.go rename to pulsaradmin/connector_definition.go index 72b12893cd..323d21d60b 100644 --- a/pulsaradmin/pkg/utils/connector_definition.go +++ b/pulsaradmin/connector_definition.go @@ -15,7 +15,7 @@ // specific language governing permissions and limitations // under the License. -package utils +package pulsaradmin // Basic information about a Pulsar connector type ConnectorDefinition struct { diff --git a/pulsaradmin/pkg/utils/consumer_config.go b/pulsaradmin/consumer_config.go similarity index 98% rename from pulsaradmin/pkg/utils/consumer_config.go rename to pulsaradmin/consumer_config.go index f609ae48d8..d3cb90f814 100644 --- a/pulsaradmin/pkg/utils/consumer_config.go +++ b/pulsaradmin/consumer_config.go @@ -15,7 +15,7 @@ // specific language governing permissions and limitations // under the License. -package utils +package pulsaradmin type ConsumerConfig struct { SchemaType string `json:"schemaType,omitempty" yaml:"schemaType"` diff --git a/pulsaradmin/pkg/utils/crypto_config.go b/pulsaradmin/crypto_config.go similarity index 98% rename from pulsaradmin/pkg/utils/crypto_config.go rename to pulsaradmin/crypto_config.go index e411bb8007..e04a168f34 100644 --- a/pulsaradmin/pkg/utils/crypto_config.go +++ b/pulsaradmin/crypto_config.go @@ -15,7 +15,7 @@ // specific language governing permissions and limitations // under the License. -package utils +package pulsaradmin type CryptoConfig struct { CryptoKeyReaderClassName string `json:"cryptoKeyReaderClassName" yaml:"cryptoKeyReaderClassName"` diff --git a/pulsaradmin/pkg/utils/data.go b/pulsaradmin/data.go similarity index 99% rename from pulsaradmin/pkg/utils/data.go rename to pulsaradmin/data.go index 55888aab2b..0c3a9f2562 100644 --- a/pulsaradmin/pkg/utils/data.go +++ b/pulsaradmin/data.go @@ -15,7 +15,7 @@ // specific language governing permissions and limitations // under the License. -package utils +package pulsaradmin // ClusterData information on a cluster type ClusterData struct { diff --git a/pulsaradmin/pkg/utils/dispatch_rate.go b/pulsaradmin/dispatch_rate.go similarity index 98% rename from pulsaradmin/pkg/utils/dispatch_rate.go rename to pulsaradmin/dispatch_rate.go index 9c6ccce88c..2a6b6e2324 100644 --- a/pulsaradmin/pkg/utils/dispatch_rate.go +++ b/pulsaradmin/dispatch_rate.go @@ -15,7 +15,7 @@ // specific language governing permissions and limitations // under the License. -package utils +package pulsaradmin type DispatchRate struct { DispatchThrottlingRateInMsg int `json:"dispatchThrottlingRateInMsg"` diff --git a/pulsaradmin/errors.go b/pulsaradmin/errors.go new file mode 100644 index 0000000000..4b0eebaac7 --- /dev/null +++ b/pulsaradmin/errors.go @@ -0,0 +1,35 @@ +package pulsaradmin + +import ( + "errors" + "net/http" +) + +// APIErr is an error described in the Pulsar Admin API contract with a defined reson. +type APIErr interface { + error + Reason() string + Code() int +} + +// ServerErr is an unexpected or abnormal error, such as an error 500 with stack +// trace that is not described by the Pulsar Admin API +type ServerErr interface { + error + Response() string + Code() int +} + +type codedErr interface { + Code() int +} + +// IsNotFound will return true if the error represents a Pulsar resource that +// does not exist. +func IsNotFound(err error) bool { + var ce codedErr + if errors.As(err, &ce) { + return ce.Code() == http.StatusNotFound + } + return false +} diff --git a/pulsaradmin/pkg/utils/function_confg.go b/pulsaradmin/function_confg.go similarity index 97% rename from pulsaradmin/pkg/utils/function_confg.go rename to pulsaradmin/function_confg.go index 02a00db3b4..ba11bd6409 100644 --- a/pulsaradmin/pkg/utils/function_confg.go +++ b/pulsaradmin/function_confg.go @@ -15,7 +15,7 @@ // specific language governing permissions and limitations // under the License. -package utils +package pulsaradmin const ( JavaRuntime = "JAVA" @@ -89,6 +89,6 @@ type FunctionConfig struct { MaxPendingAsyncRequests int `json:"maxPendingAsyncRequests,omitempty" yaml:"maxPendingAsyncRequests"` //nolint ExposePulsarAdminClientEnabled bool `json:"exposePulsarAdminClientEnabled" yaml:"exposePulsarAdminClientEnabled"` - SkipToLatest bool `json:"skipToLatest" yaml:"skipToLatest"` + SkipToLatest bool `json:"skipToLatest,omitempty" yaml:"skipToLatest"` SubscriptionPosition string `json:"subscriptionPosition,omitempty" yaml:"subscriptionPosition"` } diff --git a/pulsaradmin/pkg/utils/function_state.go b/pulsaradmin/function_state.go similarity index 98% rename from pulsaradmin/pkg/utils/function_state.go rename to pulsaradmin/function_state.go index 63fa15057c..513dda8775 100644 --- a/pulsaradmin/pkg/utils/function_state.go +++ b/pulsaradmin/function_state.go @@ -15,7 +15,7 @@ // specific language governing permissions and limitations // under the License. -package utils +package pulsaradmin type FunctionState struct { Key string `json:"key"` diff --git a/pulsaradmin/pkg/utils/function_status.go b/pulsaradmin/function_status.go similarity index 99% rename from pulsaradmin/pkg/utils/function_status.go rename to pulsaradmin/function_status.go index 360e61b077..3c16b03d13 100644 --- a/pulsaradmin/pkg/utils/function_status.go +++ b/pulsaradmin/function_status.go @@ -15,7 +15,7 @@ // specific language governing permissions and limitations // under the License. -package utils +package pulsaradmin type FunctionStatus struct { NumInstances int `json:"numInstances"` diff --git a/pulsaradmin/pkg/utils/functions_stats.go b/pulsaradmin/functions_stats.go similarity index 99% rename from pulsaradmin/pkg/utils/functions_stats.go rename to pulsaradmin/functions_stats.go index 82761afe51..8d35ea61bd 100644 --- a/pulsaradmin/pkg/utils/functions_stats.go +++ b/pulsaradmin/functions_stats.go @@ -15,7 +15,7 @@ // specific language governing permissions and limitations // under the License. -package utils +package pulsaradmin type FunctionStats struct { // Overall total number of records function received from source diff --git a/pulsaradmin/pkg/utils/inactive_topic_policies.go b/pulsaradmin/inactive_topic_policies.go similarity index 99% rename from pulsaradmin/pkg/utils/inactive_topic_policies.go rename to pulsaradmin/inactive_topic_policies.go index 05f81b6645..cd8936ee78 100644 --- a/pulsaradmin/pkg/utils/inactive_topic_policies.go +++ b/pulsaradmin/inactive_topic_policies.go @@ -15,7 +15,7 @@ // specific language governing permissions and limitations // under the License. -package utils +package pulsaradmin import "github.com/pkg/errors" diff --git a/pulsaradmin/pkg/admin/auth/oauth2.go b/pulsaradmin/internal/auth/oauth2.go similarity index 65% rename from pulsaradmin/pkg/admin/auth/oauth2.go rename to pulsaradmin/internal/auth/oauth2.go index eab64cace5..7f3f46a7d4 100644 --- a/pulsaradmin/pkg/admin/auth/oauth2.go +++ b/pulsaradmin/internal/auth/oauth2.go @@ -18,43 +18,69 @@ package auth import ( - "encoding/json" "net/http" "path/filepath" "github.com/99designs/keyring" + "github.com/pkg/errors" + xoauth2 "golang.org/x/oauth2" + "github.com/apache/pulsar-client-go/oauth2" "github.com/apache/pulsar-client-go/oauth2/cache" clock2 "github.com/apache/pulsar-client-go/oauth2/clock" "github.com/apache/pulsar-client-go/oauth2/store" - "github.com/pkg/errors" - xoauth2 "golang.org/x/oauth2" + "github.com/apache/pulsar-client-go/pulsaradmin/internal/httptools" ) -const ( - OAuth2PluginName = "org.apache.pulsar.client.impl.auth.oauth2.AuthenticationOAuth2" - OAuth2PluginShortName = "oauth2" -) - -type OAuth2ClientCredentials struct { - IssuerURL string `json:"issuerUrl,omitempty"` - Audience string `json:"audience,omitempty"` - Scope string `json:"scope,omitempty"` - PrivateKey string `json:"privateKey,omitempty"` - ClientID string `json:"clientId,omitempty"` -} - -type OAuth2Provider struct { +type Oauth2Transport struct { clock clock2.RealClock issuer oauth2.Issuer store store.Store source cache.CachingTokenSource defaultTransport http.RoundTripper - tokenTransport *transport + tokenTransport *oa2Transport } -func NewAuthenticationOAuth2(issuer oauth2.Issuer, store store.Store) (*OAuth2Provider, error) { - p := &OAuth2Provider{ +func NewOauth2Provider( + issuerEndpoint, + clientID, + audience, + scope, + privateKey string, + transport *http.Transport, +) (*Oauth2Transport, error) { + issuer := oauth2.Issuer{ + IssuerEndpoint: issuerEndpoint, + ClientID: clientID, + Audience: audience, + } + // TODO: is it an error here if private key comes in with scope? + if privateKey != "" { + return oAuth2WithDefaultFlow(issuer, privateKey) + } + + keyringStore, err := makeKeyringStore() + if err != nil { + return nil, err + } + + p := &Oauth2Transport{ + clock: clock2.RealClock{}, + issuer: issuer, + store: keyringStore, + defaultTransport: transport, + } + + err = p.loadGrant() + if err != nil { + return nil, err + } + + return p, nil +} + +func NewAuthenticationOAuth2(issuer oauth2.Issuer, store store.Store) (*Oauth2Transport, error) { + p := &Oauth2Transport{ clock: clock2.RealClock{}, issuer: issuer, store: store, @@ -68,8 +94,8 @@ func NewAuthenticationOAuth2(issuer oauth2.Issuer, store store.Store) (*OAuth2Pr return p, nil } -// NewAuthenticationOAuth2WithDefaultFlow uses memory to save the grant -func NewAuthenticationOAuth2WithDefaultFlow(issuer oauth2.Issuer, keyFile string) (Provider, error) { +// oAuth2WithDefaultFlow uses memory to save the grant +func oAuth2WithDefaultFlow(issuer oauth2.Issuer, keyFile string) (*Oauth2Transport, error) { st := store.NewMemoryStore() flow, err := oauth2.NewDefaultClientCredentialsFlow(oauth2.ClientCredentialsFlowOptions{ KeyFile: keyFile, @@ -88,52 +114,12 @@ func NewAuthenticationOAuth2WithDefaultFlow(issuer oauth2.Issuer, keyFile string return nil, err } - p := &OAuth2Provider{ + p := &Oauth2Transport{ clock: clock2.RealClock{}, issuer: issuer, store: st, } - return p, p.loadGrant() -} - -func NewAuthenticationOAuth2FromAuthParams(encodedAuthParam string, - transport http.RoundTripper) (*OAuth2Provider, error) { - - var paramsJSON OAuth2ClientCredentials - err := json.Unmarshal([]byte(encodedAuthParam), ¶msJSON) - if err != nil { - return nil, err - } - return NewAuthenticationOAuth2WithParams(paramsJSON.IssuerURL, paramsJSON.ClientID, paramsJSON.Audience, - paramsJSON.Scope, transport) -} - -func NewAuthenticationOAuth2WithParams( - issuerEndpoint, - clientID, - audience string, - scope string, - transport http.RoundTripper) (*OAuth2Provider, error) { - - issuer := oauth2.Issuer{ - IssuerEndpoint: issuerEndpoint, - ClientID: clientID, - Audience: audience, - } - - keyringStore, err := MakeKeyringStore() - if err != nil { - return nil, err - } - - p := &OAuth2Provider{ - clock: clock2.RealClock{}, - issuer: issuer, - store: keyringStore, - defaultTransport: transport, - } - err = p.loadGrant() if err != nil { return nil, err @@ -142,7 +128,7 @@ func NewAuthenticationOAuth2WithParams( return p, nil } -func (o *OAuth2Provider) loadGrant() error { +func (o *Oauth2Transport) loadGrant() error { grant, err := o.store.LoadGrant(o.issuer.Audience) if err != nil { if err == store.ErrNoAuthenticationData { @@ -153,7 +139,7 @@ func (o *OAuth2Provider) loadGrant() error { return o.initCache(grant) } -func (o *OAuth2Provider) initCache(grant *oauth2.AuthorizationGrant) error { +func (o *Oauth2Transport) initCache(grant *oauth2.AuthorizationGrant) error { refresher, err := o.getRefresher(grant.Type) if err != nil { return err @@ -164,7 +150,7 @@ func (o *OAuth2Provider) initCache(grant *oauth2.AuthorizationGrant) error { return err } o.source = source - o.tokenTransport = &transport{ + o.tokenTransport = &oa2Transport{ source: o.source, wrapped: &xoauth2.Transport{ Source: o.source, @@ -174,19 +160,11 @@ func (o *OAuth2Provider) initCache(grant *oauth2.AuthorizationGrant) error { return nil } -func (o *OAuth2Provider) RoundTrip(req *http.Request) (*http.Response, error) { - return o.tokenTransport.RoundTrip(req) -} - -func (o *OAuth2Provider) WithTransport(tripper http.RoundTripper) { - o.defaultTransport = tripper -} - -func (o *OAuth2Provider) Transport() http.RoundTripper { - return o.tokenTransport +func (o *Oauth2Transport) RoundTrip(req *http.Request) (*http.Response, error) { + return o.tokenTransport.RoundTrip(httptools.CloneReq(req)) } -func (o *OAuth2Provider) getRefresher(t oauth2.AuthorizationGrantType) (oauth2.AuthorizationGrantRefresher, error) { +func (o *Oauth2Transport) getRefresher(t oauth2.AuthorizationGrantType) (oauth2.AuthorizationGrantRefresher, error) { switch t { case oauth2.GrantTypeClientCredentials: return oauth2.NewDefaultClientCredentialsGrantRefresher(o.clock) @@ -197,12 +175,12 @@ func (o *OAuth2Provider) getRefresher(t oauth2.AuthorizationGrantType) (oauth2.A } } -type transport struct { +type oa2Transport struct { source cache.CachingTokenSource wrapped *xoauth2.Transport } -func (t *transport) RoundTrip(req *http.Request) (*http.Response, error) { +func (t *oa2Transport) RoundTrip(req *http.Request) (*http.Response, error) { if len(req.Header.Get("Authorization")) != 0 { return t.wrapped.Base.RoundTrip(req) } @@ -222,14 +200,12 @@ func (t *transport) RoundTrip(req *http.Request) (*http.Response, error) { return res, nil } -func (t *transport) WrappedRoundTripper() http.RoundTripper { return t.wrapped.Base } - const ( serviceName = "pulsar" - keyChainName = "pulsarctl" + keyChainName = "pulsar-admin-go" ) -func MakeKeyringStore() (store.Store, error) { +func makeKeyringStore() (store.Store, error) { kr, err := makeKeyring() if err != nil { return nil, err @@ -248,6 +224,6 @@ func makeKeyring() (keyring.Keyring, error) { }) } -func keyringPrompt(prompt string) (string, error) { +func keyringPrompt(_ string) (string, error) { return "", nil } diff --git a/pulsaradmin/pkg/admin/auth/oauth2_test.go b/pulsaradmin/internal/auth/oauth2_test.go similarity index 100% rename from pulsaradmin/pkg/admin/auth/oauth2_test.go rename to pulsaradmin/internal/auth/oauth2_test.go diff --git a/pulsaradmin/internal/auth/tls.go b/pulsaradmin/internal/auth/tls.go new file mode 100644 index 0000000000..e50148c58e --- /dev/null +++ b/pulsaradmin/internal/auth/tls.go @@ -0,0 +1,79 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package auth + +import ( + "crypto/tls" + "fmt" + "net/http" + "strings" + + "github.com/pkg/errors" +) + +type TLSTransport struct { + T http.RoundTripper +} + +// NewTLSTransport initialize the authentication provider +func NewTLSTransport(certificatePath string, privateKeyPath string, transport *http.Transport) (*TLSTransport, error) { + switch { + case certificatePath == "": + return nil, errors.New("certificate path required") + case privateKeyPath == "": + return nil, errors.New("private key path required") + } + + cert, err := tls.LoadX509KeyPair(certificatePath, privateKeyPath) + if err != nil { + return nil, fmt.Errorf("loading TLS certificates: %w", err) + } + + newTransport := transport.Clone() + newTransport.TLSClientConfig.Certificates = append([]tls.Certificate{cert}, + newTransport.TLSClientConfig.Certificates...) + + return &TLSTransport{ + T: newTransport, + }, nil +} + +func NewTLSTransportFromKV(paramString string, transport *http.Transport) (*TLSTransport, error) { + var ( + certificatePath string + privateKeyPath string + ) + parts := strings.Split(paramString, ",") + for _, part := range parts { + kv := strings.Split(part, ":") + switch kv[0] { + case "tlsCertFile": + certificatePath = kv[1] + case "tlsKeyFile": + privateKeyPath = kv[1] + } + } + if certificatePath == "" && privateKeyPath == "" { + return nil, errors.New(`TLS auth params must be in the form of "tlsCertFile:,tlsKeyFile:"`) + } + return NewTLSTransport(certificatePath, privateKeyPath, transport) +} + +func (p *TLSTransport) RoundTrip(req *http.Request) (*http.Response, error) { + return p.T.RoundTrip(req) +} diff --git a/pulsaradmin/internal/auth/token.go b/pulsaradmin/internal/auth/token.go new file mode 100644 index 0000000000..c6c4725c1b --- /dev/null +++ b/pulsaradmin/internal/auth/token.go @@ -0,0 +1,80 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package auth + +import ( + "fmt" + "net/http" + "os" + "strings" + + "github.com/pkg/errors" + + "github.com/apache/pulsar-client-go/pulsaradmin/internal/httptools" +) + +const ( + tokenPrefix = "token:" + filePrefix = "file:" +) + +type TokenTransport struct { + Token string + T http.RoundTripper +} + +func NewTokenTransport(tokenData string, transport *http.Transport) (*TokenTransport, error) { + tokenData = strings.TrimSpace(tokenData) + if len(tokenData) == 0 { + return nil, errors.New("empty token") + } + return &TokenTransport{ + Token: tokenData, + T: transport, + }, nil +} + +func NewTokenTransportFromKV(paramString string, transport *http.Transport) (*TokenTransport, error) { + switch { + case strings.HasPrefix(paramString, tokenPrefix): + token := paramString[len(tokenPrefix):] + return NewTokenTransport(token, transport) + case strings.HasPrefix(paramString, filePrefix): + tokenFile := paramString[len(filePrefix):] + return NewTokenTransportFromFile(tokenFile, transport) + default: + return NewTokenTransport(paramString, transport) + } +} + +func NewTokenTransportFromFile(tokenPath string, transport *http.Transport) (*TokenTransport, error) { + fileContents, err := os.ReadFile(tokenPath) + if err != nil { + if os.IsNotExist(err) { + return nil, errors.New("token file not found") + } + return nil, fmt.Errorf("unable to open token file: %v", err) + } + return NewTokenTransport(string(fileContents), transport) +} + +func (p *TokenTransport) RoundTrip(req *http.Request) (*http.Response, error) { + req = httptools.CloneReq(req) + req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", p.Token)) + return p.T.RoundTrip(req) +} diff --git a/pulsaradmin/pkg/utils/utils.go b/pulsaradmin/internal/data/is_nil_fixed.go similarity index 85% rename from pulsaradmin/pkg/utils/utils.go rename to pulsaradmin/internal/data/is_nil_fixed.go index 7b23b15654..d323234552 100644 --- a/pulsaradmin/pkg/utils/utils.go +++ b/pulsaradmin/internal/data/is_nil_fixed.go @@ -15,16 +15,9 @@ // specific language governing permissions and limitations // under the License. -package utils +package data -import ( - "fmt" - "reflect" -) - -func MakeHTTPPath(apiVersion string, componentPath string) string { - return fmt.Sprintf("/admin/%s%s", apiVersion, componentPath) -} +import "reflect" func IsNilFixed(i interface{}) bool { if i == nil { diff --git a/pulsaradmin/pkg/utils/utils_test.go b/pulsaradmin/internal/data/is_nil_fixed_test.go similarity index 99% rename from pulsaradmin/pkg/utils/utils_test.go rename to pulsaradmin/internal/data/is_nil_fixed_test.go index 7a7fe4abe3..0a6f63fec6 100644 --- a/pulsaradmin/pkg/utils/utils_test.go +++ b/pulsaradmin/internal/data/is_nil_fixed_test.go @@ -15,7 +15,7 @@ // specific language governing permissions and limitations // under the License. -package utils +package data import ( "testing" diff --git a/pulsaradmin/internal/httptools/request.go b/pulsaradmin/internal/httptools/request.go new file mode 100644 index 0000000000..66ea5ae00b --- /dev/null +++ b/pulsaradmin/internal/httptools/request.go @@ -0,0 +1,14 @@ +package httptools + +import ( + "context" + "net/http" +) + +func CloneReq(r *http.Request) *http.Request { + ctx := r.Context() + if ctx == nil { + ctx = context.Background() + } + return r.Clone(ctx) +} diff --git a/pulsaradmin/pkg/utils/home_dir.go b/pulsaradmin/internal/localuser/home_dir.go similarity index 99% rename from pulsaradmin/pkg/utils/home_dir.go rename to pulsaradmin/internal/localuser/home_dir.go index 330831c405..26f21c16a7 100644 --- a/pulsaradmin/pkg/utils/home_dir.go +++ b/pulsaradmin/internal/localuser/home_dir.go @@ -15,7 +15,7 @@ // specific language governing permissions and limitations // under the License. -package utils +package localuser import ( "os" diff --git a/pulsaradmin/pkg/rest/client.go b/pulsaradmin/internal/rest/client.go similarity index 91% rename from pulsaradmin/pkg/rest/client.go rename to pulsaradmin/internal/rest/client.go index a1a79737c1..89ec0af3e0 100644 --- a/pulsaradmin/pkg/rest/client.go +++ b/pulsaradmin/internal/rest/client.go @@ -26,11 +26,23 @@ import ( "path" ) +func NewClient(transport http.RoundTripper, serviceURL, userAgent string) *Client { + return &Client{ + ServiceURL: serviceURL, + HTTPClient: &http.Client{ + Transport: transport, + // TODO: Sane default timeouts? + // Timeout: 0, + }, + UserAgent: userAgent, + } +} + // Client is a base client that is used to make http request to the ServiceURL type Client struct { - ServiceURL string - HTTPClient *http.Client - VersionInfo string + ServiceURL string + HTTPClient *http.Client + UserAgent string } func (c *Client) newRequest(method, path string) (*request, error) { @@ -67,15 +79,10 @@ func (c *Client) doRequest(r *request) (*http.Response, error) { } else if req.Body != nil { req.Header.Set("Content-Type", "application/json") } - req.Header.Set("Accept", "application/json") - req.Header.Set("User-Agent", c.useragent()) - hc := c.HTTPClient - if hc == nil { - hc = http.DefaultClient - } + req.Header.Set("User-Agent", c.UserAgent) - return hc.Do(req) + return c.HTTPClient.Do(req) } // MakeRequest can make a simple request and handle the response by yourself @@ -99,13 +106,14 @@ func (c *Client) Get(endpoint string, obj interface{}) error { } func (c *Client) GetWithQueryParams(endpoint string, obj interface{}, params map[string]string, - decode bool) ([]byte, error) { + decode bool, +) ([]byte, error) { return c.GetWithOptions(endpoint, obj, params, decode, nil) } func (c *Client) GetWithOptions(endpoint string, obj interface{}, params map[string]string, - decode bool, file io.Writer) ([]byte, error) { - + decode bool, file io.Writer, +) ([]byte, error) { req, err := c.newRequest(http.MethodGet, endpoint) if err != nil { return nil, err @@ -151,10 +159,6 @@ func (c *Client) GetWithOptions(endpoint string, obj interface{}, params map[str return nil, err } -func (c *Client) useragent() string { - return c.VersionInfo -} - func (c *Client) Put(endpoint string, in interface{}) error { return c.PutWithQueryParams(endpoint, in, nil, nil) } @@ -388,27 +392,3 @@ func safeRespClose(resp *http.Response) { _ = resp.Body.Close() } } - -// responseError is used to parse a response into a client error -func responseError(resp *http.Response) error { - e := Error{ - Code: resp.StatusCode, - Reason: resp.Status, - } - - body, err := io.ReadAll(resp.Body) - if err != nil { - e.Reason = err.Error() - return e - } - - err = json.Unmarshal(body, &e) - if err != nil { - if len(body) != 0 { - e.Reason = string(body) - } - return e - } - - return e -} diff --git a/pulsaradmin/pkg/rest/client_test.go b/pulsaradmin/internal/rest/client_test.go similarity index 100% rename from pulsaradmin/pkg/rest/client_test.go rename to pulsaradmin/internal/rest/client_test.go diff --git a/pulsaradmin/internal/rest/errors.go b/pulsaradmin/internal/rest/errors.go new file mode 100644 index 0000000000..1f7b7723f5 --- /dev/null +++ b/pulsaradmin/internal/rest/errors.go @@ -0,0 +1,87 @@ +package rest + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "net/http" +) + +type apiError struct { + reason string + code int +} + +func (e *apiError) Error() string { + return e.reason +} + +func (e *apiError) Reason() string { + return e.reason +} + +func (e *apiError) Code() int { + return e.code +} + +// serverError is an unexpected or fatal error from the server. +type serverError struct { + // response is the response body returned by the server. + response string + // code is the HTTP code returned from the server + code int +} + +func (e *serverError) Error() string { + if len(e.response) > 0 { + return fmt.Sprintf("%d-%s\n%s", e.code, http.StatusText(e.code), e.response) + } + return fmt.Sprintf("%d-%s", e.code, http.StatusText(e.code)) +} + +func (e *serverError) Response() string { + return e.response +} + +func (e *serverError) Code() int { + return e.code +} + +// IsAdminErr will return true if the server returns an administrative error with +// a `reason` +func IsAdminErr(err error) bool { + _, ok := err.(*apiError) + return ok +} + +// responseError will convert an HTTP response to either an *AdminError or a +// *RequestError, depending on whether ar `reason` was found. +func responseError(resp *http.Response) error { + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return &serverError{ + response: fmt.Sprintf("%d-%s - response body could not be read: %v", resp.StatusCode, resp.Status, err), + code: resp.StatusCode, + } + } + jsonResp := struct { + Reason string `json:"reason"` + }{} + if len(body) > 0 && body[0] == '{' { + // the particulars of the unmarshal error are not important. If it is + // not well-formatted JSON, then it's not an apiError and, by + // definition, unexpected. + _ = json.Unmarshal(body, &jsonResp) + } + if jsonResp.Reason != "" { + return &apiError{ + reason: jsonResp.Reason, + code: resp.StatusCode, + } + } + + return &serverError{ + code: resp.StatusCode, + response: string(body), + } +} diff --git a/pulsaradmin/pkg/utils/internal_configuration_data.go b/pulsaradmin/internal_configuration_data.go similarity index 98% rename from pulsaradmin/pkg/utils/internal_configuration_data.go rename to pulsaradmin/internal_configuration_data.go index 75cad0e245..589023cb7a 100644 --- a/pulsaradmin/pkg/utils/internal_configuration_data.go +++ b/pulsaradmin/internal_configuration_data.go @@ -15,7 +15,7 @@ // specific language governing permissions and limitations // under the License. -package utils +package pulsaradmin type InternalConfigurationData struct { ZookeeperServers string `json:"zookeeperServers"` diff --git a/pulsaradmin/pkg/utils/load_manage_report.go b/pulsaradmin/load_manage_report.go similarity index 99% rename from pulsaradmin/pkg/utils/load_manage_report.go rename to pulsaradmin/load_manage_report.go index 5196da9b55..4dea555615 100644 --- a/pulsaradmin/pkg/utils/load_manage_report.go +++ b/pulsaradmin/load_manage_report.go @@ -15,7 +15,7 @@ // specific language governing permissions and limitations // under the License. -package utils +package pulsaradmin import ( "math" diff --git a/pulsaradmin/pkg/utils/long_running_process_status.go b/pulsaradmin/long_running_process_status.go similarity index 98% rename from pulsaradmin/pkg/utils/long_running_process_status.go rename to pulsaradmin/long_running_process_status.go index c61919ecc8..66f94217ef 100644 --- a/pulsaradmin/pkg/utils/long_running_process_status.go +++ b/pulsaradmin/long_running_process_status.go @@ -15,7 +15,7 @@ // specific language governing permissions and limitations // under the License. -package utils +package pulsaradmin type Status string diff --git a/pulsaradmin/pkg/utils/message.go b/pulsaradmin/message.go similarity index 99% rename from pulsaradmin/pkg/utils/message.go rename to pulsaradmin/message.go index 2f0e4befe8..39f5cc1f96 100644 --- a/pulsaradmin/pkg/utils/message.go +++ b/pulsaradmin/message.go @@ -15,7 +15,7 @@ // specific language governing permissions and limitations // under the License. -package utils +package pulsaradmin //nolint import ( diff --git a/pulsaradmin/pkg/utils/message_id.go b/pulsaradmin/message_id.go similarity index 99% rename from pulsaradmin/pkg/utils/message_id.go rename to pulsaradmin/message_id.go index d75b613e1b..b3d96387b8 100644 --- a/pulsaradmin/pkg/utils/message_id.go +++ b/pulsaradmin/message_id.go @@ -15,7 +15,7 @@ // specific language governing permissions and limitations // under the License. -package utils +package pulsaradmin import ( "strconv" diff --git a/pulsaradmin/pkg/utils/message_id_test.go b/pulsaradmin/message_id_test.go similarity index 99% rename from pulsaradmin/pkg/utils/message_id_test.go rename to pulsaradmin/message_id_test.go index 1ce0b5230b..dbc0d2f3d2 100644 --- a/pulsaradmin/pkg/utils/message_id_test.go +++ b/pulsaradmin/message_id_test.go @@ -15,7 +15,7 @@ // specific language governing permissions and limitations // under the License. -package utils +package pulsaradmin import ( "testing" diff --git a/pulsaradmin/pkg/utils/metrics.go b/pulsaradmin/metrics.go similarity index 98% rename from pulsaradmin/pkg/utils/metrics.go rename to pulsaradmin/metrics.go index ca1919423d..0e280ee5b9 100644 --- a/pulsaradmin/pkg/utils/metrics.go +++ b/pulsaradmin/metrics.go @@ -15,7 +15,7 @@ // specific language governing permissions and limitations // under the License. -package utils +package pulsaradmin type Metrics struct { Metrics map[string]interface{} `json:"metrics"` diff --git a/pulsaradmin/pkg/utils/namespace_name.go b/pulsaradmin/namespace_name.go similarity index 99% rename from pulsaradmin/pkg/utils/namespace_name.go rename to pulsaradmin/namespace_name.go index 11b7435545..b0fedc1f0f 100644 --- a/pulsaradmin/pkg/utils/namespace_name.go +++ b/pulsaradmin/namespace_name.go @@ -15,7 +15,7 @@ // specific language governing permissions and limitations // under the License. -package utils +package pulsaradmin import ( "fmt" diff --git a/pulsaradmin/pkg/utils/namespace_name_test.go b/pulsaradmin/namespace_name_test.go similarity index 99% rename from pulsaradmin/pkg/utils/namespace_name_test.go rename to pulsaradmin/namespace_name_test.go index bc12070e9a..212faa38a9 100644 --- a/pulsaradmin/pkg/utils/namespace_name_test.go +++ b/pulsaradmin/namespace_name_test.go @@ -15,7 +15,7 @@ // specific language governing permissions and limitations // under the License. -package utils +package pulsaradmin import ( "testing" diff --git a/pulsaradmin/pkg/utils/ns_isolation_data.go b/pulsaradmin/ns_isolation_data.go similarity index 99% rename from pulsaradmin/pkg/utils/ns_isolation_data.go rename to pulsaradmin/ns_isolation_data.go index 4589eb30c3..7f884c8ea4 100644 --- a/pulsaradmin/pkg/utils/ns_isolation_data.go +++ b/pulsaradmin/ns_isolation_data.go @@ -15,7 +15,7 @@ // specific language governing permissions and limitations // under the License. -package utils +package pulsaradmin import ( "github.com/pkg/errors" diff --git a/pulsaradmin/pkg/utils/ns_ownership_status.go b/pulsaradmin/ns_ownership_status.go similarity index 98% rename from pulsaradmin/pkg/utils/ns_ownership_status.go rename to pulsaradmin/ns_ownership_status.go index bb63b704f8..f96b1803c3 100644 --- a/pulsaradmin/pkg/utils/ns_ownership_status.go +++ b/pulsaradmin/ns_ownership_status.go @@ -15,7 +15,7 @@ // specific language governing permissions and limitations // under the License. -package utils +package pulsaradmin type NamespaceOwnershipStatus struct { BrokerAssignment BrokerAssignment `json:"broker_assignment"` diff --git a/pulsaradmin/pkg/utils/package_metadata.go b/pulsaradmin/package_metadata.go similarity index 98% rename from pulsaradmin/pkg/utils/package_metadata.go rename to pulsaradmin/package_metadata.go index 860afd9c8e..2ba9b418f5 100644 --- a/pulsaradmin/pkg/utils/package_metadata.go +++ b/pulsaradmin/package_metadata.go @@ -15,7 +15,7 @@ // specific language governing permissions and limitations // under the License. -package utils +package pulsaradmin type PackageMetadata struct { Description string `json:"description,omitempty" yaml:"description"` diff --git a/pulsaradmin/pkg/utils/package_name.go b/pulsaradmin/package_name.go similarity index 99% rename from pulsaradmin/pkg/utils/package_name.go rename to pulsaradmin/package_name.go index afc646d687..c0b8cfadb6 100644 --- a/pulsaradmin/pkg/utils/package_name.go +++ b/pulsaradmin/package_name.go @@ -15,7 +15,7 @@ // specific language governing permissions and limitations // under the License. -package utils +package pulsaradmin import ( "fmt" diff --git a/pulsaradmin/pkg/utils/package_name_test.go b/pulsaradmin/package_name_test.go similarity index 99% rename from pulsaradmin/pkg/utils/package_name_test.go rename to pulsaradmin/package_name_test.go index 8e6edd52d8..848d6ac770 100644 --- a/pulsaradmin/pkg/utils/package_name_test.go +++ b/pulsaradmin/package_name_test.go @@ -15,7 +15,7 @@ // specific language governing permissions and limitations // under the License. -package utils +package pulsaradmin import ( "testing" diff --git a/pulsaradmin/pkg/utils/package_type.go b/pulsaradmin/package_type.go similarity index 98% rename from pulsaradmin/pkg/utils/package_type.go rename to pulsaradmin/package_type.go index 70f455b253..2903718836 100644 --- a/pulsaradmin/pkg/utils/package_type.go +++ b/pulsaradmin/package_type.go @@ -15,7 +15,7 @@ // specific language governing permissions and limitations // under the License. -package utils +package pulsaradmin import "github.com/pkg/errors" diff --git a/pulsaradmin/pkg/utils/persistence_policies.go b/pulsaradmin/persistence_policies.go similarity index 98% rename from pulsaradmin/pkg/utils/persistence_policies.go rename to pulsaradmin/persistence_policies.go index d4c8bdb04e..adb8eff0e1 100644 --- a/pulsaradmin/pkg/utils/persistence_policies.go +++ b/pulsaradmin/persistence_policies.go @@ -15,7 +15,7 @@ // specific language governing permissions and limitations // under the License. -package utils +package pulsaradmin type PersistencePolicies struct { BookkeeperEnsemble int `json:"bookkeeperEnsemble"` diff --git a/pulsaradmin/pkg/admin/admin_test.go b/pulsaradmin/pkg/admin/admin_test.go deleted file mode 100644 index c4fa529567..0000000000 --- a/pulsaradmin/pkg/admin/admin_test.go +++ /dev/null @@ -1,109 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. - -package admin - -import ( - "net/http" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/apache/pulsar-client-go/pulsaradmin/pkg/admin/auth" - "github.com/apache/pulsar-client-go/pulsaradmin/pkg/admin/config" -) - -func TestPulsarClientEndpointEscapes(t *testing.T) { - client := pulsarClient{Client: nil, APIVersion: config.V2} - actual := client.endpoint("/myendpoint", "abc%? /def", "ghi") - expected := "/admin/v2/myendpoint/abc%25%3F%20%2Fdef/ghi" - assert.Equal(t, expected, actual) -} - -func TestNew(t *testing.T) { - config := &config.Config{} - admin, err := New(config) - require.NoError(t, err) - require.NotNil(t, admin) -} - -func TestNewWithAuthProvider(t *testing.T) { - config := &config.Config{} - - tokenAuth, err := auth.NewAuthenticationToken("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9."+ - "eyJzdWIiOiJhZG1pbiIsImlhdCI6MTUxNjIzOTAyMn0.sVt6cyu3HKd89LcQvZVMNbqT0DTl3FvG9oYbj8hBDqU", nil) - require.NoError(t, err) - require.NotNil(t, tokenAuth) - - admin, err := NewPulsarClientWithAuthProvider(config, tokenAuth) - require.NoError(t, err) - require.NotNil(t, admin) -} - -type customAuthProvider struct { - transport http.RoundTripper -} - -var _ auth.Provider = &customAuthProvider{} - -func (c *customAuthProvider) RoundTrip(req *http.Request) (*http.Response, error) { - panic("implement me") -} - -func (c *customAuthProvider) Transport() http.RoundTripper { - return c.transport -} - -func (c *customAuthProvider) WithTransport(transport http.RoundTripper) { - c.transport = transport -} - -func TestNewWithCustomAuthProviderWithTransport(t *testing.T) { - config := &config.Config{} - defaultTransport, err := auth.NewDefaultTransport(config) - require.NoError(t, err) - - customAuthProvider := &customAuthProvider{ - transport: defaultTransport, - } - - admin, err := NewPulsarClientWithAuthProvider(config, customAuthProvider) - require.NoError(t, err) - require.NotNil(t, admin) - - // Expected the customAuthProvider will not be overwritten. - require.Equal(t, customAuthProvider, admin.(*pulsarClient).Client.HTTPClient.Transport) -} - -func TestNewWithTlsAllowInsecure(t *testing.T) { - config := &config.Config{ - TLSAllowInsecureConnection: true, - } - admin, err := New(config) - require.NoError(t, err) - require.NotNil(t, admin) - - pulsarClientS := admin.(*pulsarClient) - require.NotNil(t, pulsarClientS.Client.HTTPClient.Transport) - - ap := pulsarClientS.Client.HTTPClient.Transport.(*auth.DefaultProvider) - tr := ap.Transport().(*http.Transport) - require.NotNil(t, tr) - require.NotNil(t, tr.TLSClientConfig) - require.True(t, tr.TLSClientConfig.InsecureSkipVerify) -} diff --git a/pulsaradmin/pkg/admin/auth/provider.go b/pulsaradmin/pkg/admin/auth/provider.go deleted file mode 100644 index 24f74d2650..0000000000 --- a/pulsaradmin/pkg/admin/auth/provider.go +++ /dev/null @@ -1,96 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. - -package auth - -import ( - "net/http" - - "github.com/apache/pulsar-client-go/oauth2" - - "github.com/apache/pulsar-client-go/pulsaradmin/pkg/admin/config" -) - -// Provider provide a general method to add auth message -type Provider interface { - RoundTrip(req *http.Request) (*http.Response, error) - Transport() http.RoundTripper - WithTransport(tripper http.RoundTripper) -} - -type DefaultProvider struct { - transport http.RoundTripper -} - -func NewDefaultProvider(t http.RoundTripper) Provider { - return &DefaultProvider{ - transport: t, - } -} - -func (dp *DefaultProvider) RoundTrip(req *http.Request) (*http.Response, error) { - return dp.transport.RoundTrip(req) -} - -func (dp *DefaultProvider) Transport() http.RoundTripper { - return dp.transport -} - -func (dp *DefaultProvider) WithTransport(t http.RoundTripper) { - dp.transport = t -} - -func GetAuthProvider(config *config.Config) (Provider, error) { - var provider Provider - defaultTransport, err := NewDefaultTransport(config) - if err != nil { - return nil, err - } - switch config.AuthPlugin { - case TLSPluginShortName: - fallthrough - case TLSPluginName: - provider, err = NewAuthenticationTLSFromAuthParams(config.AuthParams, defaultTransport) - case TokenPluginName: - fallthrough - case TokePluginShortName: - provider, err = NewAuthenticationTokenFromAuthParams(config.AuthParams, defaultTransport) - case OAuth2PluginName: - fallthrough - case OAuth2PluginShortName: - provider, err = NewAuthenticationOAuth2WithDefaultFlow(oauth2.Issuer{ - IssuerEndpoint: config.IssuerEndpoint, - ClientID: config.ClientID, - Audience: config.Audience, - }, config.KeyFile) - default: - switch { - case len(config.TLSCertFile) > 0 && len(config.TLSKeyFile) > 0: - provider, err = NewAuthenticationTLS(config.TLSCertFile, config.TLSKeyFile, defaultTransport) - case len(config.Token) > 0: - provider, err = NewAuthenticationToken(config.Token, defaultTransport) - case len(config.TokenFile) > 0: - provider, err = NewAuthenticationTokenFromFile(config.TokenFile, defaultTransport) - case len(config.IssuerEndpoint) > 0 || len(config.ClientID) > 0 || len(config.Audience) > 0 || len(config.Scope) > 0: - provider, err = NewAuthenticationOAuth2WithParams( - config.IssuerEndpoint, config.ClientID, config.Audience, config.Scope, defaultTransport) - default: - provider = NewDefaultProvider(defaultTransport) - } - } - return provider, err -} diff --git a/pulsaradmin/pkg/admin/auth/tls.go b/pulsaradmin/pkg/admin/auth/tls.go deleted file mode 100644 index 7c11fe27e7..0000000000 --- a/pulsaradmin/pkg/admin/auth/tls.go +++ /dev/null @@ -1,108 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. - -package auth - -import ( - "crypto/tls" - "encoding/json" - "net/http" - "strings" -) - -const ( - TLSPluginName = "org.apache.pulsar.client.impl.auth.AuthenticationTls" - TLSPluginShortName = "tls" -) - -type TLS struct { - TLSCertFile string `json:"tlsCertFile"` - TLSKeyFile string `json:"tlsKeyFile"` -} - -type TLSAuthProvider struct { - certificatePath string - privateKeyPath string - T http.RoundTripper -} - -// NewAuthenticationTLS initialize the authentication provider -func NewAuthenticationTLS(certificatePath string, privateKeyPath string, - transport http.RoundTripper) (*TLSAuthProvider, error) { - provider := &TLSAuthProvider{ - certificatePath: certificatePath, - privateKeyPath: privateKeyPath, - T: transport, - } - if err := provider.configTLS(); err != nil { - return nil, err - } - return provider, nil -} - -func NewAuthenticationTLSFromAuthParams(encodedAuthParams string, - transport http.RoundTripper) (*TLSAuthProvider, error) { - var certificatePath string - var privateKeyPath string - - var tlsJSON TLS - err := json.Unmarshal([]byte(encodedAuthParams), &tlsJSON) - if err != nil { - parts := strings.Split(encodedAuthParams, ",") - for _, part := range parts { - kv := strings.Split(part, ":") - switch kv[0] { - case "tlsCertFile": - certificatePath = kv[1] - case "tlsKeyFile": - privateKeyPath = kv[1] - } - } - } else { - certificatePath = tlsJSON.TLSCertFile - privateKeyPath = tlsJSON.TLSKeyFile - } - - return NewAuthenticationTLS(certificatePath, privateKeyPath, transport) -} - -func (p *TLSAuthProvider) GetTLSCertificate() (*tls.Certificate, error) { - cert, err := tls.LoadX509KeyPair(p.certificatePath, p.privateKeyPath) - return &cert, err -} - -func (p *TLSAuthProvider) RoundTrip(req *http.Request) (*http.Response, error) { - return p.T.RoundTrip(req) -} - -func (p *TLSAuthProvider) Transport() http.RoundTripper { - return p.T -} - -func (p *TLSAuthProvider) configTLS() error { - cert, err := p.GetTLSCertificate() - if err != nil { - return err - } - transport := p.T.(*http.Transport) - transport.TLSClientConfig.Certificates = []tls.Certificate{*cert} - return nil -} - -func (p *TLSAuthProvider) WithTransport(tripper http.RoundTripper) { - p.T = tripper -} diff --git a/pulsaradmin/pkg/admin/auth/token.go b/pulsaradmin/pkg/admin/auth/token.go deleted file mode 100644 index ecf57ecc8f..0000000000 --- a/pulsaradmin/pkg/admin/auth/token.go +++ /dev/null @@ -1,97 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. - -package auth - -import ( - "encoding/json" - "fmt" - "net/http" - "os" - "strings" - - "github.com/pkg/errors" -) - -const ( - tokenPrefix = "token:" - filePrefix = "file:" - TokenPluginName = "org.apache.pulsar.client.impl.auth.AuthenticationToken" - TokePluginShortName = "token" -) - -type Token struct { - Token string `json:"token"` -} - -type TokenAuthProvider struct { - T http.RoundTripper - token string -} - -// NewAuthenticationToken return a interface of Provider with a string token. -func NewAuthenticationToken(token string, transport http.RoundTripper) (*TokenAuthProvider, error) { - if len(token) == 0 { - return nil, errors.New("No token provided") - } - return &TokenAuthProvider{token: token, T: transport}, nil -} - -// NewAuthenticationTokenFromFile return a interface of a Provider with a string token file path. -func NewAuthenticationTokenFromFile(tokenFilePath string, transport http.RoundTripper) (*TokenAuthProvider, error) { - data, err := os.ReadFile(tokenFilePath) - if err != nil { - return nil, err - } - token := strings.Trim(string(data), " \n") - return NewAuthenticationToken(token, transport) -} - -func NewAuthenticationTokenFromAuthParams(encodedAuthParam string, - transport http.RoundTripper) (*TokenAuthProvider, error) { - var tokenAuthProvider *TokenAuthProvider - var err error - - var tokenJSON Token - err = json.Unmarshal([]byte(encodedAuthParam), &tokenJSON) - if err != nil { - switch { - case strings.HasPrefix(encodedAuthParam, tokenPrefix): - tokenAuthProvider, err = NewAuthenticationToken(strings.TrimPrefix(encodedAuthParam, tokenPrefix), transport) - case strings.HasPrefix(encodedAuthParam, filePrefix): - tokenAuthProvider, err = NewAuthenticationTokenFromFile(strings.TrimPrefix(encodedAuthParam, filePrefix), transport) - default: - tokenAuthProvider, err = NewAuthenticationToken(encodedAuthParam, transport) - } - } else { - tokenAuthProvider, err = NewAuthenticationToken(tokenJSON.Token, transport) - } - return tokenAuthProvider, err -} - -func (p *TokenAuthProvider) RoundTrip(req *http.Request) (*http.Response, error) { - req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", p.token)) - return p.T.RoundTrip(req) -} - -func (p *TokenAuthProvider) Transport() http.RoundTripper { - return p.T -} - -func (p *TokenAuthProvider) WithTransport(tripper http.RoundTripper) { - p.T = tripper -} diff --git a/pulsaradmin/pkg/admin/auth/transport.go b/pulsaradmin/pkg/admin/auth/transport.go deleted file mode 100644 index d96ab57f55..0000000000 --- a/pulsaradmin/pkg/admin/auth/transport.go +++ /dev/null @@ -1,60 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. - -package auth - -import ( - "crypto/tls" - "crypto/x509" - "net/http" - "os" - - "github.com/apache/pulsar-client-go/pulsaradmin/pkg/admin/config" -) - -type Transport struct { - T http.RoundTripper -} - -// GetDefaultTransport gets a default transport. -// Deprecated: Use NewDefaultTransport instead. -func GetDefaultTransport(config *config.Config) http.RoundTripper { - transport, err := NewDefaultTransport(config) - if err != nil { - panic(err) - } - - return transport -} - -func NewDefaultTransport(config *config.Config) (http.RoundTripper, error) { - transport := http.DefaultTransport.(*http.Transport).Clone() - tlsConfig := &tls.Config{ - InsecureSkipVerify: config.TLSAllowInsecureConnection, - } - if len(config.TLSTrustCertsFilePath) > 0 { - rootCA, err := os.ReadFile(config.TLSTrustCertsFilePath) - if err != nil { - return nil, err - } - tlsConfig.RootCAs = x509.NewCertPool() - tlsConfig.RootCAs.AppendCertsFromPEM(rootCA) - } - transport.MaxIdleConnsPerHost = 10 - transport.TLSClientConfig = tlsConfig - return transport, nil -} diff --git a/pulsaradmin/pkg/admin/cluster.go b/pulsaradmin/pkg/admin/cluster.go deleted file mode 100644 index b290e3ef30..0000000000 --- a/pulsaradmin/pkg/admin/cluster.go +++ /dev/null @@ -1,142 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. - -package admin - -import ( - "github.com/apache/pulsar-client-go/pulsaradmin/pkg/utils" -) - -// Clusters is admin interface for clusters management -type Clusters interface { - // List returns the list of clusters - List() ([]string, error) - - // Get the configuration data for the specified cluster - Get(string) (utils.ClusterData, error) - - // Create a new cluster - Create(utils.ClusterData) error - - // Delete an existing cluster - Delete(string) error - - // Update the configuration for a cluster - Update(utils.ClusterData) error - - // UpdatePeerClusters updates peer cluster names. - UpdatePeerClusters(string, []string) error - - // GetPeerClusters returns peer-cluster names - GetPeerClusters(string) ([]string, error) - - // CreateFailureDomain creates a domain into cluster - CreateFailureDomain(utils.FailureDomainData) error - - // GetFailureDomain returns the domain registered into a cluster - GetFailureDomain(clusterName, domainName string) (utils.FailureDomainData, error) - - // ListFailureDomains returns all registered domains in cluster - ListFailureDomains(string) (utils.FailureDomainMap, error) - - // DeleteFailureDomain deletes a domain in cluster - DeleteFailureDomain(utils.FailureDomainData) error - - // UpdateFailureDomain updates a domain into cluster - UpdateFailureDomain(utils.FailureDomainData) error -} - -type clusters struct { - pulsar *pulsarClient - basePath string -} - -// Clusters is used to access the cluster endpoints. -func (c *pulsarClient) Clusters() Clusters { - return &clusters{ - pulsar: c, - basePath: "/clusters", - } -} - -func (c *clusters) List() ([]string, error) { - var clusters []string - err := c.pulsar.Client.Get(c.pulsar.endpoint(c.basePath), &clusters) - return clusters, err -} - -func (c *clusters) Get(name string) (utils.ClusterData, error) { - cdata := utils.ClusterData{} - endpoint := c.pulsar.endpoint(c.basePath, name) - err := c.pulsar.Client.Get(endpoint, &cdata) - return cdata, err -} - -func (c *clusters) Create(cdata utils.ClusterData) error { - endpoint := c.pulsar.endpoint(c.basePath, cdata.Name) - return c.pulsar.Client.Put(endpoint, &cdata) -} - -func (c *clusters) Delete(name string) error { - endpoint := c.pulsar.endpoint(c.basePath, name) - return c.pulsar.Client.Delete(endpoint) -} - -func (c *clusters) Update(cdata utils.ClusterData) error { - endpoint := c.pulsar.endpoint(c.basePath, cdata.Name) - return c.pulsar.Client.Post(endpoint, &cdata) -} - -func (c *clusters) GetPeerClusters(name string) ([]string, error) { - var peerClusters []string - endpoint := c.pulsar.endpoint(c.basePath, name, "peers") - err := c.pulsar.Client.Get(endpoint, &peerClusters) - return peerClusters, err -} - -func (c *clusters) UpdatePeerClusters(cluster string, peerClusters []string) error { - endpoint := c.pulsar.endpoint(c.basePath, cluster, "peers") - return c.pulsar.Client.Post(endpoint, peerClusters) -} - -func (c *clusters) CreateFailureDomain(data utils.FailureDomainData) error { - endpoint := c.pulsar.endpoint(c.basePath, data.ClusterName, "failureDomains", data.DomainName) - return c.pulsar.Client.Post(endpoint, &data) -} - -func (c *clusters) GetFailureDomain(clusterName string, domainName string) (utils.FailureDomainData, error) { - var res utils.FailureDomainData - endpoint := c.pulsar.endpoint(c.basePath, clusterName, "failureDomains", domainName) - err := c.pulsar.Client.Get(endpoint, &res) - return res, err -} - -func (c *clusters) ListFailureDomains(clusterName string) (utils.FailureDomainMap, error) { - var domainData utils.FailureDomainMap - endpoint := c.pulsar.endpoint(c.basePath, clusterName, "failureDomains") - err := c.pulsar.Client.Get(endpoint, &domainData) - return domainData, err -} - -func (c *clusters) DeleteFailureDomain(data utils.FailureDomainData) error { - endpoint := c.pulsar.endpoint(c.basePath, data.ClusterName, "failureDomains", data.DomainName) - return c.pulsar.Client.Delete(endpoint) -} -func (c *clusters) UpdateFailureDomain(data utils.FailureDomainData) error { - endpoint := c.pulsar.endpoint(c.basePath, data.ClusterName, "failureDomains", data.DomainName) - return c.pulsar.Client.Post(endpoint, &data) -} diff --git a/pulsaradmin/pkg/admin/config/api_version.go b/pulsaradmin/pkg/admin/config/api_version.go deleted file mode 100644 index 95f6704580..0000000000 --- a/pulsaradmin/pkg/admin/config/api_version.go +++ /dev/null @@ -1,44 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. - -package config - -type APIVersion int - -const ( - undefined APIVersion = iota - V1 - V2 - V3 -) - -const DefaultAPIVersion = "v2" - -func (v APIVersion) String() string { - switch v { - case undefined: - return DefaultAPIVersion - case V1: - return "" - case V2: - return "v2" - case V3: - return "v3" - } - - return DefaultAPIVersion -} diff --git a/pulsaradmin/pkg/admin/config/config.go b/pulsaradmin/pkg/admin/config/config.go deleted file mode 100644 index 9428f3a909..0000000000 --- a/pulsaradmin/pkg/admin/config/config.go +++ /dev/null @@ -1,52 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. - -package config - -type Config struct { - // the web service url that pulsarctl connects to. Default is http://localhost:8080 - WebServiceURL string - - // the bookkeeper service url that pulsarctl connects to. - BKWebServiceURL string - // Set the path to the trusted TLS certificate file - TLSTrustCertsFilePath string - // Configure whether the Pulsar client accept untrusted TLS certificate from broker (default: false) - TLSAllowInsecureConnection bool - - TLSEnableHostnameVerification bool - - AuthPlugin string - - AuthParams string - - // TLS Cert and Key Files for authentication - TLSCertFile string - TLSKeyFile string - - // Token and TokenFile is used to config the pulsarctl using token to authentication - Token string - TokenFile string - PulsarAPIVersion APIVersion - - // OAuth2 configuration - IssuerEndpoint string - ClientID string - Audience string - KeyFile string - Scope string -} diff --git a/pulsaradmin/pkg/admin/namespace.go b/pulsaradmin/pkg/admin/namespace.go deleted file mode 100644 index 732441e8c2..0000000000 --- a/pulsaradmin/pkg/admin/namespace.go +++ /dev/null @@ -1,875 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. - -package admin - -import ( - "net/url" - "strconv" - "strings" - - "github.com/apache/pulsar-client-go/pulsaradmin/pkg/utils" -) - -// Namespaces is admin interface for namespaces management -type Namespaces interface { - // GetNamespaces returns the list of all the namespaces for a certain tenant - GetNamespaces(tenant string) ([]string, error) - - // GetTopics returns the list of all the topics under a certain namespace - GetTopics(namespace string) ([]string, error) - - // GetPolicies returns the dump all the policies specified for a namespace - GetPolicies(namespace string) (*utils.Policies, error) - - // CreateNamespace creates a new empty namespace with no policies attached - CreateNamespace(namespace string) error - - // CreateNsWithNumBundles creates a new empty namespace with no policies attached - CreateNsWithNumBundles(namespace string, numBundles int) error - - // CreateNsWithPolices creates a new namespace with the specified policies - CreateNsWithPolices(namespace string, polices utils.Policies) error - - // CreateNsWithBundlesData creates a new empty namespace with no policies attached - CreateNsWithBundlesData(namespace string, bundleData *utils.BundlesData) error - - // DeleteNamespace deletes an existing namespace - DeleteNamespace(namespace string) error - - // DeleteNamespaceBundle deletes an existing bundle in a namespace - DeleteNamespaceBundle(namespace string, bundleRange string) error - - // SetNamespaceMessageTTL sets the messages Time to Live for all the topics within a namespace - SetNamespaceMessageTTL(namespace string, ttlInSeconds int) error - - // GetNamespaceMessageTTL returns the message TTL for a namespace - GetNamespaceMessageTTL(namespace string) (int, error) - - // GetRetention returns the retention configuration for a namespace - GetRetention(namespace string) (*utils.RetentionPolicies, error) - - // SetRetention sets the retention configuration for all the topics on a namespace - SetRetention(namespace string, policy utils.RetentionPolicies) error - - // GetBacklogQuotaMap returns backlog quota map on a namespace - GetBacklogQuotaMap(namespace string) (map[utils.BacklogQuotaType]utils.BacklogQuota, error) - - // SetBacklogQuota sets a backlog quota for all the topics on a namespace - SetBacklogQuota(namespace string, backlogQuota utils.BacklogQuota, backlogQuotaType utils.BacklogQuotaType) error - - // RemoveBacklogQuota removes a backlog quota policy from a namespace - RemoveBacklogQuota(namespace string) error - - // SetTopicAutoCreation sets topic auto-creation config for a namespace, overriding broker settings - SetTopicAutoCreation(namespace utils.NameSpaceName, config utils.TopicAutoCreationConfig) error - - // RemoveTopicAutoCreation removes topic auto-creation config for a namespace, defaulting to broker settings - RemoveTopicAutoCreation(namespace utils.NameSpaceName) error - - // SetSchemaValidationEnforced sets schema validation enforced for namespace - SetSchemaValidationEnforced(namespace utils.NameSpaceName, schemaValidationEnforced bool) error - - // GetSchemaValidationEnforced returns schema validation enforced for namespace - GetSchemaValidationEnforced(namespace utils.NameSpaceName) (bool, error) - - // SetSchemaAutoUpdateCompatibilityStrategy sets the strategy used to check the a new schema provided - // by a producer is compatible with the current schema before it is installed - SetSchemaAutoUpdateCompatibilityStrategy(namespace utils.NameSpaceName, - strategy utils.SchemaCompatibilityStrategy) error - - // GetSchemaAutoUpdateCompatibilityStrategy returns the strategy used to check the a new schema provided - // by a producer is compatible with the current schema before it is installed - GetSchemaAutoUpdateCompatibilityStrategy(namespace utils.NameSpaceName) (utils.SchemaCompatibilityStrategy, error) - - // ClearOffloadDeleteLag clears the offload deletion lag for a namespace. - ClearOffloadDeleteLag(namespace utils.NameSpaceName) error - - // SetOffloadDeleteLag sets the offload deletion lag for a namespace - SetOffloadDeleteLag(namespace utils.NameSpaceName, timeMs int64) error - - // GetOffloadDeleteLag returns the offload deletion lag for a namespace, in milliseconds - GetOffloadDeleteLag(namespace utils.NameSpaceName) (int64, error) - - // SetOffloadThreshold sets the offloadThreshold for a namespace - SetOffloadThreshold(namespace utils.NameSpaceName, threshold int64) error - - // GetOffloadThreshold returns the offloadThreshold for a namespace - GetOffloadThreshold(namespace utils.NameSpaceName) (int64, error) - - // SetCompactionThreshold sets the compactionThreshold for a namespace - SetCompactionThreshold(namespace utils.NameSpaceName, threshold int64) error - - // GetCompactionThreshold returns the compactionThreshold for a namespace - GetCompactionThreshold(namespace utils.NameSpaceName) (int64, error) - - // SetMaxConsumersPerSubscription sets maxConsumersPerSubscription for a namespace. - SetMaxConsumersPerSubscription(namespace utils.NameSpaceName, max int) error - - // GetMaxConsumersPerSubscription returns the maxConsumersPerSubscription for a namespace. - GetMaxConsumersPerSubscription(namespace utils.NameSpaceName) (int, error) - - // SetMaxConsumersPerTopic sets maxConsumersPerTopic for a namespace. - SetMaxConsumersPerTopic(namespace utils.NameSpaceName, max int) error - - // GetMaxConsumersPerTopic returns the maxProducersPerTopic for a namespace. - GetMaxConsumersPerTopic(namespace utils.NameSpaceName) (int, error) - - // SetMaxProducersPerTopic sets maxProducersPerTopic for a namespace. - SetMaxProducersPerTopic(namespace utils.NameSpaceName, max int) error - - // GetMaxProducersPerTopic returns the maxProducersPerTopic for a namespace. - GetMaxProducersPerTopic(namespace utils.NameSpaceName) (int, error) - - // GetNamespaceReplicationClusters returns the replication clusters for a namespace - GetNamespaceReplicationClusters(namespace string) ([]string, error) - - // SetNamespaceReplicationClusters returns the replication clusters for a namespace - SetNamespaceReplicationClusters(namespace string, clusterIds []string) error - - // SetNamespaceAntiAffinityGroup sets anti-affinity group name for a namespace - SetNamespaceAntiAffinityGroup(namespace string, namespaceAntiAffinityGroup string) error - - // GetAntiAffinityNamespaces returns all namespaces that grouped with given anti-affinity group - GetAntiAffinityNamespaces(tenant, cluster, namespaceAntiAffinityGroup string) ([]string, error) - - // GetNamespaceAntiAffinityGroup returns anti-affinity group name for a namespace - GetNamespaceAntiAffinityGroup(namespace string) (string, error) - - // DeleteNamespaceAntiAffinityGroup deletes anti-affinity group name for a namespace - DeleteNamespaceAntiAffinityGroup(namespace string) error - - // SetDeduplicationStatus sets the deduplication status for all topics within a namespace - // When deduplication is enabled, the broker will prevent to store the same Message multiple times - SetDeduplicationStatus(namespace string, enableDeduplication bool) error - - // SetPersistence sets the persistence configuration for all the topics on a namespace - SetPersistence(namespace string, persistence utils.PersistencePolicies) error - - // GetPersistence returns the persistence configuration for a namespace - GetPersistence(namespace string) (*utils.PersistencePolicies, error) - - // SetBookieAffinityGroup sets bookie affinity group for a namespace to isolate namespace write to bookies that are - // part of given affinity group - SetBookieAffinityGroup(namespace string, bookieAffinityGroup utils.BookieAffinityGroupData) error - - // DeleteBookieAffinityGroup deletes bookie affinity group configured for a namespace - DeleteBookieAffinityGroup(namespace string) error - - // GetBookieAffinityGroup returns bookie affinity group configured for a namespace - GetBookieAffinityGroup(namespace string) (*utils.BookieAffinityGroupData, error) - - // Unload a namespace from the current serving broker - Unload(namespace string) error - - // UnloadNamespaceBundle unloads namespace bundle - UnloadNamespaceBundle(namespace, bundle string) error - - // SplitNamespaceBundle splits namespace bundle - SplitNamespaceBundle(namespace, bundle string, unloadSplitBundles bool) error - - // GetNamespacePermissions returns permissions on a namespace - GetNamespacePermissions(namespace utils.NameSpaceName) (map[string][]utils.AuthAction, error) - - // GrantNamespacePermission grants permission on a namespace. - GrantNamespacePermission(namespace utils.NameSpaceName, role string, action []utils.AuthAction) error - - // RevokeNamespacePermission revokes permissions on a namespace. - RevokeNamespacePermission(namespace utils.NameSpaceName, role string) error - - // GrantSubPermission grants permission to role to access subscription's admin-api - GrantSubPermission(namespace utils.NameSpaceName, sName string, roles []string) error - - // RevokeSubPermission revoke permissions on a subscription's admin-api access - RevokeSubPermission(namespace utils.NameSpaceName, sName, role string) error - - // SetSubscriptionAuthMode sets the given subscription auth mode on all topics on a namespace - SetSubscriptionAuthMode(namespace utils.NameSpaceName, mode utils.SubscriptionAuthMode) error - - // SetEncryptionRequiredStatus sets the encryption required status for all topics within a namespace - SetEncryptionRequiredStatus(namespace utils.NameSpaceName, encrypt bool) error - - // UnsubscribeNamespace unsubscribe the given subscription on all topics on a namespace - UnsubscribeNamespace(namespace utils.NameSpaceName, sName string) error - - // UnsubscribeNamespaceBundle unsubscribe the given subscription on all topics on a namespace bundle - UnsubscribeNamespaceBundle(namespace utils.NameSpaceName, bundle, sName string) error - - // ClearNamespaceBundleBacklogForSubscription clears backlog for a given subscription on all - // topics on a namespace bundle - ClearNamespaceBundleBacklogForSubscription(namespace utils.NameSpaceName, bundle, sName string) error - - // ClearNamespaceBundleBacklog clears backlog for all topics on a namespace bundle - ClearNamespaceBundleBacklog(namespace utils.NameSpaceName, bundle string) error - - // ClearNamespaceBacklogForSubscription clears backlog for a given subscription on all topics on a namespace - ClearNamespaceBacklogForSubscription(namespace utils.NameSpaceName, sName string) error - - // ClearNamespaceBacklog clears backlog for all topics on a namespace - ClearNamespaceBacklog(namespace utils.NameSpaceName) error - - // SetReplicatorDispatchRate sets replicator-Message-dispatch-rate (Replicators under this namespace - // can dispatch this many messages per second) - SetReplicatorDispatchRate(namespace utils.NameSpaceName, rate utils.DispatchRate) error - - // Get replicator-Message-dispatch-rate (Replicators under this namespace - // can dispatch this many messages per second) - GetReplicatorDispatchRate(namespace utils.NameSpaceName) (utils.DispatchRate, error) - - // SetSubscriptionDispatchRate sets subscription-Message-dispatch-rate (subscriptions under this namespace - // can dispatch this many messages per second) - SetSubscriptionDispatchRate(namespace utils.NameSpaceName, rate utils.DispatchRate) error - - // GetSubscriptionDispatchRate returns subscription-Message-dispatch-rate (subscriptions under this namespace - // can dispatch this many messages per second) - GetSubscriptionDispatchRate(namespace utils.NameSpaceName) (utils.DispatchRate, error) - - // SetSubscribeRate sets namespace-subscribe-rate (topics under this namespace will limit by subscribeRate) - SetSubscribeRate(namespace utils.NameSpaceName, rate utils.SubscribeRate) error - - // GetSubscribeRate returns namespace-subscribe-rate (topics under this namespace allow subscribe - // times per consumer in a period) - GetSubscribeRate(namespace utils.NameSpaceName) (utils.SubscribeRate, error) - - // SetDispatchRate sets Message-dispatch-rate (topics under this namespace can dispatch - // this many messages per second) - SetDispatchRate(namespace utils.NameSpaceName, rate utils.DispatchRate) error - - // GetDispatchRate returns Message-dispatch-rate (topics under this namespace can dispatch - // this many messages per second) - GetDispatchRate(namespace utils.NameSpaceName) (utils.DispatchRate, error) - - // SetPublishRate sets the maximum rate or number of messages that producers can publish to topics in this namespace - SetPublishRate(namespace utils.NameSpaceName, pubRate utils.PublishRate) error - - // GetPublishRate gets the maximum rate or number of messages that producer can publish to topics in the namespace - GetPublishRate(namespace utils.NameSpaceName) (utils.PublishRate, error) - - // SetIsAllowAutoUpdateSchema sets whether to allow auto update schema on a namespace - SetIsAllowAutoUpdateSchema(namespace utils.NameSpaceName, isAllowAutoUpdateSchema bool) error - - // GetIsAllowAutoUpdateSchema gets whether to allow auto update schema on a namespace - GetIsAllowAutoUpdateSchema(namespace utils.NameSpaceName) (bool, error) - - // GetInactiveTopicPolicies gets the inactive topic policies on a namespace - GetInactiveTopicPolicies(namespace utils.NameSpaceName) (utils.InactiveTopicPolicies, error) - - // RemoveInactiveTopicPolicies removes inactive topic policies from a namespace - RemoveInactiveTopicPolicies(namespace utils.NameSpaceName) error - - // SetInactiveTopicPolicies sets the inactive topic policies on a namespace - SetInactiveTopicPolicies(namespace utils.NameSpaceName, data utils.InactiveTopicPolicies) error -} - -type namespaces struct { - pulsar *pulsarClient - basePath string -} - -// Namespaces is used to access the namespaces endpoints -func (c *pulsarClient) Namespaces() Namespaces { - return &namespaces{ - pulsar: c, - basePath: "/namespaces", - } -} - -func (n *namespaces) GetNamespaces(tenant string) ([]string, error) { - var namespaces []string - endpoint := n.pulsar.endpoint(n.basePath, tenant) - err := n.pulsar.Client.Get(endpoint, &namespaces) - return namespaces, err -} - -func (n *namespaces) GetTopics(namespace string) ([]string, error) { - var topics []string - ns, err := utils.GetNamespaceName(namespace) - if err != nil { - return nil, err - } - endpoint := n.pulsar.endpoint(n.basePath, ns.String(), "topics") - err = n.pulsar.Client.Get(endpoint, &topics) - return topics, err -} - -func (n *namespaces) GetPolicies(namespace string) (*utils.Policies, error) { - var police utils.Policies - ns, err := utils.GetNamespaceName(namespace) - if err != nil { - return nil, err - } - endpoint := n.pulsar.endpoint(n.basePath, ns.String()) - err = n.pulsar.Client.Get(endpoint, &police) - return &police, err -} - -func (n *namespaces) CreateNsWithNumBundles(namespace string, numBundles int) error { - return n.CreateNsWithBundlesData(namespace, utils.NewBundlesDataWithNumBundles(numBundles)) -} - -func (n *namespaces) CreateNsWithPolices(namespace string, policies utils.Policies) error { - ns, err := utils.GetNamespaceName(namespace) - if err != nil { - return err - } - endpoint := n.pulsar.endpoint(n.basePath, ns.String()) - return n.pulsar.Client.Put(endpoint, &policies) -} - -func (n *namespaces) CreateNsWithBundlesData(namespace string, bundleData *utils.BundlesData) error { - ns, err := utils.GetNamespaceName(namespace) - if err != nil { - return err - } - endpoint := n.pulsar.endpoint(n.basePath, ns.String()) - polices := new(utils.Policies) - polices.Bundles = bundleData - - return n.pulsar.Client.Put(endpoint, &polices) -} - -func (n *namespaces) CreateNamespace(namespace string) error { - ns, err := utils.GetNamespaceName(namespace) - if err != nil { - return err - } - endpoint := n.pulsar.endpoint(n.basePath, ns.String()) - return n.pulsar.Client.Put(endpoint, nil) -} - -func (n *namespaces) DeleteNamespace(namespace string) error { - ns, err := utils.GetNamespaceName(namespace) - if err != nil { - return err - } - endpoint := n.pulsar.endpoint(n.basePath, ns.String()) - return n.pulsar.Client.Delete(endpoint) -} - -func (n *namespaces) DeleteNamespaceBundle(namespace string, bundleRange string) error { - ns, err := utils.GetNamespaceName(namespace) - if err != nil { - return err - } - endpoint := n.pulsar.endpoint(n.basePath, ns.String(), bundleRange) - return n.pulsar.Client.Delete(endpoint) -} - -func (n *namespaces) GetNamespaceMessageTTL(namespace string) (int, error) { - var ttl int - nsName, err := utils.GetNamespaceName(namespace) - if err != nil { - return 0, err - } - endpoint := n.pulsar.endpoint(n.basePath, nsName.String(), "messageTTL") - err = n.pulsar.Client.Get(endpoint, &ttl) - return ttl, err -} - -func (n *namespaces) SetNamespaceMessageTTL(namespace string, ttlInSeconds int) error { - nsName, err := utils.GetNamespaceName(namespace) - if err != nil { - return err - } - - endpoint := n.pulsar.endpoint(n.basePath, nsName.String(), "messageTTL") - return n.pulsar.Client.Post(endpoint, &ttlInSeconds) -} - -func (n *namespaces) SetRetention(namespace string, policy utils.RetentionPolicies) error { - nsName, err := utils.GetNamespaceName(namespace) - if err != nil { - return err - } - endpoint := n.pulsar.endpoint(n.basePath, nsName.String(), "retention") - return n.pulsar.Client.Post(endpoint, &policy) -} - -func (n *namespaces) GetRetention(namespace string) (*utils.RetentionPolicies, error) { - var policy utils.RetentionPolicies - nsName, err := utils.GetNamespaceName(namespace) - if err != nil { - return nil, err - } - endpoint := n.pulsar.endpoint(n.basePath, nsName.String(), "retention") - err = n.pulsar.Client.Get(endpoint, &policy) - return &policy, err -} - -func (n *namespaces) GetBacklogQuotaMap(namespace string) (map[utils.BacklogQuotaType]utils.BacklogQuota, error) { - var backlogQuotaMap map[utils.BacklogQuotaType]utils.BacklogQuota - nsName, err := utils.GetNamespaceName(namespace) - if err != nil { - return nil, err - } - endpoint := n.pulsar.endpoint(n.basePath, nsName.String(), "backlogQuotaMap") - err = n.pulsar.Client.Get(endpoint, &backlogQuotaMap) - return backlogQuotaMap, err -} - -func (n *namespaces) SetBacklogQuota(namespace string, backlogQuota utils.BacklogQuota, - backlogQuotaType utils.BacklogQuotaType) error { - nsName, err := utils.GetNamespaceName(namespace) - if err != nil { - return err - } - endpoint := n.pulsar.endpoint(n.basePath, nsName.String(), "backlogQuota") - params := make(map[string]string) - params["backlogQuotaType"] = string(backlogQuotaType) - return n.pulsar.Client.PostWithQueryParams(endpoint, &backlogQuota, params) -} - -func (n *namespaces) RemoveBacklogQuota(namespace string) error { - nsName, err := utils.GetNamespaceName(namespace) - if err != nil { - return err - } - endpoint := n.pulsar.endpoint(n.basePath, nsName.String(), "backlogQuota") - params := map[string]string{ - "backlogQuotaType": string(utils.DestinationStorage), - } - return n.pulsar.Client.DeleteWithQueryParams(endpoint, params) -} - -func (n *namespaces) SetTopicAutoCreation(namespace utils.NameSpaceName, config utils.TopicAutoCreationConfig) error { - endpoint := n.pulsar.endpoint(n.basePath, namespace.String(), "autoTopicCreation") - return n.pulsar.Client.Post(endpoint, &config) -} - -func (n *namespaces) RemoveTopicAutoCreation(namespace utils.NameSpaceName) error { - endpoint := n.pulsar.endpoint(n.basePath, namespace.String(), "autoTopicCreation") - return n.pulsar.Client.Delete(endpoint) -} - -func (n *namespaces) SetSchemaValidationEnforced(namespace utils.NameSpaceName, schemaValidationEnforced bool) error { - endpoint := n.pulsar.endpoint(n.basePath, namespace.String(), "schemaValidationEnforced") - return n.pulsar.Client.Post(endpoint, schemaValidationEnforced) -} - -func (n *namespaces) GetSchemaValidationEnforced(namespace utils.NameSpaceName) (bool, error) { - var result bool - endpoint := n.pulsar.endpoint(n.basePath, namespace.String(), "schemaValidationEnforced") - err := n.pulsar.Client.Get(endpoint, &result) - return result, err -} - -func (n *namespaces) SetSchemaAutoUpdateCompatibilityStrategy(namespace utils.NameSpaceName, - strategy utils.SchemaCompatibilityStrategy) error { - endpoint := n.pulsar.endpoint(n.basePath, namespace.String(), "schemaAutoUpdateCompatibilityStrategy") - return n.pulsar.Client.Put(endpoint, strategy.String()) -} - -func (n *namespaces) GetSchemaAutoUpdateCompatibilityStrategy(namespace utils.NameSpaceName) ( - utils.SchemaCompatibilityStrategy, error) { - endpoint := n.pulsar.endpoint(n.basePath, namespace.String(), "schemaAutoUpdateCompatibilityStrategy") - b, err := n.pulsar.Client.GetWithQueryParams(endpoint, nil, nil, false) - if err != nil { - return "", err - } - s, err := utils.ParseSchemaAutoUpdateCompatibilityStrategy(strings.ReplaceAll(string(b), "\"", "")) - if err != nil { - return "", err - } - return s, nil -} - -func (n *namespaces) ClearOffloadDeleteLag(namespace utils.NameSpaceName) error { - endpoint := n.pulsar.endpoint(n.basePath, namespace.String(), "offloadDeletionLagMs") - return n.pulsar.Client.Delete(endpoint) -} - -func (n *namespaces) SetOffloadDeleteLag(namespace utils.NameSpaceName, timeMs int64) error { - endpoint := n.pulsar.endpoint(n.basePath, namespace.String(), "offloadDeletionLagMs") - return n.pulsar.Client.Put(endpoint, timeMs) -} - -func (n *namespaces) GetOffloadDeleteLag(namespace utils.NameSpaceName) (int64, error) { - var result int64 - endpoint := n.pulsar.endpoint(n.basePath, namespace.String(), "offloadDeletionLagMs") - err := n.pulsar.Client.Get(endpoint, &result) - return result, err -} - -func (n *namespaces) SetMaxConsumersPerSubscription(namespace utils.NameSpaceName, max int) error { - endpoint := n.pulsar.endpoint(n.basePath, namespace.String(), "maxConsumersPerSubscription") - return n.pulsar.Client.Post(endpoint, max) -} - -func (n *namespaces) GetMaxConsumersPerSubscription(namespace utils.NameSpaceName) (int, error) { - var result int - endpoint := n.pulsar.endpoint(n.basePath, namespace.String(), "maxConsumersPerSubscription") - err := n.pulsar.Client.Get(endpoint, &result) - return result, err -} - -func (n *namespaces) SetOffloadThreshold(namespace utils.NameSpaceName, threshold int64) error { - endpoint := n.pulsar.endpoint(n.basePath, namespace.String(), "offloadThreshold") - return n.pulsar.Client.Put(endpoint, threshold) -} - -func (n *namespaces) GetOffloadThreshold(namespace utils.NameSpaceName) (int64, error) { - var result int64 - endpoint := n.pulsar.endpoint(n.basePath, namespace.String(), "offloadThreshold") - err := n.pulsar.Client.Get(endpoint, &result) - return result, err -} - -func (n *namespaces) SetMaxConsumersPerTopic(namespace utils.NameSpaceName, max int) error { - endpoint := n.pulsar.endpoint(n.basePath, namespace.String(), "maxConsumersPerTopic") - return n.pulsar.Client.Post(endpoint, max) -} - -func (n *namespaces) GetMaxConsumersPerTopic(namespace utils.NameSpaceName) (int, error) { - var result int - endpoint := n.pulsar.endpoint(n.basePath, namespace.String(), "maxConsumersPerTopic") - err := n.pulsar.Client.Get(endpoint, &result) - return result, err -} - -func (n *namespaces) SetCompactionThreshold(namespace utils.NameSpaceName, threshold int64) error { - endpoint := n.pulsar.endpoint(n.basePath, namespace.String(), "compactionThreshold") - return n.pulsar.Client.Put(endpoint, threshold) -} - -func (n *namespaces) GetCompactionThreshold(namespace utils.NameSpaceName) (int64, error) { - var result int64 - endpoint := n.pulsar.endpoint(n.basePath, namespace.String(), "compactionThreshold") - err := n.pulsar.Client.Get(endpoint, &result) - return result, err -} - -func (n *namespaces) SetMaxProducersPerTopic(namespace utils.NameSpaceName, max int) error { - endpoint := n.pulsar.endpoint(n.basePath, namespace.String(), "maxProducersPerTopic") - return n.pulsar.Client.Post(endpoint, max) -} - -func (n *namespaces) GetMaxProducersPerTopic(namespace utils.NameSpaceName) (int, error) { - var result int - endpoint := n.pulsar.endpoint(n.basePath, namespace.String(), "maxProducersPerTopic") - err := n.pulsar.Client.Get(endpoint, &result) - return result, err -} - -func (n *namespaces) GetNamespaceReplicationClusters(namespace string) ([]string, error) { - var data []string - nsName, err := utils.GetNamespaceName(namespace) - if err != nil { - return nil, err - } - endpoint := n.pulsar.endpoint(n.basePath, nsName.String(), "replication") - err = n.pulsar.Client.Get(endpoint, &data) - return data, err -} - -func (n *namespaces) SetNamespaceReplicationClusters(namespace string, clusterIds []string) error { - nsName, err := utils.GetNamespaceName(namespace) - if err != nil { - return err - } - endpoint := n.pulsar.endpoint(n.basePath, nsName.String(), "replication") - return n.pulsar.Client.Post(endpoint, &clusterIds) -} - -func (n *namespaces) SetNamespaceAntiAffinityGroup(namespace string, namespaceAntiAffinityGroup string) error { - nsName, err := utils.GetNamespaceName(namespace) - if err != nil { - return err - } - endpoint := n.pulsar.endpoint(n.basePath, nsName.String(), "antiAffinity") - return n.pulsar.Client.Post(endpoint, namespaceAntiAffinityGroup) -} - -func (n *namespaces) GetAntiAffinityNamespaces(tenant, cluster, namespaceAntiAffinityGroup string) ([]string, error) { - var data []string - endpoint := n.pulsar.endpoint(n.basePath, cluster, "antiAffinity", namespaceAntiAffinityGroup) - params := map[string]string{ - "property": tenant, - } - _, err := n.pulsar.Client.GetWithQueryParams(endpoint, &data, params, false) - return data, err -} - -func (n *namespaces) GetNamespaceAntiAffinityGroup(namespace string) (string, error) { - nsName, err := utils.GetNamespaceName(namespace) - if err != nil { - return "", err - } - endpoint := n.pulsar.endpoint(n.basePath, nsName.String(), "antiAffinity") - data, err := n.pulsar.Client.GetWithQueryParams(endpoint, nil, nil, false) - return string(data), err -} - -func (n *namespaces) DeleteNamespaceAntiAffinityGroup(namespace string) error { - nsName, err := utils.GetNamespaceName(namespace) - if err != nil { - return err - } - endpoint := n.pulsar.endpoint(n.basePath, nsName.String(), "antiAffinity") - return n.pulsar.Client.Delete(endpoint) -} - -func (n *namespaces) SetDeduplicationStatus(namespace string, enableDeduplication bool) error { - nsName, err := utils.GetNamespaceName(namespace) - if err != nil { - return err - } - endpoint := n.pulsar.endpoint(n.basePath, nsName.String(), "deduplication") - return n.pulsar.Client.Post(endpoint, enableDeduplication) -} - -func (n *namespaces) SetPersistence(namespace string, persistence utils.PersistencePolicies) error { - nsName, err := utils.GetNamespaceName(namespace) - if err != nil { - return err - } - endpoint := n.pulsar.endpoint(n.basePath, nsName.String(), "persistence") - return n.pulsar.Client.Post(endpoint, &persistence) -} - -func (n *namespaces) SetBookieAffinityGroup(namespace string, bookieAffinityGroup utils.BookieAffinityGroupData) error { - nsName, err := utils.GetNamespaceName(namespace) - if err != nil { - return err - } - endpoint := n.pulsar.endpoint(n.basePath, nsName.String(), "persistence", "bookieAffinity") - return n.pulsar.Client.Post(endpoint, &bookieAffinityGroup) -} - -func (n *namespaces) DeleteBookieAffinityGroup(namespace string) error { - nsName, err := utils.GetNamespaceName(namespace) - if err != nil { - return err - } - endpoint := n.pulsar.endpoint(n.basePath, nsName.String(), "persistence", "bookieAffinity") - return n.pulsar.Client.Delete(endpoint) -} - -func (n *namespaces) GetBookieAffinityGroup(namespace string) (*utils.BookieAffinityGroupData, error) { - var data utils.BookieAffinityGroupData - nsName, err := utils.GetNamespaceName(namespace) - if err != nil { - return nil, err - } - endpoint := n.pulsar.endpoint(n.basePath, nsName.String(), "persistence", "bookieAffinity") - err = n.pulsar.Client.Get(endpoint, &data) - return &data, err -} - -func (n *namespaces) GetPersistence(namespace string) (*utils.PersistencePolicies, error) { - var persistence utils.PersistencePolicies - nsName, err := utils.GetNamespaceName(namespace) - if err != nil { - return nil, err - } - endpoint := n.pulsar.endpoint(n.basePath, nsName.String(), "persistence") - err = n.pulsar.Client.Get(endpoint, &persistence) - return &persistence, err -} - -func (n *namespaces) Unload(namespace string) error { - nsName, err := utils.GetNamespaceName(namespace) - if err != nil { - return err - } - endpoint := n.pulsar.endpoint(n.basePath, nsName.String(), "unload") - return n.pulsar.Client.Put(endpoint, nil) -} - -func (n *namespaces) UnloadNamespaceBundle(namespace, bundle string) error { - nsName, err := utils.GetNamespaceName(namespace) - if err != nil { - return err - } - endpoint := n.pulsar.endpoint(n.basePath, nsName.String(), bundle, "unload") - return n.pulsar.Client.Put(endpoint, nil) -} - -func (n *namespaces) SplitNamespaceBundle(namespace, bundle string, unloadSplitBundles bool) error { - nsName, err := utils.GetNamespaceName(namespace) - if err != nil { - return err - } - endpoint := n.pulsar.endpoint(n.basePath, nsName.String(), bundle, "split") - params := map[string]string{ - "unload": strconv.FormatBool(unloadSplitBundles), - } - return n.pulsar.Client.PutWithQueryParams(endpoint, nil, nil, params) -} - -func (n *namespaces) GetNamespacePermissions(namespace utils.NameSpaceName) (map[string][]utils.AuthAction, error) { - endpoint := n.pulsar.endpoint(n.basePath, namespace.String(), "permissions") - var permissions map[string][]utils.AuthAction - err := n.pulsar.Client.Get(endpoint, &permissions) - return permissions, err -} - -func (n *namespaces) GrantNamespacePermission(namespace utils.NameSpaceName, role string, - action []utils.AuthAction) error { - endpoint := n.pulsar.endpoint(n.basePath, namespace.String(), "permissions", role) - s := make([]string, 0) - for _, v := range action { - s = append(s, v.String()) - } - return n.pulsar.Client.Post(endpoint, s) -} - -func (n *namespaces) RevokeNamespacePermission(namespace utils.NameSpaceName, role string) error { - endpoint := n.pulsar.endpoint(n.basePath, namespace.String(), "permissions", role) - return n.pulsar.Client.Delete(endpoint) -} - -func (n *namespaces) GrantSubPermission(namespace utils.NameSpaceName, sName string, roles []string) error { - endpoint := n.pulsar.endpoint(n.basePath, namespace.String(), "permissions", - "subscription", sName) - return n.pulsar.Client.Post(endpoint, roles) -} - -func (n *namespaces) RevokeSubPermission(namespace utils.NameSpaceName, sName, role string) error { - endpoint := n.pulsar.endpoint(n.basePath, namespace.String(), "permissions", - "subscription", sName, role) - return n.pulsar.Client.Delete(endpoint) -} - -func (n *namespaces) SetSubscriptionAuthMode(namespace utils.NameSpaceName, mode utils.SubscriptionAuthMode) error { - endpoint := n.pulsar.endpoint(n.basePath, namespace.String(), "subscriptionAuthMode") - return n.pulsar.Client.Post(endpoint, mode.String()) -} - -func (n *namespaces) SetEncryptionRequiredStatus(namespace utils.NameSpaceName, encrypt bool) error { - endpoint := n.pulsar.endpoint(n.basePath, namespace.String(), "encryptionRequired") - return n.pulsar.Client.Post(endpoint, strconv.FormatBool(encrypt)) -} - -func (n *namespaces) UnsubscribeNamespace(namespace utils.NameSpaceName, sName string) error { - endpoint := n.pulsar.endpoint(n.basePath, namespace.String(), "unsubscribe", url.QueryEscape(sName)) - return n.pulsar.Client.Post(endpoint, nil) -} - -func (n *namespaces) UnsubscribeNamespaceBundle(namespace utils.NameSpaceName, bundle, sName string) error { - endpoint := n.pulsar.endpoint(n.basePath, namespace.String(), bundle, "unsubscribe", url.QueryEscape(sName)) - return n.pulsar.Client.Post(endpoint, nil) -} - -func (n *namespaces) ClearNamespaceBundleBacklogForSubscription(namespace utils.NameSpaceName, - bundle, sName string) error { - endpoint := n.pulsar.endpoint(n.basePath, namespace.String(), bundle, "clearBacklog", url.QueryEscape(sName)) - return n.pulsar.Client.Post(endpoint, nil) -} - -func (n *namespaces) ClearNamespaceBundleBacklog(namespace utils.NameSpaceName, bundle string) error { - endpoint := n.pulsar.endpoint(n.basePath, namespace.String(), bundle, "clearBacklog") - return n.pulsar.Client.Post(endpoint, nil) -} - -func (n *namespaces) ClearNamespaceBacklogForSubscription(namespace utils.NameSpaceName, sName string) error { - endpoint := n.pulsar.endpoint(n.basePath, namespace.String(), "clearBacklog", url.QueryEscape(sName)) - return n.pulsar.Client.Post(endpoint, nil) -} - -func (n *namespaces) ClearNamespaceBacklog(namespace utils.NameSpaceName) error { - endpoint := n.pulsar.endpoint(n.basePath, namespace.String(), "clearBacklog") - return n.pulsar.Client.Post(endpoint, nil) -} - -func (n *namespaces) SetReplicatorDispatchRate(namespace utils.NameSpaceName, rate utils.DispatchRate) error { - endpoint := n.pulsar.endpoint(n.basePath, namespace.String(), "replicatorDispatchRate") - return n.pulsar.Client.Post(endpoint, rate) -} - -func (n *namespaces) GetReplicatorDispatchRate(namespace utils.NameSpaceName) (utils.DispatchRate, error) { - endpoint := n.pulsar.endpoint(n.basePath, namespace.String(), "replicatorDispatchRate") - var rate utils.DispatchRate - err := n.pulsar.Client.Get(endpoint, &rate) - return rate, err -} - -func (n *namespaces) SetSubscriptionDispatchRate(namespace utils.NameSpaceName, rate utils.DispatchRate) error { - endpoint := n.pulsar.endpoint(n.basePath, namespace.String(), "subscriptionDispatchRate") - return n.pulsar.Client.Post(endpoint, rate) -} - -func (n *namespaces) GetSubscriptionDispatchRate(namespace utils.NameSpaceName) (utils.DispatchRate, error) { - endpoint := n.pulsar.endpoint(n.basePath, namespace.String(), "subscriptionDispatchRate") - var rate utils.DispatchRate - err := n.pulsar.Client.Get(endpoint, &rate) - return rate, err -} - -func (n *namespaces) SetSubscribeRate(namespace utils.NameSpaceName, rate utils.SubscribeRate) error { - endpoint := n.pulsar.endpoint(n.basePath, namespace.String(), "subscribeRate") - return n.pulsar.Client.Post(endpoint, rate) -} - -func (n *namespaces) GetSubscribeRate(namespace utils.NameSpaceName) (utils.SubscribeRate, error) { - endpoint := n.pulsar.endpoint(n.basePath, namespace.String(), "subscribeRate") - var rate utils.SubscribeRate - err := n.pulsar.Client.Get(endpoint, &rate) - return rate, err -} - -func (n *namespaces) SetDispatchRate(namespace utils.NameSpaceName, rate utils.DispatchRate) error { - endpoint := n.pulsar.endpoint(n.basePath, namespace.String(), "dispatchRate") - return n.pulsar.Client.Post(endpoint, rate) -} - -func (n *namespaces) GetDispatchRate(namespace utils.NameSpaceName) (utils.DispatchRate, error) { - endpoint := n.pulsar.endpoint(n.basePath, namespace.String(), "dispatchRate") - var rate utils.DispatchRate - err := n.pulsar.Client.Get(endpoint, &rate) - return rate, err -} - -func (n *namespaces) SetPublishRate(namespace utils.NameSpaceName, pubRate utils.PublishRate) error { - endpoint := n.pulsar.endpoint(n.basePath, namespace.String(), "publishRate") - return n.pulsar.Client.Post(endpoint, pubRate) -} - -func (n *namespaces) GetPublishRate(namespace utils.NameSpaceName) (utils.PublishRate, error) { - endpoint := n.pulsar.endpoint(n.basePath, namespace.String(), "publishRate") - var pubRate utils.PublishRate - err := n.pulsar.Client.Get(endpoint, &pubRate) - return pubRate, err -} - -func (n *namespaces) SetIsAllowAutoUpdateSchema(namespace utils.NameSpaceName, isAllowAutoUpdateSchema bool) error { - endpoint := n.pulsar.endpoint(n.basePath, namespace.String(), "isAllowAutoUpdateSchema") - return n.pulsar.Client.Post(endpoint, &isAllowAutoUpdateSchema) -} - -func (n *namespaces) GetIsAllowAutoUpdateSchema(namespace utils.NameSpaceName) (bool, error) { - endpoint := n.pulsar.endpoint(n.basePath, namespace.String(), "isAllowAutoUpdateSchema") - var result bool - err := n.pulsar.Client.Get(endpoint, &result) - return result, err -} - -func (n *namespaces) GetInactiveTopicPolicies(namespace utils.NameSpaceName) (utils.InactiveTopicPolicies, error) { - var out utils.InactiveTopicPolicies - endpoint := n.pulsar.endpoint(n.basePath, namespace.String(), "inactiveTopicPolicies") - err := n.pulsar.Client.Get(endpoint, &out) - return out, err -} - -func (n *namespaces) RemoveInactiveTopicPolicies(namespace utils.NameSpaceName) error { - endpoint := n.pulsar.endpoint(n.basePath, namespace.String(), "inactiveTopicPolicies") - return n.pulsar.Client.Delete(endpoint) -} - -func (n *namespaces) SetInactiveTopicPolicies(namespace utils.NameSpaceName, data utils.InactiveTopicPolicies) error { - endpoint := n.pulsar.endpoint(n.basePath, namespace.String(), "inactiveTopicPolicies") - return n.pulsar.Client.Post(endpoint, data) -} diff --git a/pulsaradmin/pkg/admin/topic.go b/pulsaradmin/pkg/admin/topic.go deleted file mode 100644 index c888827bf8..0000000000 --- a/pulsaradmin/pkg/admin/topic.go +++ /dev/null @@ -1,725 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. - -package admin - -import ( - "fmt" - "strconv" - - "github.com/apache/pulsar-client-go/pulsaradmin/pkg/utils" -) - -// Topics is admin interface for topics management -type Topics interface { - // Create a topic - Create(utils.TopicName, int) error - - // Delete a topic - Delete(utils.TopicName, bool, bool) error - - // Update number of partitions of a non-global partitioned topic - // It requires partitioned-topic to be already exist and number of new partitions must be greater than existing - // number of partitions. Decrementing number of partitions requires deletion of topic which is not supported. - Update(utils.TopicName, int) error - - // GetMetadata returns metadata of a partitioned topic - GetMetadata(utils.TopicName) (utils.PartitionedTopicMetadata, error) - - // List returns the list of topics under a namespace - List(utils.NameSpaceName) ([]string, []string, error) - - // GetInternalInfo returns the internal metadata info for the topic - GetInternalInfo(utils.TopicName) (utils.ManagedLedgerInfo, error) - - // GetPermissions returns permissions on a topic - // Retrieve the effective permissions for a topic. These permissions are defined by the permissions set at the - // namespace level combined (union) with any eventual specific permission set on the topic. - GetPermissions(utils.TopicName) (map[string][]utils.AuthAction, error) - - // GrantPermission grants a new permission to a client role on a single topic - GrantPermission(utils.TopicName, string, []utils.AuthAction) error - - // RevokePermission revokes permissions to a client role on a single topic. If the permission - // was not set at the topic level, but rather at the namespace level, this operation will - // return an error (HTTP status code 412). - RevokePermission(utils.TopicName, string) error - - // Lookup a topic returns the broker URL that serves the topic - Lookup(utils.TopicName) (utils.LookupData, error) - - // GetBundleRange returns a bundle range of a topic - GetBundleRange(utils.TopicName) (string, error) - - // GetLastMessageID returns the last commit message Id of a topic - GetLastMessageID(utils.TopicName) (utils.MessageID, error) - - // GetMessageID returns the message Id by timestamp(ms) of a topic - GetMessageID(utils.TopicName, int64) (utils.MessageID, error) - - // GetStats returns the stats for the topic - // All the rates are computed over a 1 minute window and are relative the last completed 1 minute period - GetStats(utils.TopicName) (utils.TopicStats, error) - - // GetInternalStats returns the internal stats for the topic. - GetInternalStats(utils.TopicName) (utils.PersistentTopicInternalStats, error) - - // GetPartitionedStats returns the stats for the partitioned topic - // All the rates are computed over a 1 minute window and are relative the last completed 1 minute period - GetPartitionedStats(utils.TopicName, bool) (utils.PartitionedTopicStats, error) - - // Terminate the topic and prevent any more messages being published on it - Terminate(utils.TopicName) (utils.MessageID, error) - - // Offload triggers offloading messages in topic to longterm storage - Offload(utils.TopicName, utils.MessageID) error - - // OffloadStatus checks the status of an ongoing offloading operation for a topic - OffloadStatus(utils.TopicName) (utils.OffloadProcessStatus, error) - - // Unload a topic - Unload(utils.TopicName) error - - // Compact triggers compaction to run for a topic. A single topic can only have one instance of compaction - // running at any time. Any attempt to trigger another will be met with a ConflictException. - Compact(utils.TopicName) error - - // CompactStatus checks the status of an ongoing compaction for a topic - CompactStatus(utils.TopicName) (utils.LongRunningProcessStatus, error) - - // GetMessageTTL Get the message TTL for a topic - GetMessageTTL(utils.TopicName) (int, error) - - // SetMessageTTL Set the message TTL for a topic - SetMessageTTL(utils.TopicName, int) error - - // RemoveMessageTTL Remove the message TTL for a topic - RemoveMessageTTL(utils.TopicName) error - - // GetMaxProducers Get max number of producers for a topic - GetMaxProducers(utils.TopicName) (int, error) - - // SetMaxProducers Set max number of producers for a topic - SetMaxProducers(utils.TopicName, int) error - - // RemoveMaxProducers Remove max number of producers for a topic - RemoveMaxProducers(utils.TopicName) error - - // GetMaxConsumers Get max number of consumers for a topic - GetMaxConsumers(utils.TopicName) (int, error) - - // SetMaxConsumers Set max number of consumers for a topic - SetMaxConsumers(utils.TopicName, int) error - - // RemoveMaxConsumers Remove max number of consumers for a topic - RemoveMaxConsumers(utils.TopicName) error - - // GetMaxUnackMessagesPerConsumer Get max unacked messages policy on consumer for a topic - GetMaxUnackMessagesPerConsumer(utils.TopicName) (int, error) - - // SetMaxUnackMessagesPerConsumer Set max unacked messages policy on consumer for a topic - SetMaxUnackMessagesPerConsumer(utils.TopicName, int) error - - // RemoveMaxUnackMessagesPerConsumer Remove max unacked messages policy on consumer for a topic - RemoveMaxUnackMessagesPerConsumer(utils.TopicName) error - - // GetMaxUnackMessagesPerSubscription Get max unacked messages policy on subscription for a topic - GetMaxUnackMessagesPerSubscription(utils.TopicName) (int, error) - - // SetMaxUnackMessagesPerSubscription Set max unacked messages policy on subscription for a topic - SetMaxUnackMessagesPerSubscription(utils.TopicName, int) error - - // RemoveMaxUnackMessagesPerSubscription Remove max unacked messages policy on subscription for a topic - RemoveMaxUnackMessagesPerSubscription(utils.TopicName) error - - // GetPersistence Get the persistence policies for a topic - GetPersistence(utils.TopicName) (*utils.PersistenceData, error) - - // SetPersistence Set the persistence policies for a topic - SetPersistence(utils.TopicName, utils.PersistenceData) error - - // RemovePersistence Remove the persistence policies for a topic - RemovePersistence(utils.TopicName) error - - // GetDelayedDelivery Get the delayed delivery policy for a topic - GetDelayedDelivery(utils.TopicName) (*utils.DelayedDeliveryData, error) - - // SetDelayedDelivery Set the delayed delivery policy on a topic - SetDelayedDelivery(utils.TopicName, utils.DelayedDeliveryData) error - - // RemoveDelayedDelivery Remove the delayed delivery policy on a topic - RemoveDelayedDelivery(utils.TopicName) error - - // GetDispatchRate Get message dispatch rate for a topic - GetDispatchRate(utils.TopicName) (*utils.DispatchRateData, error) - - // SetDispatchRate Set message dispatch rate for a topic - SetDispatchRate(utils.TopicName, utils.DispatchRateData) error - - // RemoveDispatchRate Remove message dispatch rate for a topic - RemoveDispatchRate(utils.TopicName) error - - // GetPublishRate Get message publish rate for a topic - GetPublishRate(utils.TopicName) (*utils.PublishRateData, error) - - // SetPublishRate Set message publish rate for a topic - SetPublishRate(utils.TopicName, utils.PublishRateData) error - - // RemovePublishRate Remove message publish rate for a topic - RemovePublishRate(utils.TopicName) error - - // GetDeduplicationStatus Get the deduplication policy for a topic - GetDeduplicationStatus(utils.TopicName) (bool, error) - - // SetDeduplicationStatus Set the deduplication policy for a topic - SetDeduplicationStatus(utils.TopicName, bool) error - - // RemoveDeduplicationStatus Remove the deduplication policy for a topic - RemoveDeduplicationStatus(utils.TopicName) error - - // GetRetention returns the retention configuration for a topic - GetRetention(utils.TopicName, bool) (*utils.RetentionPolicies, error) - - // RemoveRetention removes the retention configuration on a topic - RemoveRetention(utils.TopicName) error - - // SetRetention sets the retention policy for a topic - SetRetention(utils.TopicName, utils.RetentionPolicies) error - - // Get the compaction threshold for a topic - GetCompactionThreshold(topic utils.TopicName, applied bool) (int64, error) - - // Set the compaction threshold for a topic - SetCompactionThreshold(topic utils.TopicName, threshold int64) error - - // Remove compaction threshold for a topic - RemoveCompactionThreshold(utils.TopicName) error - - // GetBacklogQuotaMap returns backlog quota map for a topic - GetBacklogQuotaMap(topic utils.TopicName, applied bool) (map[utils.BacklogQuotaType]utils.BacklogQuota, error) - - // SetBacklogQuota sets a backlog quota for a topic - SetBacklogQuota(utils.TopicName, utils.BacklogQuota, utils.BacklogQuotaType) error - - // RemoveBacklogQuota removes a backlog quota policy from a topic - RemoveBacklogQuota(utils.TopicName, utils.BacklogQuotaType) error - - // GetInactiveTopicPolicies gets the inactive topic policies on a topic - GetInactiveTopicPolicies(topic utils.TopicName, applied bool) (utils.InactiveTopicPolicies, error) - - // RemoveInactiveTopicPolicies removes inactive topic policies from a topic - RemoveInactiveTopicPolicies(utils.TopicName) error - - // SetInactiveTopicPolicies sets the inactive topic policies on a topic - SetInactiveTopicPolicies(topic utils.TopicName, data utils.InactiveTopicPolicies) error - - // GetReplicationClusters get the replication clusters of a topic - GetReplicationClusters(topic utils.TopicName) ([]string, error) - - // SetReplicationClusters sets the replication clusters on a topic - SetReplicationClusters(topic utils.TopicName, data []string) error -} - -type topics struct { - pulsar *pulsarClient - basePath string - persistentPath string - nonPersistentPath string - lookupPath string -} - -// Check whether the topics struct implements the Topics interface. -var _ Topics = &topics{} - -// Topics is used to access the topics endpoints -func (c *pulsarClient) Topics() Topics { - return &topics{ - pulsar: c, - basePath: "", - persistentPath: "/persistent", - nonPersistentPath: "/non-persistent", - lookupPath: "/lookup/v2/topic", - } -} - -func (t *topics) Create(topic utils.TopicName, partitions int) error { - endpoint := t.pulsar.endpoint(t.basePath, topic.GetRestPath(), "partitions") - data := &partitions - if partitions == 0 { - endpoint = t.pulsar.endpoint(t.basePath, topic.GetRestPath()) - data = nil - } - - return t.pulsar.Client.Put(endpoint, data) -} - -func (t *topics) Delete(topic utils.TopicName, force bool, nonPartitioned bool) error { - endpoint := t.pulsar.endpoint(t.basePath, topic.GetRestPath(), "partitions") - if nonPartitioned { - endpoint = t.pulsar.endpoint(t.basePath, topic.GetRestPath()) - } - params := map[string]string{ - "force": strconv.FormatBool(force), - } - return t.pulsar.Client.DeleteWithQueryParams(endpoint, params) -} - -func (t *topics) Update(topic utils.TopicName, partitions int) error { - endpoint := t.pulsar.endpoint(t.basePath, topic.GetRestPath(), "partitions") - return t.pulsar.Client.Post(endpoint, partitions) -} - -func (t *topics) GetMetadata(topic utils.TopicName) (utils.PartitionedTopicMetadata, error) { - endpoint := t.pulsar.endpoint(t.basePath, topic.GetRestPath(), "partitions") - var partitionedMeta utils.PartitionedTopicMetadata - err := t.pulsar.Client.Get(endpoint, &partitionedMeta) - return partitionedMeta, err -} - -func (t *topics) List(namespace utils.NameSpaceName) ([]string, []string, error) { - var partitionedTopics, nonPartitionedTopics []string - partitionedTopicsChan := make(chan []string) - nonPartitionedTopicsChan := make(chan []string) - errChan := make(chan error) - - pp := t.pulsar.endpoint(t.persistentPath, namespace.String(), "partitioned") - np := t.pulsar.endpoint(t.nonPersistentPath, namespace.String(), "partitioned") - p := t.pulsar.endpoint(t.persistentPath, namespace.String()) - n := t.pulsar.endpoint(t.nonPersistentPath, namespace.String()) - - go t.getTopics(pp, partitionedTopicsChan, errChan) - go t.getTopics(np, partitionedTopicsChan, errChan) - go t.getTopics(p, nonPartitionedTopicsChan, errChan) - go t.getTopics(n, nonPartitionedTopicsChan, errChan) - - requestCount := 4 - for { - select { - case err := <-errChan: - if err != nil { - return nil, nil, err - } - continue - case pTopic := <-partitionedTopicsChan: - requestCount-- - partitionedTopics = append(partitionedTopics, pTopic...) - case npTopic := <-nonPartitionedTopicsChan: - requestCount-- - nonPartitionedTopics = append(nonPartitionedTopics, npTopic...) - } - if requestCount == 0 { - break - } - } - return partitionedTopics, nonPartitionedTopics, nil -} - -func (t *topics) getTopics(endpoint string, out chan<- []string, err chan<- error) { - var topics []string - err <- t.pulsar.Client.Get(endpoint, &topics) - out <- topics -} - -func (t *topics) GetInternalInfo(topic utils.TopicName) (utils.ManagedLedgerInfo, error) { - endpoint := t.pulsar.endpoint(t.basePath, topic.GetRestPath(), "internal-info") - var info utils.ManagedLedgerInfo - err := t.pulsar.Client.Get(endpoint, &info) - return info, err -} - -func (t *topics) GetPermissions(topic utils.TopicName) (map[string][]utils.AuthAction, error) { - var permissions map[string][]utils.AuthAction - endpoint := t.pulsar.endpoint(t.basePath, topic.GetRestPath(), "permissions") - err := t.pulsar.Client.Get(endpoint, &permissions) - return permissions, err -} - -func (t *topics) GrantPermission(topic utils.TopicName, role string, action []utils.AuthAction) error { - endpoint := t.pulsar.endpoint(t.basePath, topic.GetRestPath(), "permissions", role) - s := []string{} - for _, v := range action { - s = append(s, v.String()) - } - return t.pulsar.Client.Post(endpoint, s) -} - -func (t *topics) RevokePermission(topic utils.TopicName, role string) error { - endpoint := t.pulsar.endpoint(t.basePath, topic.GetRestPath(), "permissions", role) - return t.pulsar.Client.Delete(endpoint) -} - -func (t *topics) Lookup(topic utils.TopicName) (utils.LookupData, error) { - var lookup utils.LookupData - endpoint := fmt.Sprintf("%s/%s", t.lookupPath, topic.GetRestPath()) - err := t.pulsar.Client.Get(endpoint, &lookup) - return lookup, err -} - -func (t *topics) GetBundleRange(topic utils.TopicName) (string, error) { - endpoint := fmt.Sprintf("%s/%s/%s", t.lookupPath, topic.GetRestPath(), "bundle") - data, err := t.pulsar.Client.GetWithQueryParams(endpoint, nil, nil, false) - return string(data), err -} - -func (t *topics) GetLastMessageID(topic utils.TopicName) (utils.MessageID, error) { - var messageID utils.MessageID - endpoint := t.pulsar.endpoint(t.basePath, topic.GetRestPath(), "lastMessageId") - err := t.pulsar.Client.Get(endpoint, &messageID) - return messageID, err -} - -func (t *topics) GetMessageID(topic utils.TopicName, timestamp int64) (utils.MessageID, error) { - var messageID utils.MessageID - endpoint := t.pulsar.endpoint(t.basePath, topic.GetRestPath(), "messageid", strconv.FormatInt(timestamp, 10)) - err := t.pulsar.Client.Get(endpoint, &messageID) - return messageID, err -} - -func (t *topics) GetStats(topic utils.TopicName) (utils.TopicStats, error) { - var stats utils.TopicStats - endpoint := t.pulsar.endpoint(t.basePath, topic.GetRestPath(), "stats") - err := t.pulsar.Client.Get(endpoint, &stats) - return stats, err -} - -func (t *topics) GetInternalStats(topic utils.TopicName) (utils.PersistentTopicInternalStats, error) { - var stats utils.PersistentTopicInternalStats - endpoint := t.pulsar.endpoint(t.basePath, topic.GetRestPath(), "internalStats") - err := t.pulsar.Client.Get(endpoint, &stats) - return stats, err -} - -func (t *topics) GetPartitionedStats(topic utils.TopicName, perPartition bool) (utils.PartitionedTopicStats, error) { - var stats utils.PartitionedTopicStats - endpoint := t.pulsar.endpoint(t.basePath, topic.GetRestPath(), "partitioned-stats") - params := map[string]string{ - "perPartition": strconv.FormatBool(perPartition), - } - _, err := t.pulsar.Client.GetWithQueryParams(endpoint, &stats, params, true) - return stats, err -} - -func (t *topics) Terminate(topic utils.TopicName) (utils.MessageID, error) { - endpoint := t.pulsar.endpoint(t.basePath, topic.GetRestPath(), "terminate") - var messageID utils.MessageID - err := t.pulsar.Client.PostWithObj(endpoint, nil, &messageID) - return messageID, err -} - -func (t *topics) Offload(topic utils.TopicName, messageID utils.MessageID) error { - endpoint := t.pulsar.endpoint(t.basePath, topic.GetRestPath(), "offload") - return t.pulsar.Client.Put(endpoint, messageID) -} - -func (t *topics) OffloadStatus(topic utils.TopicName) (utils.OffloadProcessStatus, error) { - endpoint := t.pulsar.endpoint(t.basePath, topic.GetRestPath(), "offload") - var status utils.OffloadProcessStatus - err := t.pulsar.Client.Get(endpoint, &status) - return status, err -} - -func (t *topics) Unload(topic utils.TopicName) error { - endpoint := t.pulsar.endpoint(t.basePath, topic.GetRestPath(), "unload") - return t.pulsar.Client.Put(endpoint, nil) -} - -func (t *topics) Compact(topic utils.TopicName) error { - endpoint := t.pulsar.endpoint(t.basePath, topic.GetRestPath(), "compaction") - return t.pulsar.Client.Put(endpoint, nil) -} - -func (t *topics) CompactStatus(topic utils.TopicName) (utils.LongRunningProcessStatus, error) { - endpoint := t.pulsar.endpoint(t.basePath, topic.GetRestPath(), "compaction") - var status utils.LongRunningProcessStatus - err := t.pulsar.Client.Get(endpoint, &status) - return status, err -} - -func (t *topics) GetMessageTTL(topic utils.TopicName) (int, error) { - var ttl int - endpoint := t.pulsar.endpoint(t.basePath, topic.GetRestPath(), "messageTTL") - err := t.pulsar.Client.Get(endpoint, &ttl) - return ttl, err -} - -func (t *topics) SetMessageTTL(topic utils.TopicName, messageTTL int) error { - endpoint := t.pulsar.endpoint(t.basePath, topic.GetRestPath(), "messageTTL") - var params = make(map[string]string) - params["messageTTL"] = strconv.Itoa(messageTTL) - err := t.pulsar.Client.PostWithQueryParams(endpoint, nil, params) - return err -} - -func (t *topics) RemoveMessageTTL(topic utils.TopicName) error { - endpoint := t.pulsar.endpoint(t.basePath, topic.GetRestPath(), "messageTTL") - var params = make(map[string]string) - params["messageTTL"] = strconv.Itoa(0) - err := t.pulsar.Client.DeleteWithQueryParams(endpoint, params) - return err -} - -func (t *topics) GetMaxProducers(topic utils.TopicName) (int, error) { - var maxProducers int - endpoint := t.pulsar.endpoint(t.basePath, topic.GetRestPath(), "maxProducers") - err := t.pulsar.Client.Get(endpoint, &maxProducers) - return maxProducers, err -} - -func (t *topics) SetMaxProducers(topic utils.TopicName, maxProducers int) error { - endpoint := t.pulsar.endpoint(t.basePath, topic.GetRestPath(), "maxProducers") - err := t.pulsar.Client.Post(endpoint, &maxProducers) - return err -} - -func (t *topics) RemoveMaxProducers(topic utils.TopicName) error { - endpoint := t.pulsar.endpoint(t.basePath, topic.GetRestPath(), "maxProducers") - err := t.pulsar.Client.Delete(endpoint) - return err -} - -func (t *topics) GetMaxConsumers(topic utils.TopicName) (int, error) { - var maxConsumers int - endpoint := t.pulsar.endpoint(t.basePath, topic.GetRestPath(), "maxConsumers") - err := t.pulsar.Client.Get(endpoint, &maxConsumers) - return maxConsumers, err -} - -func (t *topics) SetMaxConsumers(topic utils.TopicName, maxConsumers int) error { - endpoint := t.pulsar.endpoint(t.basePath, topic.GetRestPath(), "maxConsumers") - err := t.pulsar.Client.Post(endpoint, &maxConsumers) - return err -} - -func (t *topics) RemoveMaxConsumers(topic utils.TopicName) error { - endpoint := t.pulsar.endpoint(t.basePath, topic.GetRestPath(), "maxConsumers") - err := t.pulsar.Client.Delete(endpoint) - return err -} - -func (t *topics) GetMaxUnackMessagesPerConsumer(topic utils.TopicName) (int, error) { - var maxNum int - endpoint := t.pulsar.endpoint(t.basePath, topic.GetRestPath(), "maxUnackedMessagesOnConsumer") - err := t.pulsar.Client.Get(endpoint, &maxNum) - return maxNum, err -} - -func (t *topics) SetMaxUnackMessagesPerConsumer(topic utils.TopicName, maxUnackedNum int) error { - endpoint := t.pulsar.endpoint(t.basePath, topic.GetRestPath(), "maxUnackedMessagesOnConsumer") - return t.pulsar.Client.Post(endpoint, &maxUnackedNum) -} - -func (t *topics) RemoveMaxUnackMessagesPerConsumer(topic utils.TopicName) error { - endpoint := t.pulsar.endpoint(t.basePath, topic.GetRestPath(), "maxUnackedMessagesOnConsumer") - return t.pulsar.Client.Delete(endpoint) -} - -func (t *topics) GetMaxUnackMessagesPerSubscription(topic utils.TopicName) (int, error) { - var maxNum int - endpoint := t.pulsar.endpoint(t.basePath, topic.GetRestPath(), "maxUnackedMessagesOnSubscription") - err := t.pulsar.Client.Get(endpoint, &maxNum) - return maxNum, err -} - -func (t *topics) SetMaxUnackMessagesPerSubscription(topic utils.TopicName, maxUnackedNum int) error { - endpoint := t.pulsar.endpoint(t.basePath, topic.GetRestPath(), "maxUnackedMessagesOnSubscription") - return t.pulsar.Client.Post(endpoint, &maxUnackedNum) -} - -func (t *topics) RemoveMaxUnackMessagesPerSubscription(topic utils.TopicName) error { - endpoint := t.pulsar.endpoint(t.basePath, topic.GetRestPath(), "maxUnackedMessagesOnSubscription") - return t.pulsar.Client.Delete(endpoint) -} - -func (t *topics) GetPersistence(topic utils.TopicName) (*utils.PersistenceData, error) { - var persistenceData utils.PersistenceData - endpoint := t.pulsar.endpoint(t.basePath, topic.GetRestPath(), "persistence") - err := t.pulsar.Client.Get(endpoint, &persistenceData) - return &persistenceData, err -} - -func (t *topics) SetPersistence(topic utils.TopicName, persistenceData utils.PersistenceData) error { - endpoint := t.pulsar.endpoint(t.basePath, topic.GetRestPath(), "persistence") - return t.pulsar.Client.Post(endpoint, &persistenceData) -} - -func (t *topics) RemovePersistence(topic utils.TopicName) error { - endpoint := t.pulsar.endpoint(t.basePath, topic.GetRestPath(), "persistence") - return t.pulsar.Client.Delete(endpoint) -} - -func (t *topics) GetDelayedDelivery(topic utils.TopicName) (*utils.DelayedDeliveryData, error) { - var delayedDeliveryData utils.DelayedDeliveryData - endpoint := t.pulsar.endpoint(t.basePath, topic.GetRestPath(), "delayedDelivery") - err := t.pulsar.Client.Get(endpoint, &delayedDeliveryData) - return &delayedDeliveryData, err -} - -func (t *topics) SetDelayedDelivery(topic utils.TopicName, delayedDeliveryData utils.DelayedDeliveryData) error { - endpoint := t.pulsar.endpoint(t.basePath, topic.GetRestPath(), "delayedDelivery") - return t.pulsar.Client.Post(endpoint, &delayedDeliveryData) -} - -func (t *topics) RemoveDelayedDelivery(topic utils.TopicName) error { - endpoint := t.pulsar.endpoint(t.basePath, topic.GetRestPath(), "delayedDelivery") - return t.pulsar.Client.Delete(endpoint) -} - -func (t *topics) GetDispatchRate(topic utils.TopicName) (*utils.DispatchRateData, error) { - var dispatchRateData utils.DispatchRateData - endpoint := t.pulsar.endpoint(t.basePath, topic.GetRestPath(), "dispatchRate") - err := t.pulsar.Client.Get(endpoint, &dispatchRateData) - return &dispatchRateData, err -} - -func (t *topics) SetDispatchRate(topic utils.TopicName, dispatchRateData utils.DispatchRateData) error { - endpoint := t.pulsar.endpoint(t.basePath, topic.GetRestPath(), "dispatchRate") - return t.pulsar.Client.Post(endpoint, &dispatchRateData) -} - -func (t *topics) RemoveDispatchRate(topic utils.TopicName) error { - endpoint := t.pulsar.endpoint(t.basePath, topic.GetRestPath(), "dispatchRate") - return t.pulsar.Client.Delete(endpoint) -} - -func (t *topics) GetPublishRate(topic utils.TopicName) (*utils.PublishRateData, error) { - var publishRateData utils.PublishRateData - endpoint := t.pulsar.endpoint(t.basePath, topic.GetRestPath(), "publishRate") - err := t.pulsar.Client.Get(endpoint, &publishRateData) - return &publishRateData, err -} - -func (t *topics) SetPublishRate(topic utils.TopicName, publishRateData utils.PublishRateData) error { - endpoint := t.pulsar.endpoint(t.basePath, topic.GetRestPath(), "publishRate") - return t.pulsar.Client.Post(endpoint, &publishRateData) -} - -func (t *topics) RemovePublishRate(topic utils.TopicName) error { - endpoint := t.pulsar.endpoint(t.basePath, topic.GetRestPath(), "publishRate") - return t.pulsar.Client.Delete(endpoint) -} -func (t *topics) GetDeduplicationStatus(topic utils.TopicName) (bool, error) { - var enabled bool - endpoint := t.pulsar.endpoint(t.basePath, topic.GetRestPath(), "deduplicationEnabled") - err := t.pulsar.Client.Get(endpoint, &enabled) - return enabled, err -} - -func (t *topics) SetDeduplicationStatus(topic utils.TopicName, enabled bool) error { - endpoint := t.pulsar.endpoint(t.basePath, topic.GetRestPath(), "deduplicationEnabled") - return t.pulsar.Client.Post(endpoint, enabled) -} -func (t *topics) RemoveDeduplicationStatus(topic utils.TopicName) error { - endpoint := t.pulsar.endpoint(t.basePath, topic.GetRestPath(), "deduplicationEnabled") - return t.pulsar.Client.Delete(endpoint) -} - -func (t *topics) GetRetention(topic utils.TopicName, applied bool) (*utils.RetentionPolicies, error) { - var policy utils.RetentionPolicies - endpoint := t.pulsar.endpoint(t.basePath, topic.GetRestPath(), "retention") - _, err := t.pulsar.Client.GetWithQueryParams(endpoint, &policy, map[string]string{ - "applied": strconv.FormatBool(applied), - }, true) - return &policy, err -} - -func (t *topics) RemoveRetention(topic utils.TopicName) error { - endpoint := t.pulsar.endpoint(t.basePath, topic.GetRestPath(), "retention") - return t.pulsar.Client.Delete(endpoint) -} - -func (t *topics) SetRetention(topic utils.TopicName, data utils.RetentionPolicies) error { - endpoint := t.pulsar.endpoint(t.basePath, topic.GetRestPath(), "retention") - return t.pulsar.Client.Post(endpoint, data) -} - -func (t *topics) GetCompactionThreshold(topic utils.TopicName, applied bool) (int64, error) { - var threshold int64 - endpoint := t.pulsar.endpoint(t.basePath, topic.GetRestPath(), "compactionThreshold") - _, err := t.pulsar.Client.GetWithQueryParams(endpoint, &threshold, map[string]string{ - "applied": strconv.FormatBool(applied), - }, true) - return threshold, err -} - -func (t *topics) SetCompactionThreshold(topic utils.TopicName, threshold int64) error { - endpoint := t.pulsar.endpoint(t.basePath, topic.GetRestPath(), "compactionThreshold") - err := t.pulsar.Client.Post(endpoint, threshold) - return err -} - -func (t *topics) RemoveCompactionThreshold(topic utils.TopicName) error { - endpoint := t.pulsar.endpoint(t.basePath, topic.GetRestPath(), "compactionThreshold") - err := t.pulsar.Client.Delete(endpoint) - return err -} - -func (t *topics) GetBacklogQuotaMap(topic utils.TopicName, applied bool) (map[utils.BacklogQuotaType]utils.BacklogQuota, - error) { - var backlogQuotaMap map[utils.BacklogQuotaType]utils.BacklogQuota - endpoint := t.pulsar.endpoint(t.basePath, topic.GetRestPath(), "backlogQuotaMap") - - queryParams := map[string]string{"applied": strconv.FormatBool(applied)} - _, err := t.pulsar.Client.GetWithQueryParams(endpoint, &backlogQuotaMap, queryParams, true) - - return backlogQuotaMap, err -} - -func (t *topics) SetBacklogQuota(topic utils.TopicName, backlogQuota utils.BacklogQuota, - backlogQuotaType utils.BacklogQuotaType) error { - endpoint := t.pulsar.endpoint(t.basePath, topic.GetRestPath(), "backlogQuota") - params := make(map[string]string) - params["backlogQuotaType"] = string(backlogQuotaType) - return t.pulsar.Client.PostWithQueryParams(endpoint, &backlogQuota, params) -} - -func (t *topics) RemoveBacklogQuota(topic utils.TopicName, backlogQuotaType utils.BacklogQuotaType) error { - endpoint := t.pulsar.endpoint(t.basePath, topic.GetRestPath(), "backlogQuota") - return t.pulsar.Client.DeleteWithQueryParams(endpoint, map[string]string{ - "backlogQuotaType": string(backlogQuotaType), - }) -} - -func (t *topics) GetInactiveTopicPolicies(topic utils.TopicName, applied bool) (utils.InactiveTopicPolicies, error) { - var out utils.InactiveTopicPolicies - endpoint := t.pulsar.endpoint(t.basePath, topic.GetRestPath(), "inactiveTopicPolicies") - _, err := t.pulsar.Client.GetWithQueryParams(endpoint, &out, map[string]string{ - "applied": strconv.FormatBool(applied), - }, true) - return out, err -} - -func (t *topics) RemoveInactiveTopicPolicies(topic utils.TopicName) error { - endpoint := t.pulsar.endpoint(t.basePath, topic.GetRestPath(), "inactiveTopicPolicies") - return t.pulsar.Client.Delete(endpoint) -} - -func (t *topics) SetInactiveTopicPolicies(topic utils.TopicName, data utils.InactiveTopicPolicies) error { - endpoint := t.pulsar.endpoint(t.basePath, topic.GetRestPath(), "inactiveTopicPolicies") - return t.pulsar.Client.Post(endpoint, data) -} - -func (t *topics) SetReplicationClusters(topic utils.TopicName, data []string) error { - endpoint := t.pulsar.endpoint(t.basePath, topic.GetRestPath(), "replication") - return t.pulsar.Client.Post(endpoint, data) -} - -func (t *topics) GetReplicationClusters(topic utils.TopicName) ([]string, error) { - var data []string - endpoint := t.pulsar.endpoint(t.basePath, topic.GetRestPath(), "replication") - err := t.pulsar.Client.Get(endpoint, &data) - return data, err -} diff --git a/pulsaradmin/pkg/rest/errors.go b/pulsaradmin/pkg/rest/errors.go deleted file mode 100644 index dc611ec388..0000000000 --- a/pulsaradmin/pkg/rest/errors.go +++ /dev/null @@ -1,35 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. - -package rest - -import "fmt" - -// Error is a admin error type -type Error struct { - Reason string `json:"reason"` - Code int -} - -func (e Error) Error() string { - return fmt.Sprintf("code: %d reason: %s", e.Code, e.Reason) -} - -func IsAdminError(err error) bool { - _, ok := err.(Error) - return ok -} diff --git a/pulsaradmin/pkg/utils/policies.go b/pulsaradmin/policies.go similarity index 99% rename from pulsaradmin/pkg/utils/policies.go rename to pulsaradmin/policies.go index 3d727994c3..4466a87b3b 100644 --- a/pulsaradmin/pkg/utils/policies.go +++ b/pulsaradmin/policies.go @@ -15,7 +15,7 @@ // specific language governing permissions and limitations // under the License. -package utils +package pulsaradmin const ( FirstBoundary string = "0x00000000" diff --git a/pulsaradmin/pkg/utils/producer_config.go b/pulsaradmin/producer_config.go similarity index 98% rename from pulsaradmin/pkg/utils/producer_config.go rename to pulsaradmin/producer_config.go index d4c1c3eb6d..0e90449247 100644 --- a/pulsaradmin/pkg/utils/producer_config.go +++ b/pulsaradmin/producer_config.go @@ -15,7 +15,7 @@ // specific language governing permissions and limitations // under the License. -package utils +package pulsaradmin type ProducerConfig struct { MaxPendingMessages int `json:"maxPendingMessages" yaml:"maxPendingMessages"` diff --git a/pulsaradmin/pkg/utils/publish_rate.go b/pulsaradmin/publish_rate.go similarity index 98% rename from pulsaradmin/pkg/utils/publish_rate.go rename to pulsaradmin/publish_rate.go index 9dbc2d00d2..fb104fa895 100644 --- a/pulsaradmin/pkg/utils/publish_rate.go +++ b/pulsaradmin/publish_rate.go @@ -15,7 +15,7 @@ // specific language governing permissions and limitations // under the License. -package utils +package pulsaradmin type PublishRate struct { PublishThrottlingRateInMsg int `json:"publishThrottlingRateInMsg"` diff --git a/pulsaradmin/pkg/utils/resource_quota.go b/pulsaradmin/resource_quota.go similarity index 98% rename from pulsaradmin/pkg/utils/resource_quota.go rename to pulsaradmin/resource_quota.go index d9ef4f74db..de109e916d 100644 --- a/pulsaradmin/pkg/utils/resource_quota.go +++ b/pulsaradmin/resource_quota.go @@ -15,7 +15,7 @@ // specific language governing permissions and limitations // under the License. -package utils +package pulsaradmin type ResourceQuota struct { // messages published per second diff --git a/pulsaradmin/pkg/utils/resources.go b/pulsaradmin/resources.go similarity index 98% rename from pulsaradmin/pkg/utils/resources.go rename to pulsaradmin/resources.go index a4f3ddbcbe..c2fc55ba36 100644 --- a/pulsaradmin/pkg/utils/resources.go +++ b/pulsaradmin/resources.go @@ -15,7 +15,7 @@ // specific language governing permissions and limitations // under the License. -package utils +package pulsaradmin type Resources struct { CPU float64 `json:"cpu"` diff --git a/pulsaradmin/pkg/utils/retention_policies.go b/pulsaradmin/retention_policies.go similarity index 98% rename from pulsaradmin/pkg/utils/retention_policies.go rename to pulsaradmin/retention_policies.go index 55bf915ed2..c55f8223ca 100644 --- a/pulsaradmin/pkg/utils/retention_policies.go +++ b/pulsaradmin/retention_policies.go @@ -15,7 +15,7 @@ // specific language governing permissions and limitations // under the License. -package utils +package pulsaradmin type RetentionPolicies struct { RetentionTimeInMinutes int `json:"retentionTimeInMinutes"` diff --git a/pulsaradmin/pkg/utils/schema_strategy.go b/pulsaradmin/schema_strategy.go similarity index 99% rename from pulsaradmin/pkg/utils/schema_strategy.go rename to pulsaradmin/schema_strategy.go index 176f0e0a90..22098852bd 100644 --- a/pulsaradmin/pkg/utils/schema_strategy.go +++ b/pulsaradmin/schema_strategy.go @@ -15,7 +15,7 @@ // specific language governing permissions and limitations // under the License. -package utils +package pulsaradmin import "github.com/pkg/errors" diff --git a/pulsaradmin/pkg/utils/schema_util.go b/pulsaradmin/schema_util.go similarity index 99% rename from pulsaradmin/pkg/utils/schema_util.go rename to pulsaradmin/schema_util.go index 08aaf54ac6..57c21f7224 100644 --- a/pulsaradmin/pkg/utils/schema_util.go +++ b/pulsaradmin/schema_util.go @@ -15,7 +15,7 @@ // specific language governing permissions and limitations // under the License. -package utils +package pulsaradmin type SchemaInfo struct { Name string `json:"name"` diff --git a/pulsaradmin/pkg/utils/sink_config.go b/pulsaradmin/sink_config.go similarity index 99% rename from pulsaradmin/pkg/utils/sink_config.go rename to pulsaradmin/sink_config.go index 0e9163bf91..e198f460cd 100644 --- a/pulsaradmin/pkg/utils/sink_config.go +++ b/pulsaradmin/sink_config.go @@ -15,7 +15,7 @@ // specific language governing permissions and limitations // under the License. -package utils +package pulsaradmin type SinkConfig struct { TopicsPattern *string `json:"topicsPattern,omitempty" yaml:"topicsPattern"` diff --git a/pulsaradmin/pkg/utils/sink_status.go b/pulsaradmin/sink_status.go similarity index 99% rename from pulsaradmin/pkg/utils/sink_status.go rename to pulsaradmin/sink_status.go index 6cdb091fac..09be8a9909 100644 --- a/pulsaradmin/pkg/utils/sink_status.go +++ b/pulsaradmin/sink_status.go @@ -15,7 +15,7 @@ // specific language governing permissions and limitations // under the License. -package utils +package pulsaradmin type SinkStatus struct { // The total number of sink instances that ought to be running diff --git a/pulsaradmin/pkg/utils/source_config.go b/pulsaradmin/source_config.go similarity index 99% rename from pulsaradmin/pkg/utils/source_config.go rename to pulsaradmin/source_config.go index 7b0747610f..ade05c6672 100644 --- a/pulsaradmin/pkg/utils/source_config.go +++ b/pulsaradmin/source_config.go @@ -15,7 +15,7 @@ // specific language governing permissions and limitations // under the License. -package utils +package pulsaradmin type SourceConfig struct { Tenant string `json:"tenant,omitempty" yaml:"tenant"` diff --git a/pulsaradmin/pkg/utils/source_status.go b/pulsaradmin/source_status.go similarity index 99% rename from pulsaradmin/pkg/utils/source_status.go rename to pulsaradmin/source_status.go index 71df5a4fa8..917afd3033 100644 --- a/pulsaradmin/pkg/utils/source_status.go +++ b/pulsaradmin/source_status.go @@ -15,7 +15,7 @@ // specific language governing permissions and limitations // under the License. -package utils +package pulsaradmin type SourceStatus struct { NumInstances int `json:"numInstances"` diff --git a/pulsaradmin/pkg/utils/subscription_auth_mode.go b/pulsaradmin/subscription_auth_mode.go similarity index 98% rename from pulsaradmin/pkg/utils/subscription_auth_mode.go rename to pulsaradmin/subscription_auth_mode.go index 795b6d0aea..5112dc4239 100644 --- a/pulsaradmin/pkg/utils/subscription_auth_mode.go +++ b/pulsaradmin/subscription_auth_mode.go @@ -15,7 +15,7 @@ // specific language governing permissions and limitations // under the License. -package utils +package pulsaradmin import "github.com/pkg/errors" diff --git a/pulsaradmin/pkg/utils/topic_auto_creation_config.go b/pulsaradmin/topic_auto_creation_config.go similarity index 98% rename from pulsaradmin/pkg/utils/topic_auto_creation_config.go rename to pulsaradmin/topic_auto_creation_config.go index 6664655974..f3603b9507 100644 --- a/pulsaradmin/pkg/utils/topic_auto_creation_config.go +++ b/pulsaradmin/topic_auto_creation_config.go @@ -15,7 +15,7 @@ // specific language governing permissions and limitations // under the License. -package utils +package pulsaradmin type TopicAutoCreationConfig struct { Allow bool `json:"allowAutoTopicCreation"` diff --git a/pulsaradmin/pkg/utils/topic_domain.go b/pulsaradmin/topic_domain.go similarity index 98% rename from pulsaradmin/pkg/utils/topic_domain.go rename to pulsaradmin/topic_domain.go index 98c59a9cec..b0ed5ee6c9 100644 --- a/pulsaradmin/pkg/utils/topic_domain.go +++ b/pulsaradmin/topic_domain.go @@ -15,7 +15,7 @@ // specific language governing permissions and limitations // under the License. -package utils +package pulsaradmin import "github.com/pkg/errors" diff --git a/pulsaradmin/pkg/utils/topic_name.go b/pulsaradmin/topic_name.go similarity index 99% rename from pulsaradmin/pkg/utils/topic_name.go rename to pulsaradmin/topic_name.go index 268abd73d1..9aee5fb33c 100644 --- a/pulsaradmin/pkg/utils/topic_name.go +++ b/pulsaradmin/topic_name.go @@ -15,7 +15,7 @@ // specific language governing permissions and limitations // under the License. -package utils +package pulsaradmin import ( "fmt" diff --git a/pulsaradmin/pkg/utils/topic_name_test.go b/pulsaradmin/topic_name_test.go similarity index 99% rename from pulsaradmin/pkg/utils/topic_name_test.go rename to pulsaradmin/topic_name_test.go index 27e5002488..972dd15cf3 100644 --- a/pulsaradmin/pkg/utils/topic_name_test.go +++ b/pulsaradmin/topic_name_test.go @@ -15,7 +15,7 @@ // specific language governing permissions and limitations // under the License. -package utils +package pulsaradmin import ( "testing" diff --git a/pulsaradmin/pkg/utils/topic_type.go b/pulsaradmin/topic_type.go similarity index 98% rename from pulsaradmin/pkg/utils/topic_type.go rename to pulsaradmin/topic_type.go index 18320594ac..518fcb91f3 100644 --- a/pulsaradmin/pkg/utils/topic_type.go +++ b/pulsaradmin/topic_type.go @@ -15,7 +15,7 @@ // specific language governing permissions and limitations // under the License. -package utils +package pulsaradmin import "github.com/pkg/errors" diff --git a/pulsaradmin/pkg/utils/topics_stats_stream.go b/pulsaradmin/topics_stats_stream.go similarity index 97% rename from pulsaradmin/pkg/utils/topics_stats_stream.go rename to pulsaradmin/topics_stats_stream.go index 7554609e6e..a31ea3cbaa 100644 --- a/pulsaradmin/pkg/utils/topics_stats_stream.go +++ b/pulsaradmin/topics_stats_stream.go @@ -15,7 +15,7 @@ // specific language governing permissions and limitations // under the License. -package utils +package pulsaradmin // var TopicsMap map[string]map[string]map[string]TopicStats diff --git a/pulsaradmin/pkg/utils/update_options.go b/pulsaradmin/update_options.go similarity index 98% rename from pulsaradmin/pkg/utils/update_options.go rename to pulsaradmin/update_options.go index d78fccfcec..19eaac51a4 100644 --- a/pulsaradmin/pkg/utils/update_options.go +++ b/pulsaradmin/update_options.go @@ -15,7 +15,7 @@ // specific language governing permissions and limitations // under the License. -package utils +package pulsaradmin // Options while updating the sink type UpdateOptions struct { diff --git a/pulsaradmin/pkg/utils/window_confing.go b/pulsaradmin/window_confing.go similarity index 98% rename from pulsaradmin/pkg/utils/window_confing.go rename to pulsaradmin/window_confing.go index ccde3b68fc..cb8056f9b3 100644 --- a/pulsaradmin/pkg/utils/window_confing.go +++ b/pulsaradmin/window_confing.go @@ -15,7 +15,7 @@ // specific language governing permissions and limitations // under the License. -package utils +package pulsaradmin const WindowConfigKey = "__WINDOWCONFIGS__" diff --git a/pulsaradmin/pkg/utils/worker_info.go b/pulsaradmin/worker_info.go similarity index 98% rename from pulsaradmin/pkg/utils/worker_info.go rename to pulsaradmin/worker_info.go index bd0dd806c0..42538b1b78 100644 --- a/pulsaradmin/pkg/utils/worker_info.go +++ b/pulsaradmin/worker_info.go @@ -15,7 +15,7 @@ // specific language governing permissions and limitations // under the License. -package utils +package pulsaradmin type WorkerInfo struct { WorkerID string `json:"workerId"`