From 58c0846c47a69c43e3e689acc52ed4df91d94b0a Mon Sep 17 00:00:00 2001 From: hebestreit Date: Tue, 3 Sep 2024 22:53:59 +0200 Subject: [PATCH 1/2] Added namespace column to list repositories which are not owned by the authenticated user --- dockerhub/table_dockerhub_repository.go | 36 +++++++++++++++++++++--- dockerhub/table_dockerhub_tag.go | 9 ++++++ docs/tables/dockerhub_repository.md | 33 ++++++++++++++++++++++ docs/tables/dockerhub_tag.md | 37 +++++++++++++++++++++++++ 4 files changed, 111 insertions(+), 4 deletions(-) diff --git a/dockerhub/table_dockerhub_repository.go b/dockerhub/table_dockerhub_repository.go index 4f38496..08ea2e7 100644 --- a/dockerhub/table_dockerhub_repository.go +++ b/dockerhub/table_dockerhub_repository.go @@ -2,7 +2,6 @@ package dockerhub import ( "context" - "github.com/turbot/steampipe-plugin-sdk/v5/grpc/proto" "github.com/turbot/steampipe-plugin-sdk/v5/plugin" "github.com/turbot/steampipe-plugin-sdk/v5/plugin/transform" @@ -16,8 +15,17 @@ func tableDockerHubRepository(_ context.Context) *plugin.Table { Description: "Get details of all the repositories in your DockerHub.", List: &plugin.ListConfig{ Hydrate: listRepositories, + KeyColumns: []*plugin.KeyColumn{ + {Name: "namespace", Require: plugin.Optional, Operators: []string{"="}}, + }, }, Columns: commonColumns([]*plugin.Column{ + { + Name: "namespace", + Type: proto.ColumnType_STRING, + Description: "Namespace of the repository.", + Transform: transform.FromQual("namespace"), + }, { Name: "name", Type: proto.ColumnType_STRING, @@ -65,9 +73,9 @@ func tableDockerHubRepository(_ context.Context) *plugin.Table { func listRepositories(ctx context.Context, d *plugin.QueryData, h *plugin.HydrateData) (interface{}, error) { logger := plugin.Logger(ctx) - user, err := getUserInfo(ctx, d) + // Get namespace from "Quals" if available otherwise use the authenticated user's namespace + namespace, err := getNamespace(ctx, d) if err != nil { - logger.Error("dockerhub_repository.getUserInfo", "error", err) return nil, err } @@ -78,7 +86,7 @@ func listRepositories(ctx context.Context, d *plugin.QueryData, h *plugin.Hydrat return nil, err } - repositories, _, err := client.GetRepositories(user.Name) + repositories, _, err := client.GetRepositories(namespace) if err != nil { logger.Error("dockerhub_repository.listRepositories", "api_error", err) return nil, err @@ -90,3 +98,23 @@ func listRepositories(ctx context.Context, d *plugin.QueryData, h *plugin.Hydrat return nil, nil } + +func getNamespace(ctx context.Context, d *plugin.QueryData) (string, error) { + logger := plugin.Logger(ctx) + + if d.Quals["namespace"] != nil { + for _, q := range d.Quals["namespace"].Quals { + if q.Operator == "=" { + return q.Value.GetStringValue(), nil + } + } + } + + user, err := getUserInfo(ctx, d) + if err != nil { + logger.Error("dockerhub_repository.getUserInfo", "error", err) + return "", err + } + + return user.Name, nil +} diff --git a/dockerhub/table_dockerhub_tag.go b/dockerhub/table_dockerhub_tag.go index 38b7f7e..400e069 100644 --- a/dockerhub/table_dockerhub_tag.go +++ b/dockerhub/table_dockerhub_tag.go @@ -18,8 +18,17 @@ func tableDockerHubTag(_ context.Context) *plugin.Table { List: &plugin.ListConfig{ ParentHydrate: listRepositories, Hydrate: listTags, + KeyColumns: []*plugin.KeyColumn{ + {Name: "namespace", Require: plugin.Optional, Operators: []string{"="}}, + }, }, Columns: commonColumns([]*plugin.Column{ + { + Name: "namespace", + Type: proto.ColumnType_STRING, + Description: "Namespace of the repository.", + Transform: transform.FromQual("namespace"), + }, { Name: "name", Type: proto.ColumnType_STRING, diff --git a/docs/tables/dockerhub_repository.md b/docs/tables/dockerhub_repository.md index b77ef93..1ae4f35 100644 --- a/docs/tables/dockerhub_repository.md +++ b/docs/tables/dockerhub_repository.md @@ -11,6 +11,10 @@ DockerHub is a cloud-based registry service that allows you to link to code repo The `dockerhub_repository` table provides insights into repositories within DockerHub. As a DevOps engineer, explore repository-specific details through this table, including repository name, description, star count, pull count, and last updated date. Utilize it to uncover information about repositories, such as those with high pull counts, the most starred repositories, and recently updated repositories. +## Specify a namespace + +The `namespace` column in the `dockerhub_repository` table represents the repository namespace. By default, the namespace is set to the name of the authenticated user. To query repositories in a different namespace (e.g. `turbot` or `library`), you can specify the namespace in the `where` clause. + ## Examples ### Basic info @@ -67,6 +71,35 @@ where is_private = 1; ``` +### List public repositories owned by a different account +Explore public repositories on DockerHub which are not owned by the authenticated user and can be accessed by anyone. This query can help you get detailed information about public repositories in a specific namespace. + +```sql+postgres +select + name, + pull_count, + star_count, + is_private, + last_updated +from + dockerhub_repository +where + namespace = 'turbot'; +``` + +```sql+sqlite +select + name, + pull_count, + star_count, + is_private, + last_updated +from + dockerhub_repository +where + namespace = 'turbot'; +``` + ### List repositories with no pulls or downloads Explore which Docker repositories have not been pulled or downloaded. This can help identify unused or less-popular repositories, enabling you to better manage your resources and focus on active repositories. diff --git a/docs/tables/dockerhub_tag.md b/docs/tables/dockerhub_tag.md index e1d84cb..763bb99 100644 --- a/docs/tables/dockerhub_tag.md +++ b/docs/tables/dockerhub_tag.md @@ -11,6 +11,10 @@ DockerHub is a cloud-based registry service that allows you to link to code repo The `dockerhub_tag` table provides insights into the tags within DockerHub repositories. As a DevOps engineer, you can explore tag-specific details through this table, including the associated DockerHub repository, the tag name, and its manifest. Utilize this table to manage and monitor your DockerHub repositories, ensuring that all tags are up-to-date and follow your organization's naming conventions. +## Specify a namespace + +The `namespace` column in the `dockerhub_tag` table represents the repository namespace. By default, the namespace is set to the name of the authenticated user. To query tags in a different namespace (e.g. `turbot` or `library`), you can specify the namespace in the `where` clause. + ## Examples ### Basic info @@ -71,6 +75,39 @@ where name like 'souravthe/test%'; ``` +### List tags which are from a particular repository owned by a different account +Discover the segments that are from a specific repository, allowing you to analyze the status, last update, and size of these segments. This can be useful to get detailed information about public repositories in a specific namespace. + +```sql+postgres +select + name, + status, + last_updater_user_name, + last_pushed, + last_pulled, + full_size +from + dockerhub_tag +where + namespace = 'turbot' + and name like 'turbot/steampipe:0.21%'; +``` + +```sql+sqlite +select + name, + status, + last_updater_user_name, + last_pushed, + last_pulled, + full_size +from + dockerhub_tag +where + namespace = 'turbot' + and name like 'turbot/steampipe:0.21%'; +``` + ### List tags with no pulls or downloads Discover the segments that contain tags with no pulls or downloads in order to identify potentially unused or unpopular resources. This can be useful in optimizing resource allocation and improving overall system efficiency. From 95ea6fbc39ca6b809192bbdb70507cbdcd261d26 Mon Sep 17 00:00:00 2001 From: hebestreit Date: Wed, 4 Sep 2024 10:21:58 +0200 Subject: [PATCH 2/2] Derived namespace from first part of the repository name instead of using the qualifier --- dockerhub/table_dockerhub_repository.go | 9 ++++++++- dockerhub/table_dockerhub_tag.go | 9 +++++++-- dockerhub/utils.go | 14 ++++++++++++-- 3 files changed, 27 insertions(+), 5 deletions(-) diff --git a/dockerhub/table_dockerhub_repository.go b/dockerhub/table_dockerhub_repository.go index 08ea2e7..b67a880 100644 --- a/dockerhub/table_dockerhub_repository.go +++ b/dockerhub/table_dockerhub_repository.go @@ -2,6 +2,7 @@ package dockerhub import ( "context" + "github.com/docker/hub-tool/pkg/hub" "github.com/turbot/steampipe-plugin-sdk/v5/grpc/proto" "github.com/turbot/steampipe-plugin-sdk/v5/plugin" "github.com/turbot/steampipe-plugin-sdk/v5/plugin/transform" @@ -24,7 +25,7 @@ func tableDockerHubRepository(_ context.Context) *plugin.Table { Name: "namespace", Type: proto.ColumnType_STRING, Description: "Namespace of the repository.", - Transform: transform.FromQual("namespace"), + Transform: transform.From(fetchNamespaceFromRepository), }, { Name: "name", @@ -118,3 +119,9 @@ func getNamespace(ctx context.Context, d *plugin.QueryData) (string, error) { return user.Name, nil } + +func fetchNamespaceFromRepository(_ context.Context, d *transform.TransformData) (interface{}, error) { + repository := d.HydrateItem.(hub.Repository) + namespace, _ := splitRepositoryName(repository.Name) + return namespace, nil +} diff --git a/dockerhub/table_dockerhub_tag.go b/dockerhub/table_dockerhub_tag.go index 400e069..dac452e 100644 --- a/dockerhub/table_dockerhub_tag.go +++ b/dockerhub/table_dockerhub_tag.go @@ -2,7 +2,6 @@ package dockerhub import ( "context" - "github.com/docker/hub-tool/pkg/hub" "github.com/turbot/steampipe-plugin-sdk/v5/grpc/proto" "github.com/turbot/steampipe-plugin-sdk/v5/plugin" @@ -27,7 +26,7 @@ func tableDockerHubTag(_ context.Context) *plugin.Table { Name: "namespace", Type: proto.ColumnType_STRING, Description: "Namespace of the repository.", - Transform: transform.FromQual("namespace"), + Transform: transform.From(fetchNamespaceFromTag), }, { Name: "name", @@ -107,3 +106,9 @@ func listTags(ctx context.Context, d *plugin.QueryData, h *plugin.HydrateData) ( return nil, nil } + +func fetchNamespaceFromTag(_ context.Context, d *transform.TransformData) (interface{}, error) { + tag := d.HydrateItem.(hub.Tag) + namespace, _ := splitRepositoryName(tag.Name) + return namespace, nil +} diff --git a/dockerhub/utils.go b/dockerhub/utils.go index 6fbdce8..f7c9293 100644 --- a/dockerhub/utils.go +++ b/dockerhub/utils.go @@ -3,10 +3,10 @@ package dockerhub import ( "context" "errors" - "os" - "github.com/docker/hub-tool/pkg/hub" "github.com/turbot/steampipe-plugin-sdk/v5/plugin" + "os" + "strings" ) func getClient(ctx context.Context, d *plugin.QueryData) (*hub.Client, error) { @@ -91,3 +91,13 @@ func GetUserInfoUncached(ctx context.Context, d *plugin.QueryData, _ *plugin.Hyd return user, nil } + +// split the repository name into namespace and repository name +func splitRepositoryName(repository string) (string, string) { + parts := strings.Split(repository, "/") + if len(parts) > 1 { + return parts[0], parts[1] + } + + return "", repository +}