Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Data explorer] basic data links operations support #411

Merged
merged 27 commits into from
Aug 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
c1e5160
ignore .env file
weronikasosnowskaseqera May 10, 2024
01c3934
update local tw path in docs
weronikasosnowskaseqera May 10, 2024
b0f58f2
Implement data-links list method
weronikasosnowskaseqera May 21, 2024
ea8fb46
WIP: add --wait flag and tests
weronikasosnowskaseqera May 22, 2024
a660306
fix tests
weronikasosnowskaseqera May 22, 2024
a171d44
fix linter issues
weronikasosnowskaseqera May 22, 2024
9a521c9
cleanup + tw script changes for zsh
weronikasosnowskaseqera May 22, 2024
243fb75
wip: initial add setup cmd
weronikasosnowskaseqera May 23, 2024
faeaa66
add visibility parameter and null safe calls
weronikasosnowskaseqera May 24, 2024
d94af64
Merge branch 'task/405-list-data-links-support' into task/406-data-ex…
weronikasosnowskaseqera May 24, 2024
cfa0828
add test and license comments
weronikasosnowskaseqera May 24, 2024
93a72be
Implement delete custom data links
weronikasosnowskaseqera May 27, 2024
e55c885
Implement update custom data links
weronikasosnowskaseqera May 27, 2024
5f3bf66
Implement browse data link content
weronikasosnowskaseqera May 28, 2024
cbc5e00
Merge pull request #416 from seqeralabs/task/413-data-explorer-conten…
weronikasosnowskaseqera Jun 10, 2024
20e6e05
Merge pull request #414 from seqeralabs/task/406-data-explorer-create…
weronikasosnowskaseqera Jun 10, 2024
4f376cb
Merge remote-tracking branch 'origin/master' into task/405-list-data-…
weronikasosnowskaseqera Jul 10, 2024
3baa032
Merge remote-tracking branch 'origin/master' into task/405-list-data-…
weronikasosnowskaseqera Jul 12, 2024
584206c
Fix explorer binary tests
weronikasosnowskaseqera Jul 17, 2024
c6ea1e8
Apply review suggestions
weronikasosnowskaseqera Jul 24, 2024
5653ec8
Apply review suggestions
weronikasosnowskaseqera Jul 24, 2024
412e4c6
fix native tests
weronikasosnowskaseqera Jul 24, 2024
1e164ed
apply review fixes
weronikasosnowskaseqera Jul 25, 2024
d9376c2
apply review fixes
weronikasosnowskaseqera Jul 30, 2024
7c258ee
fix browse without path
weronikasosnowskaseqera Aug 5, 2024
8de0a09
fix credentials reference by name
weronikasosnowskaseqera Aug 5, 2024
12eab71
fix tests
weronikasosnowskaseqera Aug 5, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Ignore Gradle project-specific cache directory
.gradle
.idea

.env
# Ignore Gradle build output directory
build
**/build-info.properties
Expand Down
154 changes: 152 additions & 2 deletions conf/reflect-config.json

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions conf/resource-config.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
"pattern":"\\QMETA-INF/services/org.glassfish.jersey.internal.inject.InjectionManagerFactory\\E"
}, {
"pattern":"\\QMETA-INF/services/org.glassfish.jersey.internal.spi.AutoDiscoverable\\E"
}, {
"pattern":"java.base:\\Qjdk/internal/icu/impl/data/icudt67b/nfc.nrm\\E"
}, {
"pattern":"java.base:\\Qjdk/internal/icu/impl/data/icudt67b/nfkc.nrm\\E"
}, {
Expand Down
2 changes: 2 additions & 0 deletions src/main/java/io/seqera/tower/cli/Tower.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import io.seqera.tower.cli.commands.CollaboratorsCmd;
import io.seqera.tower.cli.commands.ComputeEnvsCmd;
import io.seqera.tower.cli.commands.CredentialsCmd;
import io.seqera.tower.cli.commands.DataLinksCmd;
import io.seqera.tower.cli.commands.DatasetsCmd;
import io.seqera.tower.cli.commands.InfoCmd;
import io.seqera.tower.cli.commands.LaunchCmd;
Expand Down Expand Up @@ -58,6 +59,7 @@
CollaboratorsCmd.class,
ComputeEnvsCmd.class,
CredentialsCmd.class,
DataLinksCmd.class,
DatasetsCmd.class,
GenerateCompletion.class,
InfoCmd.class,
Expand Down
23 changes: 23 additions & 0 deletions src/main/java/io/seqera/tower/cli/commands/AbstractApiCmd.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,10 @@
import io.seqera.tower.cli.exceptions.WorkspaceNotFoundException;
import io.seqera.tower.cli.responses.Response;
import io.seqera.tower.model.ActionQueryAttribute;
import io.seqera.tower.model.ComputeEnvComputeConfig;
import io.seqera.tower.model.ComputeEnvQueryAttribute;
import io.seqera.tower.model.ComputeEnvResponseDto;
import io.seqera.tower.model.Credentials;
import io.seqera.tower.model.ListComputeEnvsResponseEntry;
import io.seqera.tower.model.ListWorkspacesAndOrgResponse;
import io.seqera.tower.model.OrgAndWorkspaceDto;
Expand Down Expand Up @@ -273,6 +275,27 @@ protected ComputeEnvResponseDto primaryComputeEnv(Long workspaceId) throws ApiEx
return api().describeComputeEnv(primaryComputeEnvId, workspaceId, NO_CE_ATTRIBUTES).getComputeEnv();
}

protected String credentialsByRef(ComputeEnvComputeConfig.PlatformEnum type, Long wspId, String credentialsRef) throws ApiException {
List<Credentials> credentials = api().listCredentials(wspId, type == null ? null : type.getValue()).getCredentials();

if (credentials.isEmpty()) {
throw new TowerException("No valid credentials found at the workspace");
}

Credentials cred;

cred = credentials.stream()
.filter(it -> Objects.equals(it.getId(), credentialsRef) || Objects.equals(it.getName(), credentialsRef))
.findFirst()
.orElse(null);

if (cred == null) {
throw new TowerException("No valid credentials found at the workspace");
}

return cred.getId();
}

protected String serverUrl() {
if (serverUrl == null) {
serverUrl = app().url.replaceFirst("api\\.", "").replaceFirst("/api", "");
Expand Down
39 changes: 39 additions & 0 deletions src/main/java/io/seqera/tower/cli/commands/DataLinksCmd.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* Copyright 2021-2023, Seqera.
*
* Licensed 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 io.seqera.tower.cli.commands;

import io.seqera.tower.cli.commands.data.links.AddCmd;
import io.seqera.tower.cli.commands.data.links.DeleteCmd;
import io.seqera.tower.cli.commands.data.links.ListCmd;
import io.seqera.tower.cli.commands.data.links.UpdateCmd;
import io.seqera.tower.cli.commands.data.links.BrowseCmd;
import picocli.CommandLine;

@CommandLine.Command(
name = "data-links",
jimmypoms marked this conversation as resolved.
Show resolved Hide resolved
description = "Manage data links.",
subcommands = {
ListCmd.class,
AddCmd.class,
DeleteCmd.class,
UpdateCmd.class,
BrowseCmd.class
}
)
public class DataLinksCmd extends AbstractRootCmd {
}
Original file line number Diff line number Diff line change
Expand Up @@ -137,27 +137,6 @@ private List<Long> findLabels(Long wspId, List<Label> labels) throws ApiExceptio
}
}

private String credentialsByRef(PlatformEnum type, Long wspId, String credentialsRef) throws ApiException {
List<Credentials> credentials = api().listCredentials(wspId, type.getValue()).getCredentials();

if (credentials.isEmpty()) {
throw new TowerException("No valid credentials found at the workspace");
}

Credentials cred;

cred = credentials.stream()
.filter(it -> Objects.equals(it.getId(), credentialsRef) || Objects.equals(it.getName(), credentialsRef))
.findFirst()
.orElse(null);

if (cred == null) {
throw new TowerException("No valid credentials found at the workspace");
}

return cred.getId();
}

private String findWorkspaceCredentials(PlatformEnum type, Long wspId) throws ApiException {
List<Credentials> credentials = api().listCredentials(wspId, type.getValue()).getCredentials();
if (credentials.isEmpty()) {
Expand Down
92 changes: 92 additions & 0 deletions src/main/java/io/seqera/tower/cli/commands/data/links/AddCmd.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
/*
* Copyright 2021-2023, Seqera.
*
* Licensed 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 io.seqera.tower.cli.commands.data.links;

import io.seqera.tower.ApiException;
import io.seqera.tower.cli.commands.AbstractApiCmd;
import io.seqera.tower.cli.commands.global.WorkspaceOptionalOptions;
import io.seqera.tower.cli.responses.Response;
import io.seqera.tower.cli.responses.data.DataLinkView;
import io.seqera.tower.cli.utils.data.DataLinkProvider;
import io.seqera.tower.model.DataLinkCreateRequest;
import io.seqera.tower.model.DataLinkDto;
import io.seqera.tower.model.DataLinkType;
import picocli.CommandLine;

import java.io.IOException;
import java.util.Objects;

@CommandLine.Command(
name = "add",
description = "Add custom data link."
)
public class AddCmd extends AbstractApiCmd {

@CommandLine.Mixin
public WorkspaceOptionalOptions workspace;

@CommandLine.Option(names = {"-n", "--name"}, description = "Data link name.", required = true)
public String name;

@CommandLine.Option(names = {"-d", "--description"}, description = "Data link description.")
public String description;

@CommandLine.Option(names = {"-u", "--uri"}, description = "Data link uri.", required = true)
public String url;

@CommandLine.Option(names = {"-p", "--provider"}, description = "Data link provider. [aws, azure, google]", required = true)
public DataLinkProvider provider;

@CommandLine.Option(names = {"-c", "--credentials"}, description = "Credentials identifier.")
public String credentialsRef;


@Override
protected Response exec() throws ApiException, IOException {
Long wspId = workspaceId(workspace.workspace);
String credId = credentialsRef != null ? credentialsByRef(null, wspId, credentialsRef) : null;
DataLinkDto created = addDataLink(wspId, name, description, url, provider.name(), credId);

if (Objects.isNull(created)) {
app().getOut().println("Data link creation failed.");
return null;
}

return new DataLinkView(created, "Data link created");
}

DataLinkDto addDataLink(Long wspId, String name, String description, String url, String provider, String credsId) throws ApiException {
DataLinkCreateRequest req = new DataLinkCreateRequest();
req.name(name);
req.description(description);
req.resourceRef(url);
req.type(DataLinkType.BUCKET);
req.provider(io.seqera.tower.model.DataLinkProvider.fromValue(provider.toLowerCase()));

if (Objects.isNull(credsId)) {
req.publicAccessible(true);
} else {
req.publicAccessible(false);
req.credentialsId(credsId);
}

return api().createCustomDataLink(req, wspId);
}


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/*
* Copyright 2021-2023, Seqera.
*
* Licensed 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 io.seqera.tower.cli.commands.data.links;

import io.seqera.tower.ApiException;
import io.seqera.tower.StringUtil;
import io.seqera.tower.cli.commands.AbstractApiCmd;
import io.seqera.tower.cli.commands.global.WorkspaceOptionalOptions;
import io.seqera.tower.cli.responses.Response;
import io.seqera.tower.cli.responses.data.DataLinkContentList;
import io.seqera.tower.model.DataLinkContentResponse;
import io.seqera.tower.model.DataLinkDto;
import picocli.CommandLine;

import java.io.IOException;

@CommandLine.Command(
name = "browse",
description = "Browse content of data link."
)
public class BrowseCmd extends AbstractApiCmd {

@CommandLine.Mixin
public WorkspaceOptionalOptions workspace;

@CommandLine.Option(names = {"-i", "--id"}, description = "Data link id.", required = true)
public String id;

@CommandLine.Option(names = {"-c", "--credentials"}, description = "Credentials identifier.")
public String credentialsRef;

@CommandLine.Option(names = {"-p", "--path"}, description = "Path to the folder to browse.")
public String path;

@CommandLine.Option(names = {"-f", "--filter"}, description = "Filter files with the given prefix.")
public String startsWith;

@CommandLine.Option(names = {"-t", "--token"}, description = "Next page token to fetch next page.")
public String nextPageToken;

@CommandLine.Option(names = {"--page"}, description = "Pages to display [default: null].")
public Integer page;

@Override
protected Response exec() throws ApiException, IOException {
Long wspId = workspaceId(workspace.workspace);
String credId = credentialsRef != null ? credentialsByRef(null, wspId, credentialsRef) : null;
DataLinkDto dataLink = api().describeDataLink(id, wspId, credId).getDataLink();
DataLinkContentResponse response;

if (path != null)
response = api().exploreDataLink1(id, path, wspId, credId, startsWith, nextPageToken, page);
else
response = api().exploreDataLink(id, wspId, credId, startsWith, nextPageToken, page);

return new DataLinkContentList(dataLink, path, response.getObjects(), response.getNextPageToken());
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
* Copyright 2021-2023, Seqera.
*
* Licensed 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 io.seqera.tower.cli.commands.data.links;

import io.seqera.tower.ApiException;
import io.seqera.tower.cli.commands.AbstractApiCmd;
import io.seqera.tower.cli.commands.global.WorkspaceOptionalOptions;
import io.seqera.tower.cli.responses.Response;
import io.seqera.tower.cli.responses.data.DataLinkDeleted;
import picocli.CommandLine;

import java.io.IOException;

@CommandLine.Command(
name = "delete",
description = "Delete custom data link."
)
public class DeleteCmd extends AbstractApiCmd {

@CommandLine.Mixin
public WorkspaceOptionalOptions workspace;

@CommandLine.Option(names = {"-i", "--id"}, description = "Data link id.", required = true)
public String id;

@Override
protected Response exec() throws ApiException, IOException {
Long wspId = workspaceId(workspace.workspace);

api().deleteCustomDataLink(id, wspId);
return new DataLinkDeleted(id, wspId);
}
}
Loading
Loading