[ops]: get infra details (#32552)

Outputs on having the container up and running

On kubernetes:
```
root@ce32552-appsmith-66fc68d7f-97tjn:/opt/appsmith# cat /tmp/appsmith/infra.json
{"cloudProvider":"amazon","Tool":"kubernetes","EFS":"present","Hostname":"ce32552-appsmith-66fc68d7f-97tjn"}
```

On local setup:
```
root@26327db8d65a:/opt/appsmith# cat /tmp/appsmith/infra.json
{"cloudProvider":"local","Tool":"docker","EFS":"absent","Hostname":"26327db8d65a"}
```

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **New Features**
- Introduced infrastructure detection to enhance system insights,
including cloud provider, deployment tools, and host details.
- Enhanced analytics by incorporating deployment properties into event
tracking.

- **Refactor**
- Modified server configuration and initialization to integrate new
deployment properties.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Trisha Anand <trisha@appsmith.com>
This commit is contained in:
Goutham Pratapa 2024-04-26 18:56:45 +05:30 committed by GitHub
parent fe1839a132
commit 947add2f20
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 185 additions and 21 deletions

View File

@ -0,0 +1,13 @@
package com.appsmith.server.configurations;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.Getter;
import org.springframework.context.annotation.Configuration;
@Configuration
@Getter
public class DeploymentProperties extends DeploymentPropertiesCE {
public DeploymentProperties(ObjectMapper objectMapper) {
super(objectMapper);
}
}

View File

@ -0,0 +1,45 @@
package com.appsmith.server.configurations;
import com.appsmith.server.dtos.DeploymentInfo;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
@Getter
@Slf4j
public class DeploymentPropertiesCE {
private final String INFO_JSON_PATH = "/tmp/appsmith/infra.json";
private String cloudProvider;
private String tool;
private String efs;
private String hostname;
private String deployedAt;
public String getEdition() {
return "CE";
}
public DeploymentPropertiesCE(ObjectMapper objectMapper) {
try {
Path infoJsonPath = Paths.get(INFO_JSON_PATH);
if (Files.exists(infoJsonPath)) {
String jsonContent = Files.readString(infoJsonPath);
// Parse JSON content using the AppsmithInfo class
DeploymentInfo deploymentInfo = objectMapper.readValue(jsonContent, DeploymentInfo.class);
cloudProvider = deploymentInfo.getCloudProvider();
tool = deploymentInfo.getTool();
efs = deploymentInfo.getEfs();
hostname = deploymentInfo.getHostname();
deployedAt = deploymentInfo.getCurrentTime();
}
} catch (IOException e) {
log.debug("Error reading deployment properties from {} {}", INFO_JSON_PATH, e.getMessage());
}
}
}

View File

@ -0,0 +1,14 @@
package com.appsmith.server.dtos;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import lombok.Data;
@Data
@JsonIgnoreProperties(ignoreUnknown = true)
public class DeploymentInfo {
private String cloudProvider;
private String tool;
private String efs;
private String hostname;
private String currentTime;
}

View File

@ -1,6 +1,7 @@
package com.appsmith.server.services;
import com.appsmith.server.configurations.CommonConfig;
import com.appsmith.server.configurations.DeploymentProperties;
import com.appsmith.server.configurations.ProjectProperties;
import com.appsmith.server.helpers.UserUtils;
import com.appsmith.server.repositories.UserDataRepository;
@ -22,7 +23,8 @@ public class AnalyticsServiceImpl extends AnalyticsServiceCEImpl implements Anal
ConfigService configService,
UserUtils userUtils,
ProjectProperties projectProperties,
UserDataRepository userDataRepository) {
UserDataRepository userDataRepository,
DeploymentProperties deploymentProperties) {
super(
analytics,
sessionUserService,
@ -30,6 +32,7 @@ public class AnalyticsServiceImpl extends AnalyticsServiceCEImpl implements Anal
configService,
userUtils,
projectProperties,
deploymentProperties,
userDataRepository);
}
}

View File

@ -5,6 +5,7 @@ import com.appsmith.external.helpers.Identifiable;
import com.appsmith.external.models.ActionDTO;
import com.appsmith.external.models.BaseDomain;
import com.appsmith.server.configurations.CommonConfig;
import com.appsmith.server.configurations.DeploymentProperties;
import com.appsmith.server.configurations.ProjectProperties;
import com.appsmith.server.constants.FieldName;
import com.appsmith.server.domains.NewPage;
@ -50,6 +51,7 @@ public class AnalyticsServiceCEImpl implements AnalyticsServiceCE {
private final UserUtils userUtils;
private final ProjectProperties projectProperties;
private final DeploymentProperties deploymentProperties;
private final UserDataRepository userDataRepository;
@ -61,6 +63,7 @@ public class AnalyticsServiceCEImpl implements AnalyticsServiceCE {
ConfigService configService,
UserUtils userUtils,
ProjectProperties projectProperties,
DeploymentProperties deploymentProperties,
UserDataRepository userDataRepository) {
this.analytics = analytics;
this.sessionUserService = sessionUserService;
@ -68,6 +71,7 @@ public class AnalyticsServiceCEImpl implements AnalyticsServiceCE {
this.configService = configService;
this.userUtils = userUtils;
this.projectProperties = projectProperties;
this.deploymentProperties = deploymentProperties;
this.userDataRepository = userDataRepository;
}
@ -255,6 +259,13 @@ public class AnalyticsServiceCEImpl implements AnalyticsServiceCE {
analyticsProperties.put("originService", "appsmith-server");
analyticsProperties.put("instanceId", instanceId);
analyticsProperties.put("version", projectProperties.getVersion());
analyticsProperties.put("edition", deploymentProperties.getEdition());
analyticsProperties.put("cloudProvider", deploymentProperties.getCloudProvider());
analyticsProperties.put("efs", deploymentProperties.getEfs());
analyticsProperties.put("tool", deploymentProperties.getTool());
analyticsProperties.put("hostname", deploymentProperties.getHostname());
analyticsProperties.put("deployedAt", deploymentProperties.getDeployedAt());
messageBuilder = messageBuilder.properties(analyticsProperties);
analytics.enqueue(messageBuilder);
return instanceId;

View File

@ -1,6 +1,7 @@
package com.appsmith.server.solutions;
import com.appsmith.server.configurations.CommonConfig;
import com.appsmith.server.configurations.DeploymentProperties;
import com.appsmith.server.configurations.ProjectProperties;
import com.appsmith.server.configurations.SegmentConfig;
import com.appsmith.server.helpers.NetworkUtils;
@ -38,9 +39,9 @@ public class PingScheduledTaskImpl extends PingScheduledTaskCEImpl implements Pi
DatasourceRepository datasourceRepository,
UserRepository userRepository,
ProjectProperties projectProperties,
DeploymentProperties deploymentProperties,
NetworkUtils networkUtils,
PermissionGroupService permissionGroupService) {
super(
configService,
segmentConfig,
@ -52,6 +53,7 @@ public class PingScheduledTaskImpl extends PingScheduledTaskCEImpl implements Pi
datasourceRepository,
userRepository,
projectProperties,
deploymentProperties,
networkUtils,
permissionGroupService);
}

View File

@ -2,6 +2,7 @@ package com.appsmith.server.solutions.ce;
import com.appsmith.server.acl.AclPermission;
import com.appsmith.server.configurations.CommonConfig;
import com.appsmith.server.configurations.DeploymentProperties;
import com.appsmith.server.configurations.ProjectProperties;
import com.appsmith.server.configurations.SegmentConfig;
import com.appsmith.server.helpers.NetworkUtils;
@ -28,9 +29,11 @@ import reactor.util.function.Tuple6;
import java.util.Map;
import static java.util.Map.entry;
/**
* This class represents a scheduled task that pings a data point indicating that this server installation is live.
* This ping is only invoked if the Appsmith server is NOT running in Appsmith Clouud & the user has given Appsmith
* This ping is only invoked if the Appsmith server is NOT running in Appsmith Cloud & the user has given Appsmith
* permissions to collect anonymized data
*/
@Slf4j
@ -49,6 +52,7 @@ public class PingScheduledTaskCEImpl implements PingScheduledTaskCE {
private final DatasourceRepository datasourceRepository;
private final UserRepository userRepository;
private final ProjectProperties projectProperties;
private final DeploymentProperties deploymentProperties;
private final NetworkUtils networkUtils;
private final PermissionGroupService permissionGroupService;
@ -144,6 +148,23 @@ public class PingScheduledTaskCEImpl implements PingScheduledTaskCE {
applicationRepository.getAllApplicationsCountAccessibleToARoleWithPermission(
AclPermission.READ_APPLICATIONS, publicPermissionGroupId)))
.flatMap(statsData -> {
Map<String, String> propertiesMap = Map.ofEntries(
entry("instanceId", statsData.getT1()),
entry("numOrgs", statsData.getT3().getT1().toString()),
entry("numApps", statsData.getT3().getT2().toString()),
entry("numPages", statsData.getT3().getT3().toString()),
entry("numActions", statsData.getT3().getT4().toString()),
entry("numDatasources", statsData.getT3().getT5().toString()),
entry("numUsers", statsData.getT3().getT6().toString()),
entry("numPublicApps", statsData.getT4().toString()),
entry("version", projectProperties.getVersion()),
entry("edition", deploymentProperties.getEdition()),
entry("cloudProvider", deploymentProperties.getCloudProvider()),
entry("efs", deploymentProperties.getEfs()),
entry("tool", deploymentProperties.getTool()),
entry("hostname", deploymentProperties.getHostname()),
entry("deployedAt", deploymentProperties.getDeployedAt()));
final String ipAddress = statsData.getT2();
return WebClientUtils.create("https://api.segment.io")
.post()
@ -151,25 +172,14 @@ public class PingScheduledTaskCEImpl implements PingScheduledTaskCE {
.headers(headers -> headers.setBasicAuth(ceKey, ""))
.contentType(MediaType.APPLICATION_JSON)
.body(BodyInserters.fromValue(Map.of(
"userId", statsData.getT1(),
"context", Map.of("ip", ipAddress),
"userId",
statsData.getT1(),
"context",
Map.of("ip", ipAddress),
"properties",
Map.of(
"instanceId", statsData.getT1(),
"numOrgs", statsData.getT3().getT1(),
"numApps", statsData.getT3().getT2(),
"numPages",
statsData.getT3().getT3(),
"numActions",
statsData.getT3().getT4(),
"numDatasources",
statsData.getT3().getT5(),
"numUsers",
statsData.getT3().getT6(),
"numPublicApps", statsData.getT4(),
"version", projectProperties.getVersion(),
"edition", ProjectProperties.EDITION),
"event", "instance_stats")))
propertiesMap,
"event",
"instance_stats")))
.retrieve()
.bodyToMono(String.class);
})

View File

@ -462,6 +462,10 @@ print_appsmith_info(){
tr '\n' ' ' < /opt/appsmith/info.json
}
function capture_infra_details(){
bash /opt/appsmith/generate-infra-details.sh || true
}
# Main Section
print_appsmith_info
init_loading_pages
@ -499,6 +503,7 @@ export APPSMITH_LOG_DIR="${APPSMITH_LOG_DIR:-/appsmith-stacks/logs}"
mkdir -p "$APPSMITH_LOG_DIR"/{supervisor,backend,cron,editor,rts,mongodb,redis,postgres,appsmithctl}
setup_auto_heal
capture_infra_details
# Handle CMD command
exec "$@"

View File

@ -0,0 +1,61 @@
#!/usr/bin/env bash
set -e
infra_file="$TMP/infra.json"
mount_path="/appsmith-stacks"
## Get cloudProvider details
function get_cloud_provider() {
release_details=$(uname -r)
if [[ $release_details == *"amzn"* ]];then
cloud_provider="amazon";
elif [[ $release_details == *"azure"* ]];then
cloud_provider="azure";
elif [[ $release_details == *"cloud"* ]];then
cloud_provider="gcp";
else
cloud_provider="local";
fi
}
## Get deployment tool details
function get_tool() {
if [[ -z "${KUBERNETES_SERVICE_HOST}" ]]; then
dep_tool="docker";
else
dep_tool="kubernetes";
fi
}
## Check if EFS is mounted
function check_for_efs() {
findmnt --mountpoint $mount_path | grep nfs && {
efs="present"
} || {
efs="absent"
}
}
## Check hostname
function get_hostname() {
hostname="$(cat /etc/hostname)"
}
## Get current Time
function get_current_time(){
currentTime="$(date -u -Iseconds)"
}
## Main Block
get_cloud_provider
get_tool
get_hostname
check_for_efs
get_current_time
infra_json='{"cloudProvider":"'"$cloud_provider"'","tool":"'"$dep_tool"'","efs":"'"$efs"'","hostname":"'"$hostname"'", "currentTime": "'"$currentTime"'"}'
echo "$infra_json"
echo $infra_json > $infra_file