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

Cli: add profiles #371

Merged
merged 5 commits into from
Sep 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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 conf/cli.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,4 @@

webServiceUrl: http://localhost:8090
apiGatewayUrl: ws://localhost:8091
tenant: default
tenant: default
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ public String tenantAppPath(String uri) {
final String tenant = configuration.getTenant();
if (tenant == null) {
throw new IllegalStateException(
"Tenant not set. Run 'langstream configure tenant <tenant>' to set it.");
"Tenant not set. Please set the tenant in the configuration.");
}
logger.debug("Using tenant: %s".formatted(tenant));
return "/applications/%s%s".formatted(tenant, uri);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,16 @@
*/
package ai.langstream.cli;

import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.Map;
import java.util.TreeMap;
import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
public class LangStreamCLIConfig {
public class LangStreamCLIConfig extends Profile {

@JsonProperty(required = true)
private String webServiceUrl;
private Map<String, NamedProfile> profiles = new TreeMap<>();

private String apiGatewayUrl;

private String tenant;

private String token;
private String currentProfile = "default";
}
26 changes: 26 additions & 0 deletions langstream-cli/src/main/java/ai/langstream/cli/NamedProfile.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*
* Copyright DataStax, Inc.
*
* 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 ai.langstream.cli;

import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
public class NamedProfile extends Profile {

private String name;
}
32 changes: 32 additions & 0 deletions langstream-cli/src/main/java/ai/langstream/cli/Profile.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* Copyright DataStax, Inc.
*
* 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 ai.langstream.cli;

import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
public class Profile {

@JsonProperty(required = true)
private String webServiceUrl;

private String apiGatewayUrl;
private String tenant;
private String token;
}
103 changes: 82 additions & 21 deletions langstream-cli/src/main/java/ai/langstream/cli/commands/BaseCmd.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
import ai.langstream.admin.client.AdminClientConfiguration;
import ai.langstream.admin.client.AdminClientLogger;
import ai.langstream.cli.LangStreamCLIConfig;
import ai.langstream.cli.NamedProfile;
import ai.langstream.cli.commands.profiles.BaseProfileCmd;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectWriter;
Expand All @@ -28,7 +30,8 @@
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.BiFunction;
import java.util.function.Consumer;
Expand All @@ -44,7 +47,8 @@ public enum Formats {
yaml
}

private static final ObjectMapper yamlConfigReader = new ObjectMapper(new YAMLFactory());
protected static final ObjectMapper yamlConfigReader = new ObjectMapper(new YAMLFactory());
protected static final ObjectMapper jsonConfigReader = new ObjectMapper();
protected static final ObjectMapper jsonPrinter =
new ObjectMapper()
.enable(SerializationFeature.INDENT_OUTPUT)
Expand Down Expand Up @@ -81,7 +85,7 @@ public void debug(Object message) {
BaseCmd.this.debug(message);
}
};
client = new AdminClient(toAdminConfiguration(getConfig()), logger);
client = new AdminClient(toAdminConfiguration(), logger);
}
return client;
}
Expand All @@ -91,11 +95,45 @@ protected LangStreamCLIConfig getConfig() {
return config;
}

private static AdminClientConfiguration toAdminConfiguration(LangStreamCLIConfig config) {
protected NamedProfile getDefaultProfile() {
final LangStreamCLIConfig config = getConfig();
final NamedProfile defaultProfile = new NamedProfile();
defaultProfile.setName(BaseProfileCmd.DEFAULT_PROFILE_NAME);
defaultProfile.setTenant(config.getTenant());
defaultProfile.setToken(config.getToken());
defaultProfile.setWebServiceUrl(config.getWebServiceUrl());
defaultProfile.setApiGatewayUrl(config.getApiGatewayUrl());
return defaultProfile;
}

protected NamedProfile getCurrentProfile() {
final String profile;
if (getRootCmd().getProfile() != null) {
profile = getRootCmd().getProfile();
} else {
profile = getConfig().getCurrentProfile();
}
if (BaseProfileCmd.DEFAULT_PROFILE_NAME.equals(profile)) {
return getDefaultProfile();
}
final NamedProfile result = getConfig().getProfiles().get(profile);
if (result == null) {
throw new IllegalStateException(
"No profile '%s' defined in configuration".formatted(profile));
}
return result;
}

private AdminClientConfiguration toAdminConfiguration() {
final NamedProfile profile = getCurrentProfile();
if (profile.getWebServiceUrl() == null) {
throw new IllegalStateException(
"No webServiceUrl defined for profile '%s'".formatted(profile.getName()));
}
return AdminClientConfiguration.builder()
.webServiceUrl(config.getWebServiceUrl())
.token(config.getToken())
.tenant(config.getTenant())
.webServiceUrl(profile.getWebServiceUrl())
.token(profile.getToken())
.tenant(profile.getTenant())
.build();
}

Expand Down Expand Up @@ -187,34 +225,41 @@ protected void print(
case raw:
default:
{
printRawHeader(columnsForRaw);
List<String[]> rows = new ArrayList<>();

rows.add(prepareHeaderRow(columnsForRaw));
if (readValue.isArray()) {
readValue
.elements()
.forEachRemaining(
element ->
printRawRow(element, columnsForRaw, valueSupplier));
rows.add(
prepareRawRow(
element,
columnsForRaw,
valueSupplier)));
} else {
printRawRow(readValue, columnsForRaw, valueSupplier);
rows.add(prepareRawRow(readValue, columnsForRaw, valueSupplier));
}
printRows(rows);
break;
}
}
}

private void printRawHeader(String[] columnsForRaw) {
final String template = computeFormatTemplate(columnsForRaw.length);
final Object[] columns = Arrays.stream(columnsForRaw).map(String::toUpperCase).toArray();
final String header = String.format(template, columns);
log(header);
private String[] prepareHeaderRow(String[] columnsForRaw) {
String[] result = new String[columnsForRaw.length];
for (int i = 0; i < columnsForRaw.length; i++) {
result[i] = columnsForRaw[i].toUpperCase();
}
return result;
}

private void printRawRow(
private String[] prepareRawRow(
JsonNode readValue,
String[] columnsForRaw,
BiFunction<JsonNode, String, Object> valueSupplier) {
final int numColumns = columnsForRaw.length;
String formatTemplate = computeFormatTemplate(numColumns);

String[] row = new String[numColumns];
for (int i = 0; i < numColumns; i++) {
Expand All @@ -237,17 +282,33 @@ private void printRawRow(
}
row[i] = strColumn;
}
final String result = String.format(formatTemplate, row);
log(result);
return row;
}

private void printRows(List<String[]> rows) {

int countMax = 0;

for (String[] row : rows) {
for (int i = 0; i < row.length; i++) {
countMax = Math.max(countMax, row[i].length());
}
}
String formatTemplate = computeFormatTemplate(rows.get(0).length, countMax);

for (String[] row : rows) {
final String result = String.format(formatTemplate, row);
log(result);
}
}

private String computeFormatTemplate(int numColumns) {
private String computeFormatTemplate(int numColumns, int width) {
StringBuilder formatTemplate = new StringBuilder();
for (int i = 0; i < numColumns; i++) {
if (i > 0) {
formatTemplate.append(" ");
}
formatTemplate.append("%-15.15s");
formatTemplate.append("%-" + width + "." + width + "s");
}
return formatTemplate.toString();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
ConfigureCmd.class,
RootTenantCmd.class,
RootGatewayCmd.class,
RootProfileCmd.class,
AutoComplete.GenerateCompletion.class
})
public class RootCmd {
Expand All @@ -41,6 +42,12 @@ public class RootCmd {
@Getter
private String configPath;

@CommandLine.Option(
names = {"-p", "--profile"},
description = "Profile to use with the command.")
@Getter
private String profile;

@CommandLine.Option(
names = {"-v", "--verbose"},
defaultValue = "false",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* Copyright DataStax, Inc.
*
* 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 ai.langstream.cli.commands;

import ai.langstream.cli.commands.profiles.CreateUpdateProfileCmd;
import ai.langstream.cli.commands.profiles.DeleteProfileCmd;
import ai.langstream.cli.commands.profiles.GetCurrentProfileCmd;
import ai.langstream.cli.commands.profiles.GetProfileCmd;
import ai.langstream.cli.commands.profiles.ImportProfileCmd;
import ai.langstream.cli.commands.profiles.ListProfileCmd;
import ai.langstream.cli.commands.profiles.SetCurrentProfileCmd;
import lombok.Getter;
import picocli.CommandLine;

@CommandLine.Command(
name = "profiles",
header = "Manage local profiles",
subcommands = {
CreateUpdateProfileCmd.CreateProfileCmd.class,
CreateUpdateProfileCmd.UpdateProfileCmd.class,
ListProfileCmd.class,
GetCurrentProfileCmd.class,
SetCurrentProfileCmd.class,
GetProfileCmd.class,
ImportProfileCmd.class,
DeleteProfileCmd.class
})
@Getter
public class RootProfileCmd {
@CommandLine.ParentCommand private RootCmd rootCmd;
}
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ public void run() {
}
}
if (filename == null) {
filename = "%s-%s.zip".formatted(getConfig().getTenant(), applicationId);
filename = "%s-%s.zip".formatted(getCurrentProfile().getTenant(), applicationId);
}
path = Path.of(filename);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,16 @@

import ai.langstream.cli.commands.BaseCmd;
import ai.langstream.cli.commands.RootCmd;
import ai.langstream.cli.commands.profiles.BaseProfileCmd;
import java.util.Arrays;
import lombok.Getter;
import lombok.SneakyThrows;
import picocli.CommandLine;

@CommandLine.Command(name = "configure", header = "Configure LangStream tenant and authentication")
@CommandLine.Command(
name = "configure",
header =
"Configure LangStream tenant and authentication. DEPRECATED. Use 'langstream profiles' instead.")
@Getter
public class ConfigureCmd extends BaseCmd {

Expand All @@ -44,6 +48,9 @@ public enum ConfigKey {
@Override
@SneakyThrows
public void run() {
if (getRootCmd().getProfile() != null) {
throw new IllegalArgumentException("Global profile flag is not allowed here");
}
updateConfig(
clientConfig -> {
switch (configKey) {
Expand All @@ -56,6 +63,8 @@ public void run() {
.formatted(configKey, Arrays.toString(ConfigKey.values())));
}
});
log("Config updated: %s=%s".formatted(configKey, newValue));
log(
"profile %s updated: %s=%s"
.formatted(BaseProfileCmd.DEFAULT_PROFILE_NAME, configKey, newValue));
}
}
Loading
Loading