diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/configurations/DeploymentProperties.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/configurations/DeploymentProperties.java new file mode 100644 index 0000000000..7d7ab93cfb --- /dev/null +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/configurations/DeploymentProperties.java @@ -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); + } +} diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/configurations/DeploymentPropertiesCE.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/configurations/DeploymentPropertiesCE.java new file mode 100644 index 0000000000..71a8c44bf5 --- /dev/null +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/configurations/DeploymentPropertiesCE.java @@ -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()); + } + } +} diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/dtos/DeploymentInfo.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/dtos/DeploymentInfo.java new file mode 100644 index 0000000000..30cb10b441 --- /dev/null +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/dtos/DeploymentInfo.java @@ -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; +} diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/AnalyticsServiceImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/AnalyticsServiceImpl.java index 2e8d62594d..22073d5952 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/AnalyticsServiceImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/AnalyticsServiceImpl.java @@ -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); } } diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/AnalyticsServiceCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/AnalyticsServiceCEImpl.java index dac31cc330..ffd6f9d87b 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/AnalyticsServiceCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/AnalyticsServiceCEImpl.java @@ -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; diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/PingScheduledTaskImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/PingScheduledTaskImpl.java index 660afe2e75..f371993bcd 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/PingScheduledTaskImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/PingScheduledTaskImpl.java @@ -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); } diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/ce/PingScheduledTaskCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/ce/PingScheduledTaskCEImpl.java index 69df56eded..1c0b28bf1e 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/ce/PingScheduledTaskCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/solutions/ce/PingScheduledTaskCEImpl.java @@ -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 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); }) diff --git a/deploy/docker/fs/opt/appsmith/entrypoint.sh b/deploy/docker/fs/opt/appsmith/entrypoint.sh index 9caab57e08..3f30e7a522 100644 --- a/deploy/docker/fs/opt/appsmith/entrypoint.sh +++ b/deploy/docker/fs/opt/appsmith/entrypoint.sh @@ -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 "$@" diff --git a/deploy/docker/fs/opt/appsmith/generate-infra-details.sh b/deploy/docker/fs/opt/appsmith/generate-infra-details.sh new file mode 100755 index 0000000000..34281ee40b --- /dev/null +++ b/deploy/docker/fs/opt/appsmith/generate-infra-details.sh @@ -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